मुख्य सामग्री पर जाएं
यह ट्यूटोरियल दिखाता है कि Tenderly Simulation API का उपयोग करके एक wallet में “transaction preview” विकल्प कैसे जोड़ें। हम आपको दिखाएँगे कि इस विकल्प को MetaMask wallet में कैसे जोड़ें। transaction preview” सुविधा उपयोगकर्ताओं को production नेटवर्क पर submit करने से पहले अपने transactions के सटीक परिणाम देखने की अनुमति देती है। इस सुविधा से लैस wallets उपयोगकर्ताओं के लिए प्रतिबद्धता करने से पहले अपने transactions के वित्तीय निहितार्थों को समझना आसान बनाते हैं। Simulations एक सुरक्षित, जोखिम-मुक्त वातावरण में blockchain की नवीनतम स्थिति के fork पर निष्पादित होते हैं। यह wallet उपयोगकर्ताओं को दुर्भावनापूर्ण या त्रुटि-प्रवण transactions भेजने से रोकने में मदद करता है। आप GitHub पर संपूर्ण demo repository पा सकते हैं:

Tenderly Simulate Asset Changes Snap

Tenderly MetaMask Snap Demo
यह ट्यूटोरियल केवल प्रदर्शन उद्देश्यों के लिए है, विशेष रूप से यह दिखाने के लिए कि MetaMask Snap में transaction preview विकल्प कैसे जोड़ा जाए। यह किसी अन्य उपयोग के लिए न तो उद्देशित है और न ही अनुशंसित है।

प्रोजेक्ट ओवरव्यू

यह प्रोजेक्ट आपको दिखाता है कि transaction simulations को MetaMask wallet में कैसे एकीकृत करें। हम MetaMask Snaps के साथ काम करेंगे। आप सीखेंगे कि Tenderly Simulation API से कैसे जुड़ें, transaction डेटा भेजें, simulation परिणाम प्राप्त करें, और उन्हें MetaMask UI के माध्यम से उपयोगकर्ता को प्रदर्शित करें। इसमें डॉलर में asset परिवर्तन, native-asset balance परिवर्तन, output value, storage परिवर्तन, event logs, और call traces शामिल हैं। Simulated transactions को फिर आगे debugging और testing के लिए Tenderly में भी खोला जा सकता है। नीचे उन सुविधाओं की सूची है जो हम MetaMask Snap में जोड़ेंगे। समान सुविधाएँ किसी भी wallet में भी जोड़ी जा सकती हैं ताकि transactions भेजते समय उपयोगकर्ताओं को विश्वास बनाने में मदद मिले।
सुविधाविवरण
Simulation debuggingTenderly में simulation का निरीक्षण और debug करने के लिए ऑटो-जेनरेट किया गया लिंक।
सार्वजनिक रूप से साझा करने योग्य simulationsSimulations की सार्वजनिक साझेदारी को enable/disable करने की क्षमता।
डॉलर मूल्य में प्रदर्शित asset परिवर्तनमानव-पठनीय डेटा, जिसमें डॉलर में स्वचालित रूप से परिवर्तित asset परिवर्तन शामिल हैं।
Native-asset balance परिवर्तनcontract के निष्पादन के दौरान उनके native-asset balance में परिवर्तनों को ट्रैक करने की क्षमता।
Output valuecontract call का परिणाम देखें, यह दिखाते हुए कि contract क्या लौटाने के लिए सेट है।
Storage परिवर्तननिष्पादन के दौरान contract के storage में किए गए किसी भी परिवर्तन को देखें।
Event logscontract के निष्पादन के दौरान उत्सर्जित events देखें।
Call tracesनिष्पादन के दौरान हुए सभी function कॉल्स का विवरण।

आवश्यकताएँ

  • MetaMask Flask ब्राउज़र एक्सटेंशन installed
  • Node.js (संस्करण 16 या बाद का)
  • Yarn (संस्करण 3)
MetaMask Snap बनाना शुरू करने से पहले, सुनिश्चित करें कि आप MetaMask के “वास्तविक” संस्करण को अक्षम कर दें और MetaMask Flask Development Plugin install करें
चलिए बनाना शुरू करते हैं! 👷‍♂️

चरण 1: एक MetaMask Snap प्रोजेक्ट सेटअप करना

MetaMask का आधिकारिक Create Snap CLI install करें और एक नया प्रोजेक्ट बनाएँ।
example
yarn create @metamask/snap project-name

OR

