> ## 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.

# Использование Simulation RPC в UI dapp'а

> Интегрируйте симуляции транзакций в ваш dapp через Tenderly Simulation RPC. Следуйте пошаговому примеру интеграции UI Uniswap.

<Note>
  Simulation RPC совместим с Mainnet, Boba и Polygon, а другие сети будут
  интегрированы постепенно.\ Simulation API совместим со [всеми сетями, поддерживаемыми
  Tenderly](/node-rpc/overview).
</Note>

Вы можете добавить симуляции в свой dapp, интегрировав Simulation RPC или Simulation API.

### Преимущества интеграции Simulation API

Интегрируя Simulation API/Simulation RPC, вы можете:

1. Делать сухой прогон транзакций пользователей перед тем, как они подпишут и отправят их в сеть.
2. Обеспечивать лучшую видимость потенциальных откатов и избегать потерь на комиссиях за газ.
3. Обеспечивать лучшую видимость результатов успешных приложений, включая перемещения активов и изменения состояния, релевантные для пользователя.
4. Выстраивать логику вокруг результатов симуляции, чтобы показывать пользователям, приносят ли их транзакции оптимальную ценность, и предлагать улучшения.

Вот несколько примеров:

* Если вы создаёте приложение, похожее на кошелёк, вы можете показывать, как транзакция перемещает токены ERC-20, и позволять пользователям видеть движение своих средств.
* Если вы создаёте DeFi-продукт, вы можете использовать события для анализа того, соответствует ли транзакция оптимальным условиям, установленным пользователем в UI.
* Если вы готовите предложение по управлению, состоящее из нескольких транзакций, вы можете сделать симуляционный пакет, чтобы увидеть, как предложение применяется.
* Вы даже можете объединить транзакции предложения с несколькими тестовыми транзакциями, чтобы убедиться, что ваше предложение выполняется как задумано, и выявить возможные слепые зоны.

### Пример: добавление симуляций в UI Uniswap

В этом примере мы покажем, как интегрировать Simulation RPC в UI Uniswap и отобразить точные переходы токенов вдоль пути обмена. Так мы дадим пользователю более высокую видимость эффектов транзакции и позволим ему принять обоснованное решение о том, продолжать ли выполнение.

## Требования к компоненту `Simulation`

Вот требования к компоненту симуляции:

* Компонент должен отображать количество токенов у пользователя до и после подписания и отправки транзакции.
* Симуляция должна выполняться каждый раз при изменении данных сделки, поэтому ему нужно получать параметры `trade` и `allowedSlippage`.
* Компонент должен отслеживать:
  * Текущие балансы (до свопа).
  * Событие `Swap`, которое мы будем использовать для расчёта новых балансов.
  * Массив событий `Transfer`, которые мы будем использовать для расчёта новых балансов.

## Рендер `Simulation` внутри `ConfirmSwapModal`

Лучшее место, чтобы проинформировать пользователя о результатах транзакции — `ConfirmSwapModal`, непосредственно перед тем, как он сможет подписать и отправить транзакцию.

Код сокращён для краткости:

```diff title="example" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
export default function ConfirmSwapModal({
  /* ... */
}: {
  /* ... */
}) {
  // ...
  const modalHeader = useCallback(() => {
    return trade ? (
      <>
        <SwapModalHeader.../>
+        <Simulation trade={trade} recipient={null} allowedSlippage={allowedSlippage} />
      </>
    ) : null
  }, [/* ... */])
  //...

```

## Реализация компонента `Simulation`

Логика компонента лежит в функции **simulate**:

* Она запускается при изменении аргументов `trade` или `provider`, поэтому обновляется и ресимулирует всякий раз, когда своп потенциально меняется.
* Она вызывает `setOldBalances`, которая получает балансы токенов ERC-20 In и Out и сохраняет их в переменной состояния `oldBalances`.
* Она вызывает `simulateRPC`, которая выполняет вызов Simulation RPC к `tenderly_simulateTranscation` и затем:
  * Она разбирает декодированные логи, чтобы найти события `Transfer`, и сохраняет их в переменной состояния `transfers` компонента.
  * Она разбирает декодированные логи, чтобы найти событие `Swap`, и сохраняет его в переменной состояния `swap` компонента.

Наконец, для рендеринга результатов симуляции мы отображаем компонент `SimulationDetails`, который является чисто функциональным. Он вычисляет старые и новые состояния и рендерит данные на основе `trade`, `swap`, `transfers` и `oldBalances`.

```tsx title="example.tsx" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
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}
      />
    </>
  );
};
```
