Skip to content

Commit 43c9a93

Browse files
nicholaspaigrasphoperbmzigdohaki
authored andcommitted
feat: Add EVM Universal Adapter and remove deposit whitelist checks (#974)
* feat(SpokePool): Remove enabledDepositRoutes check for unsafeDeposit (#926) * fix(ZkSync_SpokePool): Add __gap (#907) * fix(ZkSync_SpokePool): Add __gap This contract gets extended by the Lens_SpokePool which doesn't add any storage but we should add it in case a future variable gets added to the Lens_SpokePool * Update ZkSync_SpokePool.json * Add `OFTTransportAdapter` to support cross-chain token transfers of `USDT0` via `OFT` messaging protocol (#902) * first draft of OFTTransportAdapter Signed-off-by: Ihor Farion <ihor@umaproject.org> * update yarn.lock file Signed-off-by: Ihor Farion <ihor@umaproject.org> * Revert "update yarn.lock file" This reverts commit 4c216ea. Signed-off-by: Ihor Farion <ihor@umaproject.org> * add yarn.lock compatible with master Signed-off-by: Ihor Farion <ihor@umaproject.org> * polish OFTTransportAdapter, add OFT support to Arbitrum_Adapter on L1, and Arbitrum_SpokePool on L2 Signed-off-by: Ihor Farion <ihor@umaproject.org> * polish + fix missing approval Signed-off-by: Ihor Farion <ihor@umaproject.org> * add context for dstEid Signed-off-by: Ihor Farion <ihor@umaproject.org> * address most of the PR comments about contracts Signed-off-by: Ihor Farion <ihor@umaproject.org> * update deploy scripts, add tests for OFT messaging, polish contracts Signed-off-by: Ihor Farion <ihor@umaproject.org> * cleanup comments and extraneous log file Signed-off-by: Ihor Farion <ihor@umaproject.org> * revert package.json prepublish change Signed-off-by: Ihor Farion <ihor@umaproject.org> * generalize oft adapter to support multiple tokens. Introduce OFTAddressBook to support that. Update deploy / test scripts to reflect new functionality Signed-off-by: Ihor Farion <ihor@umaproject.org> * add __gap to ArbitrumSpokePool, update stale comments on OFTTransportAdapter, update layouts of ArbitrumSpokePool and AlephZeroSpokePool Signed-off-by: Ihor Farion <ihor@umaproject.org> * update some comments; adjust fee cap naming Signed-off-by: Ihor Farion <ihor@umaproject.org> * address PR comments Signed-off-by: Ihor Farion <ihor@umaproject.org> * address PR comments Signed-off-by: Ihor Farion <ihor@umaproject.org> * fix deploy script, remove incorrect values from consts Signed-off-by: Ihor Farion <ihor@umaproject.org> * improve comment Signed-off-by: Ihor Farion <ihor@umaproject.org> * add oftFeeCap as a param to arbitrum adapter construction Signed-off-by: Ihor Farion <ihor@umaproject.org> * move OFT functionality to SpokePool for easy further integration and removing boilerplate code Signed-off-by: Ihor Farion <ihor@umaproject.org> * remove layerzero from foundry remappings Signed-off-by: Ihor Farion <ihor@umaproject.org> * address licensing comment; add permalink to LZ OFT code on github Signed-off-by: Ihor Farion <ihor@umaproject.org> * fix a couple of comment typos Signed-off-by: Ihor Farion <ihor@umaproject.org> --------- Signed-off-by: Ihor Farion <ihor@umaproject.org> * feat(SpokePoolPeriphery): Support multiple exchanges (#777) * feat(SpokePoolPeriphery): Support multiple exchanges Currently we can only initialize the periphery contract with a single exchange to swap with. This PR allows us to initialize it with multiple exchanges to swap with. Like before, these initial set of exchanges and function selectors cannot be changed post-initialization, which gives the user assurances. * rename * Update SpokeV3PoolPeriphery.sol * Update SpokeV3PoolPeriphery.sol * Update SpokeV3PoolPeriphery.sol * Add unit tests * Add whitelistExchanges only owner method * rename * Remove onlyOwner * Remove whitelist of exchanges, add proxy to bypass approval abuse Make user approve proxy contract so no one can use `exchange` + `routerCalldata` to steal their already approved funds via the `SpokePoolPeriphery` * Add some protection to callSpokePoolPeriphery * Only call swapAndBridge through proxy * move periphery funcs into proxy * Update SpokePoolV3Periphery.sol * remove depositERC20 * Update SpokePoolV3Periphery.sol * Add back safeTransferFron's to permit funcs * Add unit tests that check if calling deposit and swapAndBridge with no value fails directly * Add interfaces to make sure we don't add new functions as easily * Add Create2Factory * feat: add permit2 entrypoints to the periphery (#782) * feat: add permit2 entrypoints to the periphery Signed-off-by: Bennett <bennett@umaproject.org> * Update test/evm/foundry/local/SpokePoolPeriphery.t.sol * Update SpokePoolPeriphery.t.sol * move permit2 to proxy * fix permit2 Signed-off-by: bennett <bennett@umaproject.org> * wip: swap arguments refactor Signed-off-by: bennett <bennett@umaproject.org> * implement isValidSignature Signed-off-by: bennett <bennett@umaproject.org> * 1271 Signed-off-by: bennett <bennett@umaproject.org> * simplify isValidSignature Signed-off-by: bennett <bennett@umaproject.org> * rebase /programs on master Signed-off-by: nicholaspai <npai.nyc@gmail.com> * clean up comments * rebase programs * fix: consolidate structs so that permit2 witnesses cover inputs Signed-off-by: bennett <bennett@umaproject.org> * begin permit2 unit tests Signed-off-by: bennett <bennett@umaproject.org> * rebase * Update SpokePoolPeriphery.t.sol * move type definitions to interface Signed-off-by: bennett <bennett@umaproject.org> * fix permit2 test Signed-off-by: bennett <bennett@umaproject.org> * transfer type tests Signed-off-by: bennett <bennett@umaproject.org> * rename EIP1271Signature to Permi2Approval Signed-off-by: bennett <bennett@umaproject.org> --------- Signed-off-by: Bennett <bennett@umaproject.org> Signed-off-by: bennett <bennett@umaproject.org> Signed-off-by: nicholaspai <npai.nyc@gmail.com> Co-authored-by: nicholaspai <9457025+nicholaspai@users.noreply.github.com> Co-authored-by: nicholaspai <npai.nyc@gmail.com> * feat: sponsored swap and deposits (#790) * feat: add permit2 entrypoints to the periphery Signed-off-by: Bennett <bennett@umaproject.org> * Update test/evm/foundry/local/SpokePoolPeriphery.t.sol * Update SpokePoolPeriphery.t.sol * move permit2 to proxy * fix permit2 Signed-off-by: bennett <bennett@umaproject.org> * wip: swap arguments refactor Signed-off-by: bennett <bennett@umaproject.org> * implement isValidSignature Signed-off-by: bennett <bennett@umaproject.org> * 1271 Signed-off-by: bennett <bennett@umaproject.org> * simplify isValidSignature Signed-off-by: bennett <bennett@umaproject.org> * rebase /programs on master Signed-off-by: nicholaspai <npai.nyc@gmail.com> * clean up comments * rebase programs * feat: sponsored swap and deposits Signed-off-by: bennett <bennett@umaproject.org> * fix: consolidate structs so that permit2 witnesses cover inputs Signed-off-by: bennett <bennett@umaproject.org> * begin permit2 unit tests Signed-off-by: bennett <bennett@umaproject.org> * rebase * Update SpokePoolPeriphery.t.sol * move type definitions to interface Signed-off-by: bennett <bennett@umaproject.org> * fix permit2 test Signed-off-by: bennett <bennett@umaproject.org> * transfer type tests Signed-off-by: bennett <bennett@umaproject.org> * rename EIP1271Signature to Permi2Approval Signed-off-by: bennett <bennett@umaproject.org> * add mockERC20 which implements permit/receiveWithAuthorization Signed-off-by: bennett <bennett@umaproject.org> * add tests for permit, permit2, and receiveWithAuth swaps/deposits Signed-off-by: bennett <bennett@umaproject.org> * add tests for invalid witnesses Signed-off-by: bennett <bennett@umaproject.org> * factor out signature checking Signed-off-by: bennett <bennett@umaproject.org> --------- Signed-off-by: Bennett <bennett@umaproject.org> Signed-off-by: bennett <bennett@umaproject.org> Signed-off-by: nicholaspai <npai.nyc@gmail.com> Co-authored-by: nicholaspai <9457025+nicholaspai@users.noreply.github.com> Co-authored-by: nicholaspai <npai.nyc@gmail.com> * feat: Delete SwapAndBridge and add submission fees to gasless flow (#809) * feat: add permit2 entrypoints to the periphery Signed-off-by: Bennett <bennett@umaproject.org> * Update test/evm/foundry/local/SpokePoolPeriphery.t.sol * Update SpokePoolPeriphery.t.sol * move permit2 to proxy * fix permit2 Signed-off-by: bennett <bennett@umaproject.org> * wip: swap arguments refactor Signed-off-by: bennett <bennett@umaproject.org> * implement isValidSignature Signed-off-by: bennett <bennett@umaproject.org> * 1271 Signed-off-by: bennett <bennett@umaproject.org> * simplify isValidSignature Signed-off-by: bennett <bennett@umaproject.org> * rebase /programs on master Signed-off-by: nicholaspai <npai.nyc@gmail.com> * clean up comments * rebase programs * feat: sponsored swap and deposits Signed-off-by: bennett <bennett@umaproject.org> * fix: consolidate structs so that permit2 witnesses cover inputs Signed-off-by: bennett <bennett@umaproject.org> * begin permit2 unit tests Signed-off-by: bennett <bennett@umaproject.org> * rebase * Update SpokePoolPeriphery.t.sol * move type definitions to interface Signed-off-by: bennett <bennett@umaproject.org> * fix permit2 test Signed-off-by: bennett <bennett@umaproject.org> * transfer type tests Signed-off-by: bennett <bennett@umaproject.org> * rename EIP1271Signature to Permi2Approval Signed-off-by: bennett <bennett@umaproject.org> * add mockERC20 which implements permit/receiveWithAuthorization Signed-off-by: bennett <bennett@umaproject.org> * add tests for permit, permit2, and receiveWithAuth swaps/deposits Signed-off-by: bennett <bennett@umaproject.org> * add tests for invalid witnesses Signed-off-by: bennett <bennett@umaproject.org> * feat: Delete SwapAndBridge and add submission fees to gasless flow SwapAndBridge is to be replaced with SpokePoolV3Periphery Gasless flows will require user to cover gas cost of whoever submits the transaction, but they can be set to 0 if the user wants to submit themselves. * Internal refactor * Update SpokePoolV3Periphery.sol * Update PeripherySigningLib.sol * Update SpokePoolV3Periphery.sol * Update PeripherySigningLib.sol --------- Signed-off-by: Bennett <bennett@umaproject.org> Signed-off-by: bennett <bennett@umaproject.org> Signed-off-by: nicholaspai <npai.nyc@gmail.com> Co-authored-by: Bennett <bennett@umaproject.org> * Update SpokePoolV3Periphery.sol * Update SpokePoolPeriphery.t.sol * Move all comments to interface and use inherit doc * fix: eip712 types and hashes (#821) * refactor comments Signed-off-by: bennett <bennett@umaproject.org> * Create IERC20Auth.sol * fix tests * Comments --------- Signed-off-by: Bennett <bennett@umaproject.org> Signed-off-by: bennett <bennett@umaproject.org> Signed-off-by: nicholaspai <npai.nyc@gmail.com> Co-authored-by: bmzig <57361391+bmzig@users.noreply.github.com> Co-authored-by: Bennett <bennett@umaproject.org> Co-authored-by: Dong-Ha Kim <dongha.kim210@gmail.com> * Single AddressBook for all adapters (#919) * use a single address book instead of 1 per adapter for oft / xerc20 storage needs Signed-off-by: Ihor Farion <ihor@umaproject.org> * update comments and naming Signed-off-by: Ihor Farion <ihor@umaproject.org> * add a gas optimization suggested in OFT PR Signed-off-by: Ihor Farion <ihor@umaproject.org> * address PR comments and minor improvements Signed-off-by: Ihor Farion <ihor@umaproject.org> * fix spokePool test Signed-off-by: Ihor Farion <ihor@umaproject.org> * address PR comments Signed-off-by: Ihor Farion <ihor@umaproject.org> --------- Signed-off-by: Ihor Farion <ihor@umaproject.org> * feat(SpokePool): Remove enabledDepositRoutes check for unsafeDeposit Allows Across to support inputTokens without enabling deposit routes for them, by forcing filler to take repayment of the token on the origin chain. Enhances protection against gas cost griefing vector in when executing refund leaves, since removal of this enabledDepositRoutes check would allow someone to force the refund leaf executor to call a malicious ERC20.transfer() function * add tests * Make check unilateral * Update SpokePool.Deposit.ts * apply tests * storage layouts * merge conflicts * Create SwapAndBridge.sol * Fix conflicts * Fix storage layouts * Remove solana setEnableRoute special logic * Remove MAX_ERC20_TRANSFER_GAS_COST * Update SpokePool.sol --------- Signed-off-by: Ihor Farion <ihor@umaproject.org> Signed-off-by: Bennett <bennett@umaproject.org> Signed-off-by: bennett <bennett@umaproject.org> Signed-off-by: nicholaspai <npai.nyc@gmail.com> Co-authored-by: Ihor Farion <65650773+grasphoper@users.noreply.github.com> Co-authored-by: bmzig <57361391+bmzig@users.noreply.github.com> Co-authored-by: Bennett <bennett@umaproject.org> Co-authored-by: Dong-Ha Kim <dongha.kim210@gmail.com> * feat: Add universal adapters and spoke pools (#916) * fix(ZkSync_SpokePool): Add __gap (#907) * fix(ZkSync_SpokePool): Add __gap This contract gets extended by the Lens_SpokePool which doesn't add any storage but we should add it in case a future variable gets added to the Lens_SpokePool * Update ZkSync_SpokePool.json * feat: Add SP1_Adapter and SP1_SpokePool Can be used to relay messages from L1 to L2 spoke pools using SP1 + Helios * Remove sp1 import * Add simple test * Re-use storage slots in HubPoolStore - SP1_Adapter sets target == address(0) for relayRootBundle() calls to L2 as a gas-optimization - Add contractAddress to ContractPublicValues - Add deploy script with warning to NOT use create2 as we want each target spoke pool address to be unique * Update SP1_SpokePool.sol * Added replay protection * Updated event * Don't include nonce in data hash, emit data hash * Store relayRootBundle calldata with no nonce for gas optimization * Rename contract public values variables to make it clearer how storage slot proofs could be substituted for eth_call * Add `OFTTransportAdapter` to support cross-chain token transfers of `USDT0` via `OFT` messaging protocol (#902) * first draft of OFTTransportAdapter Signed-off-by: Ihor Farion <ihor@umaproject.org> * update yarn.lock file Signed-off-by: Ihor Farion <ihor@umaproject.org> * Revert "update yarn.lock file" This reverts commit 4c216ea. Signed-off-by: Ihor Farion <ihor@umaproject.org> * add yarn.lock compatible with master Signed-off-by: Ihor Farion <ihor@umaproject.org> * polish OFTTransportAdapter, add OFT support to Arbitrum_Adapter on L1, and Arbitrum_SpokePool on L2 Signed-off-by: Ihor Farion <ihor@umaproject.org> * polish + fix missing approval Signed-off-by: Ihor Farion <ihor@umaproject.org> * add context for dstEid Signed-off-by: Ihor Farion <ihor@umaproject.org> * address most of the PR comments about contracts Signed-off-by: Ihor Farion <ihor@umaproject.org> * update deploy scripts, add tests for OFT messaging, polish contracts Signed-off-by: Ihor Farion <ihor@umaproject.org> * cleanup comments and extraneous log file Signed-off-by: Ihor Farion <ihor@umaproject.org> * revert package.json prepublish change Signed-off-by: Ihor Farion <ihor@umaproject.org> * generalize oft adapter to support multiple tokens. Introduce OFTAddressBook to support that. Update deploy / test scripts to reflect new functionality Signed-off-by: Ihor Farion <ihor@umaproject.org> * add __gap to ArbitrumSpokePool, update stale comments on OFTTransportAdapter, update layouts of ArbitrumSpokePool and AlephZeroSpokePool Signed-off-by: Ihor Farion <ihor@umaproject.org> * update some comments; adjust fee cap naming Signed-off-by: Ihor Farion <ihor@umaproject.org> * address PR comments Signed-off-by: Ihor Farion <ihor@umaproject.org> * address PR comments Signed-off-by: Ihor Farion <ihor@umaproject.org> * fix deploy script, remove incorrect values from consts Signed-off-by: Ihor Farion <ihor@umaproject.org> * improve comment Signed-off-by: Ihor Farion <ihor@umaproject.org> * add oftFeeCap as a param to arbitrum adapter construction Signed-off-by: Ihor Farion <ihor@umaproject.org> * move OFT functionality to SpokePool for easy further integration and removing boilerplate code Signed-off-by: Ihor Farion <ihor@umaproject.org> * remove layerzero from foundry remappings Signed-off-by: Ihor Farion <ihor@umaproject.org> * address licensing comment; add permalink to LZ OFT code on github Signed-off-by: Ihor Farion <ihor@umaproject.org> * fix a couple of comment typos Signed-off-by: Ihor Farion <ihor@umaproject.org> --------- Signed-off-by: Ihor Farion <ihor@umaproject.org> * In HubPoolStore, store byes rather than a struct, add simple unit tests * Update SP1_SpokePool.sol * feat(SpokePoolPeriphery): Support multiple exchanges (#777) * feat(SpokePoolPeriphery): Support multiple exchanges Currently we can only initialize the periphery contract with a single exchange to swap with. This PR allows us to initialize it with multiple exchanges to swap with. Like before, these initial set of exchanges and function selectors cannot be changed post-initialization, which gives the user assurances. * rename * Update SpokeV3PoolPeriphery.sol * Update SpokeV3PoolPeriphery.sol * Update SpokeV3PoolPeriphery.sol * Add unit tests * Add whitelistExchanges only owner method * rename * Remove onlyOwner * Remove whitelist of exchanges, add proxy to bypass approval abuse Make user approve proxy contract so no one can use `exchange` + `routerCalldata` to steal their already approved funds via the `SpokePoolPeriphery` * Add some protection to callSpokePoolPeriphery * Only call swapAndBridge through proxy * move periphery funcs into proxy * Update SpokePoolV3Periphery.sol * remove depositERC20 * Update SpokePoolV3Periphery.sol * Add back safeTransferFron's to permit funcs * Add unit tests that check if calling deposit and swapAndBridge with no value fails directly * Add interfaces to make sure we don't add new functions as easily * Add Create2Factory * feat: add permit2 entrypoints to the periphery (#782) * feat: add permit2 entrypoints to the periphery Signed-off-by: Bennett <bennett@umaproject.org> * Update test/evm/foundry/local/SpokePoolPeriphery.t.sol * Update SpokePoolPeriphery.t.sol * move permit2 to proxy * fix permit2 Signed-off-by: bennett <bennett@umaproject.org> * wip: swap arguments refactor Signed-off-by: bennett <bennett@umaproject.org> * implement isValidSignature Signed-off-by: bennett <bennett@umaproject.org> * 1271 Signed-off-by: bennett <bennett@umaproject.org> * simplify isValidSignature Signed-off-by: bennett <bennett@umaproject.org> * rebase /programs on master Signed-off-by: nicholaspai <npai.nyc@gmail.com> * clean up comments * rebase programs * fix: consolidate structs so that permit2 witnesses cover inputs Signed-off-by: bennett <bennett@umaproject.org> * begin permit2 unit tests Signed-off-by: bennett <bennett@umaproject.org> * rebase * Update SpokePoolPeriphery.t.sol * move type definitions to interface Signed-off-by: bennett <bennett@umaproject.org> * fix permit2 test Signed-off-by: bennett <bennett@umaproject.org> * transfer type tests Signed-off-by: bennett <bennett@umaproject.org> * rename EIP1271Signature to Permi2Approval Signed-off-by: bennett <bennett@umaproject.org> --------- Signed-off-by: Bennett <bennett@umaproject.org> Signed-off-by: bennett <bennett@umaproject.org> Signed-off-by: nicholaspai <npai.nyc@gmail.com> Co-authored-by: nicholaspai <9457025+nicholaspai@users.noreply.github.com> Co-authored-by: nicholaspai <npai.nyc@gmail.com> * feat: sponsored swap and deposits (#790) * feat: add permit2 entrypoints to the periphery Signed-off-by: Bennett <bennett@umaproject.org> * Update test/evm/foundry/local/SpokePoolPeriphery.t.sol * Update SpokePoolPeriphery.t.sol * move permit2 to proxy * fix permit2 Signed-off-by: bennett <bennett@umaproject.org> * wip: swap arguments refactor Signed-off-by: bennett <bennett@umaproject.org> * implement isValidSignature Signed-off-by: bennett <bennett@umaproject.org> * 1271 Signed-off-by: bennett <bennett@umaproject.org> * simplify isValidSignature Signed-off-by: bennett <bennett@umaproject.org> * rebase /programs on master Signed-off-by: nicholaspai <npai.nyc@gmail.com> * clean up comments * rebase programs * feat: sponsored swap and deposits Signed-off-by: bennett <bennett@umaproject.org> * fix: consolidate structs so that permit2 witnesses cover inputs Signed-off-by: bennett <bennett@umaproject.org> * begin permit2 unit tests Signed-off-by: bennett <bennett@umaproject.org> * rebase * Update SpokePoolPeriphery.t.sol * move type definitions to interface Signed-off-by: bennett <bennett@umaproject.org> * fix permit2 test Signed-off-by: bennett <bennett@umaproject.org> * transfer type tests Signed-off-by: bennett <bennett@umaproject.org> * rename EIP1271Signature to Permi2Approval Signed-off-by: bennett <bennett@umaproject.org> * add mockERC20 which implements permit/receiveWithAuthorization Signed-off-by: bennett <bennett@umaproject.org> * add tests for permit, permit2, and receiveWithAuth swaps/deposits Signed-off-by: bennett <bennett@umaproject.org> * add tests for invalid witnesses Signed-off-by: bennett <bennett@umaproject.org> * factor out signature checking Signed-off-by: bennett <bennett@umaproject.org> --------- Signed-off-by: Bennett <bennett@umaproject.org> Signed-off-by: bennett <bennett@umaproject.org> Signed-off-by: nicholaspai <npai.nyc@gmail.com> Co-authored-by: nicholaspai <9457025+nicholaspai@users.noreply.github.com> Co-authored-by: nicholaspai <npai.nyc@gmail.com> * feat: Delete SwapAndBridge and add submission fees to gasless flow (#809) * feat: add permit2 entrypoints to the periphery Signed-off-by: Bennett <bennett@umaproject.org> * Update test/evm/foundry/local/SpokePoolPeriphery.t.sol * Update SpokePoolPeriphery.t.sol * move permit2 to proxy * fix permit2 Signed-off-by: bennett <bennett@umaproject.org> * wip: swap arguments refactor Signed-off-by: bennett <bennett@umaproject.org> * implement isValidSignature Signed-off-by: bennett <bennett@umaproject.org> * 1271 Signed-off-by: bennett <bennett@umaproject.org> * simplify isValidSignature Signed-off-by: bennett <bennett@umaproject.org> * rebase /programs on master Signed-off-by: nicholaspai <npai.nyc@gmail.com> * clean up comments * rebase programs * feat: sponsored swap and deposits Signed-off-by: bennett <bennett@umaproject.org> * fix: consolidate structs so that permit2 witnesses cover inputs Signed-off-by: bennett <bennett@umaproject.org> * begin permit2 unit tests Signed-off-by: bennett <bennett@umaproject.org> * rebase * Update SpokePoolPeriphery.t.sol * move type definitions to interface Signed-off-by: bennett <bennett@umaproject.org> * fix permit2 test Signed-off-by: bennett <bennett@umaproject.org> * transfer type tests Signed-off-by: bennett <bennett@umaproject.org> * rename EIP1271Signature to Permi2Approval Signed-off-by: bennett <bennett@umaproject.org> * add mockERC20 which implements permit/receiveWithAuthorization Signed-off-by: bennett <bennett@umaproject.org> * add tests for permit, permit2, and receiveWithAuth swaps/deposits Signed-off-by: bennett <bennett@umaproject.org> * add tests for invalid witnesses Signed-off-by: bennett <bennett@umaproject.org> * feat: Delete SwapAndBridge and add submission fees to gasless flow SwapAndBridge is to be replaced with SpokePoolV3Periphery Gasless flows will require user to cover gas cost of whoever submits the transaction, but they can be set to 0 if the user wants to submit themselves. * Internal refactor * Update SpokePoolV3Periphery.sol * Update PeripherySigningLib.sol * Update SpokePoolV3Periphery.sol * Update PeripherySigningLib.sol --------- Signed-off-by: Bennett <bennett@umaproject.org> Signed-off-by: bennett <bennett@umaproject.org> Signed-off-by: nicholaspai <npai.nyc@gmail.com> Co-authored-by: Bennett <bennett@umaproject.org> * Update SpokePoolV3Periphery.sol * Update SpokePoolPeriphery.t.sol * Move all comments to interface and use inherit doc * fix: eip712 types and hashes (#821) * refactor comments Signed-off-by: bennett <bennett@umaproject.org> * Create IERC20Auth.sol * fix tests * Comments --------- Signed-off-by: Bennett <bennett@umaproject.org> Signed-off-by: bennett <bennett@umaproject.org> Signed-off-by: nicholaspai <npai.nyc@gmail.com> Co-authored-by: bmzig <57361391+bmzig@users.noreply.github.com> Co-authored-by: Bennett <bennett@umaproject.org> Co-authored-by: Dong-Ha Kim <dongha.kim210@gmail.com> * Single AddressBook for all adapters (#919) * use a single address book instead of 1 per adapter for oft / xerc20 storage needs Signed-off-by: Ihor Farion <ihor@umaproject.org> * update comments and naming Signed-off-by: Ihor Farion <ihor@umaproject.org> * add a gas optimization suggested in OFT PR Signed-off-by: Ihor Farion <ihor@umaproject.org> * address PR comments and minor improvements Signed-off-by: Ihor Farion <ihor@umaproject.org> * fix spokePool test Signed-off-by: Ihor Farion <ihor@umaproject.org> * address PR comments Signed-off-by: Ihor Farion <ihor@umaproject.org> --------- Signed-off-by: Ihor Farion <ihor@umaproject.org> * Rename to universal adapter * Update UniversalEventInclusionProof_Adapter.sol * Add R0_SpokePool capable of receiving events via event inclusion proofs * Update R0Steel.sol * Steel light client commitments * Update R0_SpokePool.sol * read storage slots from Helios * Change Steel call to more likely interface validateCommitment * Link Steel to SP1Helios light client * Update HeliosSteelValidator.sol * rename to IHelios * Pass in Journal instead of bytes; use eventKey as replay protection key. * Add OFT adapter to L2 spoke pools * Add OFT adapter to Universal adapter * Replace OFT/HYP with CCTP * Update SP1_SpokePool.t.sol * Rebase to master * fix * Add hub pool store deploy script * Update Journal params * Update SP1_SpokePool.sol * remove verifier from SP1SpokePool * update logs * Update SP1_SpokePool.sol * Rename Sp1SpokePool to StorageProofSpokePool, remove R0 Spoke * use challenge period timestamp as nonce in storage proof adapter * Update UniversalStorageProof_SpokePool.sol * Use slotKey as data hash * Add test to spoke pool about dataHash * Allow admin root bundles in between livenesses * Add checks for admin root bundle * Add fallback function to spoke pool * move HubPoolStore to utilities folder * Remove challenge period timestamp check * Adds more robust isAdminRootBundle check, plus unit tests We know an admin root bundle is definitely being sent whenever the pending root bundle is empty or in liveness period, or the root bundle calldata is identical to the pending root bundle. In the edge case where an admin root bundle is identicl to the pending root bundle and that pending root bundle has passed liveness, we treat the admin bundle as a normal root bundle, which is pretty much harmless * add placeholder unit tests * Update IHelios.sol * Update HubPoolStore.sol * Finish universal adapter tests * Store bytes32 at relayAdminFunctionCalldata * Finish tests * Use uint256 nonce as key in HubPoolStore * rename deploy scripts * Change isAdminSender check * Add helios.headTimestamp check * Compute slot key in contract to improve UX * Update checkStorageLayout.sh * Delete UniversalStorageProof_SpokePool.json * Delete UniversalStorageProof_SpokePool.json * Rename shorter * Update utils.hre.ts * Update admin messaging * Add storage layout * fix --------- Signed-off-by: Ihor Farion <ihor@umaproject.org> Signed-off-by: Bennett <bennett@umaproject.org> Signed-off-by: bennett <bennett@umaproject.org> Signed-off-by: nicholaspai <npai.nyc@gmail.com> Co-authored-by: Ihor Farion <65650773+grasphoper@users.noreply.github.com> Co-authored-by: bmzig <57361391+bmzig@users.noreply.github.com> Co-authored-by: Bennett <bennett@umaproject.org> Co-authored-by: Dong-Ha Kim <dongha.kim210@gmail.com> * Rename test file to .t * improve: Add Security contact to contracts (#951) * improve(Universal_SpokePool): Clarify comments + variable names (#952) * improve(Universal_SpokePool): Clarify comments * improve(UniversalSpokePool): Clarify variable names * Deploy HubPoolStore and UniversalAdapter to Ethereum * Add some WIP deployments - still need official Helios contract * Bump constants * Make DEPRECATED_enabledDepositRoutes private * Update yarn.lock * Update upgradeSpokePool.ts * Update package.json * Update SpokePool.Fixture.ts * Deploy new impl * Update package.json --------- Signed-off-by: Ihor Farion <ihor@umaproject.org> Signed-off-by: Bennett <bennett@umaproject.org> Signed-off-by: bennett <bennett@umaproject.org> Signed-off-by: nicholaspai <npai.nyc@gmail.com> Co-authored-by: Ihor Farion <65650773+grasphoper@users.noreply.github.com> Co-authored-by: bmzig <57361391+bmzig@users.noreply.github.com> Co-authored-by: Bennett <bennett@umaproject.org> Co-authored-by: Dong-Ha Kim <dongha.kim210@gmail.com> Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
1 parent b03420b commit 43c9a93

File tree

61 files changed

+6996
-298
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+6996
-298
lines changed

contracts/SpokePool.sol

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ abstract contract SpokePool is
7575
RootBundle[] public rootBundles;
7676

7777
// Origin token to destination token routings can be turned on or off, which can enable or disable deposits.
78-
mapping(address => mapping(uint256 => bool)) public enabledDepositRoutes;
78+
mapping(address => mapping(uint256 => bool)) private DEPRECATED_enabledDepositRoutes;
7979

8080
// Each relay is associated with the hash of parameters that uniquely identify the original deposit and a relay
8181
// attempt for that deposit. The relay itself is just represented as the amount filled so far. The total amount to
@@ -309,21 +309,6 @@ abstract contract SpokePool is
309309
_setWithdrawalRecipient(newWithdrawalRecipient);
310310
}
311311

312-
/**
313-
* @notice Enable/Disable an origin token => destination chain ID route for deposits. Callable by admin only.
314-
* @param originToken Token that depositor can deposit to this contract.
315-
* @param destinationChainId Chain ID for where depositor wants to receive funds.
316-
* @param enabled True to enable deposits, False otherwise.
317-
*/
318-
function setEnableRoute(
319-
address originToken,
320-
uint256 destinationChainId,
321-
bool enabled
322-
) public override onlyAdmin nonReentrant {
323-
enabledDepositRoutes[originToken][destinationChainId] = enabled;
324-
emit EnabledDepositRoute(originToken, destinationChainId, enabled);
325-
}
326-
327312
/**
328313
* @notice This method stores a new root bundle in this contract that can be executed to refund relayers, fulfill
329314
* slow relays, and send funds back to the HubPool on L1. This method can only be called by the admin and is
@@ -1309,10 +1294,6 @@ abstract contract SpokePool is
13091294
// Verify depositor is a valid EVM address.
13101295
params.depositor.checkAddress();
13111296

1312-
// Check that deposit route is enabled for the input token. There are no checks required for the output token
1313-
// which is pulled from the relayer at fill time and passed through this contract atomically to the recipient.
1314-
if (!enabledDepositRoutes[params.inputToken.toAddress()][params.destinationChainId]) revert DisabledRoute();
1315-
13161297
// Require that quoteTimestamp has a maximum age so that depositors pay an LP fee based on recent HubPool usage.
13171298
// It is assumed that cross-chain timestamps are normally loosely in-sync, but clock drift can occur. If the
13181299
// SpokePool time stalls or lags significantly, it is still possible to make deposits by setting quoteTimestamp
@@ -1398,9 +1379,6 @@ abstract contract SpokePool is
13981379
uint32 quoteTimestamp,
13991380
bytes memory message
14001381
) internal {
1401-
// Check that deposit route is enabled.
1402-
if (!enabledDepositRoutes[originToken][destinationChainId]) revert DisabledRoute();
1403-
14041382
// We limit the relay fees to prevent the user spending all their funds on fees.
14051383
if (SignedMath.abs(relayerFeePct) >= 0.5e18) revert InvalidRelayerFeePct();
14061384
if (amount > MAX_TRANSFER_SIZE) revert MaxTransferSizeExceeded();

contracts/Universal_SpokePool.sol

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.0;
3+
4+
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
5+
6+
import { IHelios } from "./external/interfaces/IHelios.sol";
7+
import "./libraries/CircleCCTPAdapter.sol";
8+
9+
import "./SpokePool.sol";
10+
11+
/**
12+
* @notice Spoke pool capable of executing calldata stored in L1 state via storage proof + Helios light client.
13+
* @dev This contract has one onlyOwner function to be used as an emergency fallback to execute a message to
14+
* this SpokePool in the case where the light-client is not functioning correctly. The owner is designed to be set
15+
* to a multisig contract on this chain.
16+
* @custom:security-contact bugs@across.to
17+
*/
18+
contract Universal_SpokePool is OwnableUpgradeable, SpokePool, CircleCCTPAdapter {
19+
/// @notice The data store contract that only the HubPool can write to. This spoke pool can only act on
20+
/// data that has been written to this store.
21+
address public immutable hubPoolStore;
22+
23+
/// @notice Slot index of the HubPoolStore's relayMessageCallData mapping.
24+
uint256 public constant HUB_POOL_STORE_CALLDATA_MAPPING_SLOT_INDEX = 0;
25+
26+
/// @notice The address of the Helios L1 light client contract.
27+
address public immutable helios;
28+
29+
/// @notice The owner of this contract must wait until this amount of seconds have passed since the latest
30+
/// helios light client update to emergency execute a message. This prevents the owner from executing a message
31+
/// in the happy case where the light client is being regularly updated. Therefore, this value should be
32+
/// set to a very high value, like 24 hours.
33+
uint256 public immutable ADMIN_UPDATE_BUFFER;
34+
35+
/// @notice Stores nonces of calldata stored in HubPoolStore that gets executed via executeMessage()
36+
/// to prevent replay attacks.
37+
mapping(uint256 => bool) public executedMessages;
38+
39+
// Warning: this variable should _never_ be touched outside of this contract. It is intentionally set to be
40+
// private. Leaving it set to true can permanently disable admin calls.
41+
bool private _adminCallValidated;
42+
43+
/// @notice Event emitted after off-chain agent sees HubPoolStore's emitted StoredCallData event and calls
44+
/// executeMessage() on this contract to relay the stored calldata.
45+
event RelayedCallData(uint256 indexed nonce, address caller);
46+
47+
error NotTarget();
48+
error AdminCallAlreadySet();
49+
error SlotValueMismatch();
50+
error AdminCallNotValidated();
51+
error DelegateCallFailed();
52+
error AlreadyExecuted();
53+
error NotImplemented();
54+
error AdminUpdateTooCloseToLastHeliosUpdate();
55+
56+
// All calls that have admin privileges must be fired from within the executeMessage method that validates that
57+
// the input data was published on L1 by the HubPool. This input data is then executed on this contract.
58+
// This modifier sets the adminCallValidated variable so this condition can be checked in _requireAdminSender().
59+
modifier validateInternalCalls() {
60+
// Make sure adminCallValidated is set to True only once at beginning of the function, which prevents
61+
// the function from being re-entered.
62+
if (_adminCallValidated) {
63+
revert AdminCallAlreadySet();
64+
}
65+
66+
// This sets a variable indicating that we're now inside a validated call.
67+
// Note: this is used by other methods to ensure that this call has been validated by this method and is not
68+
// spoofed.
69+
_adminCallValidated = true;
70+
71+
_;
72+
73+
// Reset adminCallValidated to false to disallow admin calls after this method exits.
74+
_adminCallValidated = false;
75+
}
76+
77+
/// @custom:oz-upgrades-unsafe-allow constructor
78+
constructor(
79+
uint256 _adminUpdateBufferSeconds,
80+
address _helios,
81+
address _hubPoolStore,
82+
address _wrappedNativeTokenAddress,
83+
uint32 _depositQuoteTimeBuffer,
84+
uint32 _fillDeadlineBuffer,
85+
IERC20 _l2Usdc,
86+
ITokenMessenger _cctpTokenMessenger
87+
)
88+
SpokePool(_wrappedNativeTokenAddress, _depositQuoteTimeBuffer, _fillDeadlineBuffer)
89+
CircleCCTPAdapter(_l2Usdc, _cctpTokenMessenger, CircleDomainIds.Ethereum)
90+
{
91+
ADMIN_UPDATE_BUFFER = _adminUpdateBufferSeconds;
92+
helios = _helios;
93+
hubPoolStore = _hubPoolStore;
94+
}
95+
96+
function initialize(
97+
uint32 _initialDepositId,
98+
address _crossDomainAdmin,
99+
address _withdrawalRecipient
100+
) public initializer {
101+
__Ownable_init();
102+
__SpokePool_init(_initialDepositId, _crossDomainAdmin, _withdrawalRecipient);
103+
}
104+
105+
/**
106+
* @notice Relays calldata stored by the HubPool on L1 into this contract.
107+
* @dev Replay attacks are possible with this _message if this contract has the same address on another chain.
108+
* @param _messageNonce Nonce of message stored in HubPoolStore.
109+
* @param _message Message stored in HubPoolStore's relayMessageCallData mapping. Compared against raw value
110+
* in Helios light client for slot key corresponding to _messageNonce at block number.
111+
* @param _blockNumber Block number in light client we use to check slot value of slot key
112+
*/
113+
function executeMessage(
114+
uint256 _messageNonce,
115+
bytes calldata _message,
116+
uint256 _blockNumber
117+
) external validateInternalCalls {
118+
bytes32 slotKey = getSlotKey(_messageNonce);
119+
// The expected slot value corresponds to the hash of the L2 calldata and its target,
120+
// as originally stored in the HubPoolStore's relayMessageCallData mapping.
121+
bytes32 expectedSlotValue = keccak256(_message);
122+
123+
// Verify Helios light client has expected slot value.
124+
bytes32 slotValue = IHelios(helios).getStorageSlot(_blockNumber, hubPoolStore, slotKey);
125+
if (expectedSlotValue != slotValue) {
126+
revert SlotValueMismatch();
127+
}
128+
129+
// Validate state is intended to be sent to this contract. The target could have been set to the zero address
130+
// which is used by the StorageProof_Adapter to denote messages that can be sent to any target.
131+
(address target, bytes memory message) = abi.decode(_message, (address, bytes));
132+
if (target != address(0) && target != address(this)) {
133+
revert NotTarget();
134+
}
135+
136+
// Prevent replay attacks. The slot key should be a hash of the nonce associated with this calldata in the
137+
// HubPoolStore, which maps the nonce to the _value.
138+
if (executedMessages[_messageNonce]) {
139+
revert AlreadyExecuted();
140+
}
141+
executedMessages[_messageNonce] = true;
142+
emit RelayedCallData(_messageNonce, msg.sender);
143+
144+
_executeCalldata(message);
145+
}
146+
147+
/**
148+
* @notice This function is only callable by the owner and is used as an emergency fallback to execute
149+
* calldata to this SpokePool in the case where the light-client is not able to be updated.
150+
* @dev This function will revert if the last Helios update was less than ADMIN_UPDATE_BUFFER seconds ago.
151+
* @param _message The calldata to execute on this contract.
152+
*/
153+
function adminExecuteMessage(bytes memory _message) external onlyOwner validateInternalCalls {
154+
uint256 heliosHeadTimestamp = IHelios(helios).headTimestamp();
155+
if (heliosHeadTimestamp > block.timestamp || block.timestamp - heliosHeadTimestamp < ADMIN_UPDATE_BUFFER) {
156+
revert AdminUpdateTooCloseToLastHeliosUpdate();
157+
}
158+
_executeCalldata(_message);
159+
}
160+
161+
/**
162+
* @notice Computes the EVM storage slot key for a message nonce using the formula keccak256(key, slotIndex)
163+
* to find the storage slot for a value within a mapping(key=>value) at a slot index. We already know the
164+
* slot index of the relayMessageCallData mapping in the HubPoolStore.
165+
* @param _nonce The nonce associated with the message.
166+
* @return The computed storage slot key.
167+
*/
168+
function getSlotKey(uint256 _nonce) public pure returns (bytes32) {
169+
return keccak256(abi.encode(_nonce, HUB_POOL_STORE_CALLDATA_MAPPING_SLOT_INDEX));
170+
}
171+
172+
function _executeCalldata(bytes memory _calldata) internal {
173+
/// @custom:oz-upgrades-unsafe-allow delegatecall
174+
(bool success, ) = address(this).delegatecall(_calldata);
175+
if (!success) {
176+
revert DelegateCallFailed();
177+
}
178+
}
179+
180+
function _bridgeTokensToHubPool(uint256 amountToReturn, address l2TokenAddress) internal override {
181+
if (_isCCTPEnabled() && l2TokenAddress == address(usdcToken)) {
182+
_transferUsdc(withdrawalRecipient, amountToReturn);
183+
} else {
184+
revert NotImplemented();
185+
}
186+
}
187+
188+
// Check that the admin call is only triggered by a executeMessage() call.
189+
function _requireAdminSender() internal view override {
190+
if (!_adminCallValidated) {
191+
revert AdminCallNotValidated();
192+
}
193+
}
194+
}

contracts/chain-adapters/Solana_Adapter.sol

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ contract Solana_Adapter is AdapterInterface, CircleCCTPAdapter {
4141
// Solana spoke pool address, mapped to its EVM address representation.
4242
address public immutable SOLANA_SPOKE_POOL_ADDRESS;
4343

44-
// USDC mint address on Solana, decoded from Base58 to bytes32.
45-
bytes32 public immutable SOLANA_USDC_BYTES32;
46-
4744
// USDC mint address on Solana, mapped to its EVM address representation.
4845
address public immutable SOLANA_USDC_ADDRESS;
4946

@@ -56,8 +53,6 @@ contract Solana_Adapter is AdapterInterface, CircleCCTPAdapter {
5653

5754
// Custom errors for relayMessage validation.
5855
error InvalidRelayMessageTarget(address target);
59-
error InvalidOriginToken(address originToken);
60-
error InvalidDestinationChainId(uint256 destinationChainId);
6156

6257
// Custom errors for relayTokens validation.
6358
error InvalidL1Token(address l1Token);
@@ -95,7 +90,6 @@ contract Solana_Adapter is AdapterInterface, CircleCCTPAdapter {
9590
SOLANA_SPOKE_POOL_BYTES32 = solanaSpokePool;
9691
SOLANA_SPOKE_POOL_ADDRESS = solanaSpokePool.toAddressUnchecked();
9792

98-
SOLANA_USDC_BYTES32 = solanaUsdc;
9993
SOLANA_USDC_ADDRESS = solanaUsdc.toAddressUnchecked();
10094

10195
SOLANA_SPOKE_POOL_USDC_VAULT = solanaSpokePoolUsdcVault;
@@ -111,17 +105,7 @@ contract Solana_Adapter is AdapterInterface, CircleCCTPAdapter {
111105
if (target != SOLANA_SPOKE_POOL_ADDRESS) {
112106
revert InvalidRelayMessageTarget(target);
113107
}
114-
115-
bytes4 selector = bytes4(message[:4]);
116-
if (selector == SpokePoolInterface.setEnableRoute.selector) {
117-
cctpMessageTransmitter.sendMessage(
118-
CircleDomainIds.Solana,
119-
SOLANA_SPOKE_POOL_BYTES32,
120-
_translateSetEnableRoute(message)
121-
);
122-
} else {
123-
cctpMessageTransmitter.sendMessage(CircleDomainIds.Solana, SOLANA_SPOKE_POOL_BYTES32, message);
124-
}
108+
cctpMessageTransmitter.sendMessage(CircleDomainIds.Solana, SOLANA_SPOKE_POOL_BYTES32, message);
125109

126110
// TODO: consider if we need also to emit the translated message.
127111
emit MessageRelayed(target, message);
@@ -159,32 +143,4 @@ contract Solana_Adapter is AdapterInterface, CircleCCTPAdapter {
159143
// TODO: consider if we need also to emit the translated addresses.
160144
emit TokensRelayed(l1Token, l2Token, amount, to);
161145
}
162-
163-
/**
164-
* @notice Translates a message to enable/disable a route on Solana spoke pool.
165-
* @param message Message to translate, expecting setEnableRoute(address,uint256,bool).
166-
* @return Translated message, using setEnableRoute(bytes32,uint64,bool).
167-
*/
168-
function _translateSetEnableRoute(bytes calldata message) internal view returns (bytes memory) {
169-
(address originToken, uint256 destinationChainId, bool enable) = abi.decode(
170-
message[4:],
171-
(address, uint256, bool)
172-
);
173-
174-
if (originToken != SOLANA_USDC_ADDRESS) {
175-
revert InvalidOriginToken(originToken);
176-
}
177-
178-
if (destinationChainId > type(uint64).max) {
179-
revert InvalidDestinationChainId(destinationChainId);
180-
}
181-
182-
return
183-
abi.encodeWithSignature(
184-
"setEnableRoute(bytes32,uint64,bool)",
185-
SOLANA_USDC_BYTES32,
186-
uint64(destinationChainId),
187-
enable
188-
);
189-
}
190146
}

0 commit comments

Comments
 (0)