diff --git a/configs/offline/baseline.toml b/configs/offline/baseline.toml index 56da780ab0..0065362391 100644 --- a/configs/offline/baseline.toml +++ b/configs/offline/baseline.toml @@ -1,10 +1,10 @@ chain-id = "31337" # Anvil local chain base-tokens = [ - "0x786cab982f69a055a9d08ac2e3e9a8c3c9ec184a", # WETH (auto-generated from deployment) - "0x470c43112b93f96980b3100034852b5187c81a4a", # DAI (auto-generated from deployment) - "0x2195f5c2dc29235c4f79c671f84a616f17eddd17", # USDC (auto-generated from deployment) - "0xf933c090bd235d2b54642c2ad78d36b168386d09", # USDT (auto-generated from deployment) - "0x7e347942bece146555998242624a27e0cfb12c8d", # GNO (auto-generated from deployment) + "0xa704ea4640d91a9c1823172d8e1e8be7a137b465", # WETH (auto-generated from deployment) + "0xd6289b8bfbd913bce31de03e6f5694bd502a2f81", # DAI (auto-generated from deployment) + "0xbf0e313a70b853f8505ad38ddbcad6f552de61fe", # USDC (auto-generated from deployment) + "0x43893a9c3d1b513ef8ffdd209ba76af829298647", # USDT (auto-generated from deployment) + "0x9168d2ec32cddd21da7945b53993cc583c4bf562", # GNO (auto-generated from deployment) ] max-hops = 2 max-partial-attempts = 5 diff --git a/configs/offline/driver.toml b/configs/offline/driver.toml index 952387e7f2..d81690e732 100644 --- a/configs/offline/driver.toml +++ b/configs/offline/driver.toml @@ -17,21 +17,21 @@ gas-price-cap = "1000000000000" mempool = "public" [contracts] -gp-v2-settlement = "0x2a45e345a42ce34a0138386a6df25b9e6d922874" -weth = "0x786cab982f69a055a9d08ac2e3e9a8c3c9ec184a" -balances = "0xa31e8d1ec61607e6fd0ed8dff62f4dbd7928b434" -signatures = "0xcd573d563d6c2618b997dd26eeec4a6d5bf1977b" +gp-v2-settlement = "0x3cdd3645de8f861d42bff8a4f5a6baf6e4c95659" +weth = "0xa704ea4640d91a9c1823172d8e1e8be7a137b465" +balances = "0xdeee00caea1b6786092c301c81d6c0d7fac9159c" +signatures = "0xf98a8cd2734c2723e2eaf57e20063db21cb90492" [liquidity] base-tokens = [ - "0x786cab982f69a055a9d08ac2e3e9a8c3c9ec184a", # WETH (auto-generated from deployment) - "0x470c43112b93f96980b3100034852b5187c81a4a", # DAI (auto-generated from deployment) - "0x2195f5c2dc29235c4f79c671f84a616f17eddd17", # USDC (auto-generated from deployment) - "0xf933c090bd235d2b54642c2ad78d36b168386d09", # USDT (auto-generated from deployment) - "0x7e347942bece146555998242624a27e0cfb12c8d", # GNO (auto-generated from deployment) + "0xa704ea4640d91a9c1823172d8e1e8be7a137b465", # WETH (auto-generated from deployment) + "0xd6289b8bfbd913bce31de03e6f5694bd502a2f81", # DAI (auto-generated from deployment) + "0xbf0e313a70b853f8505ad38ddbcad6f552de61fe", # USDC (auto-generated from deployment) + "0x43893a9c3d1b513ef8ffdd209ba76af829298647", # USDT (auto-generated from deployment) + "0x9168d2ec32cddd21da7945b53993cc583c4bf562", # GNO (auto-generated from deployment) ] [[liquidity.uniswap-v2]] # Uniswap V2 configuration (auto-generated from deployment) -router = "0x6895c6e3ec54cc78d6ab8dc0a6f6d275f3dffc06" +router = "0xbe6c4cec0c73de412175590410f48d9b639723f4" pool-code = "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f" # Uniswap V2 init code hash missing-pool-cache-time = "1h" diff --git a/playground/.env.offline b/playground/.env.offline index 2f71a0fe2c..0f8aed4e08 100644 --- a/playground/.env.offline +++ b/playground/.env.offline @@ -1,5 +1,5 @@ # Auto-generated by deploy-all.sh -# Generated at: 1764168852 +# Generated at: 1764252995 # Network Configuration CHAIN_ID=31337 @@ -7,22 +7,22 @@ NODE_URL=http://chain:8545 SIMULATION_NODE_URL=http://chain:8545 # Token Addresses (from deployment) -WETH_ADDRESS=0x786cab982f69a055a9d08ac2e3e9a8c3c9ec184a -DAI_ADDRESS=0x470c43112b93f96980b3100034852b5187c81a4a -USDC_ADDRESS=0x2195f5c2dc29235c4f79c671f84a616f17eddd17 -USDT_ADDRESS=0xf933c090bd235d2b54642c2ad78d36b168386d09 -GNO_ADDRESS=0x7e347942bece146555998242624a27e0cfb12c8d -NATIVE_TOKEN_ADDRESS=0x786cab982f69a055a9d08ac2e3e9a8c3c9ec184a +WETH_ADDRESS=0xa704ea4640d91a9c1823172d8e1e8be7a137b465 +DAI_ADDRESS=0xd6289b8bfbd913bce31de03e6f5694bd502a2f81 +USDC_ADDRESS=0xbf0e313a70b853f8505ad38ddbcad6f552de61fe +USDT_ADDRESS=0x43893a9c3d1b513ef8ffdd209ba76af829298647 +GNO_ADDRESS=0x9168d2ec32cddd21da7945b53993cc583c4bf562 +NATIVE_TOKEN_ADDRESS=0xa704ea4640d91a9c1823172d8e1e8be7a137b465 # Uniswap V2 Addresses (from deployment) UNISWAP_V2_FACTORY_ADDRESS=0x51a5ea12b7e61c14bf3026e5b89be587af31f8a3 -UNISWAP_V2_ROUTER_ADDRESS=0x6895c6e3ec54cc78d6ab8dc0a6f6d275f3dffc06 +UNISWAP_V2_ROUTER_ADDRESS=0xbe6c4cec0c73de412175590410f48d9b639723f4 # CoW Protocol Addresses (from deployment) -SETTLEMENT_CONTRACT_ADDRESS=0x2a45e345a42ce34a0138386a6df25b9e6d922874 +SETTLEMENT_CONTRACT_ADDRESS=0x3cdd3645de8f861d42bff8a4f5a6baf6e4c95659 AUTHENTICATOR_ADDRESS=0x667e3f15f5bdf6634b6e454c2d8391bd25b94480 -VAULT_RELAYER_ADDRESS=3df7e9a903b96a556ef2bd0710dcf48c707601b7 -BALANCER_VAULT_ADDRESS=0xc488ceac619c76ee1fe3a7357884b0d5a8143256 -BALANCES_CONTRACT_ADDRESS=0xa31e8d1ec61607e6fd0ed8dff62f4dbd7928b434 -SIGNATURES_CONTRACT_ADDRESS=0xcd573d563d6c2618b997dd26eeec4a6d5bf1977b -HOOKS_TRAMPOLINE_ADDRESS=0xc2fcb053b186405f9ef786f3c5c773e8d71183c0 +VAULT_RELAYER_ADDRESS=0x5482cbcbf984860af9fdc8ea50a4ab732ad0e24e +BALANCER_VAULT_ADDRESS=0x284a7878a31b3d13d9a0115a63a92af752bd4b21 +BALANCES_CONTRACT_ADDRESS=0xdeee00caea1b6786092c301c81d6c0d7fac9159c +SIGNATURES_CONTRACT_ADDRESS=0xf98a8cd2734c2723e2eaf57e20063db21cb90492 +HOOKS_CONTRACT_ADDRESS=0x169609056a9b01719ca5e413486322d7a4dc00e1 diff --git a/playground/docker-compose.offline.yml b/playground/docker-compose.offline.yml index 228508b1f3..629c7e3100 100644 --- a/playground/docker-compose.offline.yml +++ b/playground/docker-compose.offline.yml @@ -42,7 +42,8 @@ services: ports: - 3001:3000 healthcheck: - test: ["CMD-SHELL", "wget -q --spider http://localhost:3000/health || exit 1"] + test: + ["CMD-SHELL", "wget -q --spider http://localhost:3000/health || exit 1"] interval: 5s timeout: 3s retries: 5 @@ -119,7 +120,6 @@ services: - BASELINE_SOURCES=UniswapV2 - TOKEN_OWNER_FINDERS=liquidity - AMOUNT_TO_ESTIMATE_PRICES_WITH=100000000000000000 - - HOOKS_CONTRACT_ADDRESS=0x0000000000000000000000000000000000000000 - RUST_BACKTRACE=1 - TOML_TRACE_ERROR=1 - TRACING_COLLECTOR_ENDPOINT=http://tempo:4317 @@ -188,7 +188,6 @@ services: - DISABLE_ORDER_FILTERING=true - SKIP_EVENT_SYNC=true - AMOUNT_TO_ESTIMATE_PRICES_WITH=100000000000000000 - - HOOKS_CONTRACT_ADDRESS=0x0000000000000000000000000000000000000000 - RUST_BACKTRACE=1 - TOML_TRACE_ERROR=1 - TOKIO_CONSOLE=true diff --git a/playground/offline-mode/config/addresses.json b/playground/offline-mode/config/addresses.json index aed5772357..6ffff1cf9f 100644 --- a/playground/offline-mode/config/addresses.json +++ b/playground/offline-mode/config/addresses.json @@ -1,33 +1,33 @@ { "chainId": "31337", "tokens": { - "WETH": "0x786CAb982f69A055A9d08AC2e3E9A8C3C9Ec184a", - "USDC": "0x2195f5C2dc29235C4F79c671F84A616F17EDdd17", - "DAI": "0x470c43112b93f96980b3100034852b5187C81A4A", - "USDT": "0xF933C090bd235d2B54642c2aD78d36B168386d09", - "GNO": "0x7e347942BecE146555998242624A27e0Cfb12C8D" + "WETH": "0xA704Ea4640D91a9C1823172D8e1e8BE7a137B465", + "USDC": "0xBF0E313a70b853F8505AD38DDbCad6F552de61fe", + "DAI": "0xD6289b8BFbd913bce31DE03e6F5694bD502A2F81", + "USDT": "0x43893A9c3D1b513ef8ffDd209ba76Af829298647", + "GNO": "0x9168D2EC32CDDd21da7945b53993cC583C4bF562" }, "uniswapV2": { "factory": "0x51a5ea12B7E61c14BF3026e5B89Be587af31F8a3", - "router": "0x6895C6E3EC54cc78D6ab8dc0A6F6D275f3dFfc06", + "router": "0xBE6C4CeC0C73DE412175590410F48D9B639723F4", "pairs": { - "WETH-USDC": "0x29DFde24Da69D50030E4d70bfF2DA81F8944d228", - "WETH-DAI": "0x8799b65Cd81a69Aa5C83FE595aD062a2b5B98f7c", - "WETH-USDT": "0xAc973837d6B3D3b00eF7A794526aF343f7AadC43", - "WETH-GNO": "0x8592C488f6F886fa61297134F07d3B71B0DD88b6", - "USDC-DAI": "0xe92a0E180F7AA705966c54A90Bd2e75b4D9097Ae", - "USDC-USDT": "0x5Ff051d3c09a0DeEe31d13e9BAEAf94755F97EB0", - "USDC-GNO": "0x69D619eD34C90D3b69F21bEFE23f2652E17DeDDf", - "DAI-USDT": "0x47B1c32809d8CAdDa443D35880E3189201B71957", - "DAI-GNO": "0x8f33B62Ef3286837A0c95e8566018b311984c374", - "USDT-GNO": "0x2Fc25e5Bc404d553b377dE6a2a691349dEdBA791" + "WETH-USDC": "0xD8ca4697c1e5026097f63DC2C57018D3F308A177", + "WETH-DAI": "0xd3038cc8738b94f98F3963879210A49ea6EDa3c8", + "WETH-USDT": "0x3b86f715a8f8AF13fd4BD443AE060Cc70E15c971", + "WETH-GNO": "0xd9edc00150ced104409AC7a3BF5fA37e8ddB80f1", + "USDC-DAI": "0xbDF089dD65C023a91E243ABE8BAa3ca18269d6E5", + "USDC-USDT": "0xcDF43Ee5E3dc1875a261994288Df51aa55401Ce7", + "USDC-GNO": "0x6A9ef682dfD593faB8a141743f8F97251F3E39EC", + "DAI-USDT": "0xD1e3D5D2d64877CB1236b03c54edAc340A6819f9", + "DAI-GNO": "0xF6511D0b0034De5bf6cb0E9e06a5e7E0Bf9cb8DA", + "USDT-GNO": "0x8F5834A15e81A46809729cE8f1d149074ebf1949" } }, "cowProtocol": { - "settlement": "0x2a45e345A42CE34A0138386a6df25b9E6d922874", + "settlement": "0x3CDD3645De8f861D42bFF8A4F5A6Baf6e4C95659", "authenticator": "0x667e3f15f5bDf6634b6E454c2d8391Bd25B94480", - "vaultRelayer": "0x3df7E9a903B96a556ef2BD0710DcF48c707601B7", - "balancerVault": "0xC488CeAc619c76Ee1FE3A7357884b0D5A8143256", - "hooksTrampoline": "0xC2fcB053B186405F9ef786F3c5c773e8D71183C0" + "vaultRelayer": "0x5482cbcBf984860Af9fDc8EA50A4aB732aD0e24E", + "balancerVault": "0x284A7878A31B3D13D9A0115A63A92aF752bd4B21", + "hooksTrampoline": "0x169609056a9B01719ca5E413486322d7A4dc00e1" } } diff --git a/playground/offline-mode/contracts/script/DeployHooksTrampoline.s.sol b/playground/offline-mode/contracts/script/DeployHooksTrampoline.s.sol new file mode 100644 index 0000000000..2d50cfe7fe --- /dev/null +++ b/playground/offline-mode/contracts/script/DeployHooksTrampoline.s.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "forge-std/Script.sol"; +import {HooksTrampoline} from "@cowprotocol/hooks-trampoline/HooksTrampoline.sol"; + +contract DeployHooksTrampoline is Script { + // Deterministic salt for CREATE2 + bytes32 constant HOOKS_TRAMPOLINE_SALT = keccak256("cowswap-hooks-trampoline"); + + function run() public { + // Read settlement address from environment + address settlement = vm.envAddress("SETTLEMENT"); + + vm.startBroadcast(); + + // Deploy HooksTrampoline contract with CREATE2 for deterministic address + HooksTrampoline hooksTrampoline = new HooksTrampoline{salt: HOOKS_TRAMPOLINE_SALT}(settlement); + + console.log("HooksTrampoline deployed at:", address(hooksTrampoline)); + + vm.stopBroadcast(); + } +} diff --git a/playground/offline-mode/contracts/script/ExportAddresses.s.sol b/playground/offline-mode/contracts/script/ExportAddresses.s.sol index 7c6e007d42..722242f2eb 100644 --- a/playground/offline-mode/contracts/script/ExportAddresses.s.sol +++ b/playground/offline-mode/contracts/script/ExportAddresses.s.sol @@ -29,7 +29,8 @@ contract ExportAddresses is Script { address cowVaultRelayer = vm.envAddress("COW_VAULT_RELAYER"); address cowSettlement = vm.envAddress("COW_SETTLEMENT"); address balancerVault = vm.envAddress("BALANCER_VAULT"); - + address hooksTrampoline = vm.envAddress("HOOKS_TRAMPOLINE"); + console.log("Exporting addresses to JSON..."); console.log(""); @@ -81,7 +82,8 @@ contract ExportAddresses is Script { ' "settlement": "', vm.toString(cowSettlement), '",\n', ' "authenticator": "', vm.toString(cowAuthenticator), '",\n', ' "vaultRelayer": "', vm.toString(cowVaultRelayer), '",\n', - ' "balancerVault": "', vm.toString(balancerVault), '"\n', + ' "balancerVault": "', vm.toString(balancerVault), '",\n', + ' "hooksTrampoline": "', vm.toString(hooksTrampoline), '"\n', ' }' )); diff --git a/playground/offline-mode/contracts/test/Counter.sol b/playground/offline-mode/contracts/test/Counter.sol new file mode 100644 index 0000000000..a862721451 --- /dev/null +++ b/playground/offline-mode/contracts/test/Counter.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +/** + * @title Counter + * @dev Simple test contract for HooksTrampoline testing + * This contract demonstrates a basic hook that increments a counter when called + */ +contract Counter { + uint256 public counter; + address public lastCaller; + + event CounterIncremented(address indexed caller, uint256 newValue); + + /** + * @dev Increment the counter + * This function is designed to be called via HooksTrampoline + */ + function increment() external { + counter++; + lastCaller = msg.sender; + emit CounterIncremented(msg.sender, counter); + } + + /** + * @dev Get the current counter value + */ + function getCounter() external view returns (uint256) { + return counter; + } + + /** + * @dev Reset the counter (for testing purposes) + */ + function reset() external { + counter = 0; + lastCaller = address(0); + } +} diff --git a/playground/offline-mode/foundry.toml b/playground/offline-mode/foundry.toml index 5b9e8be498..6a1f26726f 100644 --- a/playground/offline-mode/foundry.toml +++ b/playground/offline-mode/foundry.toml @@ -23,7 +23,7 @@ remappings = [ "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/", "@openzeppelin/contracts-old/=node_modules/@openzeppelin/contracts-old/", "@cowprotocol/contracts/=node_modules/@cowprotocol/contracts/src/contracts/", - "@cowprotocol/hooks-trampoline/=node_modules/@cowprotocol/hooks-trampoline/src/", + "@cowprotocol/hooks-trampoline/=/Users/lgahdl/Documents/Trabalho/cowswap/hooks-trampoline/src/", "@uniswap/v2-core/=node_modules/@uniswap/v2-core/", "@uniswap/v2-periphery/=node_modules/@uniswap/v2-periphery/", "@uniswap/lib/=node_modules/@uniswap/lib/", diff --git a/playground/offline-mode/package.json b/playground/offline-mode/package.json index eb00cfcf2f..7880a961da 100644 --- a/playground/offline-mode/package.json +++ b/playground/offline-mode/package.json @@ -16,7 +16,6 @@ "@openzeppelin/contracts": "^5.0.2", "@openzeppelin/contracts-old": "npm:@openzeppelin/contracts@^3.4.0", "@cowprotocol/contracts": "^1.6.0", - "@cowprotocol/hooks-trampoline": "github:cowprotocol/cow-hooks-trampoline", "forge-std": "github:foundry-rs/forge-std", "solmate": "github:transmissions11/solmate", "@uniswap/v2-core": "^1.0.1", diff --git a/playground/offline-mode/scripts/deploy-all.sh b/playground/offline-mode/scripts/deploy-all.sh index d992d730be..df38848a97 100755 --- a/playground/offline-mode/scripts/deploy-all.sh +++ b/playground/offline-mode/scripts/deploy-all.sh @@ -8,6 +8,10 @@ echo "" : ${RPC_URL:=http://localhost:8545} : ${DEPLOYER_PRIVATE_KEY:=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80} +# Export for forge scripts to use +export RPC_URL +export DEPLOYER_PRIVATE_KEY + echo "Using RPC URL: $RPC_URL" echo "" @@ -157,8 +161,8 @@ COW_AUTHENTICATOR=$(jq -r '[.transactions[] | select(.transactionType == "CREATE # Settlement is second (index 1) COW_SETTLEMENT=$(jq -r '[.transactions[] | select(.transactionType == "CREATE2")] | .[1].contractAddress' broadcast/DeployCowProtocol.s.sol/31337/run-latest.json) # VaultRelayer is created by Settlement contract, need to read it from chain -# cast call returns bytes32, we need to extract the address (last 20 bytes = 40 hex chars) -COW_VAULT_RELAYER=$(cast call $COW_SETTLEMENT "vaultRelayer()" --rpc-url $RPC_URL | xargs | cut -c 27-66) +# cast call returns bytes32, we need to extract the address (last 20 bytes = 40 hex chars) and add 0x prefix +COW_VAULT_RELAYER="0x$(cast call $COW_SETTLEMENT "vaultRelayer()" --rpc-url $RPC_URL | xargs | cut -c 27-66)" # Export for next scripts export COW_AUTHENTICATOR @@ -257,6 +261,35 @@ echo "๐Ÿ“ Deployed Signatures address:" echo " Signatures: $SIGNATURES_CONTRACT" echo "" +# Step 3.7: Deploy HooksTrampoline Contract +echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" +echo "STEP 3.7: Deploying HooksTrampoline Contract" +echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + +# Set SETTLEMENT environment variable for the deployment script +export SETTLEMENT=$COW_SETTLEMENT + +forge script contracts/script/DeployHooksTrampoline.s.sol:DeployHooksTrampoline \ + --rpc-url $RPC_URL \ + --broadcast \ + --private-key $DEPLOYER_PRIVATE_KEY \ + --skip-simulation \ + -vvv + +echo "" +echo "โœ… HooksTrampoline contract deployed!" +echo "" + +# Extract HooksTrampoline address from broadcast (CREATE2 transaction) +HOOKS_TRAMPOLINE=$(jq -r '.transactions[] | select(.contractName == "HooksTrampoline") | .contractAddress' broadcast/DeployHooksTrampoline.s.sol/31337/run-latest.json) + +# Export for next scripts +export HOOKS_TRAMPOLINE + +echo "๐Ÿ“ Deployed HooksTrampoline address:" +echo " HooksTrampoline: $HOOKS_TRAMPOLINE" +echo "" + # Step 4: Add Liquidity (using direct method to bypass router) echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "STEP 4: Adding Initial Liquidity" @@ -321,6 +354,7 @@ export VAULT_RELAYER_ADDRESS=${COW_VAULT_RELAYER} export BALANCER_VAULT_ADDRESS=${BALANCER_VAULT} export BALANCES_CONTRACT_ADDRESS=${BALANCES_CONTRACT} export SIGNATURES_CONTRACT_ADDRESS=${SIGNATURES_CONTRACT} +export HOOKS_CONTRACT_ADDRESS=${HOOKS_TRAMPOLINE} # Generate configuration files using bash (avoid running solidity script which causes "stack too deep" errors) generate_configs() { @@ -341,6 +375,7 @@ generate_configs() { BALANCER_VAULT_ADDRESS=${BALANCER_VAULT_ADDRESS} BALANCES_CONTRACT_ADDRESS=${BALANCES_CONTRACT_ADDRESS} SIGNATURES_CONTRACT_ADDRESS=${SIGNATURES_CONTRACT_ADDRESS} + HOOKS_CONTRACT_ADDRESS=${HOOKS_CONTRACT_ADDRESS} # driver.toml cat > ../../configs/offline/driver.toml < /dev/null 2>&1 + +# Deploy Counter contract +COUNTER_DEPLOY_OUTPUT=$(forge create contracts/test/Counter.sol:Counter \ + --rpc-url $RPC_URL \ + --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ + --broadcast \ + 2>&1) + +COUNTER_ADDRESS=$(echo "$COUNTER_DEPLOY_OUTPUT" | grep "Deployed to:" | awk '{print $3}') + +if [ -z "$COUNTER_ADDRESS" ]; then + echo "โŒ Error: Failed to deploy Counter contract" + echo "$COUNTER_DEPLOY_OUTPUT" + exit 1 +fi + +echo " โœ… Counter deployed at: $COUNTER_ADDRESS" +echo "" + +# Step 2: Verify initial counter value is 0 +echo "๐Ÿ” Verifying initial counter value..." +INITIAL_COUNTER=$(cast call $COUNTER_ADDRESS --rpc-url $RPC_URL "getCounter()(uint256)") +echo " Initial counter: $INITIAL_COUNTER" + +if [ "$INITIAL_COUNTER" != "0" ]; then + echo "โŒ Error: Expected initial counter to be 0, got $INITIAL_COUNTER" + exit 1 +fi +echo "" + +# Step 3: Prepare hook calldata +echo "๐Ÿ”ง Preparing hook calldata..." +# Encode the increment() function call +HOOK_CALLDATA=$(cast calldata "increment()") +# Set a reasonable gas limit for the hook (100,000 gas) +HOOK_GAS_LIMIT="100000" +echo " Hook calldata: $HOOK_CALLDATA" +echo " Hook gas limit: $HOOK_GAS_LIMIT" +echo "" + +# Step 4: Execute hook via HooksTrampoline +echo "๐Ÿš€ Executing hook via HooksTrampoline (impersonating Settlement)..." + +# Give the Settlement contract some ETH for gas +cast rpc anvil_setBalance $SETTLEMENT_CONTRACT "0x1000000000000000000" --rpc-url $RPC_URL > /dev/null 2>&1 + +# Enable impersonation for the Settlement contract address +cast rpc anvil_impersonateAccount $SETTLEMENT_CONTRACT --rpc-url $RPC_URL > /dev/null 2>&1 + +# Execute the hook from the impersonated Settlement address +# The execute function takes an array of Hook structs: execute((address,bytes,uint256)[]) +EXECUTE_TX=$(cast send $HOOKS_TRAMPOLINE \ + --from $SETTLEMENT_CONTRACT \ + --unlocked \ + --rpc-url $RPC_URL \ + "execute((address,bytes,uint256)[])" \ + "[($COUNTER_ADDRESS,$HOOK_CALLDATA,$HOOK_GAS_LIMIT)]" \ + 2>&1) + +EXECUTE_EXIT_CODE=$? + +# Stop impersonation +cast rpc anvil_stopImpersonatingAccount $SETTLEMENT_CONTRACT --rpc-url $RPC_URL > /dev/null 2>&1 + +if [ $EXECUTE_EXIT_CODE -ne 0 ]; then + echo "โŒ Error: Failed to execute hook" + echo "$EXECUTE_TX" + exit 1 +fi + +echo " โœ… Hook executed successfully" +echo "" + +# Step 5: Verify counter was incremented +echo "๐Ÿ” Verifying counter was incremented..." +FINAL_COUNTER=$(cast call $COUNTER_ADDRESS --rpc-url $RPC_URL "getCounter()(uint256)") +echo " Final counter: $FINAL_COUNTER" + +if [ "$FINAL_COUNTER" != "1" ]; then + echo "โŒ Error: Expected counter to be 1, got $FINAL_COUNTER" + exit 1 +fi +echo "" + +# Step 6: Verify last caller was HooksTrampoline +echo "๐Ÿ” Verifying last caller was HooksTrampoline..." +LAST_CALLER=$(cast call $COUNTER_ADDRESS --rpc-url $RPC_URL "lastCaller()(address)") +echo " Last caller: $LAST_CALLER" + +# Normalize addresses for comparison (lowercase) +LAST_CALLER_NORMALIZED=$(echo "$LAST_CALLER" | tr '[:upper:]' '[:lower:]') +HOOKS_TRAMPOLINE_NORMALIZED=$(echo "$HOOKS_TRAMPOLINE" | tr '[:upper:]' '[:lower:]') + +if [ "$LAST_CALLER_NORMALIZED" != "$HOOKS_TRAMPOLINE_NORMALIZED" ]; then + echo "โŒ Error: Expected last caller to be HooksTrampoline ($HOOKS_TRAMPOLINE), got $LAST_CALLER" + exit 1 +fi +echo "" + +# Step 7: Test calling from non-Settlement address (should fail) +echo "๐Ÿ”’ Testing access control (calling from non-Settlement address)..." +NON_SETTLEMENT="0x70997970C51812dc3A010C7d01b50e0d17dc79C8" +UNAUTHORIZED_TX=$(cast send $HOOKS_TRAMPOLINE \ + --from $NON_SETTLEMENT \ + --private-key 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d \ + --rpc-url $RPC_URL \ + "execute(address,bytes)" \ + $COUNTER_ADDRESS \ + $HOOK_CALLDATA \ + 2>&1 || true) + +if echo "$UNAUTHORIZED_TX" | grep -q "reverted"; then + echo " โœ… Access control working: unauthorized call was rejected" +else + echo "โŒ Error: Unauthorized call should have been rejected" + exit 1 +fi +echo "" + +echo "โœ… All tests passed!" +echo "" +echo "Summary:" +echo " โœ“ Counter contract deployed successfully" +echo " โœ“ Initial counter value was 0" +echo " โœ“ Hook executed via HooksTrampoline" +echo " โœ“ Counter incremented to 1" +echo " โœ“ Last caller was HooksTrampoline contract" +echo " โœ“ Access control prevents unauthorized calls" +echo "" +echo "๐ŸŽ‰ HooksTrampoline is working correctly!" +echo "===================================="