> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tenderly.co/llms.txt
> Use this file to discover all available pages before exploring further.

# On-Chain Events को कैसे Handle करें

> on-chain events पर प्रतिक्रिया देने के लिए serverless backend के रूप में Web3 Actions का उपयोग करें। game changes की निगरानी के लिए Tic-Tac-Toe उदाहरण का पालन करें।

यह tutorial आपको सिखाएगा कि **Tenderly Web3 Actions का उपयोग करके अपने smart contract के लिए serverless backend कैसे बनाएँ**। Web3 Actions आपको अपने smart contract द्वारा शुरू किए गए on-chain या off-chain events के जवाब में custom code चलाने की अनुमति देते हैं।

यह चित्रित करने के लिए कि Web3 Actions कैसे काम करते हैं, हम एक सरल Tic-Tac-Toe game बनाते हैं और इसे test network पर deploy करते हैं। smart contract game state बनाए रखता है जबकि Web3 Actions game में परिवर्तनों की निगरानी करते हैं।

**जब भी smart contract से कोई विशिष्ट event fire होता है, Tenderly आपका custom code NodeJS project के रूप में execute करेगा**। game के परिणाम और game board को हर बार खिलाड़ी द्वारा move करने पर या game समाप्त होने पर console में print किया जाएगा।

