मुख्य सामग्री पर जाएं
Simulation RPC Mainnet, Boba और Polygon के साथ संगत है, जबकि अन्य नेटवर्क को धीरे-धीरे एकीकृत किया जाएगा।\ Simulation API सभी Tenderly-समर्थित नेटवर्क के साथ संगत है।
आप Simulation RPC या Simulation API को एकीकृत करके अपने dapp में simulations पेश कर सकते हैं।

Simulation API को एकीकृत करने के लाभ

Simulation API/Simulation RPC को एकीकृत करके
  1. उपयोगकर्ता के हस्ताक्षर करने और on-chain सबमिट करने से पहले उनके transactions का dry-run करें।
  2. संभावित rollbacks में बेहतर दृश्यता प्रदान करें और gas शुल्क पर पैसे खोने से बचें।
  3. सफल apps के परिणामों में बेहतर दृश्यता प्रदान करें, जिसमें असेट्स की गति और उपयोगकर्ता के लिए प्रासंगिक state परिवर्तन शामिल हैं।
  4. उपयोगकर्ताओं को यह दिखाने के लिए simulation परिणामों के आसपास logic बनाएँ कि क्या उनके transactions इष्टतम मूल्य लाते हैं और सुधार सुझाएँ।
यहाँ कुछ उदाहरण दिए गए हैं:
  • यदि आप एक wallet-जैसा app बना रहे हैं, तो आप दिखा सकते हैं कि transaction ERC-20 tokens को कैसे स्थानांतरित करता है और उपयोगकर्ताओं को अपने funds के बदलाव देखने में सक्षम बना सकते हैं।
  • यदि आप एक DeFi उत्पाद बना रहे हैं, तो आप events का उपयोग यह विश्लेषण करने के लिए कर सकते हैं कि क्या कोई transaction UI में उपयोगकर्ता द्वारा सेट की गई इष्टतम शर्तों को पूरा करता है।
  • यदि आप कई transactions से युक्त एक governance proposal तैयार कर रहे हैं, तो आप यह देखने के लिए एक simulation bundle कर सकते हैं कि proposal कैसे लागू होता है।
  • आप अपने proposal transactions को कई परीक्षण transactions के साथ भी bundle कर सकते हैं ताकि यह सत्यापित हो सके कि आपका proposal इच्छित रूप से निष्पादित होता है और संभावित अंधे धब्बों की पहचान की जा सके।

उदाहरण: Uniswap UI में Simulations जोड़ना

इस उदाहरण में, हम दिखाएँगे कि Simulation RPC को Uniswap UI में कैसे एकीकृत करें और exchange पथ के साथ सटीक token hops कैसे दिखाएँ। इस तरह, हम उपयोगकर्ता को transaction के प्रभावों में उच्च दृश्यता देंगे और उन्हें यह तय करने के लिए एक अच्छी तरह से सूचित निर्णय लेने की अनुमति देंगे कि आगे बढ़ना है या नहीं।

Simulation component आवश्यकताएँ

यहाँ simulation component के लिए आवश्यकताएँ हैं:
  • component को transaction पर हस्ताक्षर करने और भेजने से पहले और बाद में उपयोगकर्ता के पास मौजूद tokens की संख्या प्रदर्शित करनी चाहिए।
  • Simulation हर बार trade डेटा बदलने पर किया जाना चाहिए, इसलिए इसे trade और allowedSlippage पैरामीटर्स प्राप्त करने की आवश्यकता है।
  • Component को निम्नलिखित का ट्रैक रखना चाहिए:
    • वर्तमान balances (swap से पहले)।
    • Swap event जिसका उपयोग हम नए balances की गणना के लिए करेंगे।
    • Transfer events की एक array जिसका उपयोग हम नए balances की गणना के लिए करेंगे।

Simulation को ConfirmSwapModal में Render करें