npm create @metamask/snap project-name
इसके बाद, हमें Snap प्रोजेक्ट शुरू करना होगा और https://localhost:8000 पर front end को serve करना होगा। नए बनाए गए प्रोजेक्ट के root से, Yarn का उपयोग करके प्रोजेक्ट dependencies install करें।
example
yarn
Development server शुरू करें।
example
yarn start

सही अनुमतियाँ सेट करना

एक बार जब आप Snap install कर लें, तो /packages/snap/snap.manifest.json फ़ाइल खोजें और नीचे दिखाए अनुसार अनुमतियाँ सेट करें। MetaMask अनुमतियों के बारे में यहाँ जानें।
example.json
{
  // ...
  "initialPermissions": {
    "snap_dialog": {},
    "endowment:rpc": {
      "dapps": true,
      "snaps": false
    },
    "endowment:transaction-insight": {
      "allowTransactionOrigin": true
    },
    "endowment:network-access": {},
    "snap_manageState": {},
    "endowment:ethereum-provider": {
      "dapps": true,
      "snaps": true
    }
  }
}
जब आप app चलाते हैं और wallet कनेक्ट करने का प्रयास करते हैं, तो एक अनुमति अनुरोध पॉप अप होगा। जारी रखने के लिए Connect और Approve & install बटन पर क्लिक करें।
Install MetaMask Snap Permissions

चरण 2: Tenderly API एक्सेस टोकन उत्पन्न करना

MetaMask Snap में transaction preview विकल्प Tenderly Simulation API द्वारा संचालित है। API का उपयोग शुरू करने से पहले, आपको एक्सेस टोकन उत्पन्न करने होंगे। इन चरणों का पालन करें:
  1. Tenderly में लॉग इन करें या यहाँ एक निःशुल्क खाता बनाएँ
  2. Authorization page पर जाएँ और Generate Access Token बटन पर क्लिक करें।
यदि आपको API प्रमाणीकरण में सहायता चाहिए, तो कृपया इस गाइड का पालन करें:

API एक्सेस टोकन कैसे उत्पन्न करें

Generate Access Token from Authorization page

चरण 3: Snap के लिए logic लिखना

Snap को काम करने वाला मुख्य logic तीन फ़ाइलों में संग्रहीत है:
  • Credentials Access (credentials-access.ts): Tenderly API प्रमाणीकरण और एक्सेस का प्रबंधन करता है।
  • Simulation (simulation.ts): Tenderly API के साथ interact करने के लिए मुख्य logic ताकि transactions का simulation किया जा सके और simulation परिणाम प्राप्त किए जा सकें।
  • Formatter (formatter.ts): simulation परिणामों को parse करने और उन्हें MetaMask UI में उपयोगकर्ता-अनुकूल तरीके से format करने के लिए logic।

Credentials Access

हम Tenderly API credentials का अनुरोध, अपडेट और fetch करने के लिए ज़िम्मेदार सभी विधियों को credentials-access.ts नामक फ़ाइल में संग्रहीत कर सकते हैं। यहाँ source code देखें सबसे महत्वपूर्ण विधियाँ हैं:
  • fetchCredentials(): यह function एक Tenderly project के credentials retrieve करता है। यदि कोई credentials संग्रहीत नहीं हैं, तो यह नए credentials का अनुरोध करने के लिए handleUpdateTenderlyCredentials को trigger करता है।
  • handleUpdateTenderlyCredentials(): यह function Tenderly project credentials को अपडेट करने की प्रक्रिया को संभालता है। यह requestNewTenderlyCredentials को कॉल करके नए credentials प्राप्त करता है और फिर उन्हें 'update' operation के साथ snap_manageState विधि का उपयोग करके save करता है।
  • requestNewTenderlyCredentials(): यह function नए Tenderly credentials का अनुरोध करता है। यह raw credentials डेटा प्राप्त करने के लिए requestCredentials को कॉल करता है और accountId, projectId, और accessToken के साथ एक object लौटाने से पहले इसकी शुद्धता को सत्यापित करता है।
snap_manageState एक अंतर्निहित विधि है जो Snap को disk पर 100 MB तक डेटा को persist करने की अनुमति देती है। अधिक जानें यहाँ

Simulation