<Info>
  इस project के लिए source code खोजने के लिए इस [Github repo](https://github.com/Tenderly/examples-web3-actions/) को देखें। repo को clone करने और इसके साथ खेलने, या code साथ लिखने के लिए स्वतंत्र महसूस करें।
</Info>

## Web3 Actions को समझना

Smart contracts आपको तब custom code execute करने की अनुमति देते हैं जब कोई event trigger होता है, कोई function invoke होता है, या शायद समय-समय पर।

Tenderly आपको Web3 Actions के साथ इस प्रक्रिया को सुव्यवस्थित करने में मदद करता है। आप अपनी Web3 Actions को एक single Javascript file में लिख सकते हैं या उन्हें NodeJS project के रूप में deploy कर सकते हैं।

**Web3 Actions आपको वे सभी actions करने की अनुमति भी देते हैं जो आप आम तौर पर NodeJS के साथ करते हैं**। यह tutorial आपको दिखाएगा कि अपनी Web3 Actions को deploy करने के लिए Tenderly CLI का उपयोग कैसे करें और यह सुनिश्चित करें कि जब विशिष्ट शर्तें पूरी हों तो वे चलें।

<Note>
  Web3 Actions के बारे में अधिक जानें और [**Web3 Actions की Basics**](/monitoring/web3-actions/tutorials/on-chain-events) के साथ अपने projects में उनका उपयोग कैसे कर सकते हैं इसका अन्वेषण करें।
</Note>

### Project अवलोकन

इस project का उद्देश्य आपको यह दिखाना है कि एक smart contract कैसे deploy करें और कई Javascript functions कैसे लिखें जिन्हें Tenderly किसी event के होने पर invoke करेगा। आप सीखेंगे कि अपनी Web3 Actions को Tenderly की infrastructure पर deploy करने के लिए Tenderly CLI का उपयोग कैसे करें।

यहाँ ऐसा करने का step-by-step अवलोकन है:

1. smart contract को test network पर deploy करें
2. Web3 Actions चलाने के लिए आवश्यक Javascript और config files सेट अप करने के लिए Tenderly CLI का उपयोग करें
3. game events पर प्रतिक्रिया देने वाले functions develop करें
4. उन functions को CLI का उपयोग करके Tenderly की infrastructure पर deploy करें

<Warning>
  इस tutorial के लिए, आपको **Tenderly Dashboard** तक पहुँच की आवश्यकता होगी। यदि आपके पास account नहीं है, तो [**यहाँ मुफ्त में sign up करें**](https://dashboard.tenderly.co/register?utm_source=homepage) (कोई cc भी आवश्यक नहीं)।
</Warning>

## 0: smart contract deploy करें

<Note>
  यदि आप साथ code कर रहे हैं, तो आप इस चरण को skip कर सकते हैं और उस contract का उपयोग कर सकते हैं जिसे हमने [**Tenderly में deploy और verify किया**](https://dashboard.tenderly.co/contract/sepolia/0x1338d7232786b365b0a6bbd06552f885371f5f06)।
</Note>

हम एक pre-written smart contract का उपयोग करते हैं। [**GitHub पर smart contract**](https://github.com/Tenderly/examples-web3-actions/blob/main/tic-tac-toe/TicTacToe.sol) का source code देखें। इस smart contract को इस तरह डिज़ाइन किया गया है कि जब भी game की state में कोई परिवर्तन होता है तो यह events emit करता है।

हमारे सरल Tic-Tac-Toe game में चार संभावित states हो सकती हैं:

* Game start
* Player joins the game
* Player makes a move
* Game over

### पूर्वापेक्षा

**दो Accounts बनाएँ** - किसी भी [Tenderly द्वारा समर्थित network](/platform/supported-networks) पर smart contract deploy करें। ऐसा करने का सबसे सुविधाजनक तरीका [Remix](https://remix.ethereum.org/) और [Metamask](https://metamask.io/) wallet plugin के साथ है। आपको सकारात्मक Ether balance वाले दो accounts की आवश्यकता है। ये accounts दो खिलाड़ियों का प्रतिनिधित्व करेंगे। इस tutorial के प्रयोजन के लिए हम Sepolia का उपयोग करते हैं। यदि आप इस tutorial के साथ चलने की योजना बनाते हैं, तो आप accounts में Ether जोड़ने के लिए [Sepolia faucet](https://faucet.chainstack.com/sepolia-testnet-faucet/) का उपयोग कर सकते हैं।

**contract को Compile करें -** smart contract को compile करने के लिए Remix IDE का उपयोग करें। एक नया contract file बनाएँ और [**यहाँ**](https://github.com/Tenderly/examples-web3-actions/blob/main/tic-tac-toe/TicTacToe.sol) पाया गया code जोड़ें।

<Frame caption="Compiling the contract in the Remix IDE">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(69).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=6f20b3090790b771b014692cdcf7be9a" alt="Compiling the contract in the Remix IDE" width="2878" height="1642" data-path="images/image (69).webp" />
</Frame>

**test network पर Deploy करें** - अपने Metamask browser plugin में, सुनिश्चित करें कि Sepolia आपके पसंदीदा network के रूप में चयनित है। इसके बाद, Remix में **"Deploy And Run Transactions"** अनुभाग पर जाएँ और **`Injected Web3`** का चयन करें। यह सुनिश्चित करने के बाद कि account Metamask में account का reference देता है, **"Deploy"** पर क्लिक करें।

<Frame caption="Deploying the contract to a testnet">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(73).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=a8cfef3f43f563adbb3dfdd62177b50f" alt="Deploying the contract to a testnet" width="1070" height="1372" data-path="images/image (73).webp" />
</Frame>

<Frame caption="Copying the contract address">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(92).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=4a2339153a44fa17921bce22e01e703b" alt="Copying the contract address" width="912" height="1070" data-path="images/image (92).webp" />
</Frame>

deployed contract पर अधिक जानकारी प्राप्त करने के लिए, **"Deployed Contracts"** अनुभाग देखें। पूरा contract address (`0x133...`) copy करने के लिए copy icon पर क्लिक करें और इसे कहीं store करें क्योंकि हमें अगले चरणों के लिए इसकी आवश्यकता होगी।

अब **contract को verify करने के लिए Tenderly Dashboard पर जाएँ**। इससे हमारे लिए tutorial में बाद में contract के साथ interact करना संभव हो जाएगा।

## 1: Tenderly CLI के माध्यम से Web3 Actions सेट अप करें

इस tutorial के साथ जारी रखने के लिए, आपके पास अपनी machine पर **Tenderly CLI** स्थापित होना चाहिए। इसे सेट अप करने और access authenticate करने के तरीके के बारे में जानने के लिए [**इस गाइड**](https://github.com/Tenderly/tenderly-cli#installation) का पालन करें।

CLI स्थापित होने के साथ, एक नई directory बनाएँ और `cd` इसमें। `tenderly actions init` command चलाकर अपनी Web3 Actions को initialize करें:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
$> cd tdly-actions
$> tenderly actions init
```

आपको अपने मौजूदा Tenderly projects में से एक का चयन करने के लिए कहा जाएगा। आपकी Web3 Actions इस project पर deploy की जाएंगी और आपकी directory structure में इस तरह दिखाई देनी चाहिए:

```bash title="example" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
$> ls actions
  example.ts     # where we write Web3 actions code
  tsconfig.json
  package.json
```

Typescript default भाषा है लेकिन आप plain Javascript पर switch कर सकते हैं। init command execute करने से पहले, अपनी पसंदीदा भाषा के रूप में Javascript को इस तरह सेट करें: `tenderly actions init --language javascript`।

<Note>
  `package.json` npm dependencies रखता है जो आपके Web3 Action को deploy करने पर उपलब्ध होंगी। `tsconfig.json` file में केवल `actions` directory के भीतर `.ts` files से संबंधित Typescript configuration है।
</Note>

### 1.1. Tic-Tac-Toe Contract का ABI जोड़ें

code में गहराई से जाने से पहले, compiler द्वारा उत्पन्न ABI को actions directory में copy करें। हमारे उदाहरण में, यह `tdly-actions` directory है।

Remix में, `files/artifacts/TicTacToe.json` पर जाएँ, file की contents copy/paste करें और उन्हें अपने project की `TicTacToe.json` file में paste करें।

<Warning>
  आपकी Web3 Action code द्वारा उपयोग की जाने वाली और referenced सभी files को `actions` directory में रखा जाना चाहिए (जैसे `TicTacToe.json`)।
</Warning>

### 1.2. Typescript को JSON File को Module के रूप में Import करने के लिए Configure करें

default रूप से, Typescript आपको JSON files को modules के रूप में import करने की अनुमति नहीं देता है। आपको Typescript को कॉन्फ़िगर करने की आवश्यकता है ताकि `TicTacToe.json` file को module के रूप में import कर सकें और object के रूप में access कर सकें।

अपनी `tsconfig.json` file पर जाएँ और `compilerOptions` entry के तहत निम्न दो configurations शामिल करें:

```diff title="example" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
    ...
    "compilerOptions": {
	...
+        "resolveJsonModule": true,
+        "esModuleInterop": true
    },
   ...
}
```

## 2: New Game Event को Handle करने के लिए Function लिखें

एक function लिखें जो नया game शुरू होने पर execute होगा। आइए Typescript file का नाम कुछ अधिक वर्णनात्मक में बदलें:

```bash title="example" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
mv example.ts ticTacToeActions.ts
```

Typescript की शक्ति का उपयोग करने के लिए, हमें पहले game state का प्रतिनिधित्व करने वाला एक type परिभाषित करने की आवश्यकता होगी। संक्षेप में, हम आपकी Web3 Action के storage में game state की एक replica store करेंगे। प्रत्येक field में उस खिलाड़ी का ID होता है जिसने वहाँ खेला। हम `players` object में खिलाड़ी के address को उनकी turn (पहली, दूसरी, आदि) से map करेंगे।

### 2.1. एक Action जोड़ें

```typescript title="example.ts" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
// ticTacToeActions.ts

export type Game = {
  players: { [address: string]: number };
  board: number[][];
};
```

इस बिंदु पर, हम वास्तविक Web3 Action को इस तरह परिभाषित करने के लिए तैयार हैं:

```typescript title="example.ts" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
export const createNewGame = (): Game => {
  return {
    players: {},
    board: [
      [0, 0, 0],
      [0, 0, 0],
      [0, 0, 0],
    ],
  };
};

// ticTacToeActions.ts continued
export const newGameAction: ActionFn = async (context: Context, event: Event) => {
  let txEvent = event as TransactionEvent;

  let iface = new ethers.utils.Interface(TicTacToe.abi);

  const result = iface.decodeEventLog('GameCreated', txEvent.logs[0].data, txEvent.logs[0].topics);

  const { gameId, playerNumber, player } = result;

  console.log('Game Created Event:', {
    gameId: gameId.toString(),
    playerNumber,
    player,
  });

  const game: Game = createNewGame();
  await context.storage.putJson(gameId.toString(), game);
};
```

यह Web3 Action smart contract में परिभाषित `GameCreated` event को handle करेगी।

smart contract को देखकर, हम देख सकते हैं कि `newGame` function से केवल एक event fire हो रहा है, इसलिए हम पहली log entry में रुचि रखते हैं। हम `TicTacToe.abi` के आधार पर GameCreated event के `txEvent.logs[0].data` को decode करके ethers.js के साथ `result` प्राप्त कर सकते हैं।

यहाँ हम इस विशेष game के साथ जुड़े ID तक पहुँच सकते हैं जब यह बनाया गया हो: `result.gameId`। हम इस विशेष game के लिए data को track करना चाहते हैं: खिलाड़ी और उनके द्वारा किए गए moves, एक बिल्कुल नए `Game` instance का उपयोग करते हुए। हम नए game का प्रतिनिधित्व करने वाले object को Storage में इस command के साथ save कर रहे हैं: `context.storage.putJson(gameId, game)`।

एक खाली board के साथ, हम भविष्य के परिवर्तनों को persist करने की नींव सेट कर रहे हैं जो अन्य actions द्वारा संभाले जाते हैं।

आप Web3 Action के behaviour को verify करने के लिए automated tests भी लिख सकते हैं। कुछ tests repository में उपलब्ध हैं, लेकिन यह इस tutorial के दायरे से बाहर है।

### 2.2. New Game Action Invocation निर्दिष्ट करें

tenderly.yaml खोलें। `specs` अनुभाग में, `newGame` (arbitrary name) के लिए specs परिभाषित करें ताकि function `newGameAction` को invoke करें। आप इसे इस तरह कर सकते हैं `newGameAction:newGameAction`, पहले हम function वाली file का नाम परिभाषित करते हैं और फिर function name।

इसके बाद, `trigger` निर्दिष्ट करें जिसे Tenderly action को invoke करने के लिए देखने वाला है। यह एक `transaction` trigger है जो block mine होने पर चलेगा। हम इसे `network 3` के लिए कर रहे हैं जब निर्दिष्ट address पर contract से event `NewGame` emit होता है।

`TTT_CONTRACT_ADDRESS` को अपने smart contract के वास्तविक address से बदलें। यदि आप contract को Sepolia के अलावा किसी अन्य network पर deploy करना चाहते हैं, तो network के ID को network के मान के रूप में निर्दिष्ट करें।

<Note>
  `YOUR_USERNAME` और `YOUR_PROJECT_SLUG` को अपने Tenderly username और अपने project के slug से बदलें। आप उन्हें Dashboard URL से copy कर सकते हैं: `https://dashboard.tenderly.co/{YOUR_USERNAME}/{YOUR_PROJECT_SLUG}/transactions`
</Note>

```yaml title="example.yaml" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
account_id: ''
actions:
  YOUR_USERNAME/YOUR_PROJECT_SLUG:
    runtime: v1
    sources: actions
    specs:
      newGame:
        description: Respond to newGame event
        function: ticTacToeActions:newGameAction
        trigger:
          type: transaction
          transaction:
            status:
              - mined
            filters:
              - network: 3
                eventEmitted:
                  contract:
                    address: TTT_CONTRACT_ADDRESS
                  name: GameCreated
project_slug: ''
```

### 2.3. Tenderly पर अपने Tic-Tac-Toe Smart Contract को Verify करें

contract को deploy करने से पहले, आपको इसे अपने Tenderly Dashboard में verify करना होगा।

यदि आप चाहें, तो आप [contract को अपने browser के माध्यम से upload कर सकते हैं](/contract-verification/overview)। एक बार upload होने के बाद, TicTacToe contract, आपने जिस network पर इसे deploy किया, और contract address का चयन करें।

Add Contract पर क्लिक करें और नीचे दी गई तस्वीर में दिखाए अनुसार compiler options भरें:

<Frame caption="Verifying and adding the contract to Tenderly ">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(74).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=01b598bfc2a6fbdf63ddb1533f10d40c" alt="Verifying and adding the contract to Tenderly " width="2154" height="1142" data-path="images/image (74).webp" />
</Frame>

<Frame caption="Adding the contract compiler information ">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(87).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=e99c1eb47857101c573bddf8131cf40d" alt="Adding the contract compiler information " width="1668" height="660" data-path="images/image (87).webp" />
</Frame>

### 2.4. Web3 Action को Tenderly पर Deploy करें

अपनी Web3 Action deploy करने के लिए, Tenderly CLI का उपयोग करके `deploy` command execute करें:

```bash title="example" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
tenderly actions deploy
```

output इस तरह दिखना चाहिए:

<Frame caption="The Web3 Action execution output">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(79).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=265837ec27e0378acfbc192074661c47" alt="The Web3 Action execution output" width="1111" height="202" data-path="images/image (79).webp" />
</Frame>

अपनी Web3 Action के deployment के बारे में विवरण देखने के लिए, Tenderly Dashboard देखें। यदि deployment सफल था, तो आपको कुछ इस तरह दिखना चाहिए:

<Frame caption="Opening the Web3 Action deployment information ">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(80).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=c35821d0a7d044029d8e1047cfa89ff6" alt="Opening the Web3 Action deployment information " width="2878" height="1394" data-path="images/image (80).webp" />
</Frame>

### 2.5. एक New Game में शामिल होने का प्रयास करें 🎉

यह सत्यापित करने के लिए कि सब कुछ ठीक से काम कर रहा है, Remix पर वापस जाएँ और एक नया game या यहाँ तक कि कई games बनाएँ।

TicTacToe contract खोलें और `newGame` दबाएँ। Metamask को आपको Web3 Action के execution की पुष्टि करने के लिए prompt करना चाहिए।

एक बार transaction chain पर submit हो जाने पर, Remix को इसी तरह का output produce करना चाहिए:

<Frame caption="Creating a new game in Remix">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(96).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=a0aad1196ca95ba6470b8b5f0edcee12" alt="Creating a new game in Remix" width="2880" height="1648" data-path="images/image (96).webp" />
</Frame>

इसके बाद, अपने Tenderly Dashboard पर वापस जाएँ और अपना transaction देखने के लिए Transactions अनुभाग खोलें। Actions अनुभाग में, आप देखेंगे कि **"Latest Execution"** column बदल गया है।

execution history देखने के लिए, अपनी Web3 Action खोलें और Execution History tab पर क्लिक करें:

<Frame caption="Opening the Execution history tab for your Web3 Action ">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(81).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=7b2dedf972e0e4a6f9bc11fe27a33f85" alt="Opening the Execution history tab for your Web3 Action " width="2868" height="1444" data-path="images/image (81).webp" />
</Frame>

execution history आपको निम्न data प्रदान करेगी:

<Frame caption="The execution history data">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(89).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=ec2d6994130b322e35d858124d104898" alt="The execution history data" width="2169" height="1106" data-path="images/image (89).webp" />
</Frame>

ऊपरी pane में, आपको chain से आ रहे payload के बारे में जानकारी मिलेगी। निचले pane में logged game number के बारे में विवरण है। हमारे मामले में, यह `0xb` है, जिसका अर्थ है कि यह इस contract के लिए शुरू किया गया 11वाँ game है।

### 2.6. अपनी Web 3 Actions के Storage की जाँच करें

Storage की contents देखने के लिए **"Go To Storage"** बटन पर क्लिक करें। शुरू किए गए प्रत्येक game को इस key-value map में अपना खुद का storage slot मिलेगा।

जब आप हमारे अभी बनाए गए game को **ID 11** के साथ खोलते हैं, तो आपको सभी fields में zeros दिखाई देंगे, जिसका अर्थ है कि किसी भी खिलाड़ी ने अभी तक game नहीं खेला है।

<Frame caption="Opening the Storage of your Web3 Action ">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(90).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=88f11391c94122ab621cac47f2bc8bdd" alt="Opening the Storage of your Web3 Action " width="1522" height="558" data-path="images/image (90).webp" />
</Frame>

## 3: नए खिलाड़ी Game में शामिल होने को Handle करने के लिए Web3 Action जोड़ें

game में शामिल होने वाले खिलाड़ी को खिलाड़ी के address और उनके move (1 या 2) को register करके process किया जाना चाहिए।

boilerplate code के अलावा जो हमें event data retrieve करने में मदद करता है, `playerJoinAction.ts` file में वह code भी होता है जो हमें अनुमति देता है:

* game के ID (`storage.getJson`) का उपयोग करके storage से वर्तमान game state पढ़ें।
* खिलाड़ी के address को retrieve करें और उनकी turn store करें: `game.players[player] = playerNumber`
* `storage.putJson` का उपयोग करके Web3 Action के storage में updated game object save करें।

```typescript title="example.ts" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
// playerJoinAction.ts

export const playerJoinedAction: ActionFn = async (context: Context, event: Event) => {
  let txEvent = event as TransactionEvent;
  let iface = new ethers.utils.Interface(TicTacToe.abi);
  const result = iface.decodeEventLog(
    'PlayerJoinedGame',
    txEvent.logs[0].data,
    txEvent.logs[0].topics,
  );

  const gameId = result.gameId.toString();
  const playerAddress = result.player.toLowerCase() as string;
  const playerNumber = result.playerNumber;

  console.log('Player joined event:', {
    gameId,
    playerAddress,
    playerNumber,
  });

  const game: Game = (await context.storage.getJson(gameId)) as Game;
  game.players[playerAddress] = playerNumber;

  await context.storage.putJson(result.gameId.toString(), game);
};
```

### 3.1. PlayerJoinedGame Action Invocation निर्दिष्ट करें

हमें Web3 Action को invoke करने के लिए आवश्यक specifications शामिल करने के लिए `tenderly.yaml` file से `specs` का विस्तार करने की भी आवश्यकता है।

```yaml title="example.yaml" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
playerJoined:
  description: Respond to player joining game
  function: ticTacToeActions:playerJoinedAction
  trigger:
    type: transaction
    transaction:
      status:
        - mined
      filters:
        - network: 3
          eventEmitted:
            contract:
              address: TTT_CONTRACT_ADDRESS
            name: PlayerJoinedGame
```

### 3.2. action को Tenderly पर deploy करें

`deploy` command चलाकर अपनी Web3 Action deploy करें। यह command पहले deploy की गई Web3 Actions को भी redeploy करेगा।

```javascript title="example.js" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
tenderly action deploy
```

### 3.3. एक New Game में शामिल होने का प्रयास करें

`newGame` input field में logs से game number जोड़कर Remix पर जाकर एक नए game में शामिल हों। transaction submit करने के लिए, `joinGame` बटन पर क्लिक करें:

<Frame caption="Joining a new game in Remix ">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(85).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=b775e77378e6a2706fe73eed98a3d79d" alt="Joining a new game in Remix " width="852" height="796" data-path="images/image (85).webp" />
</Frame>

एक बार transaction mine हो जाने पर, execution के logs में `playerNumber: 1` दिखाई देगा।

<Frame caption="The execution log">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(93).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=c528321ee8ce731435000c561537e60a" alt="The execution log" width="1116" height="345" data-path="images/image (93).webp" />
</Frame>

game खेलने के लिए, Metamask में अपने दूसरे account पर switch करें और फिर से `joinGame` पर क्लिक करें। transaction के पूरा होने पर, आप Execution History में एक समान log output देखेंगे।

### 3.4. अपनी Web 3 Actions के Storage की जाँच करें

<Frame caption="Opening the execution of your Web3 Action">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(94).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=0e7db1401134a1407e2857804a9ec87e" alt="Opening the execution of your Web3 Action" width="1763" height="728" data-path="images/image (94).webp" />
</Frame>

इन executions में से किसी को भी खोलें और **"Go To Storage"** बटन पर क्लिक करें।

हमारे खिलाड़ियों द्वारा शामिल हुआ game ID 11 है, और यह किसी भी move के होने से पहले की state है। Tic-Tac-Toe board में केवल zeros हैं और Ethereum address से खिलाड़ी की turn तक map मौजूद है।

<Frame caption="Opening the Storage key value ">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(91).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=d98b4d0220c38499bde2925eabcc1a6c" alt="Opening the Storage key value " width="1400" height="678" data-path="images/image (91).webp" />
</Frame>

### 3.5. जब खिलाड़ी Move करे उसे Handle करने के लिए एक Action जोड़ें

Ethers का उपयोग करके, हम game ID प्राप्त करते हैं और storage से game instance load करते हैं। इसके बाद, row `result.boardRow` और column `result.boardCol` में field को खिलाड़ी के input `game.players[player]` से update करें।

function `processNewGameState`, board को console में log करेगा, लेकिन आप move होने पर एक tweet भी भेज सकते हैं, chain पर एक नया transaction trigger कर सकते हैं, या इसे किसी अन्य तरीके से उपयोग कर सकते हैं।

```typescript title="example.ts" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
// ticTacToeActions.ts
//...
export const playerMadeMoveAction: ActionFn = async (context: Context, event: Event) => {
  let txEvent = event as TransactionEvent;
  let iface = new ethers.utils.Interface(TicTacToe.abi);
  const result = iface.decodeEventLog(
    'PlayerMadeMove',
    txEvent.logs[0].data,
    txEvent.logs[0].topics,
  );

  const gameId = result.gameId.toString();
  const game = (await context.storage.getJson(gameId)) as Game;
  const player = result.player.toLowerCase() as string;
  const { boardRow, boardCol } = result;

  console.log("Player's move event log:", {
    gameId,
    player,
    boardRow: boardRow.toString(),
    boardCol: boardCol.toString(),
  });

  console.log(
    `Move: gameId ${gameId}, game ${JSON.stringify(
      game,
    )}, boradRow ${boardRow}, boardCol ${boardCol}, player ${player}`,
  );

  game.board[boardRow][boardCol] = game.players[player];
  console.log('MV', JSON.stringify(game));
  await context.storage.putJson(gameId, game);

  processNewGameState(game);
};

const processNewGameState = (game: Game) => {
  let board = '\n';
  game.board.forEach(row => {
    row.forEach(field => {
      if (field == 1) {
        board += '❎ ';
        return;
      }

      if (field == 2) {
        board += '🅾️ ';
        return;
      }

      board += '💜 ';
    });

    board += '\n';
  });

  console.log(board);
};
```

इस action के लिए संबंधित spec है:

```yaml title="example.yaml" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
playerMadeMove:
  description: Respond to player making a move event
  function: ticTacToeActions:playerMadeMoveAction
  trigger:
    type: transaction
    transaction:
      status:
        - mined
      filters:
        - network: 3
          eventEmitted:
            contract:
              address: TTT_CONTRACT_ADDRESS
            name: PlayerMadeMove
```

### 3.6. Game खेलने के लिए Move करें

move करने के लिए, Metamask का उपयोग करके game में शामिल होने वाले पहले खिलाड़ी पर switch करें। इसके बाद, आपको प्राप्त game number, साथ ही board (0, 1) पर row और column दर्ज करें।

<Frame caption="Making a move in Remix ">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(88).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=d87ef8ceb06a0bbd9474af3eb12c2169" alt="Making a move in Remix " width="914" height="934" data-path="images/image (88).webp" />
</Frame>

जब action execute हो जाता है, तो output इस तरह दिखना चाहिए:

<Frame caption="The Web3 Action execution output">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(95).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=781967b49bfe714430a3558cbdb95f5d" alt="The Web3 Action execution output" width="698" height="236" data-path="images/image (95).webp" />
</Frame>

## चरण 4. Game समाप्त होने पर Handle करने के लिए Web3 Action जोड़ें

नीचे आपको `GameOver` event के लिए code मिलेगा। `GameOver` event तब fire होता है जब कोई खिलाड़ी ऐसा move करता है जो game जीतता है या जब board भर जाता है। यह event `PlayerMadeMove` event के बाद fire होता है। `txEvent.logs` list में, `GameOver` event दूसरा element है।

`GameOver` event प्राप्त करने का एक आसान तरीका इसे `txEvent.logs[1]` के माध्यम से access करना है। हालाँकि, हम एक अधिक मजबूत समाधान implement करेंगे जो fire होने वाले events के order और संख्या पर निर्भर नहीं करता है।

पहले, आपको `iface.getEventTopics` के माध्यम से ethers का उपयोग करके `gameOverTopic` प्राप्त करने की आवश्यकता है। यह आपको संबंधित hexadecimal value देगा। इसके बाद, आपको `txEvent.logs` में log entry खोजनी होगी, जिसकी topics list में `gameOverTopic` है। यह हमारा `GameOver` event log है जिसे हम Ethers का उपयोग करके decode कर सकते हैं।

```javascript title="example.js" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
export const gameOverAction: ActionFn = async (context: Context, event: Event) => {
	let txEvent = event as TransactionEvent;
	let iface = new ethers.utils.Interface(TicTacToe.abi);

	const gameOverTopic = iface.getEventTopic("GameOver");
	const gameOverLog = txEvent.logs.find(log => log.topics.find(topic => topic == gameOverTopic) !== undefined);

	if (gameOverLog == undefined) {
		// impossible
		throw Error("GameOver log not found in event's logs");
	}

	const result = iface.decodeEventLog("GameOver", gameOverLog.data, gameOverLog.topics);

	console.log(result);

	const gameId = result.gameId.toString();
	const winner = result.winner as number;

	const winnerMessage = getWinnerMessage(winner);
	if (winnerMessage !== false) {
		console.info(`🎉 Winner of the game ${gameId} is ${winnerMessage}`);
	} else {
		console.error("🤔 weird winner code");
	}
}
```

### 4.1. GameOver Action Invocation निर्दिष्ट करें

अंत में, हमें `tenderly.yaml` में `specs` का विस्तार करके `GameOver` action को invoke करने के लिए specification जोड़ने की आवश्यकता है:

```yaml title="example.yaml" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
gameOver:
  description: Respond to game over
  function: ticTacToeActions:gameOverAction
  trigger:
    type: transaction
    transaction:
      status:
        - mined
      filters:
        - network: 3
          eventEmitted:
            contract:
              address: TTT_CONTRACT_ADDRESS
            name: GameOver
```

### 4.2. Game खेलें

तब तक खेलते रहें जब तक कि एक खिलाड़ी game जीत नहीं जाता या board पूरी तरह से भर नहीं जाता। game के अंत में, Execution History इस तरह दिखनी चाहिए:

<Frame caption="The execution history at the end of the game">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(78).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=eb6b64f3d40bbc512205c312c51d4c04" alt="The execution history at the end of the game" width="2542" height="826" data-path="images/image (78).webp" />
</Frame>
