From 0440094dd940aea5f08cea3ec0205f61784c223c Mon Sep 17 00:00:00 2001 From: voith Date: Thu, 6 Mar 2025 04:38:14 +0530 Subject: [PATCH 1/2] added script for caliming tcap perp fees --- hardhat.config.ts | 15 +- test/arbitrum/ArbitrumBridgeTest.t.sol | 167 ++++++++++++++ test/ccip/GovernanceCCIPIntegrationTest.t.sol | 66 +----- test/interfaces/IArbitrumInboxErrors.sol | 215 ++++++++++++++++++ test/interfaces/ICtx.sol | 64 ++++++ test/interfaces/IGovernorBeta.sol | 37 +++ test/interfaces/ITimelock.sol | 26 +++ 7 files changed, 521 insertions(+), 69 deletions(-) create mode 100644 test/arbitrum/ArbitrumBridgeTest.t.sol create mode 100644 test/interfaces/IArbitrumInboxErrors.sol create mode 100644 test/interfaces/ICtx.sol create mode 100644 test/interfaces/IGovernorBeta.sol create mode 100644 test/interfaces/ITimelock.sol diff --git a/hardhat.config.ts b/hardhat.config.ts index a0917080..96fc2bbe 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -24,13 +24,16 @@ const config: HardhatUserConfig = { }, }, solidity: { - version: "0.7.5", - settings: { - optimizer: { - enabled: true, - runs: 200, + compilers: [ + { + version: "0.7.5", + settings: { optimizer: { enabled: true, runs: 200 } }, }, - }, + { + version: "0.8.26", + settings: { viaIR: true, optimizer: { enabled: true, runs: 200 } }, + }, + ] }, networks: { hardhat: { diff --git a/test/arbitrum/ArbitrumBridgeTest.t.sol b/test/arbitrum/ArbitrumBridgeTest.t.sol new file mode 100644 index 00000000..a3c0149e --- /dev/null +++ b/test/arbitrum/ArbitrumBridgeTest.t.sol @@ -0,0 +1,167 @@ +// forge test --match-path test/arbitrum/ArbitrumBridgeTest.t.sol -vvv +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Test, console, console2} from "forge-std/Test.sol"; +import {IGovernorBeta} from "../interfaces/IGovernorBeta.sol"; +import {ITimelock} from "../interfaces/ITimelock.sol"; +import {ICtx} from "../interfaces/ICtx.sol"; +import {IArbitrumInboxErrors} from "../interfaces/IArbitrumInboxErrors.sol"; + +interface IPerennialCollateral { + function claimFee() external; +} + +interface IL1MessageRelayer { + function relayMessage( + address target, + bytes memory payLoad, + uint256 maxSubmissionCost, + uint256 maxGas, + uint256 gasPriceBid + ) external returns (uint256); +} + +interface IL2MessageExecutor { + function executeMessage(bytes calldata payLoad) external; +} + +interface IArbitrumTreasury{ + function executeTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data + ) external payable returns (bytes memory); +} + +library AddressAliasHelper { + uint160 constant OFFSET = uint160(0x1111000000000000000000000000000000001111); + + /// @notice Utility function that converts the address in the L1 that submitted a tx to + /// the inbox to the msg.sender viewed in the L2 + /// @param l1Address the address in the L1 that triggered the tx to L2 + /// @return l2Address L2 address as viewed in msg.sender + function applyL1ToL2Alias(address l1Address) + internal + pure + returns (address l2Address) + { + l2Address = address(uint160(l1Address) + OFFSET); + } + + /// @notice Utility function that converts the msg.sender viewed in the L2 to the + /// address in the L1 that submitted a tx to the inbox + /// @param l2Address L2 address as viewed in msg.sender + /// @return l1Address the address in the L1 that triggered the tx to L2 + function undoL1ToL2Alias(address l2Address) + internal + pure + returns (address l1Address) + { + l1Address = address(uint160(l2Address) - OFFSET); + } +} + + +contract AbritrumBridgeTest is Test { + ICtx ctx = ICtx(0x321C2fE4446C7c963dc41Dd58879AF648838f98D); + IGovernorBeta public governorBeta = IGovernorBeta(0x874C5D592AfC6803c3DD60d6442357879F196d5b); + ITimelock public timelock = ITimelock(0xa54074b2cc0e96a43048d4a68472F7F046aC0DA8); + IL1MessageRelayer l1MessageRelayer = IL1MessageRelayer(0x209c23DB16298504354112fa4210d368e1d564dA); + // 0x3769b6aA269995297a539BEd7a463105466733A5 --> L2MessageExecutorProxy.so + IL2MessageExecutor l2MessageExecutor = IL2MessageExecutor(0x3769b6aA269995297a539BEd7a463105466733A5); + IArbitrumTreasury arbitrumTreasury = IArbitrumTreasury(0x9474B771Fb46E538cfED114Ca816A3e25Bb346CF); + IPerennialCollateral perennialCollateral = IPerennialCollateral(0xAF8CeD28FcE00ABD30463D55dA81156AA5aEEEc2); + + uint256 public ethereumMainnetForkId; + uint256 public arbitrumMainnetForkId; + address user = address(0x51); + + function setUp() public { + string memory ETHEREUM_MAINNET_RPC_URL = vm.envString( + "ETHEREUM_MAINNET_RPC_URL" + ); + string memory ARBITRUM_MAINNET_RPC_URL = vm.envString( + "ARBITRUM_API_URL" + ); + ethereumMainnetForkId = vm.createFork(ETHEREUM_MAINNET_RPC_URL); + arbitrumMainnetForkId = vm.createFork(ARBITRUM_MAINNET_RPC_URL); + + vm.selectFork(ethereumMainnetForkId); + deal(address(ctx), user, 900_000 ether); + vm.prank(user); + ctx.delegate(user); + } + + function createAndExecuteGovernanceProposal( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description + ) internal { + vm.startPrank(user); + vm.roll(block.number + 100); + governorBeta.propose(targets, values, signatures, calldatas, description); + uint256 proposalID = governorBeta.latestProposalIds(user); + vm.roll(block.number + governorBeta.votingDelay() + 1); + governorBeta.castVote(proposalID, true); + vm.roll(block.number + governorBeta.votingPeriod() + 1); + governorBeta.queue(proposalID); + vm.warp(block.timestamp + timelock.delay() + 1 days); + governorBeta.execute(proposalID); + assertEq( + uint256(governorBeta.state(proposalID)), + uint256(IGovernorBeta.ProposalState.Executed) + ); + vm.stopPrank(); + } + + function test() external { + vm.selectFork(ethereumMainnetForkId); + address target = address(l2MessageExecutor); + bytes memory payload = abi.encode( + address(arbitrumTreasury), + abi.encodeWithSelector( + IArbitrumTreasury.executeTransaction.selector, + address(perennialCollateral), // target + 0, // value + "claimFee()", // signature + bytes("") // data + ) + ); + + address[] memory targets = new address[](1); + uint256[] memory values = new uint256[](1); + string[] memory signatures = new string[](1); + bytes[] memory calldatas = new bytes[](1); + + targets[0] = address(l1MessageRelayer); + values[0] = 0.03 ether; + signatures[0] = "relayMessage(address,bytes,uint256,uint256,uint256)"; + calldatas[0] = abi.encode( + target, + payload, + 3815530707376, + 82096, + 100000000 + ); + string memory description = "Claim TCAP Perp Fees"; + console.log("targets[0]", targets[0]); + console.log("=================================================================================="); + console2.log("values[0]", values[0]); + console.log("=================================================================================="); + console.log("signatures[0]", signatures[0]); + console.log("=================================================================================="); + console.log("calldatas[0]"); + console.logBytes(calldatas[0]); + console.log("=================================================================================="); + console.log("description", description); + console.log("=================================================================================="); + createAndExecuteGovernanceProposal(targets, values, signatures, calldatas, description); + vm.selectFork(arbitrumMainnetForkId); + vm.startPrank(AddressAliasHelper.applyL1ToL2Alias(address(l1MessageRelayer))); + l2MessageExecutor.executeMessage(payload); + } +} diff --git a/test/ccip/GovernanceCCIPIntegrationTest.t.sol b/test/ccip/GovernanceCCIPIntegrationTest.t.sol index 6068830a..8f73e910 100644 --- a/test/ccip/GovernanceCCIPIntegrationTest.t.sol +++ b/test/ccip/GovernanceCCIPIntegrationTest.t.sol @@ -8,69 +8,9 @@ import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.s import {GovernanceCCIPRelay, IGovernanceCCIPRelay} from "contracts/ccip/GovernanceCCIPRelay.sol"; import {GovernanceCCIPReceiver, IGovernanceCCIPReceiver} from "contracts/ccip/GovernanceCCIPReceiver.sol"; import {NumberUpdater} from "contracts/mocks/NumberUpdater.sol"; - -interface IGovernorBeta { - enum ProposalState { - Pending, - Active, - Canceled, - Defeated, - Succeeded, - Queued, - Expired, - Executed - } - - function votingDelay() external pure returns (uint256); - - function votingPeriod() external pure returns (uint256); - - function state(uint256 proposalId) external view returns (ProposalState); - - function propose( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas, - string memory description - ) external returns (uint256); - - function queue(uint256 proposalId) external; - - function execute(uint256 proposalId) external payable; - - function castVote(uint256 proposalId, bool support) external; - - function latestProposalIds(address) external returns (uint256); -} - -interface ITimelock { - function delay() external returns (uint256); - - function queueTransaction( - address target, - uint256 value, - string memory signature, - bytes memory data, - uint256 eta - ) external returns (bytes32); - - function executeTransaction( - address target, - uint256 value, - string memory signature, - bytes memory data, - uint256 eta - ) external payable returns (bytes memory); - - function admin() external returns (address); - - function acceptAdmin() external; -} - -interface ICtx { - function delegate(address delegatee) external; -} +import {IGovernorBeta} from "../interfaces/IGovernorBeta.sol"; +import {ITimelock} from "../interfaces/ITimelock.sol"; +import {ICtx} from "../interfaces/ICtx.sol"; interface IPriceRegistry { error StaleGasPrice( diff --git a/test/interfaces/IArbitrumInboxErrors.sol b/test/interfaces/IArbitrumInboxErrors.sol new file mode 100644 index 00000000..166920e4 --- /dev/null +++ b/test/interfaces/IArbitrumInboxErrors.sol @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IArbitrumInboxErrors { + /// @dev Init was already called +error AlreadyInit(); + +/// @dev Init was called with param set to zero that must be nonzero +error HadZeroInit(); + +/// @dev Thrown when post upgrade init validation fails +error BadPostUpgradeInit(); + +/// @dev Thrown when the caller is not a codeless origin +error NotCodelessOrigin(); + +/// @dev Thrown when non owner tries to access an only-owner function +/// @param sender The msg.sender who is not the owner +/// @param owner The owner address +error NotOwner(address sender, address owner); + +/// @dev Thrown when an address that is not the rollup tries to call an only-rollup function +/// @param sender The sender who is not the rollup +/// @param rollup The rollup address authorized to call this function +error NotRollup(address sender, address rollup); + +/// @dev Thrown when the contract was not called directly from the origin ie msg.sender != tx.origin +error NotOrigin(); + +/// @dev Provided data was too large +/// @param dataLength The length of the data that is too large +/// @param maxDataLength The max length the data can be +error DataTooLarge(uint256 dataLength, uint256 maxDataLength); + +/// @dev The provided is not a contract and was expected to be +/// @param addr The adddress in question +error NotContract(address addr); + +/// @dev The merkle proof provided was too long +/// @param actualLength The length of the merkle proof provided +/// @param maxProofLength The max length a merkle proof can have +error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength); + +/// @dev Thrown when an un-authorized address tries to access an admin function +/// @param sender The un-authorized sender +/// @param rollup The rollup, which would be authorized +/// @param owner The rollup's owner, which would be authorized +error NotRollupOrOwner(address sender, address rollup, address owner); + +// Bridge Errors + +/// @dev Thrown when an un-authorized address tries to access an only-inbox function +/// @param sender The un-authorized sender +error NotDelayedInbox(address sender); + +/// @dev Thrown when an un-authorized address tries to access an only-sequencer-inbox function +/// @param sender The un-authorized sender +error NotSequencerInbox(address sender); + +/// @dev Thrown when an un-authorized address tries to access an only-outbox function +/// @param sender The un-authorized sender +error NotOutbox(address sender); + +/// @dev the provided outbox address isn't valid +/// @param outbox address of outbox being set +error InvalidOutboxSet(address outbox); + +/// @dev The provided token address isn't valid +/// @param token address of token being set +error InvalidTokenSet(address token); + +/// @dev Call to this specific address is not allowed +/// @param target address of the call receiver +error CallTargetNotAllowed(address target); + +/// @dev Call that changes the balance of ERC20Bridge is not allowed +error CallNotAllowed(); + +// Inbox Errors + +/// @dev msg.value sent to the inbox isn't high enough +error InsufficientValue(uint256 expected, uint256 actual); + +/// @dev submission cost provided isn't enough to create retryable ticket +error InsufficientSubmissionCost(uint256 expected, uint256 actual); + +/// @dev address not allowed to interact with the given contract +error NotAllowedOrigin(address origin); + +/// @dev used to convey retryable tx data in eth calls without requiring a tx trace +/// this follows a pattern similar to EIP-3668 where reverts surface call information +error RetryableData( + address from, + address to, + uint256 l2CallValue, + uint256 deposit, + uint256 maxSubmissionCost, + address excessFeeRefundAddress, + address callValueRefundAddress, + uint256 gasLimit, + uint256 maxFeePerGas, + bytes data +); + +/// @dev Thrown when a L1 chainId fork is detected +error L1Forked(); + +/// @dev Thrown when a L1 chainId fork is not detected +error NotForked(); + +/// @dev The provided gasLimit is larger than uint64 +error GasLimitTooLarge(); + +/// @dev The provided amount cannot be adjusted to 18 decimals due to overflow +error AmountTooLarge(uint256 amount); + +/// @dev Number of native token's decimals is restricted to enable conversions to 18 decimals +error NativeTokenDecimalsTooLarge(uint256 decimals); + +// Outbox Errors + +/// @dev The provided proof was too long +/// @param proofLength The length of the too-long proof +error ProofTooLong(uint256 proofLength); + +/// @dev The output index was greater than the maximum +/// @param index The output index +/// @param maxIndex The max the index could be +error PathNotMinimal(uint256 index, uint256 maxIndex); + +/// @dev The calculated root does not exist +/// @param root The calculated root +error UnknownRoot(bytes32 root); + +/// @dev The record has already been spent +/// @param index The index of the spent record +error AlreadySpent(uint256 index); + +/// @dev A call to the bridge failed with no return data +error BridgeCallFailed(); + +// Sequencer Inbox Errors + +/// @dev Thrown when someone attempts to read fewer messages than have already been read +error DelayedBackwards(); + +/// @dev Thrown when someone attempts to read more messages than exist +error DelayedTooFar(); + +/// @dev Force include can only read messages more blocks old than the delay period +error ForceIncludeBlockTooSoon(); + +/// @dev The message provided did not match the hash in the delayed inbox +error IncorrectMessagePreimage(); + +/// @dev This can only be called by the batch poster +error NotBatchPoster(); + +/// @dev The sequence number provided to this message was inconsistent with the number of batches already included +error BadSequencerNumber(uint256 stored, uint256 received); + +/// @dev The sequence message number provided to this message was inconsistent with the previous one +error BadSequencerMessageNumber(uint256 stored, uint256 received); + +/// @dev Tried to create an already valid Data Availability Service keyset +error AlreadyValidDASKeyset(bytes32); + +/// @dev Tried to use or invalidate an already invalid Data Availability Service keyset +error NoSuchKeyset(bytes32); + +/// @dev Thrown when the provided address is not the designated batch poster manager +error NotBatchPosterManager(address); + +/// @dev Thrown when a data blob feature is attempted to be used on a chain that doesnt support it +error DataBlobsNotSupported(); + +/// @dev Thrown when batches are posted without buffer proof, this is only allowed in a sync state or when no new delayed messages are read +error DelayProofRequired(); + +/// @dev The DelayedAccPreimage is invalid +error InvalidDelayedAccPreimage(); + +/// @dev Thrown when the sequencer attempts to post a batch with delay / sync proofs without delay bufferability enabled +error NotDelayBufferable(); + +/// @dev Thrown when an init param was supplied as empty +error InitParamZero(string name); + +/// @dev Thrown when data hashes where expected but not where present on the tx +error MissingDataHashes(); + +/// @dev Thrown when rollup is not updated with updateRollupAddress +error RollupNotChanged(); + +/// @dev Unsupported header flag was provided +error InvalidHeaderFlag(bytes1); + +/// @dev SequencerInbox and Bridge are not in the same feeToken/ETH mode +error NativeTokenMismatch(); + +/// @dev Thrown when a deprecated function is called +error Deprecated(); + +/// @dev Thrown when any component of maxTimeVariation is over uint64 +error BadMaxTimeVariation(); + +/// @dev Thrown when any component of bufferConfig is zero +error BadBufferConfig(); + +/// @dev Thrown when extra gas is not a uint64 +error ExtraGasNotUint64(); + +/// @dev Thrown when keysetBytes is too large +error KeysetTooLarge(); +} diff --git a/test/interfaces/ICtx.sol b/test/interfaces/ICtx.sol new file mode 100644 index 00000000..80eef533 --- /dev/null +++ b/test/interfaces/ICtx.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface ICtx { + // Events + event MinterChanged(address minter, address newMinter); + event DelegateChanged( + address indexed delegator, + address indexed fromDelegate, + address indexed toDelegate + ); + event DelegateVotesChanged( + address indexed delegate, + uint256 previousBalance, + uint256 newBalance + ); + event Transfer(address indexed from, address indexed to, uint256 amount); + event Approval( + address indexed owner, + address indexed spender, + uint256 amount + ); + + // View Functions + function name() external view returns (string memory); + function symbol() external view returns (string memory); + function decimals() external view returns (uint8); + function totalSupply() external view returns (uint256); + function minter() external view returns (address); + function mintingAllowedAfter() external view returns (uint256); + function balanceOf(address account) external view returns (uint256); + function allowance(address account, address spender) external view returns (uint256); + function getCurrentVotes(address account) external view returns (uint96); + function getPriorVotes(address account, uint256 blockNumber) external view returns (uint96); + function delegates(address account) external view returns (address); + function nonces(address account) external view returns (uint256); + + // State-Changing Functions + function setMinter(address minter_) external; + function mint(address dst, uint256 rawAmount) external; + function transfer(address dst, uint256 rawAmount) external returns (bool); + function transferFrom(address src, address dst, uint256 rawAmount) external returns (bool); + function approve(address spender, uint256 rawAmount) external returns (bool); + function increaseAllowance(address spender, uint256 addedValue) external returns (bool); + function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); + function delegate(address delegatee) external; + function delegateBySig( + address delegatee, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) external; + function permit( + address owner, + address spender, + uint256 rawAmount, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; +} diff --git a/test/interfaces/IGovernorBeta.sol b/test/interfaces/IGovernorBeta.sol new file mode 100644 index 00000000..9999bc80 --- /dev/null +++ b/test/interfaces/IGovernorBeta.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IGovernorBeta { + enum ProposalState { + Pending, + Active, + Canceled, + Defeated, + Succeeded, + Queued, + Expired, + Executed + } + + function votingDelay() external pure returns (uint256); + + function votingPeriod() external pure returns (uint256); + + function state(uint256 proposalId) external view returns (ProposalState); + + function propose( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description + ) external returns (uint256); + + function queue(uint256 proposalId) external; + + function execute(uint256 proposalId) external payable; + + function castVote(uint256 proposalId, bool support) external; + + function latestProposalIds(address) external returns (uint256); +} diff --git a/test/interfaces/ITimelock.sol b/test/interfaces/ITimelock.sol new file mode 100644 index 00000000..e6ab5769 --- /dev/null +++ b/test/interfaces/ITimelock.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface ITimelock { + function delay() external returns (uint256); + + function queueTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external returns (bytes32); + + function executeTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external payable returns (bytes memory); + + function admin() external returns (address); + + function acceptAdmin() external; +} From d0cf3bc76ebaade6d562ce20563e78e53f068c4f Mon Sep 17 00:00:00 2001 From: voith Date: Thu, 6 Mar 2025 22:36:58 +0530 Subject: [PATCH 2/2] changed the gas prices --- test/arbitrum/ArbitrumBridgeTest.t.sol | 177 ++++++++------ test/interfaces/IArbitrumInboxErrors.sol | 282 +++++++++++------------ test/interfaces/ICtx.sol | 152 +++++++----- 3 files changed, 346 insertions(+), 265 deletions(-) diff --git a/test/arbitrum/ArbitrumBridgeTest.t.sol b/test/arbitrum/ArbitrumBridgeTest.t.sol index a3c0149e..5e792f0a 100644 --- a/test/arbitrum/ArbitrumBridgeTest.t.sol +++ b/test/arbitrum/ArbitrumBridgeTest.t.sol @@ -9,11 +9,11 @@ import {ICtx} from "../interfaces/ICtx.sol"; import {IArbitrumInboxErrors} from "../interfaces/IArbitrumInboxErrors.sol"; interface IPerennialCollateral { - function claimFee() external; + function claimFee() external; } interface IL1MessageRelayer { - function relayMessage( + function relayMessage( address target, bytes memory payLoad, uint256 maxSubmissionCost, @@ -23,11 +23,11 @@ interface IL1MessageRelayer { } interface IL2MessageExecutor { - function executeMessage(bytes calldata payLoad) external; + function executeMessage(bytes calldata payLoad) external; } -interface IArbitrumTreasury{ - function executeTransaction( +interface IArbitrumTreasury { + function executeTransaction( address target, uint256 value, string memory signature, @@ -63,43 +63,52 @@ library AddressAliasHelper { } } +interface IERC20 { + function balanceOf(address account) external returns (uint256); +} contract AbritrumBridgeTest is Test { - ICtx ctx = ICtx(0x321C2fE4446C7c963dc41Dd58879AF648838f98D); - IGovernorBeta public governorBeta = IGovernorBeta(0x874C5D592AfC6803c3DD60d6442357879F196d5b); - ITimelock public timelock = ITimelock(0xa54074b2cc0e96a43048d4a68472F7F046aC0DA8); - IL1MessageRelayer l1MessageRelayer = IL1MessageRelayer(0x209c23DB16298504354112fa4210d368e1d564dA); - // 0x3769b6aA269995297a539BEd7a463105466733A5 --> L2MessageExecutorProxy.so - IL2MessageExecutor l2MessageExecutor = IL2MessageExecutor(0x3769b6aA269995297a539BEd7a463105466733A5); - IArbitrumTreasury arbitrumTreasury = IArbitrumTreasury(0x9474B771Fb46E538cfED114Ca816A3e25Bb346CF); - IPerennialCollateral perennialCollateral = IPerennialCollateral(0xAF8CeD28FcE00ABD30463D55dA81156AA5aEEEc2); - - uint256 public ethereumMainnetForkId; + ICtx ctx = ICtx(0x321C2fE4446C7c963dc41Dd58879AF648838f98D); + IGovernorBeta public governorBeta = + IGovernorBeta(0x874C5D592AfC6803c3DD60d6442357879F196d5b); + ITimelock public timelock = + ITimelock(0xa54074b2cc0e96a43048d4a68472F7F046aC0DA8); + IL1MessageRelayer l1MessageRelayer = + IL1MessageRelayer(0x209c23DB16298504354112fa4210d368e1d564dA); + // 0x3769b6aA269995297a539BEd7a463105466733A5 --> L2MessageExecutorProxy.so + IL2MessageExecutor l2MessageExecutor = + IL2MessageExecutor(0x3769b6aA269995297a539BEd7a463105466733A5); + IArbitrumTreasury arbitrumTreasury = + IArbitrumTreasury(0x9474B771Fb46E538cfED114Ca816A3e25Bb346CF); + IPerennialCollateral perennialCollateral = + IPerennialCollateral(0xAF8CeD28FcE00ABD30463D55dA81156AA5aEEEc2); + + IERC20 dsu = IERC20(0x52C64b8998eB7C80b6F526E99E29ABdcC86B841b); + + uint256 public ethereumMainnetForkId; uint256 public arbitrumMainnetForkId; - address user = address(0x51); + address user = address(0x51); - function setUp() public { - string memory ETHEREUM_MAINNET_RPC_URL = vm.envString( + function setUp() public { + string memory ETHEREUM_MAINNET_RPC_URL = vm.envString( "ETHEREUM_MAINNET_RPC_URL" ); - string memory ARBITRUM_MAINNET_RPC_URL = vm.envString( - "ARBITRUM_API_URL" - ); - ethereumMainnetForkId = vm.createFork(ETHEREUM_MAINNET_RPC_URL); + string memory ARBITRUM_MAINNET_RPC_URL = vm.envString("ARBITRUM_API_URL"); + ethereumMainnetForkId = vm.createFork(ETHEREUM_MAINNET_RPC_URL); arbitrumMainnetForkId = vm.createFork(ARBITRUM_MAINNET_RPC_URL); - vm.selectFork(ethereumMainnetForkId); - deal(address(ctx), user, 900_000 ether); - vm.prank(user); - ctx.delegate(user); - } + vm.selectFork(ethereumMainnetForkId); + deal(address(ctx), user, 900_000 ether); + vm.prank(user); + ctx.delegate(user); + } - function createAndExecuteGovernanceProposal( + function createAndExecuteGovernanceProposal( address[] memory targets, uint256[] memory values, string[] memory signatures, bytes[] memory calldatas, - string memory description + string memory description ) internal { vm.startPrank(user); vm.roll(block.number + 100); @@ -118,50 +127,88 @@ contract AbritrumBridgeTest is Test { vm.stopPrank(); } - function test() external { - vm.selectFork(ethereumMainnetForkId); - address target = address(l2MessageExecutor); - bytes memory payload = abi.encode( - address(arbitrumTreasury), - abi.encodeWithSelector( - IArbitrumTreasury.executeTransaction.selector, - address(perennialCollateral), // target - 0, // value - "claimFee()", // signature - bytes("") // data - ) - ); + function test() external { + vm.selectFork(ethereumMainnetForkId); + address l2Target = address(l2MessageExecutor); + bytes memory executorPayload = abi.encode( + address(arbitrumTreasury), + abi.encodeWithSelector( + IArbitrumTreasury.executeTransaction.selector, + address(perennialCollateral), // target + 0, // value + "claimFee()", // signature + bytes("") // data + ) + ); + console2.log( + "==================================================================================" + ); + console2.log("payload to feed the script for calculating gas related data"); + console2.logBytes(executorPayload); + console2.log( + "==================================================================================" + ); address[] memory targets = new address[](1); uint256[] memory values = new uint256[](1); string[] memory signatures = new string[](1); bytes[] memory calldatas = new bytes[](1); + bytes memory l2CallData = abi.encodeWithSelector( + IL2MessageExecutor.executeMessage.selector, + executorPayload + ); + targets[0] = address(l1MessageRelayer); - values[0] = 0.03 ether; + values[0] = 349782448131600; signatures[0] = "relayMessage(address,bytes,uint256,uint256,uint256)"; calldatas[0] = abi.encode( - target, - payload, - 3815530707376, - 82096, - 100000000 + l2Target, + l2CallData, + 344212668313600, + 111311, + 50038000 + ); + string memory description = "Claim TCAP Perp Fees"; + console2.log( + "==================================================================================" ); - string memory description = "Claim TCAP Perp Fees"; - console.log("targets[0]", targets[0]); - console.log("=================================================================================="); - console2.log("values[0]", values[0]); - console.log("=================================================================================="); - console.log("signatures[0]", signatures[0]); - console.log("=================================================================================="); - console.log("calldatas[0]"); - console.logBytes(calldatas[0]); - console.log("=================================================================================="); - console.log("description", description); - console.log("=================================================================================="); - createAndExecuteGovernanceProposal(targets, values, signatures, calldatas, description); - vm.selectFork(arbitrumMainnetForkId); - vm.startPrank(AddressAliasHelper.applyL1ToL2Alias(address(l1MessageRelayer))); - l2MessageExecutor.executeMessage(payload); - } + console2.log("targets[0]", targets[0]); + console2.log( + "==================================================================================" + ); + console2.log("values[0]", values[0]); + console2.log( + "==================================================================================" + ); + console2.log("signatures[0]", signatures[0]); + console2.log( + "==================================================================================" + ); + console2.log("calldatas[0]"); + console2.logBytes(calldatas[0]); + console2.log( + "==================================================================================" + ); + console2.log("description", description); + console2.log( + "==================================================================================" + ); + createAndExecuteGovernanceProposal( + targets, + values, + signatures, + calldatas, + description + ); + vm.selectFork(arbitrumMainnetForkId); + vm.startPrank( + AddressAliasHelper.applyL1ToL2Alias(address(l1MessageRelayer)) + ); + uint256 oldBalance = dsu.balanceOf(address(arbitrumTreasury)); + (bool success, ) = l2Target.call(l2CallData); + require(success, "Message call failed"); + uint256 newBalance = dsu.balanceOf(address(arbitrumTreasury)); + assertTrue((newBalance - oldBalance) > 15887 ether); + } } diff --git a/test/interfaces/IArbitrumInboxErrors.sol b/test/interfaces/IArbitrumInboxErrors.sol index 166920e4..4a78961d 100644 --- a/test/interfaces/IArbitrumInboxErrors.sol +++ b/test/interfaces/IArbitrumInboxErrors.sol @@ -2,94 +2,94 @@ pragma solidity ^0.8.0; interface IArbitrumInboxErrors { - /// @dev Init was already called -error AlreadyInit(); + /// @dev Init was already called + error AlreadyInit(); -/// @dev Init was called with param set to zero that must be nonzero -error HadZeroInit(); + /// @dev Init was called with param set to zero that must be nonzero + error HadZeroInit(); -/// @dev Thrown when post upgrade init validation fails -error BadPostUpgradeInit(); + /// @dev Thrown when post upgrade init validation fails + error BadPostUpgradeInit(); -/// @dev Thrown when the caller is not a codeless origin -error NotCodelessOrigin(); + /// @dev Thrown when the caller is not a codeless origin + error NotCodelessOrigin(); -/// @dev Thrown when non owner tries to access an only-owner function -/// @param sender The msg.sender who is not the owner -/// @param owner The owner address -error NotOwner(address sender, address owner); + /// @dev Thrown when non owner tries to access an only-owner function + /// @param sender The msg.sender who is not the owner + /// @param owner The owner address + error NotOwner(address sender, address owner); -/// @dev Thrown when an address that is not the rollup tries to call an only-rollup function -/// @param sender The sender who is not the rollup -/// @param rollup The rollup address authorized to call this function -error NotRollup(address sender, address rollup); + /// @dev Thrown when an address that is not the rollup tries to call an only-rollup function + /// @param sender The sender who is not the rollup + /// @param rollup The rollup address authorized to call this function + error NotRollup(address sender, address rollup); -/// @dev Thrown when the contract was not called directly from the origin ie msg.sender != tx.origin -error NotOrigin(); + /// @dev Thrown when the contract was not called directly from the origin ie msg.sender != tx.origin + error NotOrigin(); -/// @dev Provided data was too large -/// @param dataLength The length of the data that is too large -/// @param maxDataLength The max length the data can be -error DataTooLarge(uint256 dataLength, uint256 maxDataLength); + /// @dev Provided data was too large + /// @param dataLength The length of the data that is too large + /// @param maxDataLength The max length the data can be + error DataTooLarge(uint256 dataLength, uint256 maxDataLength); -/// @dev The provided is not a contract and was expected to be -/// @param addr The adddress in question -error NotContract(address addr); + /// @dev The provided is not a contract and was expected to be + /// @param addr The adddress in question + error NotContract(address addr); -/// @dev The merkle proof provided was too long -/// @param actualLength The length of the merkle proof provided -/// @param maxProofLength The max length a merkle proof can have -error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength); + /// @dev The merkle proof provided was too long + /// @param actualLength The length of the merkle proof provided + /// @param maxProofLength The max length a merkle proof can have + error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength); -/// @dev Thrown when an un-authorized address tries to access an admin function -/// @param sender The un-authorized sender -/// @param rollup The rollup, which would be authorized -/// @param owner The rollup's owner, which would be authorized -error NotRollupOrOwner(address sender, address rollup, address owner); + /// @dev Thrown when an un-authorized address tries to access an admin function + /// @param sender The un-authorized sender + /// @param rollup The rollup, which would be authorized + /// @param owner The rollup's owner, which would be authorized + error NotRollupOrOwner(address sender, address rollup, address owner); -// Bridge Errors + // Bridge Errors -/// @dev Thrown when an un-authorized address tries to access an only-inbox function -/// @param sender The un-authorized sender -error NotDelayedInbox(address sender); + /// @dev Thrown when an un-authorized address tries to access an only-inbox function + /// @param sender The un-authorized sender + error NotDelayedInbox(address sender); -/// @dev Thrown when an un-authorized address tries to access an only-sequencer-inbox function -/// @param sender The un-authorized sender -error NotSequencerInbox(address sender); + /// @dev Thrown when an un-authorized address tries to access an only-sequencer-inbox function + /// @param sender The un-authorized sender + error NotSequencerInbox(address sender); -/// @dev Thrown when an un-authorized address tries to access an only-outbox function -/// @param sender The un-authorized sender -error NotOutbox(address sender); + /// @dev Thrown when an un-authorized address tries to access an only-outbox function + /// @param sender The un-authorized sender + error NotOutbox(address sender); -/// @dev the provided outbox address isn't valid -/// @param outbox address of outbox being set -error InvalidOutboxSet(address outbox); + /// @dev the provided outbox address isn't valid + /// @param outbox address of outbox being set + error InvalidOutboxSet(address outbox); -/// @dev The provided token address isn't valid -/// @param token address of token being set -error InvalidTokenSet(address token); + /// @dev The provided token address isn't valid + /// @param token address of token being set + error InvalidTokenSet(address token); -/// @dev Call to this specific address is not allowed -/// @param target address of the call receiver -error CallTargetNotAllowed(address target); + /// @dev Call to this specific address is not allowed + /// @param target address of the call receiver + error CallTargetNotAllowed(address target); -/// @dev Call that changes the balance of ERC20Bridge is not allowed -error CallNotAllowed(); + /// @dev Call that changes the balance of ERC20Bridge is not allowed + error CallNotAllowed(); -// Inbox Errors + // Inbox Errors -/// @dev msg.value sent to the inbox isn't high enough -error InsufficientValue(uint256 expected, uint256 actual); + /// @dev msg.value sent to the inbox isn't high enough + error InsufficientValue(uint256 expected, uint256 actual); -/// @dev submission cost provided isn't enough to create retryable ticket -error InsufficientSubmissionCost(uint256 expected, uint256 actual); + /// @dev submission cost provided isn't enough to create retryable ticket + error InsufficientSubmissionCost(uint256 expected, uint256 actual); -/// @dev address not allowed to interact with the given contract -error NotAllowedOrigin(address origin); + /// @dev address not allowed to interact with the given contract + error NotAllowedOrigin(address origin); -/// @dev used to convey retryable tx data in eth calls without requiring a tx trace -/// this follows a pattern similar to EIP-3668 where reverts surface call information -error RetryableData( + /// @dev used to convey retryable tx data in eth calls without requiring a tx trace + /// this follows a pattern similar to EIP-3668 where reverts surface call information + error RetryableData( address from, address to, uint256 l2CallValue, @@ -100,116 +100,116 @@ error RetryableData( uint256 gasLimit, uint256 maxFeePerGas, bytes data -); + ); -/// @dev Thrown when a L1 chainId fork is detected -error L1Forked(); + /// @dev Thrown when a L1 chainId fork is detected + error L1Forked(); -/// @dev Thrown when a L1 chainId fork is not detected -error NotForked(); + /// @dev Thrown when a L1 chainId fork is not detected + error NotForked(); -/// @dev The provided gasLimit is larger than uint64 -error GasLimitTooLarge(); + /// @dev The provided gasLimit is larger than uint64 + error GasLimitTooLarge(); -/// @dev The provided amount cannot be adjusted to 18 decimals due to overflow -error AmountTooLarge(uint256 amount); + /// @dev The provided amount cannot be adjusted to 18 decimals due to overflow + error AmountTooLarge(uint256 amount); -/// @dev Number of native token's decimals is restricted to enable conversions to 18 decimals -error NativeTokenDecimalsTooLarge(uint256 decimals); + /// @dev Number of native token's decimals is restricted to enable conversions to 18 decimals + error NativeTokenDecimalsTooLarge(uint256 decimals); -// Outbox Errors + // Outbox Errors -/// @dev The provided proof was too long -/// @param proofLength The length of the too-long proof -error ProofTooLong(uint256 proofLength); + /// @dev The provided proof was too long + /// @param proofLength The length of the too-long proof + error ProofTooLong(uint256 proofLength); -/// @dev The output index was greater than the maximum -/// @param index The output index -/// @param maxIndex The max the index could be -error PathNotMinimal(uint256 index, uint256 maxIndex); + /// @dev The output index was greater than the maximum + /// @param index The output index + /// @param maxIndex The max the index could be + error PathNotMinimal(uint256 index, uint256 maxIndex); -/// @dev The calculated root does not exist -/// @param root The calculated root -error UnknownRoot(bytes32 root); + /// @dev The calculated root does not exist + /// @param root The calculated root + error UnknownRoot(bytes32 root); -/// @dev The record has already been spent -/// @param index The index of the spent record -error AlreadySpent(uint256 index); + /// @dev The record has already been spent + /// @param index The index of the spent record + error AlreadySpent(uint256 index); -/// @dev A call to the bridge failed with no return data -error BridgeCallFailed(); + /// @dev A call to the bridge failed with no return data + error BridgeCallFailed(); -// Sequencer Inbox Errors + // Sequencer Inbox Errors -/// @dev Thrown when someone attempts to read fewer messages than have already been read -error DelayedBackwards(); + /// @dev Thrown when someone attempts to read fewer messages than have already been read + error DelayedBackwards(); -/// @dev Thrown when someone attempts to read more messages than exist -error DelayedTooFar(); + /// @dev Thrown when someone attempts to read more messages than exist + error DelayedTooFar(); -/// @dev Force include can only read messages more blocks old than the delay period -error ForceIncludeBlockTooSoon(); + /// @dev Force include can only read messages more blocks old than the delay period + error ForceIncludeBlockTooSoon(); -/// @dev The message provided did not match the hash in the delayed inbox -error IncorrectMessagePreimage(); + /// @dev The message provided did not match the hash in the delayed inbox + error IncorrectMessagePreimage(); -/// @dev This can only be called by the batch poster -error NotBatchPoster(); + /// @dev This can only be called by the batch poster + error NotBatchPoster(); -/// @dev The sequence number provided to this message was inconsistent with the number of batches already included -error BadSequencerNumber(uint256 stored, uint256 received); + /// @dev The sequence number provided to this message was inconsistent with the number of batches already included + error BadSequencerNumber(uint256 stored, uint256 received); -/// @dev The sequence message number provided to this message was inconsistent with the previous one -error BadSequencerMessageNumber(uint256 stored, uint256 received); + /// @dev The sequence message number provided to this message was inconsistent with the previous one + error BadSequencerMessageNumber(uint256 stored, uint256 received); -/// @dev Tried to create an already valid Data Availability Service keyset -error AlreadyValidDASKeyset(bytes32); + /// @dev Tried to create an already valid Data Availability Service keyset + error AlreadyValidDASKeyset(bytes32); -/// @dev Tried to use or invalidate an already invalid Data Availability Service keyset -error NoSuchKeyset(bytes32); + /// @dev Tried to use or invalidate an already invalid Data Availability Service keyset + error NoSuchKeyset(bytes32); -/// @dev Thrown when the provided address is not the designated batch poster manager -error NotBatchPosterManager(address); + /// @dev Thrown when the provided address is not the designated batch poster manager + error NotBatchPosterManager(address); -/// @dev Thrown when a data blob feature is attempted to be used on a chain that doesnt support it -error DataBlobsNotSupported(); + /// @dev Thrown when a data blob feature is attempted to be used on a chain that doesnt support it + error DataBlobsNotSupported(); -/// @dev Thrown when batches are posted without buffer proof, this is only allowed in a sync state or when no new delayed messages are read -error DelayProofRequired(); + /// @dev Thrown when batches are posted without buffer proof, this is only allowed in a sync state or when no new delayed messages are read + error DelayProofRequired(); -/// @dev The DelayedAccPreimage is invalid -error InvalidDelayedAccPreimage(); + /// @dev The DelayedAccPreimage is invalid + error InvalidDelayedAccPreimage(); -/// @dev Thrown when the sequencer attempts to post a batch with delay / sync proofs without delay bufferability enabled -error NotDelayBufferable(); + /// @dev Thrown when the sequencer attempts to post a batch with delay / sync proofs without delay bufferability enabled + error NotDelayBufferable(); -/// @dev Thrown when an init param was supplied as empty -error InitParamZero(string name); + /// @dev Thrown when an init param was supplied as empty + error InitParamZero(string name); -/// @dev Thrown when data hashes where expected but not where present on the tx -error MissingDataHashes(); + /// @dev Thrown when data hashes where expected but not where present on the tx + error MissingDataHashes(); -/// @dev Thrown when rollup is not updated with updateRollupAddress -error RollupNotChanged(); + /// @dev Thrown when rollup is not updated with updateRollupAddress + error RollupNotChanged(); -/// @dev Unsupported header flag was provided -error InvalidHeaderFlag(bytes1); + /// @dev Unsupported header flag was provided + error InvalidHeaderFlag(bytes1); -/// @dev SequencerInbox and Bridge are not in the same feeToken/ETH mode -error NativeTokenMismatch(); + /// @dev SequencerInbox and Bridge are not in the same feeToken/ETH mode + error NativeTokenMismatch(); -/// @dev Thrown when a deprecated function is called -error Deprecated(); + /// @dev Thrown when a deprecated function is called + error Deprecated(); -/// @dev Thrown when any component of maxTimeVariation is over uint64 -error BadMaxTimeVariation(); + /// @dev Thrown when any component of maxTimeVariation is over uint64 + error BadMaxTimeVariation(); -/// @dev Thrown when any component of bufferConfig is zero -error BadBufferConfig(); + /// @dev Thrown when any component of bufferConfig is zero + error BadBufferConfig(); -/// @dev Thrown when extra gas is not a uint64 -error ExtraGasNotUint64(); + /// @dev Thrown when extra gas is not a uint64 + error ExtraGasNotUint64(); -/// @dev Thrown when keysetBytes is too large -error KeysetTooLarge(); + /// @dev Thrown when keysetBytes is too large + error KeysetTooLarge(); } diff --git a/test/interfaces/ICtx.sol b/test/interfaces/ICtx.sol index 80eef533..f016892f 100644 --- a/test/interfaces/ICtx.sol +++ b/test/interfaces/ICtx.sol @@ -2,63 +2,97 @@ pragma solidity ^0.8.0; interface ICtx { - // Events - event MinterChanged(address minter, address newMinter); - event DelegateChanged( - address indexed delegator, - address indexed fromDelegate, - address indexed toDelegate - ); - event DelegateVotesChanged( - address indexed delegate, - uint256 previousBalance, - uint256 newBalance - ); - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); - - // View Functions - function name() external view returns (string memory); - function symbol() external view returns (string memory); - function decimals() external view returns (uint8); - function totalSupply() external view returns (uint256); - function minter() external view returns (address); - function mintingAllowedAfter() external view returns (uint256); - function balanceOf(address account) external view returns (uint256); - function allowance(address account, address spender) external view returns (uint256); - function getCurrentVotes(address account) external view returns (uint96); - function getPriorVotes(address account, uint256 blockNumber) external view returns (uint96); - function delegates(address account) external view returns (address); - function nonces(address account) external view returns (uint256); - - // State-Changing Functions - function setMinter(address minter_) external; - function mint(address dst, uint256 rawAmount) external; - function transfer(address dst, uint256 rawAmount) external returns (bool); - function transferFrom(address src, address dst, uint256 rawAmount) external returns (bool); - function approve(address spender, uint256 rawAmount) external returns (bool); - function increaseAllowance(address spender, uint256 addedValue) external returns (bool); - function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); - function delegate(address delegatee) external; - function delegateBySig( - address delegatee, - uint256 nonce, - uint256 expiry, - uint8 v, - bytes32 r, - bytes32 s - ) external; - function permit( - address owner, - address spender, - uint256 rawAmount, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) external; + // Events + event MinterChanged(address minter, address newMinter); + event DelegateChanged( + address indexed delegator, + address indexed fromDelegate, + address indexed toDelegate + ); + event DelegateVotesChanged( + address indexed delegate, + uint256 previousBalance, + uint256 newBalance + ); + event Transfer(address indexed from, address indexed to, uint256 amount); + event Approval( + address indexed owner, + address indexed spender, + uint256 amount + ); + + // View Functions + function name() external view returns (string memory); + + function symbol() external view returns (string memory); + + function decimals() external view returns (uint8); + + function totalSupply() external view returns (uint256); + + function minter() external view returns (address); + + function mintingAllowedAfter() external view returns (uint256); + + function balanceOf(address account) external view returns (uint256); + + function allowance(address account, address spender) + external + view + returns (uint256); + + function getCurrentVotes(address account) external view returns (uint96); + + function getPriorVotes(address account, uint256 blockNumber) + external + view + returns (uint96); + + function delegates(address account) external view returns (address); + + function nonces(address account) external view returns (uint256); + + // State-Changing Functions + function setMinter(address minter_) external; + + function mint(address dst, uint256 rawAmount) external; + + function transfer(address dst, uint256 rawAmount) external returns (bool); + + function transferFrom( + address src, + address dst, + uint256 rawAmount + ) external returns (bool); + + function approve(address spender, uint256 rawAmount) external returns (bool); + + function increaseAllowance(address spender, uint256 addedValue) + external + returns (bool); + + function decreaseAllowance(address spender, uint256 subtractedValue) + external + returns (bool); + + function delegate(address delegatee) external; + + function delegateBySig( + address delegatee, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + function permit( + address owner, + address spender, + uint256 rawAmount, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; }