उपयोगकर्ता को transaction के परिणामों के बारे में सूचित करने का सबसे अच्छा स्थान ConfirmSwapModal है, ठीक इससे पहले कि वे transaction पर हस्ताक्षर कर सकें और भेज सकें। Code को संक्षिप्तता के लिए संपादित किया गया है:
example
export default function ConfirmSwapModal({
  /* ... */
}: {
  /* ... */
}) {
  // ...
  const modalHeader = useCallback(() => {
    return trade ? (
      <>
        <SwapModalHeader.../>
+        <Simulation trade={trade} recipient={null} allowedSlippage={allowedSlippage} />
      </>
    ) : null
  }, [/* ... */])
  //...

Simulation component implementation

Component का logic simulate function में निहित है:
  • यह trade या provider arguments बदलने की स्थिति में चलता है, इसलिए जब भी swap संभावित रूप से बदलता है, यह अपडेट और re-simulate होता है।
  • यह setOldBalances को कॉल करता है, जो In और Out ERC-20 tokens के balances प्राप्त करता है और उन्हें oldBalances state variable में संग्रहीत करता है।
  • यह simulateRPC को कॉल करता है, जो tenderly_simulateTranscation को Simulation RPC कॉल करता है और फिर:
    • यह Transfer events खोजने के लिए decoded logs के माध्यम से parse करता है और उन्हें component के transfers state variable में संग्रहीत करता है।
    • यह Swap event खोजने के लिए decoded logs के माध्यम से parse करता है और उसे component के swap state variable में संग्रहीत करता है।
अंत में, simulation परिणामों को render करने के लिए, हम SimulationDetails component प्रदर्शित करते हैं, जो एक शुद्ध functional component है। यह पुराने और नए states की गणना करता है और trade, swap, transfers, और oldBalances के आधार पर डेटा render करता है।
example.tsx
const Simulation = ({
  trade,
  allowedSlippage,
  recipient,
}: {
  trade: InterfaceTrade<Currency, Currency, TradeType> | undefined;
  recipient: string | null;
  allowedSlippage: Percent;
}) => {
  const { account, provider } = useWeb3React();
  const nativeCurrency = useNativeCurrency();

  const deadline = useTransactionDeadline();
  const signatureData = useERC20PermitFromTrade(trade, allowedSlippage, deadline);
  const args = useSwapCallArguments(
    trade,
    allowedSlippage,
    recipient,
    signatureData.signatureData,
    deadline,
    undefined,
  );

  const [oldBalances, setOldBalances] = useState<any[]>([]);
  const [transfers, setTransfers] = useState<any[]>([]);
  const [swap, setSwap] = useState<any>({});

  useEffect(() => {
    onSimulate();
  }, [trade, provider]);

  async function onSimulate() {
    setOldBalances([]);
    setSwap({});
    const { address, calldata, value } = args[0];
    const provider = RPC_PROVIDERS[SupportedChainId.MAINNET];

    await getCurrentBalances();
    await simulateRPC(account, address, calldata, value);
  }

  async function getCurrentBalances() {
    return Promise.all([
      provider.send('eth_getBalance', [account, 'latest']),
      provider.send('eth_call', [
        {
          to: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
          data: `0x70a0823100000000000000000000000000${stripX(account)}`,
        },
        'latest',
      ]),
    ]).then(oldBalances => {
      setOldBalances(oldBalances);
    });
  }

  async function simulateRPC(account: string, address: string, calldata: string, value: string) {
    RPC_PROVIDERS[SupportedChainId.MAINNET]
      .send('tenderly_simulateTransaction', [
        {
          from: account,
          to: address,
          data: calldata,
          value: stripHexZero(value),
        },
        'latest', // block number to simulate on
        null, // optional state overrides for involved contracts
      ])
      .then(simulationResponse => {
        console.log('Simulation Response', simulationResponse);
        setTransfers(simulationResponse.logs.filter((log: any) => log.name === 'Transfer'));
        setSwap(simulationResponse.logs.filter((log: any) => log.name === 'Swap')[0]);
      });
  }

  return (
    <>
      ...
      <SimulationDetails
        trade={trade}
        syncing={oldBalances.length == 0 && transfers.length == 0 && !!swap.inputs}
        transfers={transfers}
        oldBalances={oldBalances}
        swap={swap}
      />
    </>
  );
};