इसके बाद, हमें वह logic बनाना होगा जो transaction डेटा को Tenderly Simulation API को भेजता है, इसका simulation करता है, और परिणाम retrieve करता है। हम इसके लिए simulate API एंडपॉइंट का उपयोग करेंगे। Endpoint: https://api.tenderly.co/api/v1/account/{accountId}/project/{projectId}/simulate चीज़ों को व्यवस्थित रखने के लिए, चलिए simulation logic को simulation.ts नामक फ़ाइल में संग्रहीत करें। यहाँ source code देखें। Tenderly Simulation API को transaction डेटा भेजने के लिए, हमें दो मुख्य विधियाँ बनानी होंगी:
  • simulate(): यह मुख्य function है जो एक transaction के simulation को संभालता है। यह API एक्सेस credentials fetch करता है, transaction डेटा को Tenderly Simulation API को submit करता है, और API द्वारा लौटाई गई किसी भी त्रुटि को संभालता है।
example.tsx
export async function simulate(
  transaction: { [key: string]: Json },
  transactionOrigin: string,
): Promise<Panel> {
  const credentials = await fetchCredentials(transactionOrigin);

  if (!credentials) {
    return panel([text('🚨 Tenderly access token updated. Please try again.')]);
  }

  const simulationResponse = await submitSimulation(transaction, credentials);
  const err = catchError(simulationResponse, credentials);

  return err || formatResponse(simulationResponse, credentials);
}
  • submitSimulation(): यह function transaction डेटा के साथ API को एक अनुरोध भेजता है ताकि उसका simulation किया जा सके।
जब transaction का simulation किया जाता है, तो हम share API endpoint को कॉल करके इसे सार्वजनिक रूप से सुलभ बना सकते हैं। Simulation को shareable बनाने से आप transaction का लिंक copy कर सकते हैं और इसे किसी को भी भेज सकते हैं। Shared transactions को Tenderly account के बिना देखा जा सकता है।
example.tsx
async function submitSimulation(
  transaction: { [key: string]: Json },
  credentials: TenderlyCredentials,
) {
  const chainId = await ethereum.request({ method: 'eth_chainId' });
  const response = await fetch(
    `https://api.tenderly.co/api/v1/account/${credentials.accountId}/project/${credentials.projectId}/simulate`,
    {
      method: 'POST',
      body: JSON.stringify({
        from: transaction.from,
        to: transaction.to,
        input: transaction.data,
        gas: hex2int(transaction.gas),
        value: hex2int(transaction.value),
        network_id: hex2int(chainId as string),
        save: true,
        save_if_fails: true,
        simulation_type: 'full',
        generate_access_list: false,
        source: 'tenderly-metamask-snap',
      }),
      headers: {
        'Content-Type': 'application/json',
        'X-Access-Key': credentials.accessToken,
      },
    },
  );

  const parsedResponse = await response.json();

  // Make the simulation publicly accessible
  if (parsedResponse?.simulation?.id) {
    await fetch(
      `https://api.tenderly.co/api/v1/account/${credentials.accountId}/project/${credentials.projectId}/simulations/${parsedResponse.simulation.id}/share`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Access-Key': credentials.accessToken,
        },
      },
    );
  }

  return parsedResponse;
}

Formatter

एक बार जब API simulation परिणाम लौटाती है, तो हमें इस डेटा को parse करना होगा और इसे MetaMask UI में प्रदर्शित करने के लिए उपयोगकर्ता-अनुकूल तरीके से format करना होगा। हम इस logic को formatter.ts नामक फ़ाइल में संग्रहीत कर सकते हैं। यहाँ source code देखें। मुख्य formatting विधियाँ हैं:
  • formatResponse(): यह function एक Tenderly project simulation का raw डेटा और credentials प्राप्त करता है, प्रत्येक प्रासंगिक अनुभाग (जैसे balance परिवर्तन, output value, asset परिवर्तन, आदि) के लिए individual formatter functions को कॉल करता है, और सभी formatted outputs के साथ एक panel लौटाता है।
  • formatBalanceDiff(): यह function transaction में शामिल प्रत्येक account के लिए balance परिवर्तन दिखाने वाला एक panel उत्पन्न करता है।
  • formatOutputValue(): यह function एक panel बनाता है जो यदि कोई output मान मौजूद है तो transaction के output मानों को प्रस्तुत करता है। यह output को यदि संभव हो तो decode भी करता है।
  • formatAssetChanges(): यह function किसी भी asset परिवर्तन को दिखाने के लिए एक panel format करता है, ERC20, ERC721, और अन्य परिवर्तनों के बीच अंतर करता है।
  • formatStorageChanges(): यह function एक panel बनाता है जो transaction के दौरान हुए storage में किसी भी परिवर्तन को सूचीबद्ध करता है। स्पष्टता के लिए यह पते और nested डेटा संरचनाओं को विशिष्ट रूप से format करता है।
  • formatEventLogs(): यह function प्रत्येक transaction के लिए event logs, यदि वे मौजूद हैं, प्रस्तुत करता है। Logs को पठनीयता के लिए format किया जाता है और इनमें input मान शामिल होते हैं।
  • formatCallTrace(): यह function call traces का एक formatted दृश्य पदानुक्रम उत्पन्न करता है, nested कॉल्स को recursively दिखाता है।
  • formatSimulationUrl(): यह function Tenderly Dashboard पर simulation के पूर्ण विवरण का एक लिंक और एक अलग shareable लिंक लौटाता है।

