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

# 捆绑模拟

> 了解如何在一次 API 或 RPC 请求中模拟多笔交易。

模拟捆绑（Simulation Bundles）允许您连续模拟多笔交易。例如，为了在模拟目标交易之前设置特定
条件，您需要先执行其他若干笔交易。

[Simulation API](/simulations/bundled-simulations#rpc-bundled-simulations) 和 [Simulation RPC](/simulations/bundled-simulations#api-bundled-simulations) 均支持捆绑模拟。端点会接收一个交易数组，并在同一区块内依次模拟这些交易。

## RPC 捆绑模拟

[Node RPC](/node-rpc/overview) 允许您读取区块链数据并发送交易。但您也可以通过单个 RPC URL 在 Node 上模拟捆绑交易。通过 RPC 进行的模拟仅在受支持的网络上可用。如果您的网络不受 Node 支持，请改为通过 [Simulation API](/simulations/bundled-simulations#api-bundled-simulations) 运行捆绑模拟。

从 [Dashboard](https://dashboard.tenderly.co/register?redirectTo=gateways) 获取 RPC URL。

前往 **Node** > **Copy HTTPS URL** 复制所需网络的 URL。

```bash title="example" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
https://mainnet.gateway.tenderly.co/$TENDERLY_NODE_ACCESS_KEY
```

要通过 RPC 模拟捆绑交易，请调用 `tenderly_simulateBundle` 方法。该自定义方法允许您通过将多笔交易作为数组传递来对其进行模拟。[请参阅 RPC 参考](/node-rpc/rpc-reference?network=ethereum-mainnet\&method=tenderly_simulateBundle)。

<Note>
  交易会在同一区块内依次进行模拟。
</Note>

**示例**

<Tabs>
  <Tab title="example">
    ```bash title="example" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
    curl https://mainnet.gateway.tenderly.co/$TENDERLY_NODE_ACCESS_KEY \
      -X POST \
      -H "Content-Type: application/json" \
      -d \
      '{
        "id": 0,
        "jsonrpc": "2.0",
        "method": "tenderly_simulateBundle",
        "params": [
          [
            {
              "from": "0xe2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2",
              "to": "0x6b175474e89094c44da98b954eedeac495271d0f",
              "data": "0x40c10f19000000000000000000000000e58b9ee93700a616b50509c8292977fa7a0f8ce10000000000000000000000000000000000000000000000001bc16d674ec80000"
            },
            {
              "from": "0xe58b9ee93700a616b50509c8292977fa7a0f8ce1",
              "to": "0x6b175474e89094c44da98b954eedeac495271d0f",
              "gas": "0x7a1200",
              "data": "0x095ea7b3000000000000000000000000f7ddedc66b1d482e5c38e4730b3357d32411e5dd0000000000000000000000000000000000000000000000000de0b6b3a7640000"
            },
            {
              "from": "0xf7ddedc66b1d482e5c38e4730b3357d32411e5dd",
              "to": "0x6b175474e89094c44da98b954eedeac495271d0f",
              "gas": "0x7a1200",
              "data": "0x23b872dd000000000000000000000000e58b9ee93700a616b50509c8292977fa7a0f8ce1000000000000000000000000bd8daa414fda8a8a129f7035e7496759c5af8570000000000000000000000000000000000000000000000000006a94d74f430000"
            }
          ],
          "latest",
          {
            "0x6b175474e89094c44da98b954eedeac495271d0f": {
              "stateDiff": {
                "0xedd7d04419e9c48ceb6055956cbb4e2091ae310313a4d1fa7cbcfe7561616e03": "0x0000000000000000000000000000000000000000000000000000000000000001"
              }
            }
          }
        ]
      }'
    ```
  </Tab>

  <Tab title="response.json">
    ```json title="response.json" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
    {
      "id": 0,
      "jsonrpc": "2.0",
      "result": [
        {
          "status": true,
          "gasUsed": "0xd0d9",
          "cumulativeGasUsed": "0x0",
          "blockNumber": "0x121c950",
          "type": "0x0",
          "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000010000000020000000000000000000800000000000000000000000010000000000000000000004000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000020000000002000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000",
          "logs": [
            {
              "name": "Transfer",
              "anonymous": false,
              "inputs": [
                {
                  "value": "0x0000000000000000000000000000000000000000",
                  "type": "address",
                  "name": "src"
                },
                {
                  "value": "0xe58b9ee93700a616b50509c8292977fa7a0f8ce1",
                  "type": "address",
                  "name": "dst"
                },
                {
                  "value": "2000000000000000000",
                  "type": "uint256",
                  "name": "wad"
                }
              ],
              "raw": {
                "address": "0x6b175474e89094c44da98b954eedeac495271d0f",
                "topics": [
                  "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
                  "0x0000000000000000000000000000000000000000000000000000000000000000",
                  "0x000000000000000000000000e58b9ee93700a616b50509c8292977fa7a0f8ce1"
                ],
                "data": "0x0000000000000000000000000000000000000000000000001bc16d674ec80000"
              }
            }
          ],
          "trace": [
            {
              "type": "CALL",
              "from": "0xe2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2",
              "to": "0x6b175474e89094c44da98b954eedeac495271d0f",
              "gas": "0xbeb6d8c",
              "gasUsed": "0x7c65",
              "value": "0x0",
              "input": "0x40c10f19000000000000000000000000e58b9ee93700a616b50509c8292977fa7a0f8ce10000000000000000000000000000000000000000000000001bc16d674ec80000",
              "decodedInput": [
                {
                  "value": "0xe58b9ee93700a616b50509c8292977fa7a0f8ce1",
                  "type": "address",
                  "name": "usr"
                },
                {
                  "value": "2000000000000000000",
                  "type": "uint256",
                  "name": "wad"
                }
              ],
              "method": "mint",
              "output": "0x",
              "subtraces": 0,
              "traceAddress": []
            }
          ],
          "assetChanges": [
            {
              "assetInfo": {
                "standard": "ERC20",
                "type": "Fungible",
                "contractAddress": "0x6b175474e89094c44da98b954eedeac495271d0f",
                "symbol": "dai",
                "name": "Dai",
                "logo": "https://assets.coingecko.com/coins/images/9956/large/Badge_Dai.webp?1696509996",
                "decimals": 18,
                "dollarValue": "0.9996880292892456"
              },
              "type": "Mint",
              "to": "0xe58b9ee93700a616b50509c8292977fa7a0f8ce1",
              "rawAmount": "0x1bc16d674ec80000",
              "amount": "2",
              "dollarValue": "1.9993760585784912109"
            }
          ],
          "balanceChanges": [
            {
              "address": "0xe58b9ee93700a616b50509c8292977fa7a0f8ce1",
              "dollarValue": "1.9993760585784912109",
              "transfers": [
                0
              ]
            }
          ]
        },
        {
          "status": true,
          "gasUsed": "0xb442",
          "cumulativeGasUsed": "0x0",
          "blockNumber": "0x121c950",
          "type": "0x0",
          "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000200000000000000000000000000008000000000000000000000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000004000800000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000002000000000000000000000000100010000000000000000000000000000000000000000000000000000000000000",
          "logs": [
            {
              "name": "Approval",
              "anonymous": false,
              "inputs": [
                {
                  "value": "0xe58b9ee93700a616b50509c8292977fa7a0f8ce1",
                  "type": "address",
                  "name": "src"
                },
                {
                  "value": "0xf7ddedc66b1d482e5c38e4730b3357d32411e5dd",
                  "type": "address",
                  "name": "guy"
                },
                {
                  "value": "1000000000000000000",
                  "type": "uint256",
                  "name": "wad"
                }
              ],
              "raw": {
                "address": "0x6b175474e89094c44da98b954eedeac495271d0f",
                "topics": [
                  "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925",
                  "0x000000000000000000000000e58b9ee93700a616b50509c8292977fa7a0f8ce1",
                  "0x000000000000000000000000f7ddedc66b1d482e5c38e4730b3357d32411e5dd"
                ],
                "data": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
              }
            }
          ],
          "trace": [
            {
              "type": "CALL",
              "from": "0xe58b9ee93700a616b50509c8292977fa7a0f8ce1",
              "to": "0x6b175474e89094c44da98b954eedeac495271d0f",
              "gas": "0x79bd80",
              "gasUsed": "0x5fc2",
              "value": "0x0",
              "input": "0x095ea7b3000000000000000000000000f7ddedc66b1d482e5c38e4730b3357d32411e5dd0000000000000000000000000000000000000000000000000de0b6b3a7640000",
              "decodedInput": [
                {
                  "value": "0xf7ddedc66b1d482e5c38e4730b3357d32411e5dd",
                  "type": "address",
                  "name": "usr"
                },
                {
                  "value": "1000000000000000000",
                  "type": "uint256",
                  "name": "wad"
                }
              ],
              "method": "approve",
              "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
              "decodedOutput": [
                {
                  "value": true,
                  "type": "bool",
                  "name": ""
                }
              ],
              "subtraces": 0,
              "traceAddress": []
            }
          ]
        },
        {
          "status": true,
          "gasUsed": "0xe38b",
          "cumulativeGasUsed": "0x0",
          "blockNumber": "0x121c950",
          "type": "0x0",
          "logsBloom": "0x00000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000010000000000000000000004000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000002000000000000000000020000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000",
          "logs": [
            {
              "name": "Transfer",
              "anonymous": false,
              "inputs": [
                {
                  "value": "0xe58b9ee93700a616b50509c8292977fa7a0f8ce1",
                  "type": "address",
                  "name": "src"
                },
                {
                  "value": "0xbd8daa414fda8a8a129f7035e7496759c5af8570",
                  "type": "address",
                  "name": "dst"
                },
                {
                  "value": "30000000000000000",
                  "type": "uint256",
                  "name": "wad"
                }
              ],
              "raw": {
                "address": "0x6b175474e89094c44da98b954eedeac495271d0f",
                "topics": [
                  "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
                  "0x000000000000000000000000e58b9ee93700a616b50509c8292977fa7a0f8ce1",
                  "0x000000000000000000000000bd8daa414fda8a8a129f7035e7496759c5af8570"
                ],
                "data": "0x000000000000000000000000000000000000000000000000006a94d74f430000"
              }
            }
          ],
          "trace": [
            {
              "type": "CALL",
              "from": "0xf7ddedc66b1d482e5c38e4730b3357d32411e5dd",
              "to": "0x6b175474e89094c44da98b954eedeac495271d0f",
              "gas": "0x79bc28",
              "gasUsed": "0x8db3",
              "value": "0x0",
              "input": "0x23b872dd000000000000000000000000e58b9ee93700a616b50509c8292977fa7a0f8ce1000000000000000000000000bd8daa414fda8a8a129f7035e7496759c5af8570000000000000000000000000000000000000000000000000006a94d74f430000",
              "decodedInput": [
                {
                  "value": "0xe58b9ee93700a616b50509c8292977fa7a0f8ce1",
                  "type": "address",
                  "name": "src"
                },
                {
                  "value": "0xbd8daa414fda8a8a129f7035e7496759c5af8570",
                  "type": "address",
                  "name": "dst"
                },
                {
                  "value": "30000000000000000",
                  "type": "uint256",
                  "name": "wad"
                }
              ],
              "method": "transferFrom",
              "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
              "decodedOutput": [
                {
                  "value": true,
                  "type": "bool",
                  "name": ""
                }
              ],
              "subtraces": 0,
              "traceAddress": []
            }
          ],
          "assetChanges": [
            {
              "assetInfo": {
                "standard": "ERC20",
                "type": "Fungible",
                "contractAddress": "0x6b175474e89094c44da98b954eedeac495271d0f",
                "symbol": "dai",
                "name": "Dai",
                "logo": "https://assets.coingecko.com/coins/images/9956/large/Badge_Dai.webp?1696509996",
                "decimals": 18,
                "dollarValue": "0.9996880292892456"
              },
              "type": "Transfer",
              "from": "0xe58b9ee93700a616b50509c8292977fa7a0f8ce1",
              "to": "0xbd8daa414fda8a8a129f7035e7496759c5af8570",
              "rawAmount": "0x6a94d74f430000",
              "amount": "0.03",
              "dollarValue": "0.029990640878677368163"
            }
          ],
          "balanceChanges": [
            {
              "address": "0xbd8daa414fda8a8a129f7035e7496759c5af8570",
              "dollarValue": "0.029990640878677368163",
              "transfers": [
                0
              ]
            },
            {
              "address": "0xe58b9ee93700a616b50509c8292977fa7a0f8ce1",
              "dollarValue": "-0.029990640878677368163",
              "transfers": [
                0
              ]
            }
          ]
        }
      ]
    }
    ```
  </Tab>
</Tabs>

## API 捆绑模拟

使用 `simulate-bundle` API 端点一次性模拟多笔连续的交易。[请参阅 API 参考](/api-reference)。

```bash title="example" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
https://api.tenderly.co/api/v1/account/${TENDERLY_ACCOUNT_SLUG}/project/${TENDERLY_PROJECT_SLUG}/simulate-bundle
```

模拟输出显示了如果您将该交易发送到区块链上时可能引发的事件和状态变化。

如果某笔交易失败，将提前返回，包含直至失败点的所有模拟结果。

**示例**

<Tabs>
  <Tab title="Shell">
    ```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
    curl --request POST \
      --url https://api.tenderly.co/api/v1/account/me/project/project/simulate-bundle \
      --header 'Accept: application/json' \
      --header 'Content-Type: application/json' \
      --header "X-Access-Key: $TENDERLY_ACCESS_KEY" \
      --data '{
      "simulations": [
        {
          "network_id": "1",
          "save": true,
          "save_if_fails": true,
          "simulation_type": "full",
          "from": "0xe2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2",
          "to": "0x6b175474e89094c44da98b954eedeac495271d0f",
          "input": "0x40c10f19000000000000000000000000e58b9ee93700a616b50509c8292977fa7a0f8ce10000000000000000000000000000000000000000000000001bc16d674ec80000",
          "state_objects": {
            "0x6b175474e89094c44da98b954eedeac495271d0f": {
              "storage": {
                "0xedd7d04419e9c48ceb6055956cbb4e2091ae310313a4d1fa7cbcfe7561616e03": "0x0000000000000000000000000000000000000000000000000000000000000001"
              }
            }
          }
        },
        {
          "network_id": "1",
          "save": true,
          "save_if_fails": true,
          "simulation_type": "full",
          "from": "0xe58b9ee93700a616b50509c8292977fa7a0f8ce1",
          "to": "0x6b175474e89094c44da98b954eedeac495271d0f",
          "input": "0x095ea7b3000000000000000000000000f7ddedc66b1d482e5c38e4730b3357d32411e5dd0000000000000000000000000000000000000000000000000de0b6b3a7640000"
        },
        {
          "network_id": "1",
          "save": true,
          "save_if_fails": true,
          "simulation_type": "full",
          "from": "0xf7ddedc66b1d482e5c38e4730b3357d32411e5dd",
          "to": "0x6b175474e89094c44da98b954eedeac495271d0f",
          "input": "0x23b872dd000000000000000000000000e58b9ee93700a616b50509c8292977fa7a0f8ce1000000000000000000000000bd8daa414fda8a8a129f7035e7496759c5af8570000000000000000000000000000000000000000000000000006a94d74f430000"
        }
      ]
    }'
    ```
  </Tab>

  <Tab title="request.ts">
    ```ts title="request.ts" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}

    dotenv.config();

    // assuming environment variables TENDERLY_ACCOUNT_SLUG, TENDERLY_PROJECT_SLUG and TENDERLY_ACCESS_KEY are set
    const { TENDERLY_ACCOUNT_SLUG, TENDERLY_PROJECT_SLUG, TENDERLY_ACCESS_KEY } = process.env;

    const batchedSimulations = async () => {
      console.time('Batch Simulation');

      const daiSequence = (
        await axios.post(
          `https://api.tenderly.co/api/v1/account/${TENDERLY_ACCOUNT_SLUG}/project/${TENDERLY_PROJECT_SLUG}/simulate-bundle`,
          // the transaction
          {
            simulations: getTxSequence().map((transaction) => ({
              network_id: '1', // network to simulate on
              save: true,
              save_if_fails: true,
              simulation_type: 'full',
              ...transaction,
            })),
          },
          {
            headers: {
              'X-Access-Key': TENDERLY_ACCESS_KEY as string,
            },
          },
        )
      ).data;
      console.timeEnd('Batch Simulation');
      console.log(JSON.stringify(daiSequence, null, 2));
    };

    function getTxSequence() {
      const fakeWardAddress = '0xe2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2';
      const daiOwner = 'e58b9ee93700a616b50509c8292977fa7a0f8ce1';
      const daiSpend = 'f7ddedc66b1d482e5c38e4730b3357d32411e5dd';
      const daiRecip = 'e58b9ee93700a616b50509c8292977fa7a0f8ce1';
      const daiContract = '0x6b175474e89094c44da98b954eedeac495271d0f';
      return [
        // TX1: Mint 2 DAI for e58b9ee93700a616b50509c8292977fa7a0f8ce1.
        // Must do state override so sender (from) is considered a ward for this simulation
        {
          from: fakeWardAddress,
          to: '0x6b175474e89094c44da98b954eedeac495271d0f',
          input:
            '0x40c10f19000000000000000000000000e58b9ee93700a616b50509c8292977fa7a0f8ce10000000000000000000000000000000000000000000000001bc16d674ec80000',
          // make 0xcace477c66b1f2e151974eeada9ac8b95a31c50593ae1db2f048f0a2b54c1424 a ward
          state_objects: {
            '0x6b175474e89094c44da98b954eedeac495271d0f': {
              storage: {
                '0xedd7d04419e9c48ceb6055956cbb4e2091ae310313a4d1fa7cbcfe7561616e03':
                  '0x0000000000000000000000000000000000000000000000000000000000000001',
              },
            },
          },
        },
        // TX2: e58b9ee93700a616b50509c8292977fa7a0f8ce1 approves 1 DAI to f7ddedc66b1d482e5c38e4730b3357d32411e5dd
        {
          from: '0xe58b9ee93700a616b50509c8292977fa7a0f8ce1',
          to: '0x6b175474e89094c44da98b954eedeac495271d0f',
          input:
            '0x095ea7b3000000000000000000000000f7ddedc66b1d482e5c38e4730b3357d32411e5dd0000000000000000000000000000000000000000000000000de0b6b3a7640000',
        },
        {
          // TX3: 0xf7ddedc66b1d482e5c38e4730b3357d32411e5dd calls transferFrom to transfer 0.5 DAI belonging to e58b9ee93700a616b50509c8292977fa7a0f8ce1, sending them to e58b9ee93700a616b50509c8292977fa7a0f8ce1
          from: '0xf7ddedc66b1d482e5c38e4730b3357d32411e5dd',
          to: '0x6b175474e89094c44da98b954eedeac495271d0f',
          input:
            '0x23b872dd000000000000000000000000e58b9ee93700a616b50509c8292977fa7a0f8ce1000000000000000000000000bd8daa414fda8a8a129f7035e7496759c5af8570000000000000000000000000000000000000000000000000006a94d74f430000',
        },
      ];
    }

    function getWardStorageLocation(wardAddress: string) {
      // calculate the storage location of `wards[wardAddress]`
      // yields 0xedd7d04419e9c48ceb6055956cbb4e2091ae310313a4d1fa7cbcfe7561616e03
      return ethers.utils.keccak256(
        ethers.utils.concat([
          ethers.utils.hexZeroPad(wardAddress, 32), // the ward address (address 0x000..0) - mapping key
          ethers.utils.hexZeroPad('0x0', 32), // the wards slot is 0th in the DAI contract - the mapping variable
        ]),
      );
    }

    batchedSimulations();
    ```
  </Tab>
</Tabs>

## 探索使用场景

* [**资产与余额变化**](/simulations/asset-balance-changes)：获取即将发生的所有余额与资产变化的确切美元价值。
* [**Gas 估算**](/simulations/gas-estimation)：在发送交易之前准确预测 gas 费用。
* [**状态覆盖**](/simulations/state-overrides)：修改时间戳、合约数据等区块链状态，以测试不同的场景。
* [**预览交易结果**](/simulations/transaction-preview)：识别并修复可能导致交易失败的问题。

## 后续内容

<Card title="单笔模拟" href="" />

<Card title="通过 SDK 模拟" href="" />
