diff --git a/hello_virtual_testnets/.github/workflows/test.yml b/hello_virtual_testnets/.github/workflows/test.yml new file mode 100644 index 0000000..9282e82 --- /dev/null +++ b/hello_virtual_testnets/.github/workflows/test.yml @@ -0,0 +1,34 @@ +name: test + +on: workflow_dispatch + +env: + FOUNDRY_PROFILE: ci + +jobs: + check: + strategy: + fail-fast: true + + name: Foundry project + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Run Forge build + run: | + forge --version + forge build --sizes + id: build + + - name: Run Forge tests + run: | + forge test -vvv + id: test diff --git a/hello_virtual_testnets/.gitignore b/hello_virtual_testnets/.gitignore new file mode 100644 index 0000000..85198aa --- /dev/null +++ b/hello_virtual_testnets/.gitignore @@ -0,0 +1,14 @@ +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file +.env diff --git a/hello_virtual_testnets/README.md b/hello_virtual_testnets/README.md new file mode 100644 index 0000000..9265b45 --- /dev/null +++ b/hello_virtual_testnets/README.md @@ -0,0 +1,66 @@ +## Foundry + +**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** + +Foundry consists of: + +- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). +- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. +- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. +- **Chisel**: Fast, utilitarian, and verbose solidity REPL. + +## Documentation + +https://book.getfoundry.sh/ + +## Usage + +### Build + +```shell +$ forge build +``` + +### Test + +```shell +$ forge test +``` + +### Format + +```shell +$ forge fmt +``` + +### Gas Snapshots + +```shell +$ forge snapshot +``` + +### Anvil + +```shell +$ anvil +``` + +### Deploy + +```shell +$ forge script script/Counter.s.sol:CounterScript --rpc-url --private-key +``` + +### Cast + +```shell +$ cast +``` + +### Help + +```shell +$ forge --help +$ anvil --help +$ cast --help +``` diff --git a/hello_virtual_testnets/foundry.toml b/hello_virtual_testnets/foundry.toml new file mode 100644 index 0000000..25b918f --- /dev/null +++ b/hello_virtual_testnets/foundry.toml @@ -0,0 +1,6 @@ +[profile.default] +src = "src" +out = "out" +libs = ["lib"] + +# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options diff --git a/hello_virtual_testnets/lib/forge-std b/hello_virtual_testnets/lib/forge-std new file mode 160000 index 0000000..bb4ceea --- /dev/null +++ b/hello_virtual_testnets/lib/forge-std @@ -0,0 +1 @@ +Subproject commit bb4ceea94d6f10eeb5b41dc2391c6c8bf8e734ef diff --git a/hello_virtual_testnets/script/Counter.s.sol b/hello_virtual_testnets/script/Counter.s.sol new file mode 100644 index 0000000..df9ee8b --- /dev/null +++ b/hello_virtual_testnets/script/Counter.s.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import {Script, console} from "forge-std/Script.sol"; + +contract CounterScript is Script { + function setUp() public {} + + function run() public { + vm.broadcast(); + } +} diff --git a/hello_virtual_testnets/src/Counter.sol b/hello_virtual_testnets/src/Counter.sol new file mode 100644 index 0000000..aded799 --- /dev/null +++ b/hello_virtual_testnets/src/Counter.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +contract Counter { + uint256 public number; + + function setNumber(uint256 newNumber) public { + number = newNumber; + } + + function increment() public { + number++; + } +} diff --git a/hello_virtual_testnets/test/Counter.t.sol b/hello_virtual_testnets/test/Counter.t.sol new file mode 100644 index 0000000..54b724f --- /dev/null +++ b/hello_virtual_testnets/test/Counter.t.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import {Test, console} from "forge-std/Test.sol"; +import {Counter} from "../src/Counter.sol"; + +contract CounterTest is Test { + Counter public counter; + + function setUp() public { + counter = new Counter(); + counter.setNumber(0); + } + + function test_Increment() public { + counter.increment(); + assertEq(counter.number(), 1); + } + + function testFuzz_SetNumber(uint256 x) public { + counter.setNumber(x); + assertEq(counter.number(), x); + } +} diff --git a/simulations/api/linea/0-simulate.txt b/simulations/api/linea/0-simulate.txt new file mode 100644 index 0000000..21bc902 --- /dev/null +++ b/simulations/api/linea/0-simulate.txt @@ -0,0 +1,705 @@ +{ + TENDERLY_ACCESS_KEY: 'xIvit7oqo8lTRd-w3udlZnXLCcHbzGyL', + NVM_INC: '/Users/nenadvitorovic/.nvm/versions/node/v20.12.0/include/node', + TENDERLY_ACCOUNT_ID: 'nenad', + MANPATH: '/Users/nenadvitorovic/.nvm/versions/node/v20.12.0/share/man:/opt/homebrew/share/man::', + NODE: '/Users/nenadvitorovic/.nvm/versions/node/v20.12.0/bin/node', + INIT_CWD: '/Users/nenadvitorovic/Projects/tenderly-examples/simulations/api/linea', + PYENV_ROOT: '/Users/nenadvitorovic/.pyenv', + NVM_CD_FLAGS: '-q', + TERM: 'xterm-256color', + SHELL: '/bin/zsh', + HOMEBREW_REPOSITORY: '/opt/homebrew', + TMPDIR: '/var/folders/th/1g_v1n411d31dh1q9qjrmlkw0000gn/T/', + npm_config_global_prefix: '/Users/nenadvitorovic/.nvm/versions/node/v20.12.0', + COLOR: '0', + TERM_SESSION_ID: '7ce52678-5d85-44fc-b70e-009622b22bdd', + npm_config_noproxy: '', + npm_config_local_prefix: '/Users/nenadvitorovic/Projects/tenderly-examples/simulations', + PNPM_HOME: '/Users/nenadvitorovic/Library/pnpm', + ZSH: '/Users/nenadvitorovic/.oh-my-zsh', + NVM_DIR: '/Users/nenadvitorovic/.nvm', + USER: 'nenadvitorovic', + LS_COLORS: 'di=1;36:ln=35:so=32:pi=33:ex=31:bd=34;46:cd=34;43:su=30;41:sg=30;46:tw=30;42:ow=30;43', + COMMAND_MODE: 'unix2003', + npm_config_globalconfig: '/Users/nenadvitorovic/.nvm/versions/node/v20.12.0/etc/npmrc', + SSH_AUTH_SOCK: '/private/tmp/com.apple.launchd.cJGYw7ImCB/Listeners', + __CF_USER_TEXT_ENCODING: '0x1F5:0x0:0x0', + npm_execpath: '/Users/nenadvitorovic/.nvm/versions/node/v20.12.0/lib/node_modules/npm/bin/npm-cli.js', + PAGER: 'less', + TENDERLY_NODE_ACCESS_KEY: '1lr3OYkmWkcpDIypxzF5U8', + LSCOLORS: 'Gxfxcxdxbxegedabagacad', + PATH: '/Users/nenadvitorovic/Projects/tenderly-examples/simulations/node_modules/.bin:/Users/nenadvitorovic/Projects/tenderly-examples/simulations/api/linea/node_modules/.bin:/Users/nenadvitorovic/Projects/tenderly-examples/simulations/api/node_modules/.bin:/Users/nenadvitorovic/Projects/tenderly-examples/simulations/node_modules/.bin:/Users/nenadvitorovic/Projects/tenderly-examples/node_modules/.bin:/Users/nenadvitorovic/Projects/node_modules/.bin:/Users/nenadvitorovic/node_modules/.bin:/Users/node_modules/.bin:/node_modules/.bin:/Users/nenadvitorovic/.nvm/versions/node/v20.12.0/lib/node_modules/npm/node_modules/@npmcli/run-script/lib/node-gyp-bin:/Users/nenadvitorovic/.pyenv/shims:/Users/nenadvitorovic/Library/pnpm:/Users/nenadvitorovic/.nvm/versions/node/v20.12.0/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Users/nenadvitorovic/.foundry/bin', + TERMINAL_EMULATOR: 'JetBrains-JediTerm', + npm_package_json: '/Users/nenadvitorovic/Projects/tenderly-examples/simulations/api/linea/package.json', + _: '/Users/nenadvitorovic/Projects/tenderly-examples/simulations/node_modules/.bin/ts-node', + IJ_RESTARTER_LOG: '/Users/nenadvitorovic/Library/Logs/JetBrains/WebStorm2023.3/restarter.log', + npm_config_userconfig: '/Users/nenadvitorovic/.npmrc', + npm_config_init_module: '/Users/nenadvitorovic/.npm-init.js', + __CFBundleIdentifier: 'com.jetbrains.WebStorm', + npm_command: 'exec', + PWD: '/Users/nenadvitorovic/Projects/tenderly-examples/simulations/api/linea', + npm_lifecycle_event: 'npx', + EDITOR: 'vi', + npm_package_name: 'simulations', + npm_config_npm_version: '10.5.0', + XPC_FLAGS: '0x0', + npm_config_node_gyp: '/Users/nenadvitorovic/.nvm/versions/node/v20.12.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js', + npm_package_version: '1.0.0', + XPC_SERVICE_NAME: '0', + PYENV_SHELL: 'zsh', + SHLVL: '2', + HOME: '/Users/nenadvitorovic', + HOMEBREW_PREFIX: '/opt/homebrew', + IDEA_INITIAL_DIRECTORY: '/', + npm_config_cache: '/Users/nenadvitorovic/.npm', + LESS: '-R', + LOGNAME: 'nenadvitorovic', + npm_lifecycle_script: 'ts-node', + LC_CTYPE: 'UTF-8', + NVM_BIN: '/Users/nenadvitorovic/.nvm/versions/node/v20.12.0/bin', + npm_config_user_agent: 'npm/10.5.0 node/v20.12.0 darwin arm64 workspaces/false', + TENDERLY_PROJECT: 'live-demo', + INFOPATH: '/opt/homebrew/share/info:', + HOMEBREW_CELLAR: '/opt/homebrew/Cellar', + npm_node_execpath: '/Users/nenadvitorovic/.nvm/versions/node/v20.12.0/bin/node', + npm_config_prefix: '/Users/nenadvitorovic/.nvm/versions/node/v20.12.0' +} +Decoded Events: Full Decoding Mode: 1.540s +Access List undefined +Asset Changes [ + { + "token_info": { + "standard": "ERC20", + "type": "Fungible", + "contract_address": "0xeb466342c4d449bc9f53a865d5cb90586f405215", + "symbol": "axlusdc", + "name": "Axelar Bridged USDC", + "logo": "https://assets.coingecko.com/coins/images/26476/large/uausdc_D_3x.png?1696525548", + "decimals": 6, + "dollar_value": "0.9987220168113708" + }, + "type": "Transfer", + "from": "0x81ee7797156ef586b49731a490f83066241b1220", + "to": "0xa5282a67337e0381dc47b9a16a91960b0a5eb9b2", + "amount": "11.264696", + "raw_amount": "11264696", + "dollar_value": "11.250299907886981964" + }, + { + "token_info": { + "standard": "ERC20", + "type": "Fungible", + "contract_address": "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f", + "symbol": "weth", + "name": "Bridged Wrapped Ether (Linea)", + "logo": "https://assets.coingecko.com/coins/images/31019/large/download_%2817%29.png?1696529855", + "decimals": 18, + "dollar_value": "3148.1201171875" + }, + "type": "Mint", + "to": "0x272e156df8da513c69cb41cc7a99185d53f926bb", + "amount": "0.005", + "raw_amount": "5000000000000000", + "dollar_value": "15.7406005859375" + }, + { + "token_info": { + "standard": "ERC20", + "type": "Fungible", + "contract_address": "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f", + "symbol": "weth", + "name": "Bridged Wrapped Ether (Linea)", + "logo": "https://assets.coingecko.com/coins/images/31019/large/download_%2817%29.png?1696529855", + "decimals": 18, + "dollar_value": "3148.1201171875" + }, + "type": "Transfer", + "from": "0x272e156df8da513c69cb41cc7a99185d53f926bb", + "to": "0x81ee7797156ef586b49731a490f83066241b1220", + "amount": "0.005", + "raw_amount": "5000000000000000", + "dollar_value": "15.7406005859375" + }, + { + "token_info": { + "standard": "NativeCurrency", + "type": "Native", + "symbol": "eth", + "name": "Ethereum", + "logo": "https://assets.coingecko.com/coins/images/279/large/ethereum.png?1696501628", + "decimals": 18, + "dollar_value": "3146.659912109375" + }, + "type": "Transfer", + "from": "0xa5282a67337e0381dc47b9a16a91960b0a5eb9b2", + "to": "0x272e156df8da513c69cb41cc7a99185d53f926bb", + "amount": "0.005", + "raw_amount": "5000000000000000", + "dollar_value": "15.733299560546875" + }, + { + "token_info": { + "standard": "NativeCurrency", + "type": "Native", + "symbol": "eth", + "name": "Ethereum", + "logo": "https://assets.coingecko.com/coins/images/279/large/ethereum.png?1696501628", + "decimals": 18, + "dollar_value": "3146.659912109375" + }, + "type": "Transfer", + "from": "0x272e156df8da513c69cb41cc7a99185d53f926bb", + "to": "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f", + "amount": "0.005", + "raw_amount": "5000000000000000", + "dollar_value": "15.733299560546875" + } +] +Balance Changes [ + { + "address": "0x272e156df8da513c69cb41cc7a99185d53f926bb", + "dollar_value": "0", + "transfers": [ + 1, + 2, + 3, + 4 + ] + }, + { + "address": "0x81ee7797156ef586b49731a490f83066241b1220", + "dollar_value": "4.490300678050518036", + "transfers": [ + 0, + 2 + ] + }, + { + "address": "0xa5282a67337e0381dc47b9a16a91960b0a5eb9b2", + "dollar_value": "-4.482999652659893036", + "transfers": [ + 0, + 3 + ] + }, + { + "address": "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f", + "dollar_value": "15.733299560546875", + "transfers": [ + 4 + ] + } +] +Decoded logs/events [ + { + "name": "Transfer", + "anonymous": false, + "inputs": [ + { + "soltype": { + "name": "from", + "type": "address", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": true, + "simple_type": { + "type": "address" + } + }, + "value": "0x81ee7797156ef586b49731a490f83066241b1220" + }, + { + "soltype": { + "name": "to", + "type": "address", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": true, + "simple_type": { + "type": "address" + } + }, + "value": "0xa5282a67337e0381dc47b9a16a91960b0a5eb9b2" + }, + { + "soltype": { + "name": "value", + "type": "uint256", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": false, + "simple_type": { + "type": "uint" + } + }, + "value": "11264696" + } + ], + "raw": { + "address": "0xeb466342c4d449bc9f53a865d5cb90586f405215", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000081ee7797156ef586b49731a490f83066241b1220", + "0x000000000000000000000000a5282a67337e0381dc47b9a16a91960b0a5eb9b2" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000abe2b8" + }, + "trace_index": null + }, + { + "name": "Deposit", + "anonymous": false, + "inputs": [ + { + "soltype": { + "name": "dst", + "type": "address", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": true, + "simple_type": { + "type": "address" + } + }, + "value": "0x272e156df8da513c69cb41cc7a99185d53f926bb" + }, + { + "soltype": { + "name": "wad", + "type": "uint256", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": false, + "simple_type": { + "type": "uint" + } + }, + "value": "5000000000000000" + } + ], + "raw": { + "address": "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f", + "topics": [ + "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + "0x000000000000000000000000272e156df8da513c69cb41cc7a99185d53f926bb" + ], + "data": "0x0000000000000000000000000000000000000000000000000011c37937e08000" + }, + "trace_index": null + }, + { + "name": "Transfer", + "anonymous": false, + "inputs": [ + { + "soltype": { + "name": "src", + "type": "address", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": true, + "simple_type": { + "type": "address" + } + }, + "value": "0x272e156df8da513c69cb41cc7a99185d53f926bb" + }, + { + "soltype": { + "name": "dst", + "type": "address", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": true, + "simple_type": { + "type": "address" + } + }, + "value": "0x81ee7797156ef586b49731a490f83066241b1220" + }, + { + "soltype": { + "name": "wad", + "type": "uint256", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": false, + "simple_type": { + "type": "uint" + } + }, + "value": "5000000000000000" + } + ], + "raw": { + "address": "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000272e156df8da513c69cb41cc7a99185d53f926bb", + "0x00000000000000000000000081ee7797156ef586b49731a490f83066241b1220" + ], + "data": "0x0000000000000000000000000000000000000000000000000011c37937e08000" + }, + "trace_index": null + }, + { + "name": "Swap", + "anonymous": false, + "inputs": [ + { + "soltype": { + "name": "sender", + "type": "address", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": true, + "simple_type": { + "type": "address" + } + }, + "value": "0x272e156df8da513c69cb41cc7a99185d53f926bb" + }, + { + "soltype": { + "name": "recipient", + "type": "address", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": true, + "simple_type": { + "type": "address" + } + }, + "value": "0xa5282a67337e0381dc47b9a16a91960b0a5eb9b2" + }, + { + "soltype": { + "name": "deltaQty0", + "type": "int256", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": false, + "simple_type": { + "type": "int" + } + }, + "value": "5000000000000000" + }, + { + "soltype": { + "name": "deltaQty1", + "type": "int256", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": false, + "simple_type": { + "type": "int" + } + }, + "value": "-11264696" + }, + { + "soltype": { + "name": "sqrtP", + "type": "uint160", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": false, + "simple_type": { + "type": "uint" + } + }, + "value": "3754906319996325259607083" + }, + { + "soltype": { + "name": "liquidity", + "type": "uint128", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": false, + "simple_type": { + "type": "uint" + } + }, + "value": "31646979687084" + }, + { + "soltype": { + "name": "currentTick", + "type": "int24", + "storage_location": "default", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": false, + "simple_type": { + "type": "int" + } + }, + "value": "-199151" + } + ], + "raw": { + "address": "0x81ee7797156ef586b49731a490f83066241b1220", + "topics": [ + "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67", + "0x000000000000000000000000272e156df8da513c69cb41cc7a99185d53f926bb", + "0x000000000000000000000000a5282a67337e0381dc47b9a16a91960b0a5eb9b2" + ], + "data": "0x0000000000000000000000000000000000000000000000000011c37937e08000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff541d48000000000000000000000000000000000000000000031b21e125aa575eaf7c2b00000000000000000000000000000000000000000000000000001cc862fb82acfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcf611" + }, + "trace_index": null + } +] +Gas used: 146949 wei +State changes: [ + { + "address": "0x79756d90a882a1621ec35723849dac785694d93a", + "soltype": null, + "original": null, + "dirty": null, + "raw": [ + { + "address": "0x79756d90a882a1621ec35723849dac785694d93a", + "key": "0x80c669875ec214080692b27904c5f35a1c60223a8dbf50e771bf84dd521cfa26", + "original": "0x000000000000000000000000000000000000000001fffd0a2da9d0f065bf9174", + "dirty": "0x000000000000000000000000000000000000000001fffd0a2ae93e0065bf925c" + } + ] + }, + { + "address": "0x81ee7797156ef586b49731a490f83066241b1220", + "soltype": { + "name": "poolData", + "type": "tuple", + "storage_location": "memory", + "components": [ + { + "name": "sqrtP", + "type": "uint160", + "storage_location": "memory", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000003", + "indexed": false, + "simple_type": { + "type": "uint" + } + }, + { + "name": "nearestCurrentTick", + "type": "int24", + "storage_location": "memory", + "offset": 160, + "index": "0x0000000000000000000000000000000000000000000000000000000000000003", + "indexed": false, + "simple_type": { + "type": "int" + } + }, + { + "name": "currentTick", + "type": "int24", + "storage_location": "memory", + "offset": 184, + "index": "0x0000000000000000000000000000000000000000000000000000000000000003", + "indexed": false, + "simple_type": { + "type": "int" + } + }, + { + "name": "locked", + "type": "bool", + "storage_location": "memory", + "offset": 208, + "index": "0x0000000000000000000000000000000000000000000000000000000000000003", + "indexed": false, + "simple_type": { + "type": "bool" + } + }, + { + "name": "baseL", + "type": "uint128", + "storage_location": "memory", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000004", + "indexed": false, + "simple_type": { + "type": "uint" + } + }, + { + "name": "reinvestL", + "type": "uint128", + "storage_location": "memory", + "offset": 128, + "index": "0x0000000000000000000000000000000000000000000000000000000000000004", + "indexed": false, + "simple_type": { + "type": "uint" + } + }, + { + "name": "reinvestLLast", + "type": "uint128", + "storage_location": "memory", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000005", + "indexed": false, + "simple_type": { + "type": "uint" + } + }, + { + "name": "feeGrowthGlobal", + "type": "uint256", + "storage_location": "memory", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000006", + "indexed": false, + "simple_type": { + "type": "uint" + } + }, + { + "name": "secondsPerLiquidityGlobal", + "type": "uint128", + "storage_location": "memory", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000007", + "indexed": false, + "simple_type": { + "type": "uint" + } + }, + { + "name": "secondsPerLiquidityUpdateTime", + "type": "uint32", + "storage_location": "memory", + "offset": 128, + "index": "0x0000000000000000000000000000000000000000000000000000000000000007", + "indexed": false, + "simple_type": { + "type": "uint" + } + } + ], + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000003", + "indexed": false + }, + "original": { + "sqrtP": "3777620921490428765892629", + "nearestCurrentTick": "16577896", + "currentTick": "16578186", + "locked": false, + "baseL": "31646979687084", + "reinvestL": "7703216552394", + "reinvestLLast": null, + "feeGrowthGlobal": null, + "secondsPerLiquidityGlobal": null, + "secondsPerLiquidityUpdateTime": 0 + }, + "dirty": { + "sqrtP": "3754906319996325259607083", + "nearestCurrentTick": "16577896", + "currentTick": "16578065", + "locked": false, + "baseL": "31646979687084", + "reinvestL": "7703574154489", + "reinvestLLast": null, + "feeGrowthGlobal": null, + "secondsPerLiquidityGlobal": null, + "secondsPerLiquidityUpdateTime": 0 + }, + "raw": [ + { + "address": "0x81ee7797156ef586b49731a490f83066241b1220", + "key": "0x0000000000000000000000000000000000000000000000000000000000000003", + "original": "0x000000000000fcf68afcf568000000000000000000031ff13d911a1ca3537015", + "dirty": "0x000000000000fcf611fcf568000000000000000000031b21e125aa575eaf7c2b" + }, + { + "address": "0x81ee7797156ef586b49731a490f83066241b1220", + "key": "0x0000000000000000000000000000000000000000000000000000000000000004", + "original": "0x0000000000000000000007018b7c79ca000000000000000000001cc862fb82ac", + "dirty": "0x000000000000000000000701a0cd0cf9000000000000000000001cc862fb82ac" + } + ] + }, + { + "address": "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f", + "soltype": { + "name": "balanceOf", + "type": "mapping (address => uint256)", + "storage_location": "storage", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000003", + "indexed": false + }, + "original": { + "0x81ee7797156ef586b49731a490f83066241b1220": "363560785517824022" + }, + "dirty": { + "0x81ee7797156ef586b49731a490f83066241b1220": "368560785517824022" + }, + "raw": [ + { + "address": "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f", + "key": "0x7bea5896c366fa319e36152733dc094b1924a56da6a2d10bd022bbc3b0915d2c", + "original": "0x000000000000000000000000000000000000000000000000050ba09bb30d4816", + "dirty": "0x000000000000000000000000000000000000000000000000051d6414eaedc816" + } + ] + }, + { + "address": "0xeb466342c4d449bc9f53a865d5cb90586f405215", + "soltype": { + "name": "balanceOf", + "type": "mapping (address => uint256)", + "storage_location": "storage", + "offset": 0, + "index": "0x0000000000000000000000000000000000000000000000000000000000000000", + "indexed": false + }, + "original": { + "0x81ee7797156ef586b49731a490f83066241b1220": "1956135741", + "0xa5282a67337e0381dc47b9a16a91960b0a5eb9b2": "0" + }, + "dirty": { + "0x81ee7797156ef586b49731a490f83066241b1220": "1944871045", + "0xa5282a67337e0381dc47b9a16a91960b0a5eb9b2": "11264696" + }, + "raw": [ + { + "address": "0xeb466342c4d449bc9f53a865d5cb90586f405215", + "key": "0x5712af6a6b56237b3d9b88e39c94b0cc2e43fac70b98d89b437528eee9f3b0d2", + "original": "0x0000000000000000000000000000000000000000000000000000000000000000", + "dirty": "0x0000000000000000000000000000000000000000000000000000000000abe2b8" + }, + { + "address": "0xeb466342c4d449bc9f53a865d5cb90586f405215", + "key": "0xba7f47d1a70216b3013bd52fef753931cef6b2b461fc26a5cc7cf46c8aaf9cf5", + "original": "0x000000000000000000000000000000000000000000000000000000007498433d", + "dirty": "0x0000000000000000000000000000000000000000000000000000000073ec6085" + } + ] + } +] +Simulation Success true diff --git a/uniswap-factory-pool-monitoring/README.md b/uniswap-factory-pool-monitoring/README.md new file mode 100644 index 0000000..77f7755 --- /dev/null +++ b/uniswap-factory-pool-monitoring/README.md @@ -0,0 +1,62 @@ +# How to to interact and manage new pools created by the UniswapV3Factory contract using Tenderly Alerts and Web3 Actions + +This README provides a comprehensive guide on setting up a Tenderly alert for the `PoolCreated` event emitted by the UniswapV3Factory contract on Ethereum Mainnet, and deploying a Web3Action using the Tenderly CLI to handle the event. + +## Prerequisites + +- A Tenderly account. +- Access to the Tenderly dashboard. +- A project within Tenderly configured with your Ethereum smart contracts. +- Tenderly CLI installed on your machine. + +## Step 1: Creating an Alert in Tenderly + +1. **Log into your Tenderly Dashboard.** +2. Navigate to the project where you want to set the alert. +3. Go to the **Alerts** tab and click on **New Alert**. +4. Set the Alert Type to **Event Emitted**. +5. Configure the alert: + - **Contract Address:** `0x1f98431c8ad98523631ae4a59f267346ea31f984` (UniswapV3Factory contract) + - **Event Signature:** `PoolCreated(address,indexed address,uint24)` + - Name your alert appropriately for easy reference. +6. Save the alert. + +## Step 2: Setting Up Your `tenderly.yaml` File + +Create a `tenderly.yaml` file in the root directory of your local project with the following configuration: + +```yaml +account_id: "" +actions: + account_id/project_slug: + runtime: v2 + sources: actions + specs: + uniswapV3: + description: "Monitoring UniswapV3 Factory Contract and adding Child/Pool to Contracts page with proper tag" + function: example:actionFn + trigger: + type: alert + alert: {alert_id} + execution_type: parallel +project_slug: "" +``` + +This configuration sets up the deployment details, including the account, action runtime, and the specific alert trigger. + +## Step 3: Adding the ACCESS-KEY to Secrets + +1. Navigate to the **Web3Actions** page on your Tenderly dashboard. +2. Go to the **Secrets** tab. +3. Add a new secret with the key `ACCESS-KEY` and the value of your actual access key. + +## Step 4: Deploying with Tenderly CLI + +1. Open a terminal and navigate to your project directory. +2. Run the following command to deploy your actions: + + ```bash + tenderly actions deploy + ``` + +This command deploys your Web3Action as configured in the `tenderly.yaml` file. \ No newline at end of file diff --git a/uniswap-factory-pool-monitoring/actions/.gitignore b/uniswap-factory-pool-monitoring/actions/.gitignore new file mode 100755 index 0000000..2f5b2a0 --- /dev/null +++ b/uniswap-factory-pool-monitoring/actions/.gitignore @@ -0,0 +1,5 @@ +# Dependency directories +node_modules/ + +# Ignore tsc output +out/**/* diff --git a/uniswap-factory-pool-monitoring/actions/example.ts b/uniswap-factory-pool-monitoring/actions/example.ts new file mode 100755 index 0000000..6da0fa9 --- /dev/null +++ b/uniswap-factory-pool-monitoring/actions/example.ts @@ -0,0 +1,42 @@ +import { Context, AlertEvent } from '@tenderly/actions'; +import { Tenderly } from '@tenderly/sdk'; +const ethers = require('ethers'); + +const actionFn = async (context: Context, alertEvent: AlertEvent) => { + const key = await context.secrets.get('ACCESS-KEY'); + + const accountSlug = '{account_id}'; + const projectSlug = '{project_slug}'; + const tagName = 'pool'; + + const tenderly = new Tenderly({ + accountName: accountSlug, + projectName: projectSlug, + accessKey: key, + network: Number(alertEvent.network), + }); + + const poolCreatedSignature = ethers.utils.id("PoolCreated(address,address,uint24,int24,address)"); + + let poolAddress = ""; + for (const log of alertEvent.logs) { + if (log.topics[0] === poolCreatedSignature) { + const data = log.data; + const addressHex = data.substring(data.length - 40); + poolAddress = ethers.utils.getAddress('0x' + addressHex).toLowerCase(); + break; + } + } + + try { + await tenderly.contracts.add(poolAddress, { + displayName: 'Pool' + }); + await tenderly.contracts.update(poolAddress, { appendTags: [tagName] }); + console.log(`Pool contract is: ${poolAddress}, and has been added with tag ${tagName}`); + } catch (error) { + console.error('Error adding contract:', error); + } +}; + +module.exports = { actionFn }; diff --git a/uniswap-factory-pool-monitoring/actions/package.json b/uniswap-factory-pool-monitoring/actions/package.json new file mode 100755 index 0000000..fa16001 --- /dev/null +++ b/uniswap-factory-pool-monitoring/actions/package.json @@ -0,0 +1,15 @@ +{ + "name": "actions", + "scripts": { + "build": "tsc" + }, + "devDependencies": { + "@types/node": "^20.12.7", + "typescript": "^4.3.5" + }, + "dependencies": { + "@tenderly/actions": "^0.2.0", + "@tenderly/sdk": "^0.2.5" + }, + "private": true +} diff --git a/uniswap-factory-pool-monitoring/actions/tsconfig.json b/uniswap-factory-pool-monitoring/actions/tsconfig.json new file mode 100755 index 0000000..d8d9a78 --- /dev/null +++ b/uniswap-factory-pool-monitoring/actions/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compileOnSave": true, + "compilerOptions": { + "module": "commonjs", + "noImplicitReturns": true, + "noUnusedLocals": true, + "outDir": "out", + "rootDir": "", + "sourceMap": true, + "strict": true, + "target": "es2020", + }, + "exclude": [ + "**/*.spec.ts" + ], + "include": [ + "**/*" + ] +} \ No newline at end of file diff --git a/uniswap-factory-pool-monitoring/tenderly.yaml b/uniswap-factory-pool-monitoring/tenderly.yaml new file mode 100644 index 0000000..5c4600a --- /dev/null +++ b/uniswap-factory-pool-monitoring/tenderly.yaml @@ -0,0 +1,14 @@ +account_id: "" +actions: + account_id/project_slug: # these will need to be changed according to the actual account_id/project_slug + runtime: v2 + sources: actions + specs: + uniswapV3: + description: Monitoring UniswapV3 Factory Contract and adding Child/Pool to Contracts page with proper tag + function: example:actionFn + trigger: + type: alert + alert: {alert_id} + execution_type: parallel +project_slug: "" \ No newline at end of file diff --git a/virtual-testnets/src/utils.ts b/virtual-testnets/src/utils.ts new file mode 100644 index 0000000..27deb47 --- /dev/null +++ b/virtual-testnets/src/utils.ts @@ -0,0 +1,3 @@ +export function basename(uri: string) { + return uri.split("/").reverse()[0]; +} \ No newline at end of file