Перейти к основному содержанию

Обзор

Узнайте, как использовать Simulation API в вашем dapp’е, чтобы позволить пользователям предварительно просматривать результаты транзакций перед их отправкой в сеть. Так вы сможете помочь им избежать финансовых потерь из-за неудачных или некорректных транзакций и повысить их уверенность при использовании вашего dapp’а. Чтобы интегрировать Simulation API от Tenderly в ваш dapp для обнаружения потенциальных сбоев транзакции ещё до её отправки в сеть, вам нужно:
  1. Сформировать сырые транзакции из библиотеки ethers.js.
  2. Симулировать транзакции перед их отправкой.
  3. (опционально) Обернуть каждое взаимодействие с блокчейном в симуляцию Tenderly.
Подробности запроса и ответа для отдельного вызова см. в разделе одиночные симуляции.

Формирование сырых транзакций из ethers.js

Первый шаг — создать объект транзакции, который будет отправлен в наш эндпоинт симуляции. Мы сгенерируем его непосредственно из библиотеки ethers.js. В приведённом ниже примере показано, как это можно сделать для функции transfer() поверх контракта DAI:
example.tsx
const dai = new ethers.Contract(DAI_ADDRESS, DAI_ABI, tenderlyForkProvider);

const unsignedTx = await dai.populateTransaction.transfer(
  ZERO_ADDRESS,
  YOUR_ADDRESS,
  util.ether(1),
);

Симуляция транзакций перед отправкой

Теперь, когда мы извлекли неподписанную сырую транзакцию, давайте симулируем её перед отправкой в сеть (в Ethereum Mainnet):
example.tsx
...

const body = {
    "network_id": "1",
    "from": senderAddr,
    "to": contract.address,
    "input": unsignedTx.data,
    "gas": 21204,
    "gas_price": "0",
    "value": 0,
    "save_if_fails": true
}

const headers = {
    headers: {
        'content-type': 'application/JSON',
        'X-Access-Key': TENDERLY_ACCESS_KEY,
  }
}
const resp = await axios.post(apiURL, body, headers);

if (resp.data.simulation.status === false) {
	// it failed, do as you please
}

Оборачивание каждого взаимодействия с блокчейном в симуляцию Tenderly (опционально)

Чтобы гарантировать, что каждое взаимодействие с блокчейном сначала симулируется, напишите простую обёртку вокруг объекта signer из ethers.js, которая всегда будет симулировать транзакции. Кроме того, в дальнейшем вы можете ввести типизированные ошибки, с которыми может взаимодействовать ваша логика:
example.tsx
export class TenderlySimulationSigner {
  public _provider: ethers.Provider;

  constructor(provider: ethers.Provider) {
    this._provider = provider;
  }

  public async sendTransaction(
    transaction: Deferrable<TransactionRequest>,
  ): Promise<TransactionResponse> {
    await this._simulateTx(transaction);

    return this._signer.sendTransaction(transaction);
  }

  public async getAddress(): Promise<string> {
    return this._signer.getAddress();
  }

  public async signTransaction(transaction: Deferrable<TransactionRequest>): Promise<string> {
    return this._signer.signTransaction(transaction);
  }

  _simulateTx(transaction: Deferrable<TransactionRequest>): Promise<void> {
    const unsignedTx = await contract.populateTransaction[funcName](...args);

    const apiURL = `https://api.tenderly.co/api/v1/account/me/project/project/simulate`;
    const body = {
      network_id: '1',
      from: senderAddr,
      to: contract.address,
      input: unsignedTx.data,
      gas: 21204,
      gas_price: '0',
      value: 0,
      save_if_fails: true,
    };

    const headers = {
      headers: {
        'content-type': 'application/JSON',
        'X-Access-Key': REACT_APP_TENDERLY_ACCESS_KEY as string,
      },
    };
    const resp = await axios.post(apiURL, body, headers);
    if (resp.data.simulation.status == false) {
      throw new Error('Transaction is going to fail');
    }

    return;
  }
}
Вот репозиторий на GitHub, где вы можете найти пример этой реализации.