--- title: Simulate Transaction RPC Endpoint Specification version: 2022.09.05 description: Simulate Transaction RPC Endpoint Specification --- > specification for a new RPC method, `tx_optimizeSwap` for simulating transactions # Simulate Transaction RPC Endpoint Specification [TOC] ## Simple Summary Wallet/DApp browser software should provide as much information as possible when presenting a transaction to the user to sign, as there may be unforeseen consequences including a potential loss of funds. A new JSONRPC method `eth_simulateTransaction` enables wallets to perform a dry run of the transaction so that it can provide more information about what might happen such as token movements. ## Abstract This is a standard for a new JSONRPC endpoint `eth_simulateTransaction` that enables clients to perform a dry run (transaction simulation) before signing and submitting an actual transaction. `eth_simulateTransaction`: the base RPC method `tx_optimizeSwap`: built ontop of `eth_simulateTransaction` with the use case of simulating swap transactions for the purposes of triggering OpenMev Router Backrunning function ### Transaction Parameters for Simulation #### Example Block number: 15048064 Current block: 15048064 Use Pending Block: Block number: [] Current block: [] Tx index: 0 Maximum Block Index: 199 From: 0x0000000000000000000000000000000000000000 Gas: 8000000 Gas Price: 0 Value: 0 Use Block Header Overrides Block number: 0 Timestamp: 1656554914 State Overrides Add contracts and set state overrides. Access Lists: This Simulation will have the Berlin fork enabled, which includes support for EIP-2930 Optional access lists. Add address to access list > Recommended Access List ## Motivation When transaction signing is requested and presented to the user, wallet/DApp browser software ("wallets") should attempt to inform the user of what the transaction entails and what the side effects may be. Currently, most wallets simply show basic transaction parameters such as the recipient address, the value of ETH being transferred, the gas price/limit, and the encoded data. For well-known transaction types such as ERC20 `approve()` and `transfer()`, some wallets decode the call data and present additional information. For most smart contract transactions however, what the transaction entails is completely opaque to average users, and a malicious transaction may even appear completely harmless (a smart contract transaction will show the value being transferred as zero as if no ETH is moved, but may nevertheless be moving other types of assets such as ERC20 tokens if an allowance was set previously). This is terrible for user experience as it encourages users to be accustomed to signing transactions blindly, which may have adverse consequences such as loss of funds. A new JSONRPC method `eth_simulateTransaction` aims to improve the situation by providing a way for wallets to perform a dry run and read events emitted (such as the ERC20 `Transfer` events), thereby enabling the user to make a more informed decision about whether to sign a transaction that is requested. ## Specification #### `eth_simulateTransaction` Performs a dry-run of the transaction and returns a transaction result object. The transaction will not be added to the blockchain. Note that the actual transaction may have a different result for a variety of reasons including EVM mechanics, node performance, and the difference in the state of the blockchain when the transaction is processed. ##### Parameters 1. `Object` - The transaction object - `from`: `DATA`, 20 Bytes - The address the transaction is send from. - `to`: `DATA`, 20 Bytes - (optional when creating new contract) The address the transaction is directed to. - `gas`: `QUANTITY` - (optional, default: 90000) Integer of the gas provided for the transaction execution. It will return unused gas. - `gasPrice`: `QUANTITY` - (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas - `value`: `QUANTITY` - (optional) Integer of the value sent with this transaction - `data`: `DATA` - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see [Ethereum Contract ABI](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) - `nonce`: `QUANTITY` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. ##### Example Parameters ```js params: [{ "from": "0x1111111111111111111111111111111111111111", "to": "0x2222222222222222222222222222222222222222", "gas": "0x200000", "gasPrice": "0x3b9aca00", "value": "0x0", "data": "0xdeadbeef000000000000000000000001111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000abcde" }] ``` ##### Returns `Object` - A transaction result object. - `transactionHash`: `DATA`, 32 Bytes - hash of the transaction. - `from`: `DATA`, 20 Bytes - address of the sender. - `to`: `DATA`, 20 Bytes - address of the receiver. null when it's a contract creation transaction. - `gasUsed`: `QUANTITY` - The amount of gas used by this specific transaction alone. - `contractAddress`: `DATA`, 20 Bytes - The contract address created, if the transaction was a contract creation, otherwise `null`. - `logs`: `Array` - Array of log objects, which this transaction generated. ##### Example Request ```bash curl -X POST --data \ '{ "jsonrpc": "2.0", "method": "eth_sendTransaction", "params": [ {see above } ], "id": 1 }' ``` - Response ```jsonc // Result { "id": 1, "jsonrpc": "2.0", "result": { "transactionHash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "from": "0x1111111111111111111111111111111111111111", "to": "0x2222222222222222222222222222222222222222", "gasUsed": "0x123456", "contractAddress": "0x3333333333333333333333333333333333333333", // or null, if none was created "logs": [ { // logs as returned by getFilterLogs, etc. }, ... ] } } ``` ## Rationale The request parameters are the same as `eth_sendTransaction`, and the response is a subset of a transaction receipt object you can obtain using `eth_getTransactionReceipt`, for consistency and familiarity. Note that it does not require a signed transaction (raw tx), as the motivation is to provide more information to the user before signing happens. ## Implementation There is an existing method `eth_estimateGas` that already performs transaction dry runs, but the method only returns the amount of gas used by the transaction. The code for `eth_estimateGas` may be reusable for the implementation of `eth_simulateTransaction`. ## SushiGuard Router Integration The purpose of this new RPC Method/Service is for providing an optimisic simulation for the purposes of determining if a users transaction will trigger the backrunning function without inccuring additional overhead. It follows that only a subset of overall transactions will meet this criteria. Below are some heruistics for determining if a transaction has such potential. > Note: over time we can backtest non-simulated submitted user transactions to further narrow the profile if need be ### Test Cases Test cases: ** Essentially any trade size over 0.1% of pool reserve value, with an alternate market on uniswap will trigger a backrun** These trades would be simulated via the RPC Method and a transaction generated would then be submitted afterwards. ### Backrun Criteria Does it have to have an alt market on uniswap or can it have two markets on sushi with different pairings? Im assuming markets have same pairings or can be different? Same pairing only, eg. - USDC-WETH (on sushi) - USDC-WETH (on uni) #### Alternative pooling to Trigger Backruns >**Warning** > This section is non-normative, and meant for facilitating discussion - WETH9-WETH10 pool That could work if on both exchanges ? Or even create WETH-'FOLD' market on uni-V2 ? Or just use a lower liquidity pool (...) - How much lower in liquidity does the pool have to be? > Examples https://analytics.sushi.com/pairs/0xec8c342bc3e07f05b9a782bc34e7f04fb9b44502 ### Simulate Transaction RPC Endpoint Use EthereumJS VM ? #### Gnois Safe Transaction Simulator Demo **Gnosis Safe Transaction Simulator reference and demo dapp** Example: https://github.com/rmeissner/safe-simulator/ https://github.com/rmeissner/safe-simulator-app https://github.com/rmeissner/safe-simulator-gh-action https://rimeissner.dev/safe-simulator-app/ ##### Tenderly Simulator Endpoint https://docs.tenderly.co/simulations-and-forks/how-to-simulate-a-transaction ##### Sushiswap Furo UI example Sushi's Furo DApp uses Tenderly to provide similar functionality ### Example, Typescript ```typescript import {ethers, providers, Signer} from "ethers" import axios from "axios" const { REACT_APP_TENDERLY_ACCESS_KEY, } = process.env export const sendTransaction = async (provider: any, sender: string, contract: any, funcName: string, ...args: any[]) => { if (provider instanceof providers.JsonRpcProvider) { const unsignedTx = await contract.populateTransaction[funcName](...args) const transactionParameters = [{ to: contract.address, from: sender, data: unsignedTx.data, gas: ethers.utils.hexValue(3000000), gasPrice: ethers.utils.hexValue(1), value: ethers.utils.hexValue(0) }]; try { const txHash = await provider.send('eth_sendTransaction', transactionParameters) return { txHash: txHash } } catch(err) { console.log(err) } } else if (provider instanceof Signer) { try { const tx = await contract[funcName](...args) return { txHash: tx.hash } } catch (err) { console.log(err) } } } export const simulateTransaction = async (senderAddr: string, contract: any, funcName: string, ...args: any[]) => { 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); return resp } ``` ## Security Considerations Wallets and DApp browsers utilizing `eth_simulateTransaction` must highlight that it can only provide an _estimated_ outcome and that the actual mileage may vary.