चरण 4: MetaMask UI में simulation डेटा प्रदर्शित करना

MetaMask Snap mono repo पूर्वनिर्धारित UI तत्वों और layout configurations का एक set प्रदान करता है। हम simulation परिणामों को प्रदर्शित करने के लिए मौजूदा MetaMask UI का विस्तार करने के लिए इन तत्वों का उपयोग करेंगे। जब आप हमारा MetaMask उदाहरण install करते हैं, तो हम आपको दिखाते हैं कि विभिन्न प्रकार के simulations कैसे चलाएँ:
  • एक पूर्वनिर्धारित payload के साथ सफल transaction simulation (सफल ERC-20 transfer और NFT transfer)
  • एक पूर्वनिर्धारित payload के साथ विफल transaction simulation
  • किसी भी payload के साथ कस्टम transaction simulation
Tenderly Snap UI
इस ट्यूटोरियल के उद्देश्य के लिए, हम आपको दिखाएँगे कि एक पूर्वनिर्धारित payload के साथ simulations कैसे चलाएँ और अपना कस्टम payload कैसे जोड़ें और simulation कैसे निष्पादित करें।

एक पूर्वनिर्धारित payload के साथ सफल simulation

Simulation शुरू करने के लिए, हम एक function लिखेंगे जो हमारे wallet पते से पूर्वनिर्धारित transaction डेटा भेजेगा और eth_sendTransaction RPC विधि को कॉल करेगा।
example.tsx
// packages/site/src/utils/snap.ts

export const sendTransaction = async (data: any): Promise<any> => {
  try {
    const [from] = (await window.ethereum.request({
      method: 'eth_requestAccounts',
    })) as string[];

    if (!from) {
      return Promise.reject(Error('Failed to get an account'));
    }

    // https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction
    return window.ethereum.request({
      method: 'eth_sendTransaction',
      params: [
        {
          ...data,
          from,
        },
      ],
    });
  } catch (e) {
    console.error(e);
    return e;
  }
};
eth_sendTransaction विधि call onTransaction handler को trigger करेगी, जो हमारे कस्टम simulate function को call करेगी, जिसे simulation.ts में परिभाषित किया गया था।
example.tsx
// packages/snap/src/index.ts

export const onTransaction: OnTransactionHandler = async ({ transaction, transactionOrigin }) => {
  if (!isObject(transaction) || !hasProperty(transaction, 'to')) {
    return {
      content: {
        value: 'Unknown transaction type',
        type: NodeType.Text,
      },
    };
  }

  const simulationResponse = await simulate(transaction, transactionOrigin || '');

  return {
    content: {
      children: simulationResponse.children,
      type: NodeType.Panel,
    },
  };
};
onTransaction handler में, simulate function को transaction और उसके origin को arguments के रूप में कॉल किया जाता है। simulate function एक्सेस credentials fetch करने, transaction डेटा को Tenderly API को submit करने, किसी भी त्रुटि को संभालने और output के लिए API प्रतिक्रिया को format करने के लिए ज़िम्मेदार है। Simulation के परिणाम MetaMask UI के भीतर प्रदर्शित होते हैं। नीचे दी गई छवियाँ demo.eth को 1 USDC का एक सफल ERC20 token transfer दिखाती हैं। Output formatter.ts फ़ाइल में परिभाषित functions द्वारा उत्पन्न होता है।
ERC20 Transfer - send 1 USDC to demo.eth
उदाहरण के लिए, Asset Changes ब्लॉक, जो हमें simulation से होने वाले डॉलर मूल्य परिवर्तन दिखाता है, formatAssetChanges() function द्वारा उत्पन्न होता है। आपको simulated transaction का एक लिंक भी मिलता है जिसे आप Tenderly में खोल सकते हैं और Debugger के साथ इसका आगे निरीक्षण कर सकते हैं या इसे विभिन्न मानों के साथ resimulate कर सकते हैं। यह लिंक formatter.ts फ़ाइल में परिभाषित formatSimulationUrl() function द्वारा उत्पन्न होता है।
example.ts
export function formatSimulationUrl(data: any, credentials: TenderlyCredentials): Component[] {
  const simulationUrl = `https://dashboard.tenderly.co/${credentials.accountId}/${credentials.projectId}/simulator/${data.simulation?.id}`;
  const sharedSimulationUrl = `https://tdly.co/shared/simulation/${data.simulation?.id}`;

  return [
    heading('Tenderly Dashboard:'),
    text('See full simulation details in Tenderly.'),
    text(`**Status:** ${data.transaction?.status ? 'Success ✅' : 'Failed ❌'}`),
    copyable(`${simulationUrl}`),
    text('Share simulation details with others! 🤗'),
    copyable(`${sharedSimulationUrl}`),
  ];
}

