# EIF Week 1
### Notes
Two types of transactions
- Simple Transfer
- Function calls (This one is to be simulated)
Contracts are basically EVM opcodes sitting on the blockchain to be executed.
Contracts can call other contracts and also themselves creating "internal transactions"
What if one of that calls reaches a "scam contract"?
What if the overall transaction fails for blurry reasons, burning all the gas for nothing.
Losses in DeFi counts in billons of dollars, enough to legitimate "what if" startments and start bringing more security to the ecosystem.
So here are some ways to improve user confidence when signing complex transaction.
- Contract Code Review
- Smart Contract owners should usually have their contracts verified.
- The tool should raise a concern if not.
However, this is not so straightforward even though we can see the functions code. The function names could be misleading. Contracts can call other contracts and make it obscure to figure out what is happening.
- Smart Contract Metadata checks
- If the smart contract has been recently deployed and if the user is one of the early wallets to interact with it, it should raise concerns.
- The contract can be an angel looking interface but could call evil contracts under the hood.
- Complex Transaction Simulation
- The only way to fight internal transaction is to dry-run the transaction on-the-go on the latest state trie of the blockchain to analyze the exact EVM opcodes executed in the specific context.
- One problem to this is that we still don't know for sure which the block the transaction will be included in, however simulation does reduce the risk significantly.
Existing Solutions
- [Alchemy API](https://www.alchemy.com/transaction-simulation)
- [Mopsus](https://mopsus.blocksec.com/) (by Blocksec)
- Pocket Universe (Chrome Extension)
- Stelo
- JoinFire
What do the existing solutions provide?
### Alchemy
---
"With our Simulation APIs, you can know the exact impact of a transaction before it hits the blockchain." - Alchemy
#### Simulate Asset Changes
Simulates a transaction and returns a list of asset changes.
**Example**
Sample Request
```js
const options = {
method: 'POST',
headers: {accept: 'application/json', 'content-type': 'application/json'},
body: JSON.stringify({
id: 1,
jsonrpc: '2.0',
method: 'alchemy_simulateAssetChanges',
params: [
{
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
value: '0x0',
data: '0xa9059cbb000000000000000000000000fc43f5f9dd45258b3aff31bdbe6561d97e8b71de00000000000000000000000000000000000000000000000000000000000f4240'
}
]
})
};
fetch('https://eth-mainnet.g.alchemy.com/v2/docs-demo', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));
```
Sample Response
```json
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "invalid argument 0: json: cannot unmarshal hex string of odd length into Go struct field TransactionArgs.data of type hexutil.Bytes"
}
}
```
Looks like it is not even working properly.
#### Simulate Execution
Simulates a transaction and returns decoded execution traces and decoded logs.
**Example**
Sample Request
```js
const options = {
method: 'POST',
headers: {accept: 'application/json', 'content-type': 'application/json'},
body: JSON.stringify({
id: 1,
jsonrpc: '2.0',
method: 'alchemy_simulateExecution',
params: [
{
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
value: '0x0',
data: '0xa9059cbb000000000000000000000000fc43f5f9dd45258b3aff31bdbe6561d97e8b71de00000000000000000000000000000000000000000000000000000000000f4240'
}
]
})
};
fetch('https://eth-mainnet.g.alchemy.com/v2/docs-demo', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));
```
Sample Response
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"calls": [
{
"type": "CALL",
"from": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
"to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"value": "0x0",
"gas": "0x7fffffffffffaad0",
"gasUsed": "0x40b4",
"input": "0xa9059cbb000000000000000000000000fc43f5f9dd45258b3aff31bdbe6561d97e8b71de00000000000000000000000000000000000000000000000000000000000f4240",
"output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002645524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63650000000000000000000000000000000000000000000000000000",
"error": "execution reverted"
},
{
"decoded": {
"authority": "ETHERSCAN",
"methodName": "transfer",
"inputs": [
{
"name": "to",
"value": "0xfc43f5f9dd45258b3aff31bdbe6561d97e8b71de",
"type": "address"
},
{
"name": "value",
"value": "1000000",
"type": "uint256"
}
],
"outputs": []
},
"type": "DELEGATECALL",
"from": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"to": "0xa2327a938febf5fec13bacfb16ae10ecbc4cbdcf",
"gas": "0x7dffffffffff8ef8",
"gasUsed": "0x2428",
"input": "0xa9059cbb000000000000000000000000fc43f5f9dd45258b3aff31bdbe6561d97e8b71de00000000000000000000000000000000000000000000000000000000000f4240",
"error": "execution reverted"
}
],
"logs": []
}
}
```
#### Simulate Asset Change Bundle
Simulates multiple transactions and returns a list of asset changes.
**Example**
Sample Request
```js
const options = {
method: 'POST',
headers: {accept: 'application/json', 'content-type': 'application/json'},
body: JSON.stringify({
id: 1,
jsonrpc: '2.0',
method: 'alchemy_simulateAssetChangesBundle',
params: [
[
{
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
value: '0x0',
data: '0xa9059cbb000000000000000000000000fc43f5f9dd45258b3aff31bdbe6561d97e8b71de00000000000000000000000000000000000000000000000000000000000f4240'
}
]
]
})
};
fetch('https://eth-mainnet.g.alchemy.com/v2/docs-demo', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));
```
Sample Response
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"changes": [],
"gasUsed": null,
"error": {
"message": "execution reverted"
}
}
]
}
```
#### Simulate Execution Bundle
Simulates multiple transactions sequentially and returns decoded execution traces and decoded logs.
**Example**
Sample Request
```js
const options = {
method: 'POST',
headers: {accept: 'application/json', 'content-type': 'application/json'},
body: JSON.stringify({
id: 1,
jsonrpc: '2.0',
method: 'alchemy_simulateExecutionBundle',
params: [
[
{
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
value: '0x0',
data: '0xa9059cbb000000000000000000000000fc43f5f9dd45258b3aff31bdbe6561d97e8b71de00000000000000000000000000000000000000000000000000000000000f4240'
}
]
]
})
};
fetch('https://eth-mainnet.g.alchemy.com/v2/docs-demo', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));
```
Sample Response
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"calls": [
{
"type": "CALL",
"from": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
"to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"value": "0x0",
"gas": "0x7fffffffffffaad0",
"gasUsed": "0x40b4",
"input": "0xa9059cbb000000000000000000000000fc43f5f9dd45258b3aff31bdbe6561d97e8b71de00000000000000000000000000000000000000000000000000000000000f4240",
"output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002645524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63650000000000000000000000000000000000000000000000000000",
"error": "execution reverted"
},
{
"decoded": {
"authority": "ETHERSCAN",
"methodName": "transfer",
"inputs": [
{
"name": "to",
"value": "0xfc43f5f9dd45258b3aff31bdbe6561d97e8b71de",
"type": "address"
},
{
"name": "value",
"value": "1000000",
"type": "uint256"
}
],
"outputs": []
},
"type": "DELEGATECALL",
"from": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"to": "0xa2327a938febf5fec13bacfb16ae10ecbc4cbdcf",
"gas": "0x7dffffffffff8ef8",
"gasUsed": "0x2428",
"input": "0xa9059cbb000000000000000000000000fc43f5f9dd45258b3aff31bdbe6561d97e8b71de00000000000000000000000000000000000000000000000000000000000f4240",
"error": "execution reverted"
}
],
"logs": []
}
]
}
```
[Alchemy's Metamask Snap Video](https://www.loom.com/share/719db9c1345648ab83169cc0f7eb7ed2)
[Alchemy's Repo](https://github.com/bmoyroud/alchemy-snap)
**What Alchemy can't do?**
- No info on smart contract age, that is being interacted with
- No info on deployer
- Didn't see an ERC721 example, they might be doing it but I am not sure yet
- Only ETH, Polygon and Arbitrum supported
- Since it's an API can provide website context, meaning is the user on a malicious website?
### Mopsus
---
Mopsus provides "industry-leading" (their claim) transaction pre-execution service.
Supported Chains
- Ethereum
- BSC
#### Pre-execution with raw transactions
`https://api.blocksec.com/v1/mopsus/prerun/raw`
Sample Request
```json
{
"bundle":[ "0xf86d8205f085029f64e98282659094388c818ca8b9251b393131c08a736a67ccb1929787a2507840d1e38f8025a02ebb225fe0858da50af8ac78e15b3fe136578f091685f04fe35da1a8cccd21aea070b88e2d9e82adb77af5daf85a06b2676e213e9bfd5e79aa98144d4c4c6ef798"]
}
```
Sample Response
```json
{
"code": 0,
"message": "OK",
"data": {
"txns": [
{
"balanceChanges": [
{
"account": "0x388c818ca8b9251b393131c08a736a67ccb19297",
"assets": [
{
"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"amount": "45687423640920975",
"decimals": 18,
"value": "69.06293707"
}
]
},
{
"account": "0x25d88437df70730122b73ef35462435d187c466f",
"assets": [
{
"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"amount": "-45687423640920975",
"decimals": 18,
"value": "-69.06293707"
}
]
}
],
"baseFee": "9103732876",
"block": 15845006,
"chainID": 1,
"error": "",
"events": [
{
"address": "0x388c818ca8b9251b393131c08a736a67ccb19297",
"data": "0x00000000000000000000000000000000000000000000000000a2507840d1e38f",
"topics": [
"0x27f12abfe35860a9a927b465bb3d4a9c23c8428174b83f278fe45ed7b4da2662"
]
}
],
"from": "0x25d88437df70730122b73ef35462435d187c466f",
"gasLimit": 26000,
"gasPrice": "11264125314",
"gasUsed": 22111,
"hash": "0x8aba23d5005aa00b7ace5ec485c924f299cc290a3a3b7291857d20c4922fef64",
"input": "0x",
"internalTxns": [],
"nonce": 1520,
"position": 0,
"status": true,
"to": "0x388c818ca8b9251b393131c08a736a67ccb19297",
"transactionFee": "249061074817854",
"type": "Legacy",
"value": "45687423640920975"
}
]
}
}
```
A maximum of **three** transactions are allowed in a bundle.
#### Pre-execution with custom parameters
`https://api.blocksec.com/v1/mopsus/prerun/custom`
Sample Request
```json
{
"chainID": 1,
"bundle": [{
"sender": "0x151b381058f91cf871e7ea1ee83c45326f61e96d",
"receiver": "0x55dbac71d136a8ad02edd815b1e1b9217e4a9e22",
"gasLimit": 21000,
"gasPrice": "20634341671000",// Wei
"value": "9000000000000000", // Wei
"input": "0x"
}]
}
```
Sample Repsonse
```json
{
"code": 0,
"message": "OK",
"data": {
"txns": [
{
"balanceChanges": [
{
"account": "0x151b381058f91cf871e7ea1ee83c45326f61e96d",
"assets": [
{
"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"amount": "-90000000000000000000",
"decimals": 18,
"value": "-136047.6"
}
]
},
{
"account": "0x55dbac71d136a8ad02edd815b1e1b9217e4a9e22",
"assets": [
{
"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"amount": "90000000000000000000",
"decimals": 18,
"value": "136047.6"
}
]
}
],
"baseFee": "8438268121",
"block": 15845014,
"chainID": 1,
"error": "",
"events": [],
"from": "0x151b381058f91cf871e7ea1ee83c45326f61e96d",
"gasLimit": 21000,
"gasPrice": "20634341671",
"gasUsed": 21000,
"hash": "0x3bc7ecae2e0ef7d4523eb456c450670a527df4af43cde4036f485d81341958a2",
"input": "0x",
"internalTxns": [],
"nonce": 285388,
"position": 0,
"status": true,
"to": "0x55dbac71d136a8ad02edd815b1e1b9217e4a9e22",
"transactionFee": "433321175091000",
"type": "Legacy",
"value": "90000000000000000000"
}
]
}
}
```
What Mopsus can't do?
- No data about token (name, symbol)
- Same things as Alchemy
<!--
One of the projects winner at the Ledger Live competition did implement transaction simulation to show users what they were signing before doing it.

Under the hood they were using BlockNative to simulate transactions.
Brave is also currently looking to integrate simulation and considering Tenderly for this.
Let's get hands dirty.
A basic smart contract execution simulation
- One could achieve this by using an archival node from QuickNode, Alchemy etc.. or their own node.
- A fully synced node (not archival) is enough to simulate transactions in the latest blockchain context.
- Once the node is up one can interact with it using the JSON-RPC methods
-->