एक पूर्वनिर्धारित payload के साथ विफल transaction

दूसरे उदाहरण के लिए, हम एक पूर्वनिर्धारित payload के साथ एक विफल transaction का simulation करेंगे। नीचे दी गई छवि demo.eth को 1,000,000 USDC का एक विफल ERC20 token transfer दिखाती है।
Preview of the failed transaction
हमें Tenderly Dashboard का एक लिंक भी मिलता है, जहाँ उपयोगकर्ता stack trace, events, state परिवर्तन, gas consumption, आदि का निरीक्षण कर सकता है। यह विशेष रूप से यह समझने के लिए उपयोगी है कि transaction क्यों विफल हुआ। उपयोगकर्ता विफल transaction को debug करना और विभिन्न समाधानों का परीक्षण करने के लिए resimulating जारी रख सकता है।

एक कस्टम payload के साथ Simulation

एक कस्टम payload के साथ simulation चलाने के लिए, आपको एक ऐसा object जोड़ना होगा जो Ethereum transaction specification के अनुरूप हो।
Custom payload UI
इसमें निम्नलिखित फ़ील्ड हो सकते हैं:
  • from: DATA, 20 Bytes - वह पता जहाँ से transaction भेजा गया है।
  • to: DATA, 20 Bytes - (नए contract बनाते समय वैकल्पिक) वह पता जहाँ transaction निर्देशित है।
  • gas: QUANTITY - (वैकल्पिक, default: 90000) transaction निष्पादन के लिए प्रदान किए गए gas का Integer। यह अप्रयुक्त gas लौटाएगा।
  • gasPrice: QUANTITY - (वैकल्पिक, default: निर्धारित किया जाना है) प्रत्येक paid gas के लिए उपयोग किए गए gasPrice का Integer।
  • value: QUANTITY - (वैकल्पिक) इस transaction के साथ भेजे गए मान का Integer।
  • data: DATA - एक contract का compiled code या invoked method signature और encoded पैरामीटर्स का hash।
  • nonce: QUANTITY - (वैकल्पिक) एक nonce का Integer। यह आपको समान nonce का उपयोग करने वाले अपने स्वयं के pending transactions को overwrite करने की अनुमति देता है।
सभी संख्यात्मक मान hexadecimal strings होने चाहिए, और पते Ethereum पते (20 bytes) होने चाहिए।
Send a custom payload
कस्टम payload दर्ज करने के बाद, उपयोगकर्ता पहले की तरह ही sendTransaction function का उपयोग करके simulation शुरू कर सकते हैं। यह कस्टम payload को onTransaction handler को पास करता है, जो फिर simulation चलाने के लिए simulate function को trigger करता है।

आगे के चरण

इस ट्यूटोरियल में, आपने सीखा कि Tenderly Simulation API द्वारा संचालित एक MetaMask Snap में transaction preview विकल्प कैसे जोड़ें। आप इस प्रोजेक्ट के लिए source code GitHub पर पा सकते हैं Tenderly पर transaction simulation आपके प्रोजेक्ट और आवश्यकताओं के आधार पर तीन तरीकों से शुरू की जा सकती है। इन सहायता संसाधनों के साथ अपने dapps में simulations को एकीकृत करना सीखें:

Simulation UI

Simulation API

Simulation RPC