├── .editorconfig ├── .gas-snapshot ├── .gitattributes ├── .github ├── pull_request_template.md └── workflows │ └── test.yml ├── .gitignore ├── .gitmodules ├── .solhint.json ├── .solhintignore ├── .vscode └── settings.json ├── LICENSE.md ├── Makefile ├── README.md ├── codecov.yml ├── contracts ├── BaseEscrow.sol ├── BaseEscrowFactory.sol ├── Escrow.sol ├── EscrowDst.sol ├── EscrowFactory.sol ├── EscrowFactoryContext.sol ├── EscrowSrc.sol ├── MerkleStorageInvalidator.sol ├── interfaces │ ├── IBaseEscrow.sol │ ├── IEscrow.sol │ ├── IEscrowDst.sol │ ├── IEscrowFactory.sol │ ├── IEscrowSrc.sol │ ├── IMerkleStorageInvalidator.sol │ └── IResolverExample.sol ├── libraries │ ├── ImmutablesLib.sol │ ├── ProxyHashLib.sol │ └── TimelocksLib.sol ├── mocks │ ├── ERC20True.sol │ ├── NoReceiveCaller.sol │ └── ResolverExample.sol └── zkSync │ ├── EscrowDstZkSync.sol │ ├── EscrowFactoryZkSync.sol │ ├── EscrowSrcZkSync.sol │ ├── EscrowZkSync.sol │ ├── MinimalProxyZkSync.sol │ └── ZkSyncLib.sol ├── deployments ├── arbitrum │ ├── ERC20True.json │ └── EscrowFactory.json ├── aurora │ └── ERC20True.json ├── avalanche │ ├── ERC20True.json │ └── EscrowFactory.json ├── base │ ├── ERC20True.json │ └── EscrowFactory.json ├── bsc │ ├── ERC20True.json │ └── EscrowFactory.json ├── fantom │ └── ERC20True.json ├── gnosis │ ├── ERC20True.json │ └── EscrowFactory.json ├── klaytn │ └── ERC20True.json ├── linea │ ├── .chainId │ ├── ERC20True.json │ └── EscrowFactory.json ├── mainnet │ ├── ERC20True.json │ └── EscrowFactory.json ├── optimism │ ├── ERC20True.json │ └── EscrowFactory.json ├── polygon │ ├── ERC20True.json │ └── EscrowFactory.json ├── sonic │ └── EscrowFactory.json ├── unichain │ ├── ERC20True.json │ └── EscrowFactory.json └── zksync │ ├── ERC20True.json │ └── EscrowFactoryZkSync.json ├── documentation ├── .gitignore ├── book.css ├── book.toml ├── solidity.min.js └── src │ ├── README.md │ ├── SUMMARY.md │ └── contracts │ ├── Escrow.sol │ └── abstract.Escrow.md │ ├── EscrowDst.sol │ └── contract.EscrowDst.md │ ├── EscrowFactory.sol │ └── contract.EscrowFactory.md │ ├── EscrowSrc.sol │ └── contract.EscrowSrc.md │ ├── README.md │ ├── interfaces │ ├── IEscrow.sol │ │ └── interface.IEscrow.md │ ├── IEscrowDst.sol │ │ └── interface.IEscrowDst.md │ ├── IEscrowFactory.sol │ │ └── interface.IEscrowFactory.md │ ├── IEscrowSrc.sol │ │ └── interface.IEscrowSrc.md │ └── README.md │ ├── libraries │ ├── Clones.sol │ │ └── library.Clones.md │ ├── ImmutablesLib.sol │ │ └── library.ImmutablesLib.md │ ├── PackedAddressesLib.sol │ │ ├── library.PackedAddressesLib.md │ │ └── struct.PackedAddresses.md │ ├── README.md │ └── TimelocksLib.sol │ │ ├── library.TimelocksLib.md │ │ └── type.Timelocks.md │ └── mocks │ ├── ERC20True.sol │ └── contract.ERC20True.md │ └── README.md ├── examples ├── README.md ├── config │ └── config.json ├── script │ ├── CreateOrder.s.sol │ └── utils │ │ ├── ConfigLib.sol │ │ ├── DevOpsTools.sol │ │ ├── EscrowDevOpsTools.sol │ │ └── StringUtils.sol └── scripts │ └── create_order.sh ├── foundry.lock ├── foundry.toml ├── hooks └── pre-commit ├── package.json ├── release.md ├── remappings.txt ├── script ├── DeployEscrowFactory.s.sol ├── DeployEscrowFactoryZkSync.s.sol └── txn_example │ ├── CancelDst.s.sol │ ├── CancelSrc.s.sol │ ├── DeployEscrowDst.s.sol │ ├── DeployEscrowSrc.s.sol │ ├── WithdrawDst.s.sol │ └── WithdrawSrc.s.sol ├── scripts ├── coverage.sh └── deploy.sh ├── test ├── integration │ ├── EscrowFactory.t.sol │ ├── MerkleStorageInvalidator.t.sol │ └── ResolverMock.t.sol ├── libraries │ ├── FeeCalcLib.t.sol │ └── TimelocksLib.t.sol ├── unit │ ├── Escrow.t.sol │ ├── EscrowCancel.t.sol │ ├── EscrowFactory.t.sol │ └── MerkleStorageInvalidator.t.sol └── utils │ ├── BaseSetup.sol │ ├── Utils.sol │ ├── libraries │ ├── CrossChainTestLib.sol │ ├── FeeCalcLib.sol │ └── TimelocksSettersLib.sol │ └── mocks │ ├── CustomPostInteraction.sol │ ├── NoReceive.sol │ ├── ResolverReentrancy.sol │ └── TimelocksLibMock.sol ├── timelocks.png └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.{json,yml,xml,yaml}] 12 | indent_size = 2 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.gas-snapshot: -------------------------------------------------------------------------------- 1 | EscrowCancelTest:test_CancelDst() (gas: 123967) 2 | EscrowCancelTest:test_CancelDstDifferentTarget() (gas: 151802) 3 | EscrowCancelTest:test_CancelDstWithNativeToken() (gas: 101063) 4 | EscrowCancelTest:test_CancelPublicSrc() (gas: 182952) 5 | EscrowCancelTest:test_CancelResolverSrc() (gas: 180805) 6 | EscrowCancelTest:test_CancelResolverSrcReceiver() (gas: 202327) 7 | EscrowCancelTest:test_NoAnyoneCancelDuringResolverCancelSrc() (gas: 174728) 8 | EscrowCancelTest:test_NoCallsWithInvalidImmutables() (gas: 303404) 9 | EscrowCancelTest:test_NoCancelByAnyoneDst() (gas: 128060) 10 | EscrowCancelTest:test_NoCancelDuringWithdrawalDst() (gas: 128407) 11 | EscrowCancelTest:test_NoCancelDuringWithdrawalSrc() (gas: 175025) 12 | EscrowCancelTest:test_NoFailedNativeTokenTransferCancelSrc() (gas: 230304) 13 | EscrowCancelTest:test_NoPublicCallsByAnyone() (gas: 301824) 14 | EscrowCancelTest:test_NoPublicCancelDuringPrivateCancellationSrc() (gas: 179745) 15 | EscrowFactoryTest:test_MultipleFillsInvalidKey() (gas: 482426) 16 | EscrowFactoryTest:test_MultipleFillsInvalidSecretsAmount() (gas: 482170) 17 | EscrowFactoryTest:test_NoDeploymentForNotResolver() (gas: 156992) 18 | EscrowFactoryTest:test_NoInsufficientBalanceDeploymentForMaker() (gas: 139780) 19 | EscrowFactoryTest:test_NoInsufficientBalanceDeploymentForTaker() (gas: 32999) 20 | EscrowFactoryTest:test_NoInsufficientBalanceNativeDeploymentForMaker() (gas: 132654) 21 | EscrowFactoryTest:test_NoInsufficientBalanceNativeDeploymentForTaker() (gas: 33287) 22 | EscrowFactoryTest:test_NoRescueFundsERC20NotOwner() (gas: 60457) 23 | EscrowFactoryTest:test_NoRescueFundsNativeNotOwner() (gas: 24875) 24 | EscrowFactoryTest:test_NoUnsafeDeploymentForTaker() (gas: 40817) 25 | EscrowFactoryTest:test_RescueFundsERC20() (gas: 67574) 26 | EscrowFactoryTest:test_RescueFundsNative() (gas: 31067) 27 | EscrowTest:test_NoFailedNativeTokenTransferWithdrawalDst() (gas: 263622) 28 | EscrowTest:test_NoFailedNativeTokenTransferWithdrawalDstNative() (gas: 127238) 29 | EscrowTest:test_NoFailedNativeTokenTransferWithdrawalSrc() (gas: 361747) 30 | EscrowTest:test_NoPublicWithdrawOutsideOfAllowedPeriodDst() (gas: 145135) 31 | EscrowTest:test_NoPublicWithdrawalOutsideOfAllowedPeriodSrc() (gas: 191612) 32 | EscrowTest:test_NoRescueFundsByAnyoneDst() (gas: 251799) 33 | EscrowTest:test_NoRescueFundsByAnyoneSrc() (gas: 223434) 34 | EscrowTest:test_NoRescueFundsEarlierDst() (gas: 251565) 35 | EscrowTest:test_NoRescueFundsEarlierSrc() (gas: 223562) 36 | EscrowTest:test_NoWithdrawalByAnyoneSrc() (gas: 172388) 37 | EscrowTest:test_NoWithdrawalByNonResolverDst() (gas: 128322) 38 | EscrowTest:test_NoWithdrawalOutsideOfAllowedPeriodDst() (gas: 133787) 39 | EscrowTest:test_NoWithdrawalOutsideOfAllowedPeriodSrc() (gas: 181409) 40 | EscrowTest:test_NoWithdrawalWithWrongSecretDst() (gas: 129738) 41 | EscrowTest:test_NoWithdrawalWithWrongSecretSrc() (gas: 176239) 42 | EscrowTest:test_PublicWithdrawSrc() (gas: 199756) 43 | EscrowTest:test_RescueFundsDst() (gas: 231195) 44 | EscrowTest:test_RescueFundsDstNative() (gas: 262234) 45 | EscrowTest:test_RescueFundsSrc() (gas: 210031) 46 | EscrowTest:test_RescueFundsSrcNative() (gas: 212670) 47 | EscrowTest:test_WithdrawByAnyoneDst() (gas: 220204) 48 | EscrowTest:test_WithdrawByResolverDst() (gas: 213095) 49 | EscrowTest:test_WithdrawByResolverDstNative() (gas: 136994) 50 | EscrowTest:test_WithdrawByResolverPublicDst() (gas: 215234) 51 | EscrowTest:test_WithdrawSrc() (gas: 199065) 52 | EscrowTest:test_WithdrawSrcTo() (gas: 203938) 53 | FeeCalcLibTest:test_getFeeAmounts() (gas: 29011) 54 | IntegrationEscrowFactoryTest:test_DeployCloneForMakerNonWhitelistedResolverInt() (gas: 433731) 55 | IntegrationEscrowFactoryTest:test_NoInsufficientBalanceDeploymentForMakerInt() (gas: 355372) 56 | IntegrationEscrowFactoryTest:test_NoResolverReentrancy() (gas: 2354804) 57 | IntegrationResolverMockTest:test_MockCancelDst() (gas: 168508) 58 | IntegrationResolverMockTest:test_MockCancelSrc() (gas: 372184) 59 | IntegrationResolverMockTest:test_MockDeployDst() (gas: 162086) 60 | IntegrationResolverMockTest:test_MockDeploySrc() (gas: 381205) 61 | IntegrationResolverMockTest:test_MockPublicCancelSrc() (gas: 416206) 62 | IntegrationResolverMockTest:test_MockPublicWithdrawDst() (gas: 247094) 63 | IntegrationResolverMockTest:test_MockRescueFundsDst() (gas: 174407) 64 | IntegrationResolverMockTest:test_MockRescueFundsSrc() (gas: 401672) 65 | IntegrationResolverMockTest:test_MockWithdrawDst() (gas: 259529) 66 | IntegrationResolverMockTest:test_MockWithdrawToSrc() (gas: 372969) 67 | MerkleStorageInvalidatorIntTest:test_MultipleFillsFillAllExtra() (gas: 946351) 68 | MerkleStorageInvalidatorIntTest:test_MultipleFillsFillAllFromLast() (gas: 945014) 69 | MerkleStorageInvalidatorIntTest:test_MultipleFillsFillAllTwoFills() (gas: 944822) 70 | MerkleStorageInvalidatorIntTest:test_MultipleFillsFillFirst() (gas: 712311) 71 | MerkleStorageInvalidatorIntTest:test_MultipleFillsFillFirstTwoFills() (gas: 945641) 72 | MerkleStorageInvalidatorIntTest:test_MultipleFillsFillLast() (gas: 711905) 73 | MerkleStorageInvalidatorIntTest:test_MultipleFillsNoDeploymentWithoutValidation() (gas: 312192) 74 | MerkleStorageInvalidatorIntTest:test_MultipleFillsNoReuseOfSecrets() (gas: 1088938) 75 | MerkleStorageInvalidatorIntTest:test_MultipleFillsNoSecondDeploymentWithTheSameIndex() (gas: 804450) 76 | MerkleStorageInvalidatorIntTest:test_MultipleFillsOddDivision() (gas: 449559) 77 | MerkleStorageInvalidatorIntTest:test_MultipleFillsOneFill() (gas: 712351) 78 | MerkleStorageInvalidatorIntTest:test_MultipleFillsTwoFills() (gas: 943837) 79 | MerkleStorageInvalidatorTest:test_ShortenedProofIsNotValid() (gas: 237658) 80 | TimelocksLibTest:test_NoTimelocksOverflow() (gas: 264056) 81 | TimelocksLibTest:test_getStartTimestamps() (gas: 19881) 82 | TimelocksLibTest:test_setDeployedAt() (gas: 8595) -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | #### Static Code Analysis (readability, compactness): 2 | 3 | #### Dynamic Code Analysis (external APIs, interaction flows): 4 | 5 | #### Efficiency (gas costs, computational complexity, memory requirements): 6 | 7 | #### Opinion, trade-offs and other thoughts (optional): 8 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | jobs: 8 | lint: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-node@v4 13 | with: 14 | node-version: 20 15 | cache: 'yarn' 16 | - run: yarn 17 | - run: yarn lint 18 | 19 | snapshot: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | submodules: recursive 25 | - name: Install Foundry 26 | uses: foundry-rs/foundry-toolchain@v1 27 | - name: Check snapshot 28 | run: FOUNDRY_PROFILE=default forge snapshot --check --no-match-test "testFuzz_*" 29 | 30 | test: 31 | runs-on: ubuntu-latest 32 | steps: 33 | - uses: actions/checkout@v4 34 | with: 35 | submodules: recursive 36 | - name: Install Foundry 37 | uses: foundry-rs/foundry-toolchain@v1 38 | - name: Run tests 39 | run: FOUNDRY_PROFILE=default forge test -vvv --gas-report 40 | 41 | test-zksync: 42 | runs-on: ubuntu-latest 43 | steps: 44 | - uses: actions/checkout@v4 45 | with: 46 | submodules: recursive 47 | - uses: actions/checkout@v4 48 | with: 49 | repository: matter-labs/foundry-zksync 50 | ref: 'main' 51 | path: 'foundry-zksync' 52 | - name: Install Foundry for zksync 53 | run: cd foundry-zksync/foundryup-zksync && ../install-foundry-zksync 54 | - name: Run tests 55 | run: FOUNDRY_PROFILE=zksync forge test -vvv --zksync --force 56 | 57 | coverage: 58 | runs-on: ubuntu-latest 59 | steps: 60 | - uses: actions/checkout@v4 61 | with: 62 | submodules: recursive 63 | - name: Install Foundry 64 | uses: foundry-rs/foundry-toolchain@v1 65 | - name: Run coverage 66 | run: yarn coverage 67 | - uses: codecov/codecov-action@v4 68 | with: 69 | token: ${{ secrets.CODECOV_TOKEN }} 70 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | artifacts 2 | cache 3 | node_modules 4 | coverage 5 | coverage.json 6 | build 7 | .coverage_contracts 8 | .coverage_artifacts 9 | .idea 10 | .env 11 | .env.deployment 12 | .DS_Store 13 | Makefile 14 | 15 | # foundry 16 | cache_forge 17 | out 18 | broadcast 19 | 20 | # zkSync 21 | zkout 22 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | [submodule "lib/solidity-utils"] 5 | path = lib/solidity-utils 6 | url = https://github.com/1inch/solidity-utils 7 | [submodule "lib/openzeppelin-contracts"] 8 | path = lib/openzeppelin-contracts 9 | url = https://github.com/OpenZeppelin/openzeppelin-contracts 10 | [submodule "lib/limit-order-protocol"] 11 | path = lib/limit-order-protocol 12 | url = https://github.com/1inch/limit-order-protocol 13 | [submodule "lib/limit-order-settlement"] 14 | path = lib/limit-order-settlement 15 | url = https://github.com/1inch/limit-order-settlement 16 | [submodule "lib/murky"] 17 | path = lib/murky 18 | url = https://github.com/dmfxyz/murky 19 | -------------------------------------------------------------------------------- /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:recommended", 3 | "rules": { 4 | "compiler-version": ["error", "^0.8.0"], 5 | "private-vars-leading-underscore": "error", 6 | "func-visibility": ["error", { "ignoreConstructors": true }], 7 | "max-line-length": ["error", 140], 8 | "no-inline-assembly": ["off"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.solhintignore: -------------------------------------------------------------------------------- 1 | lib 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "solidity.compileUsingRemoteVersion": "0.8.23" 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | © 2023, 1inch. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | -include .env 2 | 3 | CURRENT_DIR := $(shell pwd) 4 | 5 | update:; forge update 6 | 7 | build:; forge build 8 | 9 | build-zk :; FOUNDRY_PROFILE=zksync forge build --zksync -vvvvv --zk-compile=true --build-info --via-ir 10 | 11 | tests :; forge test -vvv --gas-report 12 | 13 | tests-zk :; FOUNDRY_PROFILE=zksync forge test -vvv --zksync --force 14 | 15 | coverage :; mkdir -p coverage && FOUNDRY_PROFILE=default forge coverage --report lcov --ir-minimum --report-file coverage/lcov.info 16 | 17 | coverage-zk :; mkdir -p coverage && RUST_BACKTRACE=full FOUNDRY_PROFILE=zksync forge coverage --zksync --report lcov --ir-minimum --via-ir --report-file coverage/lcov.info 18 | 19 | snapshot :; forge snapshot --no-match-test "testFuzz_*" 20 | 21 | snapshot-check :; forge snapshot --check --no-match-test "testFuzz_*" 22 | 23 | format :; forge fmt 24 | 25 | clean :; forge clean 26 | 27 | lint :; yarn lint 28 | 29 | anvil :; anvil --fork-url $(FORK_URL) --steps-tracing --chain-id $(CHAIN_ID) --host 127.0.0.1 --port 8545 -vvvvv 30 | 31 | withdraw-src :; forge script $(CURRENT_DIR)/script/txn_example/WithdrawSrc.s.sol:WithdrawSrc --rpc-url $(RPC_URL) --broadcast --slow 32 | 33 | withdraw-dst :; forge script $(CURRENT_DIR)/script/txn_example/WithdrawDst.s.sol:WithdrawDst --rpc-url $(RPC_URL) --broadcast --slow 34 | 35 | deploy-escrow-dst :; forge script $(CURRENT_DIR)/script/txn_example/DeployEscrowDst.s.sol:DeployEscrowDst --rpc-url $(RPC_URL) --broadcast --slow 36 | 37 | deploy-escrow-src :; forge script $(CURRENT_DIR)/script/txn_example/DeployEscrowSrc.s.sol:DeployEscrowSrc --rpc-url $(RPC_URL) --broadcast --slow 38 | 39 | # deploy-resolver-example :; forge script $(CURRENT_DIR)/script/DeployResolverExample.s.sol:DeployResolverExample --rpc-url $(RPC_URL) --broadcast --interactives 1 --slow 40 | 41 | deploy-escrow-factory :; forge script $(CURRENT_DIR)/script/DeployEscrowFactory.s.sol:DeployEscrowFactory --rpc-url $(RPC_URL) --broadcast --interactives 1 --slow 42 | 43 | cancel-src :; forge script $(CURRENT_DIR)/script/txn_example/CancelSrc.s.sol:CancelSrc --rpc-url $(RPC_URL) --broadcast --slow 44 | 45 | cancel-dst :; forge script $(CURRENT_DIR)/script/txn_example/CancelDst.s.sol:CancelDst --rpc-url $(RPC_URL) --broadcast --slow 46 | 47 | balance :; cast balance $(ADDRESS) --rpc-url $(RPC_URL) | cast from-wei 48 | 49 | balance-erc20 :; cast call $(TOKEN) "balanceOf(address)(uint256)" $(ADDRESS) --rpc-url $(RPC_URL) | cast from-wei 50 | 51 | resolver-balance :; $(MAKE) ADDRESS=$(RESOLVER) balance 52 | 53 | resolver-balance-erc20 :; $(MAKE) ADDRESS=$(RESOLVER) TOKEN=$(TOKEN_SRC) balance-erc20 54 | 55 | deployer-balance :; $(MAKE) ADDRESS=$(DEPLOYER_ADDRESS) balance 56 | 57 | deployer-balance-erc20 :; $(MAKE) ADDRESS=$(DEPLOYER_ADDRESS) TOKEN=$(TOKEN_SRC) balance-erc20 58 | 59 | protocol-balance :; $(MAKE) ADDRESS=$(PROTOCOL_FEE_RECIPIENT) balance 60 | 61 | protocol-balance-erc20 :; $(MAKE) ADDRESS=$(PROTOCOL_FEE_RECIPIENT) TOKEN=$(TOKEN_SRC) balance-erc20 62 | 63 | integrator-balance :; $(MAKE) ADDRESS=$(INTEGRATOR_FEE_RECIPIENT) balance 64 | 65 | integrator-balance-erc20 :; $(MAKE) ADDRESS=$(INTEGRATOR_FEE_RECIPIENT) TOKEN=$(TOKEN_SRC) balance-erc20 66 | 67 | escrow-src-balance :; $(MAKE) ADDRESS=$(ESCROW_SRC) balance 68 | 69 | escrow-src-balance-erc20 :; $(MAKE) ADDRESS=$(ESCROW_SRC) TOKEN=$(TOKEN_SRC) balance-erc20 70 | 71 | escrow-dst-balance :; $(MAKE) ADDRESS=$(ESCROW_DST) balance 72 | 73 | escrow-dst-balance-erc20 :; $(MAKE) ADDRESS=$(ESCROW_DST) TOKEN=$(TOKEN_SRC) balance-erc20 74 | 75 | help: 76 | @echo "Available targets:" 77 | @grep -E '^[a-zA-Z0-9_.-]+ *:.*?;' $(CURRENT_DIR)/Makefile | awk -F: '{print " " $$1}' 78 | 79 | .PHONY: update build build-zk tests tests-zk coverage snapshot snapshot-check format clean anvil withdraw-src withdraw-dst deploy-escrow-dst deploy-escrow-src deploy-escrow-factory cancel-src cancel-dst balance balance-erc20 resolver-balance resolver-balance-erc20 deployer-balance deployer-balance-erc20 protocol-balance protocol-balance-erc20 integrator-balance integrator-balance-erc20 escrow-src-balance escrow-src-balance-erc20 escrow-dst-balance escrow-dst-balance-erc20 -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "test" 3 | - "contracts/mocks" 4 | - "script" 5 | -------------------------------------------------------------------------------- /contracts/BaseEscrow.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; 6 | import { AddressLib, Address } from "solidity-utils/contracts/libraries/AddressLib.sol"; 7 | import { SafeERC20 } from "solidity-utils/contracts/libraries/SafeERC20.sol"; 8 | 9 | import { ImmutablesLib } from "./libraries/ImmutablesLib.sol"; 10 | import { Timelocks, TimelocksLib } from "./libraries/TimelocksLib.sol"; 11 | 12 | import { IBaseEscrow } from "./interfaces/IBaseEscrow.sol"; 13 | 14 | /** 15 | * @title Base abstract Escrow contract for cross-chain atomic swap. 16 | * @dev {IBaseEscrow-withdraw}, {IBaseEscrow-cancel} and _validateImmutables functions must be implemented in the derived contracts. 17 | * @custom:security-contact security@1inch.io 18 | */ 19 | abstract contract BaseEscrow is IBaseEscrow { 20 | using AddressLib for Address; 21 | using SafeERC20 for IERC20; 22 | using TimelocksLib for Timelocks; 23 | using ImmutablesLib for Immutables; 24 | 25 | // Token that is used to access public withdraw or cancel functions. 26 | IERC20 private immutable _ACCESS_TOKEN; 27 | 28 | /// @notice See {IBaseEscrow-RESCUE_DELAY}. 29 | uint256 public immutable RESCUE_DELAY; 30 | /// @notice See {IBaseEscrow-FACTORY}. 31 | address public immutable FACTORY = msg.sender; 32 | 33 | constructor(uint32 rescueDelay, IERC20 accessToken) { 34 | RESCUE_DELAY = rescueDelay; 35 | _ACCESS_TOKEN = accessToken; 36 | } 37 | 38 | modifier onlyCaller(address expected) { 39 | if (msg.sender != expected) revert InvalidCaller(); 40 | _; 41 | } 42 | 43 | modifier onlyValidImmutables(bytes32 immutablesHash) virtual { 44 | _validateImmutables(immutablesHash); 45 | _; 46 | } 47 | 48 | modifier onlyValidSecret(bytes32 secret, bytes32 hashlock) { 49 | if (_keccakBytes32(secret) != hashlock) revert InvalidSecret(); 50 | _; 51 | } 52 | 53 | modifier onlyAfter(uint256 start) { 54 | if (block.timestamp < start) revert InvalidTime(); 55 | _; 56 | } 57 | 58 | modifier onlyBefore(uint256 stop) { 59 | if (block.timestamp >= stop) revert InvalidTime(); 60 | _; 61 | } 62 | 63 | modifier onlyAccessTokenHolder() { 64 | if (_ACCESS_TOKEN.balanceOf(msg.sender) == 0) revert InvalidCaller(); 65 | _; 66 | } 67 | 68 | /** 69 | * @notice See {IBaseEscrow-rescueFunds}. 70 | */ 71 | function rescueFunds(address token, uint256 amount, Immutables calldata immutables) 72 | external 73 | onlyCaller(immutables.taker.get()) 74 | onlyValidImmutables(immutables.hash()) 75 | onlyAfter(immutables.timelocks.rescueStart(RESCUE_DELAY)) 76 | { 77 | _uniTransfer(token, msg.sender, amount); 78 | emit FundsRescued(token, amount); 79 | } 80 | 81 | /** 82 | * @dev Transfers ERC20 or native tokens to the recipient. 83 | */ 84 | function _uniTransfer(address token, address to, uint256 amount) internal { 85 | if (token == address(0)) { 86 | _ethTransfer(to, amount); 87 | } else { 88 | IERC20(token).safeTransfer(to, amount); 89 | } 90 | } 91 | 92 | /** 93 | * @dev Transfers native tokens to the recipient. 94 | */ 95 | function _ethTransfer(address to, uint256 amount) internal { 96 | (bool success,) = to.call{ value: amount }(""); 97 | if (!success) revert NativeTokenSendingFailure(); 98 | } 99 | 100 | /** 101 | * @dev Should verify that the computed escrow address matches the address of this contract. 102 | */ 103 | function _validateImmutables(bytes32 immutablesHash) internal view virtual; 104 | 105 | /** 106 | * @dev Computes the Keccak-256 hash of the secret. 107 | * @param secret The secret that unlocks the escrow. 108 | * @return ret The computed hash. 109 | */ 110 | function _keccakBytes32(bytes32 secret) private pure returns (bytes32 ret) { 111 | assembly ("memory-safe") { 112 | mstore(0, secret) 113 | ret := keccak256(0, 0x20) 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /contracts/Escrow.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { Create2 } from "openzeppelin-contracts/contracts/utils/Create2.sol"; 6 | 7 | import { ProxyHashLib } from "./libraries/ProxyHashLib.sol"; 8 | 9 | import { IEscrow } from "./interfaces/IEscrow.sol"; 10 | import { BaseEscrow } from "./BaseEscrow.sol"; 11 | 12 | /** 13 | * @title Abstract Escrow contract for cross-chain atomic swap. 14 | * @dev {IBaseEscrow-withdraw} and {IBaseEscrow-cancel} functions must be implemented in the derived contracts. 15 | * @custom:security-contact security@1inch.io 16 | */ 17 | abstract contract Escrow is BaseEscrow, IEscrow { 18 | /// @notice See {IEscrow-PROXY_BYTECODE_HASH}. 19 | bytes32 public immutable PROXY_BYTECODE_HASH = ProxyHashLib.computeProxyBytecodeHash(address(this)); 20 | 21 | /** 22 | * @dev Verifies that the computed escrow address matches the address of this contract. 23 | */ 24 | function _validateImmutables(bytes32 immutablesHash) internal view virtual override { 25 | if (Create2.computeAddress(immutablesHash, PROXY_BYTECODE_HASH, FACTORY) != address(this)) { 26 | revert InvalidImmutables(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contracts/EscrowDst.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; 6 | import { SafeERC20 } from "solidity-utils/contracts/libraries/SafeERC20.sol"; 7 | import { AddressLib, Address } from "solidity-utils/contracts/libraries/AddressLib.sol"; 8 | 9 | import { Timelocks, TimelocksLib } from "./libraries/TimelocksLib.sol"; 10 | import { ImmutablesLib } from "./libraries/ImmutablesLib.sol"; 11 | 12 | import { IEscrowDst } from "./interfaces/IEscrowDst.sol"; 13 | import { BaseEscrow } from "./BaseEscrow.sol"; 14 | import { Escrow } from "./Escrow.sol"; 15 | 16 | /** 17 | * @title Destination Escrow contract for cross-chain atomic swap. 18 | * @notice Contract to initially lock funds and then unlock them with verification of the secret presented. 19 | * @dev Funds are locked in at the time of contract deployment. For this taker calls the `EscrowFactory.createDstEscrow` function. 20 | * To perform any action, the caller must provide the same Immutables values used to deploy the clone contract. 21 | * @custom:security-contact security@1inch.io 22 | */ 23 | contract EscrowDst is Escrow, IEscrowDst { 24 | using SafeERC20 for IERC20; 25 | using AddressLib for Address; 26 | using TimelocksLib for Timelocks; 27 | using ImmutablesLib for Immutables; 28 | 29 | constructor(uint32 rescueDelay, IERC20 accessToken) BaseEscrow(rescueDelay, accessToken) {} 30 | 31 | /** 32 | * @notice See {IBaseEscrow-withdraw}. 33 | * @dev The function works on the time intervals highlighted with capital letters: 34 | * ---- contract deployed --/-- finality --/-- PRIVATE WITHDRAWAL --/-- PUBLIC WITHDRAWAL --/-- private cancellation ---- 35 | */ 36 | function withdraw(bytes32 secret, Immutables calldata immutables) 37 | external 38 | onlyCaller(immutables.taker.get()) 39 | onlyAfter(immutables.timelocks.get(TimelocksLib.Stage.DstWithdrawal)) 40 | onlyBefore(immutables.timelocks.get(TimelocksLib.Stage.DstCancellation)) 41 | { 42 | _withdraw(secret, immutables); 43 | } 44 | 45 | /** 46 | * @notice See {IBaseEscrow-publicWithdraw}. 47 | * @dev The function works on the time intervals highlighted with capital letters: 48 | * ---- contract deployed --/-- finality --/-- private withdrawal --/-- PUBLIC WITHDRAWAL --/-- private cancellation ---- 49 | */ 50 | function publicWithdraw(bytes32 secret, Immutables calldata immutables) 51 | external 52 | onlyAccessTokenHolder() 53 | onlyAfter(immutables.timelocks.get(TimelocksLib.Stage.DstPublicWithdrawal)) 54 | onlyBefore(immutables.timelocks.get(TimelocksLib.Stage.DstCancellation)) 55 | { 56 | _withdraw(secret, immutables); 57 | } 58 | 59 | /** 60 | * @notice See {IBaseEscrow-cancel}. 61 | * @dev The function works on the time interval highlighted with capital letters: 62 | * ---- contract deployed --/-- finality --/-- private withdrawal --/-- public withdrawal --/-- PRIVATE CANCELLATION ---- 63 | */ 64 | function cancel(Immutables calldata immutables) 65 | external 66 | onlyCaller(immutables.taker.get()) 67 | onlyValidImmutables(immutables.hash()) 68 | onlyAfter(immutables.timelocks.get(TimelocksLib.Stage.DstCancellation)) 69 | { 70 | _uniTransfer(immutables.token.get(), immutables.taker.get(), immutables.amount); 71 | _ethTransfer(msg.sender, immutables.safetyDeposit); 72 | emit EscrowCancelled(); 73 | } 74 | 75 | /** 76 | * @dev Transfers ERC20 (or native) tokens to the maker and native tokens to the caller. 77 | * @param immutables The immutable values used to deploy the clone contract. 78 | */ 79 | function _withdraw(bytes32 secret, Immutables calldata immutables) 80 | internal 81 | onlyValidImmutables(immutables.hash()) 82 | onlyValidSecret(secret, immutables.hashlock) 83 | { 84 | uint256 integratorFeeAmount = immutables.integratorFeeAmountCd(); 85 | uint256 protocolFeeAmount = immutables.protocolFeeAmountCd(); 86 | if (integratorFeeAmount > 0) { 87 | _uniTransfer(immutables.token.get(), immutables.integratorFeeRecipientCd().get(), integratorFeeAmount); 88 | } 89 | if (protocolFeeAmount > 0) { 90 | _uniTransfer(immutables.token.get(), immutables.protocolFeeRecipientCd().get(), protocolFeeAmount); 91 | } 92 | uint256 amount = immutables.amount - integratorFeeAmount - protocolFeeAmount; 93 | _uniTransfer(immutables.token.get(), immutables.maker.get(), amount); 94 | _ethTransfer(msg.sender, immutables.safetyDeposit); 95 | emit EscrowWithdrawal(secret); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /contracts/EscrowFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; 6 | 7 | import { SimpleSettlement } from "limit-order-settlement/contracts/SimpleSettlement.sol"; 8 | 9 | import { ProxyHashLib } from "./libraries/ProxyHashLib.sol"; 10 | 11 | import { BaseEscrowFactory } from "./BaseEscrowFactory.sol"; 12 | import { EscrowDst } from "./EscrowDst.sol"; 13 | import { EscrowSrc } from "./EscrowSrc.sol"; 14 | import { MerkleStorageInvalidator } from "./MerkleStorageInvalidator.sol"; 15 | 16 | 17 | /** 18 | * @title Escrow Factory contract 19 | * @notice Contract to create escrow contracts for cross-chain atomic swap. 20 | * @custom:security-contact security@1inch.io 21 | */ 22 | contract EscrowFactory is BaseEscrowFactory { 23 | constructor( 24 | address limitOrderProtocol, 25 | IERC20 accessToken, 26 | address owner, 27 | uint32 rescueDelaySrc, 28 | uint32 rescueDelayDst 29 | ) 30 | SimpleSettlement(limitOrderProtocol, accessToken, address(0), owner) 31 | MerkleStorageInvalidator(limitOrderProtocol) { 32 | ESCROW_SRC_IMPLEMENTATION = address(new EscrowSrc(rescueDelaySrc, accessToken)); 33 | ESCROW_DST_IMPLEMENTATION = address(new EscrowDst(rescueDelayDst, accessToken)); 34 | _PROXY_SRC_BYTECODE_HASH = ProxyHashLib.computeProxyBytecodeHash(ESCROW_SRC_IMPLEMENTATION); 35 | _PROXY_DST_BYTECODE_HASH = ProxyHashLib.computeProxyBytecodeHash(ESCROW_DST_IMPLEMENTATION); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/EscrowFactoryContext.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | uint256 constant SRC_IMMUTABLES_LENGTH = 160; 6 | -------------------------------------------------------------------------------- /contracts/EscrowSrc.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; 6 | import { SafeERC20 } from "solidity-utils/contracts/libraries/SafeERC20.sol"; 7 | import { AddressLib, Address } from "solidity-utils/contracts/libraries/AddressLib.sol"; 8 | 9 | import { Timelocks, TimelocksLib } from "./libraries/TimelocksLib.sol"; 10 | import { ImmutablesLib } from "./libraries/ImmutablesLib.sol"; 11 | 12 | import { IEscrowSrc } from "./interfaces/IEscrowSrc.sol"; 13 | import { BaseEscrow } from "./BaseEscrow.sol"; 14 | import { Escrow } from "./Escrow.sol"; 15 | 16 | /** 17 | * @title Source Escrow contract for cross-chain atomic swap. 18 | * @notice Contract to initially lock funds and then unlock them with verification of the secret presented. 19 | * @dev Funds are locked in at the time of contract deployment. For this Limit Order Protocol 20 | * calls the `EscrowFactory.postInteraction` function. 21 | * To perform any action, the caller must provide the same Immutables values used to deploy the clone contract. 22 | * @custom:security-contact security@1inch.io 23 | */ 24 | contract EscrowSrc is Escrow, IEscrowSrc { 25 | using AddressLib for Address; 26 | using ImmutablesLib for Immutables; 27 | using SafeERC20 for IERC20; 28 | using TimelocksLib for Timelocks; 29 | 30 | constructor(uint32 rescueDelay, IERC20 accessToken) BaseEscrow(rescueDelay, accessToken) {} 31 | 32 | /** 33 | * @notice See {IBaseEscrow-withdraw}. 34 | * @dev The function works on the time interval highlighted with capital letters: 35 | * ---- contract deployed --/-- finality --/-- PRIVATE WITHDRAWAL --/-- PUBLIC WITHDRAWAL --/-- 36 | * --/-- private cancellation --/-- public cancellation ---- 37 | */ 38 | function withdraw(bytes32 secret, Immutables calldata immutables) 39 | external 40 | onlyCaller(immutables.taker.get()) 41 | onlyAfter(immutables.timelocks.get(TimelocksLib.Stage.SrcWithdrawal)) 42 | onlyBefore(immutables.timelocks.get(TimelocksLib.Stage.SrcCancellation)) 43 | { 44 | _withdrawTo(secret, msg.sender, immutables); 45 | } 46 | 47 | /** 48 | * @notice See {IEscrowSrc-withdrawTo}. 49 | * @dev The function works on the time interval highlighted with capital letters: 50 | * ---- contract deployed --/-- finality --/-- PRIVATE WITHDRAWAL --/-- PUBLIC WITHDRAWAL --/-- 51 | * --/-- private cancellation --/-- public cancellation ---- 52 | */ 53 | function withdrawTo(bytes32 secret, address target, Immutables calldata immutables) 54 | external 55 | onlyCaller(immutables.taker.get()) 56 | onlyAfter(immutables.timelocks.get(TimelocksLib.Stage.SrcWithdrawal)) 57 | onlyBefore(immutables.timelocks.get(TimelocksLib.Stage.SrcCancellation)) 58 | { 59 | _withdrawTo(secret, target, immutables); 60 | } 61 | 62 | /** 63 | * @notice See {IEscrowSrc-publicWithdraw}. 64 | * @dev The function works on the time interval highlighted with capital letters: 65 | * ---- contract deployed --/-- finality --/-- private withdrawal --/-- PUBLIC WITHDRAWAL --/-- 66 | * --/-- private cancellation --/-- public cancellation ---- 67 | */ 68 | function publicWithdraw(bytes32 secret, Immutables calldata immutables) 69 | external 70 | onlyAccessTokenHolder() 71 | onlyAfter(immutables.timelocks.get(TimelocksLib.Stage.SrcPublicWithdrawal)) 72 | onlyBefore(immutables.timelocks.get(TimelocksLib.Stage.SrcCancellation)) 73 | { 74 | _withdrawTo(secret, immutables.taker.get(), immutables); 75 | } 76 | 77 | /** 78 | * @notice See {IBaseEscrow-cancel}. 79 | * @dev The function works on the time intervals highlighted with capital letters: 80 | * ---- contract deployed --/-- finality --/-- private withdrawal --/-- public withdrawal --/-- 81 | * --/-- PRIVATE CANCELLATION --/-- PUBLIC CANCELLATION ---- 82 | */ 83 | function cancel(Immutables calldata immutables) 84 | external 85 | onlyCaller(immutables.taker.get()) 86 | onlyAfter(immutables.timelocks.get(TimelocksLib.Stage.SrcCancellation)) 87 | { 88 | _cancel(immutables); 89 | } 90 | 91 | /** 92 | * @notice See {IEscrowSrc-publicCancel}. 93 | * @dev The function works on the time intervals highlighted with capital letters: 94 | * ---- contract deployed --/-- finality --/-- private withdrawal --/-- public withdrawal --/-- 95 | * --/-- private cancellation --/-- PUBLIC CANCELLATION ---- 96 | */ 97 | function publicCancel(Immutables calldata immutables) 98 | external 99 | onlyAccessTokenHolder() 100 | onlyAfter(immutables.timelocks.get(TimelocksLib.Stage.SrcPublicCancellation)) 101 | { 102 | _cancel(immutables); 103 | } 104 | 105 | /** 106 | * @dev Transfers ERC20 tokens to the target and native tokens to the caller. 107 | * @param secret The secret that unlocks the escrow. 108 | * @param target The address to transfer ERC20 tokens to. 109 | * @param immutables The immutable values used to deploy the clone contract. 110 | */ 111 | function _withdrawTo(bytes32 secret, address target, Immutables calldata immutables) 112 | internal 113 | onlyValidImmutables(immutables.hash()) 114 | onlyValidSecret(secret, immutables.hashlock) 115 | { 116 | IERC20(immutables.token.get()).safeTransfer(target, immutables.amount); 117 | _ethTransfer(msg.sender, immutables.safetyDeposit); 118 | emit EscrowWithdrawal(secret); 119 | } 120 | 121 | /** 122 | * @dev Transfers ERC20 tokens to the maker and native tokens to the caller. 123 | * @param immutables The immutable values used to deploy the clone contract. 124 | */ 125 | function _cancel(Immutables calldata immutables) 126 | internal 127 | onlyValidImmutables(immutables.hash()) 128 | { 129 | IERC20(immutables.token.get()).safeTransfer(immutables.maker.get(), immutables.amount); 130 | _ethTransfer(msg.sender, immutables.safetyDeposit); 131 | emit EscrowCancelled(); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /contracts/MerkleStorageInvalidator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { IOrderMixin } from "limit-order-protocol/contracts/interfaces/IOrderMixin.sol"; 6 | import { ExtensionLib } from "limit-order-protocol/contracts/libraries/ExtensionLib.sol"; 7 | import { ITakerInteraction } from "limit-order-protocol/contracts/interfaces/ITakerInteraction.sol"; 8 | import { MerkleProof } from "openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol"; 9 | 10 | import { IEscrowFactory } from "./interfaces/IEscrowFactory.sol"; 11 | import { IMerkleStorageInvalidator } from "./interfaces/IMerkleStorageInvalidator.sol"; 12 | import { SRC_IMMUTABLES_LENGTH } from "./EscrowFactoryContext.sol"; // solhint-disable-line no-unused-import 13 | 14 | /** 15 | * @title Merkle Storage Invalidator contract 16 | * @notice Contract to invalidate hashed secrets from an order that supports multiple fills. 17 | * @custom:security-contact security@1inch.io 18 | */ 19 | contract MerkleStorageInvalidator is IMerkleStorageInvalidator, ITakerInteraction { 20 | using MerkleProof for bytes32[]; 21 | using ExtensionLib for bytes; 22 | 23 | address private immutable _LIMIT_ORDER_PROTOCOL; 24 | 25 | /// @notice See {IMerkleStorageInvalidator-lastValidated}. 26 | mapping(bytes32 key => ValidationData) public lastValidated; 27 | 28 | /// @notice Only limit order protocol can call this contract. 29 | modifier onlyLOP() { 30 | if (msg.sender != _LIMIT_ORDER_PROTOCOL) { 31 | revert AccessDenied(); 32 | } 33 | _; 34 | } 35 | 36 | constructor(address limitOrderProtocol) { 37 | _LIMIT_ORDER_PROTOCOL = limitOrderProtocol; 38 | } 39 | 40 | /** 41 | * @notice See {ITakerInteraction-takerInteraction}. 42 | * @dev Verifies the proof and stores the last validated index and hashed secret. 43 | * Only Limit Order Protocol can call this function. 44 | */ 45 | function takerInteraction( 46 | IOrderMixin.Order calldata /* order */, 47 | bytes calldata extension, 48 | bytes32 orderHash, 49 | address /* taker */, 50 | uint256 /* makingAmount */, 51 | uint256 /* takingAmount */, 52 | uint256 /* remainingMakingAmount */, 53 | bytes calldata extraData 54 | ) external onlyLOP { 55 | bytes calldata postInteraction = extension.postInteractionTargetAndData(); 56 | IEscrowFactory.ExtraDataArgs calldata extraDataArgs; 57 | TakerData calldata takerData; 58 | assembly ("memory-safe") { 59 | extraDataArgs := add(postInteraction.offset, sub(postInteraction.length, SRC_IMMUTABLES_LENGTH)) 60 | takerData := extraData.offset 61 | } 62 | uint240 rootShortened = uint240(uint256(extraDataArgs.hashlockInfo)); 63 | bytes32 key = keccak256(abi.encodePacked(orderHash, rootShortened)); 64 | bytes32 rootCalculated = takerData.proof.processProofCalldata( 65 | keccak256(abi.encodePacked(uint64(takerData.idx), takerData.secretHash)) 66 | ); 67 | if (uint240(uint256(rootCalculated)) != rootShortened) revert InvalidProof(); 68 | lastValidated[key] = ValidationData(takerData.idx + 1, takerData.secretHash); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /contracts/interfaces/IBaseEscrow.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import { Address } from "solidity-utils/contracts/libraries/AddressLib.sol"; 6 | 7 | import { Timelocks } from "../libraries/TimelocksLib.sol"; 8 | 9 | /** 10 | * @title Base Escrow interface for cross-chain atomic swap. 11 | * @notice Interface implies locking funds initially and then unlocking them with verification of the secret presented. 12 | * @custom:security-contact security@1inch.io 13 | */ 14 | interface IBaseEscrow { 15 | struct Immutables { 16 | bytes32 orderHash; 17 | bytes32 hashlock; // Hash of the secret. 18 | Address maker; 19 | Address taker; 20 | Address token; 21 | uint256 amount; 22 | uint256 safetyDeposit; 23 | Timelocks timelocks; 24 | bytes parameters; // For now only EscrowDst.withdraw() uses it. 25 | } 26 | 27 | /** 28 | * @notice Emitted on escrow cancellation. 29 | */ 30 | event EscrowCancelled(); 31 | 32 | /** 33 | * @notice Emitted when funds are rescued. 34 | * @param token The address of the token rescued. Zero address for native token. 35 | * @param amount The amount of tokens rescued. 36 | */ 37 | event FundsRescued(address token, uint256 amount); 38 | 39 | /** 40 | * @notice Emitted on successful withdrawal. 41 | * @param secret The secret that unlocks the escrow. 42 | */ 43 | event EscrowWithdrawal(bytes32 secret); 44 | 45 | error InvalidCaller(); 46 | error InvalidImmutables(); 47 | error InvalidSecret(); 48 | error InvalidTime(); 49 | error NativeTokenSendingFailure(); 50 | 51 | /* solhint-disable func-name-mixedcase */ 52 | /// @notice Returns the delay for rescuing funds from the escrow. 53 | function RESCUE_DELAY() external view returns (uint256); 54 | /// @notice Returns the address of the factory that created the escrow. 55 | function FACTORY() external view returns (address); 56 | /* solhint-enable func-name-mixedcase */ 57 | 58 | /** 59 | * @notice Withdraws funds to a predetermined recipient. 60 | * @dev Withdrawal can only be made during the withdrawal period and with secret with hash matches the hashlock. 61 | * The safety deposit is sent to the caller. 62 | * @param secret The secret that unlocks the escrow. 63 | * @param immutables The immutables of the escrow contract. 64 | */ 65 | function withdraw(bytes32 secret, Immutables calldata immutables) external; 66 | 67 | /** 68 | * @notice Cancels the escrow and returns tokens to a predetermined recipient. 69 | * @dev The escrow can only be cancelled during the cancellation period. 70 | * The safety deposit is sent to the caller. 71 | * @param immutables The immutables of the escrow contract. 72 | */ 73 | function cancel(Immutables calldata immutables) external; 74 | 75 | /** 76 | * @notice Rescues funds from the escrow. 77 | * @dev Funds can only be rescued by the taker after the rescue delay. 78 | * @param token The address of the token to rescue. Zero address for native token. 79 | * @param amount The amount of tokens to rescue. 80 | * @param immutables The immutables of the escrow contract. 81 | */ 82 | function rescueFunds(address token, uint256 amount, Immutables calldata immutables) external; 83 | } 84 | -------------------------------------------------------------------------------- /contracts/interfaces/IEscrow.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import { IBaseEscrow } from "./IBaseEscrow.sol"; 6 | 7 | /** 8 | * @title Escrow interface for cross-chain atomic swap. 9 | * @notice Interface implies locking funds initially and then unlocking them with verification of the secret presented. 10 | * @custom:security-contact security@1inch.io 11 | */ 12 | interface IEscrow is IBaseEscrow { 13 | /// @notice Returns the bytecode hash of the proxy contract. 14 | function PROXY_BYTECODE_HASH() external view returns (bytes32); // solhint-disable-line func-name-mixedcase 15 | } 16 | -------------------------------------------------------------------------------- /contracts/interfaces/IEscrowDst.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import { IEscrow } from "./IEscrow.sol"; 6 | 7 | /** 8 | * @title Destination Escrow interface for cross-chain atomic swap. 9 | * @notice Interface implies withdrawing funds initially and then unlocking them with verification of the secret presented. 10 | * @custom:security-contact security@1inch.io 11 | */ 12 | interface IEscrowDst is IEscrow { 13 | /** 14 | * @notice Withdraws funds to maker 15 | * @dev Withdrawal can only be made during the withdrawal period and with secret with hash matches the hashlock. 16 | * @param secret The secret that unlocks the escrow. 17 | * @param immutables The immutables of the escrow contract. 18 | */ 19 | function publicWithdraw(bytes32 secret, IEscrow.Immutables calldata immutables) external; 20 | } 21 | -------------------------------------------------------------------------------- /contracts/interfaces/IEscrowFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import { Address } from "solidity-utils/contracts/libraries/AddressLib.sol"; 6 | 7 | import { Timelocks } from "../libraries/TimelocksLib.sol"; 8 | 9 | import { IBaseEscrow } from "./IBaseEscrow.sol"; 10 | 11 | /** 12 | * @title Escrow Factory interface for cross-chain atomic swap. 13 | * @notice Interface to deploy escrow contracts for the destination chain and to get the deterministic address of escrow on both chains. 14 | * @custom:security-contact security@1inch.io 15 | */ 16 | interface IEscrowFactory { 17 | struct ExtraDataArgs { 18 | bytes32 hashlockInfo; // Hash of the secret or the Merkle tree root if multiple fills are allowed 19 | uint256 dstChainId; 20 | Address dstToken; 21 | uint256 deposits; 22 | Timelocks timelocks; 23 | } 24 | 25 | struct DstImmutablesComplement { 26 | Address maker; 27 | uint256 amount; 28 | Address token; 29 | uint256 safetyDeposit; 30 | uint256 chainId; 31 | bytes parameters; 32 | } 33 | 34 | error InsufficientEscrowBalance(); 35 | error InvalidCreationTime(); 36 | error InvalidPartialFill(); 37 | error InvalidSecretsAmount(); 38 | 39 | /** 40 | * @notice Emitted on EscrowSrc deployment to recreate EscrowSrc and EscrowDst immutables off-chain. 41 | * @param srcImmutables The immutables of the escrow contract that are used in deployment on the source chain. 42 | * @param dstImmutablesComplement Additional immutables related to the escrow contract on the destination chain. 43 | */ 44 | event SrcEscrowCreated(IBaseEscrow.Immutables srcImmutables, DstImmutablesComplement dstImmutablesComplement); 45 | /** 46 | * @notice Emitted on EscrowDst deployment. 47 | * @param escrow The address of the created escrow. 48 | * @param hashlock The hash of the secret. 49 | * @param taker The address of the taker. 50 | */ 51 | event DstEscrowCreated(address escrow, bytes32 hashlock, Address taker); 52 | 53 | /* solhint-disable func-name-mixedcase */ 54 | /// @notice Returns the address of implementation on the source chain. 55 | function ESCROW_SRC_IMPLEMENTATION() external view returns (address); 56 | /// @notice Returns the address of implementation on the destination chain. 57 | function ESCROW_DST_IMPLEMENTATION() external view returns (address); 58 | /* solhint-enable func-name-mixedcase */ 59 | 60 | /** 61 | * @notice Creates a new escrow contract for taker on the destination chain. 62 | * @dev The caller must send the safety deposit in the native token along with the function call 63 | * and approve the destination token to be transferred to the created escrow. 64 | * @param dstImmutables The immutables of the escrow contract that are used in deployment. 65 | * @param srcCancellationTimestamp The start of the cancellation period for the source chain. 66 | */ 67 | function createDstEscrow(IBaseEscrow.Immutables calldata dstImmutables, uint256 srcCancellationTimestamp) external payable; 68 | 69 | /** 70 | * @notice Returns the deterministic address of the source escrow based on the salt. 71 | * @param immutables The immutable arguments used to compute salt for escrow deployment. 72 | * @return The computed address of the escrow. 73 | */ 74 | function addressOfEscrowSrc(IBaseEscrow.Immutables calldata immutables) external view returns (address); 75 | 76 | /** 77 | * @notice Returns the deterministic address of the destination escrow based on the salt. 78 | * @param immutables The immutable arguments used to compute salt for escrow deployment. 79 | * @return The computed address of the escrow. 80 | */ 81 | function addressOfEscrowDst(IBaseEscrow.Immutables calldata immutables) external view returns (address); 82 | } 83 | -------------------------------------------------------------------------------- /contracts/interfaces/IEscrowSrc.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import { IEscrow } from "./IEscrow.sol"; 6 | 7 | /** 8 | * @title Source Escrow interface for cross-chain atomic swap. 9 | * @notice Interface implies locking funds initially and then unlocking them with verification of the secret presented. 10 | * @custom:security-contact security@1inch.io 11 | */ 12 | interface IEscrowSrc is IEscrow { 13 | /** 14 | * @notice Withdraws funds to a specified target. 15 | * @dev Withdrawal can only be made during the withdrawal period and with secret with hash matches the hashlock. 16 | * The safety deposit is sent to the caller. 17 | * @param secret The secret that unlocks the escrow. 18 | * @param target The address to withdraw the funds to. 19 | * @param immutables The immutables of the escrow contract. 20 | */ 21 | function withdrawTo(bytes32 secret, address target, IEscrow.Immutables calldata immutables) external; 22 | 23 | /** 24 | * @notice Withdraws funds to the taker. 25 | * @dev Withdrawal can only be made during the public withdrawal period and with secret with hash matches the hashlock. 26 | * @param secret The secret that unlocks the escrow. 27 | * @param immutables The immutables of the escrow contract. 28 | */ 29 | function publicWithdraw(bytes32 secret, Immutables calldata immutables) external; 30 | 31 | /** 32 | * @notice Cancels the escrow and returns tokens to the maker. 33 | * @dev The escrow can only be cancelled during the public cancellation period. 34 | * The safety deposit is sent to the caller. 35 | * @param immutables The immutables of the escrow contract. 36 | */ 37 | function publicCancel(IEscrow.Immutables calldata immutables) external; 38 | } 39 | -------------------------------------------------------------------------------- /contracts/interfaces/IMerkleStorageInvalidator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | /** 6 | * @title Merkle Storage Invalidator interface 7 | * @notice Interface to invalidate hashed secrets from an order that supports multiple fills. 8 | * @custom:security-contact security@1inch.io 9 | */ 10 | interface IMerkleStorageInvalidator { 11 | struct ValidationData { 12 | uint256 index; 13 | bytes32 leaf; 14 | } 15 | 16 | struct TakerData { 17 | bytes32[] proof; 18 | uint256 idx; 19 | bytes32 secretHash; 20 | } 21 | 22 | error AccessDenied(); 23 | error InvalidProof(); 24 | 25 | /** 26 | * @notice Returns the index of the last validated hashed secret and the hashed secret itself. 27 | * @param key Hash of concatenated order hash and 30 bytes of root hash. 28 | * @return index Index of the last validated hashed secret. 29 | * @return secretHash Last validated hashed secret. 30 | */ 31 | function lastValidated(bytes32 key) external view returns (uint256 index, bytes32 secretHash); 32 | } 33 | -------------------------------------------------------------------------------- /contracts/interfaces/IResolverExample.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { IOrderMixin } from "limit-order-protocol/contracts/interfaces/IOrderMixin.sol"; 6 | import { TakerTraits } from "limit-order-protocol/contracts/libraries/TakerTraitsLib.sol"; 7 | 8 | import { IBaseEscrow } from "../interfaces/IBaseEscrow.sol"; 9 | 10 | /** 11 | * @title Interface for the sample implementation of a Resolver contract for cross-chain swap. 12 | * @custom:security-contact security@1inch.io 13 | */ 14 | interface IResolverExample { 15 | error InvalidLength(); 16 | error LengthMismatch(); 17 | 18 | /** 19 | * @notice Deploys a new escrow contract for maker on the source chain. 20 | * @param immutables The immutables of the escrow contract that are used in deployment. 21 | * @param order Order quote to fill. 22 | * @param r R component of signature. 23 | * @param vs VS component of signature. 24 | * @param amount Taker amount to fill 25 | * @param takerTraits Specifies threshold as maximum allowed takingAmount when takingAmount is zero, otherwise specifies 26 | * minimum allowed makingAmount. The 2nd (0 based index) highest bit specifies whether taker wants to skip maker's permit. 27 | * @param args Arguments that are used by the taker (target, extension, interaction, permit). 28 | */ 29 | function deploySrc( 30 | IBaseEscrow.Immutables calldata immutables, 31 | IOrderMixin.Order calldata order, 32 | bytes32 r, 33 | bytes32 vs, 34 | uint256 amount, 35 | TakerTraits takerTraits, 36 | bytes calldata args 37 | ) external; 38 | 39 | /** 40 | * @notice Deploys a new escrow contract for taker on the destination chain. 41 | * @param dstImmutables The immutables of the escrow contract that are used in deployment. 42 | * @param srcCancellationTimestamp The start of the cancellation period for the source chain. 43 | */ 44 | function deployDst(IBaseEscrow.Immutables calldata dstImmutables, uint256 srcCancellationTimestamp) external payable; 45 | 46 | /** 47 | * @notice Allows the owner to make arbitrary calls to other contracts on behalf of this contract. 48 | * @param targets The addresses of the contracts to call. 49 | * @param arguments The arguments to pass to the contract calls. 50 | */ 51 | function arbitraryCalls(address[] calldata targets, bytes[] calldata arguments) external; 52 | } 53 | -------------------------------------------------------------------------------- /contracts/libraries/ProxyHashLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | /** 6 | * @title Library to compute the hash of the proxy bytecode. 7 | * @custom:security-contact security@1inch.io 8 | */ 9 | library ProxyHashLib { 10 | /** 11 | * @notice Returns the hash of the proxy bytecode concatenated with the implementation address. 12 | * @param implementation The address of the contract to clone. 13 | * @return bytecodeHash The hash of the resulting bytecode. 14 | */ 15 | function computeProxyBytecodeHash(address implementation) internal pure returns (bytes32 bytecodeHash) { 16 | assembly ("memory-safe") { 17 | // Stores the bytecode after address 18 | mstore(0x20, 0x5af43d82803e903d91602b57fd5bf3) 19 | // implementation address 20 | mstore(0x11, implementation) 21 | // Packs the first 3 bytes of the `implementation` address with the bytecode before the address. 22 | mstore(0x00, or(shr(0x88, implementation), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) 23 | bytecodeHash := keccak256(0x09, 0x37) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/libraries/TimelocksLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | /** 6 | * @dev Timelocks for the source and the destination chains plus the deployment timestamp. 7 | * Timelocks store the number of seconds from the time the contract is deployed to the start of a specific period. 8 | * For illustrative purposes, it is possible to describe timelocks by two structures: 9 | * struct SrcTimelocks { 10 | * uint256 withdrawal; 11 | * uint256 publicWithdrawal; 12 | * uint256 cancellation; 13 | * uint256 publicCancellation; 14 | * } 15 | * 16 | * struct DstTimelocks { 17 | * uint256 withdrawal; 18 | * uint256 publicWithdrawal; 19 | * uint256 cancellation; 20 | * } 21 | * 22 | * withdrawal: Period when only the taker with a secret can withdraw tokens for taker (source chain) or maker (destination chain). 23 | * publicWithdrawal: Period when anyone with a secret can withdraw tokens for taker (source chain) or maker (destination chain). 24 | * cancellation: Period when escrow can only be cancelled by the taker. 25 | * publicCancellation: Period when escrow can be cancelled by anyone. 26 | * 27 | * @custom:security-contact security@1inch.io 28 | */ 29 | type Timelocks is uint256; 30 | 31 | /** 32 | * @title Timelocks library for compact storage of timelocks in a uint256. 33 | */ 34 | library TimelocksLib { 35 | enum Stage { 36 | SrcWithdrawal, 37 | SrcPublicWithdrawal, 38 | SrcCancellation, 39 | SrcPublicCancellation, 40 | DstWithdrawal, 41 | DstPublicWithdrawal, 42 | DstCancellation 43 | } 44 | 45 | uint256 private constant _DEPLOYED_AT_MASK = 0xffffffff00000000000000000000000000000000000000000000000000000000; 46 | uint256 private constant _DEPLOYED_AT_OFFSET = 224; 47 | 48 | /** 49 | * @notice Sets the Escrow deployment timestamp. 50 | * @param timelocks The timelocks to set the deployment timestamp to. 51 | * @param value The new Escrow deployment timestamp. 52 | * @return The timelocks with the deployment timestamp set. 53 | */ 54 | function setDeployedAt(Timelocks timelocks, uint256 value) internal pure returns (Timelocks) { 55 | return Timelocks.wrap((Timelocks.unwrap(timelocks) & ~uint256(_DEPLOYED_AT_MASK)) | value << _DEPLOYED_AT_OFFSET); 56 | } 57 | 58 | /** 59 | * @notice Returns the start of the rescue period. 60 | * @param timelocks The timelocks to get the rescue delay from. 61 | * @return The start of the rescue period. 62 | */ 63 | function rescueStart(Timelocks timelocks, uint256 rescueDelay) internal pure returns (uint256) { 64 | unchecked { 65 | return rescueDelay + (Timelocks.unwrap(timelocks) >> _DEPLOYED_AT_OFFSET); 66 | } 67 | } 68 | 69 | /** 70 | * @notice Returns the timelock value for the given stage. 71 | * @param timelocks The timelocks to get the value from. 72 | * @param stage The stage to get the value for. 73 | * @return The timelock value for the given stage. 74 | */ 75 | function get(Timelocks timelocks, Stage stage) internal pure returns (uint256) { 76 | uint256 data = Timelocks.unwrap(timelocks); 77 | uint256 bitShift = uint256(stage) * 32; 78 | // The maximum uint32 value will be reached in 2106. 79 | return (data >> _DEPLOYED_AT_OFFSET) + uint32(data >> bitShift); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /contracts/mocks/ERC20True.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | contract ERC20True { 6 | function transfer(address, uint256) public pure returns (bool) { 7 | return true; 8 | } 9 | 10 | function transferFrom(address, address, uint256) public pure returns (bool) { 11 | return true; 12 | } 13 | 14 | function approve(address, uint256) public pure returns (bool) { 15 | return true; 16 | } 17 | 18 | function balanceOf(address) public pure returns (uint256) { 19 | return 0; 20 | } 21 | 22 | function allowance(address, address) public pure returns (uint256) { 23 | return 0; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /contracts/mocks/NoReceiveCaller.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { RevertReasonForwarder } from "solidity-utils/contracts/libraries/RevertReasonForwarder.sol"; 6 | 7 | contract NoReceiveCaller { 8 | function arbitraryCall(address target, bytes calldata arguments) external { 9 | // solhint-disable-next-line avoid-low-level-calls 10 | (bool success,) = target.call(arguments); 11 | if (!success) RevertReasonForwarder.reRevert(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /contracts/mocks/ResolverExample.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | /*────────────────────────────────────────────────────────────────────────────── 3 | * WARNING! 4 | * ---------- 5 | * This smart-contract code has **NOT** undergone a formal security audit and 6 | * may contain bugs, vulnerabilities, or other defects. It is provided solely 7 | * as an illustrative example. No warranties, express or implied, are given. 8 | * You assume all risks associated with deploying, interacting with, or 9 | * relying upon this code. USE AT YOUR OWN RISK. 10 | *──────────────────────────────────────────────────────────────────────────────*/ 11 | 12 | pragma solidity 0.8.23; 13 | 14 | import { Ownable } from "openzeppelin-contracts/contracts/access/Ownable.sol"; 15 | 16 | import { IOrderMixin } from "limit-order-protocol/contracts/interfaces/IOrderMixin.sol"; 17 | import { TakerTraits } from "limit-order-protocol/contracts/libraries/TakerTraitsLib.sol"; 18 | import { RevertReasonForwarder } from "solidity-utils/contracts/libraries/RevertReasonForwarder.sol"; 19 | 20 | import { IBaseEscrow } from "../interfaces/IBaseEscrow.sol"; 21 | import { IEscrowFactory } from "../interfaces/IEscrowFactory.sol"; 22 | import { IResolverExample } from "../interfaces/IResolverExample.sol"; 23 | import { TimelocksLib } from "../libraries/TimelocksLib.sol"; 24 | 25 | /** 26 | * @title Sample implementation of a Resolver contract for cross-chain swap. 27 | * @dev It is important when deploying an escrow on the source chain to send the safety deposit and deploy the escrow in the same 28 | * transaction, since the address of the escrow depends on the block.timestamp. 29 | * You can find sample code for this in the {ResolverExample-deploySrc}. 30 | * 31 | * @custom:security-contact security@1inch.io 32 | */ 33 | contract ResolverExample is IResolverExample, Ownable { 34 | IEscrowFactory private immutable _FACTORY; 35 | IOrderMixin private immutable _LOP; 36 | 37 | constructor(IEscrowFactory factory, IOrderMixin lop, address initialOwner) Ownable(initialOwner) { 38 | _FACTORY = factory; 39 | _LOP = lop; 40 | } 41 | 42 | receive() external payable {} // solhint-disable-line no-empty-blocks 43 | 44 | /** 45 | * @notice See {IResolverExample-deploySrc}. 46 | */ 47 | function deploySrc( 48 | IBaseEscrow.Immutables calldata immutables, 49 | IOrderMixin.Order calldata order, 50 | bytes32 r, 51 | bytes32 vs, 52 | uint256 amount, 53 | TakerTraits takerTraits, 54 | bytes calldata args 55 | ) external onlyOwner { 56 | IBaseEscrow.Immutables memory immutablesMem = immutables; 57 | immutablesMem.timelocks = TimelocksLib.setDeployedAt(immutables.timelocks, block.timestamp); 58 | address computed = _FACTORY.addressOfEscrowSrc(immutablesMem); 59 | (bool success,) = address(computed).call{ value: immutablesMem.safetyDeposit }(""); 60 | if (!success) revert IBaseEscrow.NativeTokenSendingFailure(); 61 | 62 | // _ARGS_HAS_TARGET = 1 << 251 63 | takerTraits = TakerTraits.wrap(TakerTraits.unwrap(takerTraits) | uint256(1 << 251)); 64 | bytes memory argsMem = abi.encodePacked(computed, args); 65 | _LOP.fillOrderArgs(order, r, vs, amount, takerTraits, argsMem); 66 | } 67 | 68 | /** 69 | * @notice See {IResolverExample-deployDst}. 70 | */ 71 | function deployDst(IBaseEscrow.Immutables calldata dstImmutables, uint256 srcCancellationTimestamp) external onlyOwner payable { 72 | _FACTORY.createDstEscrow{ value: msg.value }(dstImmutables, srcCancellationTimestamp); 73 | } 74 | 75 | /** 76 | * @notice See {IResolverExample-arbitraryCalls}. 77 | */ 78 | function arbitraryCalls(address[] calldata targets, bytes[] calldata arguments) external onlyOwner { 79 | uint256 length = targets.length; 80 | if (targets.length != arguments.length) revert LengthMismatch(); 81 | for (uint256 i = 0; i < length; ++i) { 82 | // solhint-disable-next-line avoid-low-level-calls 83 | (bool success,) = targets[i].call(arguments[i]); 84 | if (!success) RevertReasonForwarder.reRevert(); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /contracts/zkSync/EscrowDstZkSync.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; 6 | 7 | import { Escrow, EscrowDst } from "../EscrowDst.sol"; 8 | import { EscrowZkSync } from "./EscrowZkSync.sol"; 9 | 10 | /// @custom:security-contact security@1inch.io 11 | contract EscrowDstZkSync is EscrowDst, EscrowZkSync { 12 | constructor(uint32 rescueDelay, IERC20 accessToken) EscrowDst(rescueDelay, accessToken) EscrowZkSync() {} 13 | 14 | function _validateImmutables(bytes32 immutablesHash) internal view override(Escrow, EscrowZkSync) { 15 | EscrowZkSync._validateImmutables(immutablesHash); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contracts/zkSync/EscrowFactoryZkSync.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; 6 | import { SimpleSettlement } from "limit-order-settlement/contracts/SimpleSettlement.sol"; 7 | 8 | import { BaseEscrowFactory } from "../BaseEscrowFactory.sol"; 9 | import { MerkleStorageInvalidator } from "../MerkleStorageInvalidator.sol"; 10 | import { IBaseEscrow } from "../interfaces/IBaseEscrow.sol"; 11 | import { ImmutablesLib } from "../libraries/ImmutablesLib.sol"; 12 | 13 | import { EscrowDstZkSync } from "./EscrowDstZkSync.sol"; 14 | import { EscrowSrcZkSync } from "./EscrowSrcZkSync.sol"; 15 | import { MinimalProxyZkSync } from "./MinimalProxyZkSync.sol"; 16 | import { ZkSyncLib } from "./ZkSyncLib.sol"; 17 | 18 | /** 19 | * @title Escrow Factory contract 20 | * @notice Contract to create escrow contracts for cross-chain atomic swap. 21 | * @custom:security-contact security@1inch.io 22 | */ 23 | contract EscrowFactoryZkSync is BaseEscrowFactory { 24 | using ImmutablesLib for IBaseEscrow.Immutables; 25 | 26 | bytes32 public immutable ESCROW_SRC_INPUT_HASH; 27 | bytes32 public immutable ESCROW_DST_INPUT_HASH; 28 | 29 | constructor( 30 | address limitOrderProtocol, 31 | IERC20 accessToken, 32 | address owner, 33 | uint32 rescueDelaySrc, 34 | uint32 rescueDelayDst 35 | ) 36 | SimpleSettlement(limitOrderProtocol, accessToken, address(0), owner) 37 | MerkleStorageInvalidator(limitOrderProtocol) { 38 | ESCROW_SRC_IMPLEMENTATION = address(new EscrowSrcZkSync(rescueDelaySrc, accessToken)); 39 | ESCROW_DST_IMPLEMENTATION = address(new EscrowDstZkSync(rescueDelayDst, accessToken)); 40 | ESCROW_SRC_INPUT_HASH = keccak256(abi.encode(ESCROW_SRC_IMPLEMENTATION)); 41 | ESCROW_DST_INPUT_HASH = keccak256(abi.encode(ESCROW_DST_IMPLEMENTATION)); 42 | MinimalProxyZkSync proxySrc = new MinimalProxyZkSync(ESCROW_SRC_IMPLEMENTATION); 43 | MinimalProxyZkSync proxyDst = new MinimalProxyZkSync(ESCROW_DST_IMPLEMENTATION); 44 | bytes32 bytecodeHashSrc; 45 | bytes32 bytecodeHashDst; 46 | assembly ("memory-safe") { 47 | bytecodeHashSrc := extcodehash(proxySrc) 48 | bytecodeHashDst := extcodehash(proxyDst) 49 | } 50 | _PROXY_SRC_BYTECODE_HASH = bytecodeHashSrc; 51 | _PROXY_DST_BYTECODE_HASH = bytecodeHashDst; 52 | } 53 | 54 | /** 55 | * @notice See {IEscrowFactory-addressOfEscrowSrc}. 56 | */ 57 | function addressOfEscrowSrc(IBaseEscrow.Immutables calldata immutables) external view override returns (address) { 58 | return ZkSyncLib.computeAddressZkSync(immutables.hash(), _PROXY_SRC_BYTECODE_HASH, address(this), ESCROW_SRC_INPUT_HASH); 59 | } 60 | 61 | /** 62 | * @notice See {IEscrowFactory-addressOfEscrowDst}. 63 | */ 64 | function addressOfEscrowDst(IBaseEscrow.Immutables calldata immutables) external view override returns (address) { 65 | return ZkSyncLib.computeAddressZkSync(immutables.hash(), _PROXY_DST_BYTECODE_HASH, address(this), ESCROW_DST_INPUT_HASH); 66 | } 67 | 68 | /** 69 | * @notice Deploys a new escrow contract. 70 | * @param salt The salt for the deterministic address computation. 71 | * @param value The value to be sent to the escrow contract. 72 | * @param implementation Address of the implementation. 73 | * @return escrow The address of the deployed escrow contract. 74 | */ 75 | function _deployEscrow(bytes32 salt, uint256 value, address implementation) internal override returns (address escrow) { 76 | escrow = address(new MinimalProxyZkSync{salt: salt, value: value}(implementation)); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /contracts/zkSync/EscrowSrcZkSync.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; 6 | 7 | import { Escrow, EscrowSrc } from "../EscrowSrc.sol"; 8 | import { EscrowZkSync } from "./EscrowZkSync.sol"; 9 | 10 | /// @custom:security-contact security@1inch.io 11 | contract EscrowSrcZkSync is EscrowSrc, EscrowZkSync { 12 | constructor(uint32 rescueDelay, IERC20 accessToken) 13 | EscrowSrc(rescueDelay, accessToken) 14 | EscrowZkSync() 15 | { 16 | } 17 | 18 | function _validateImmutables(bytes32 immutablesHash) internal view override(Escrow, EscrowZkSync) { 19 | EscrowZkSync._validateImmutables(immutablesHash); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/zkSync/EscrowZkSync.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { BaseEscrow } from "../BaseEscrow.sol"; 6 | 7 | import { ZkSyncLib } from "./ZkSyncLib.sol"; 8 | 9 | /// @custom:security-contact security@1inch.io 10 | abstract contract EscrowZkSync is BaseEscrow { 11 | bytes32 private immutable _INPUT_HASH; 12 | 13 | constructor() { 14 | _INPUT_HASH = keccak256(abi.encode(address(this))); 15 | } 16 | 17 | function _validateImmutables(bytes32 immutablesHash) internal view virtual override { 18 | bytes32 bytecodeHash; 19 | assembly ("memory-safe") { 20 | bytecodeHash := extcodehash(address()) 21 | } 22 | if (ZkSyncLib.computeAddressZkSync(immutablesHash, bytecodeHash, FACTORY, _INPUT_HASH) != address(this)) { 23 | revert InvalidImmutables(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/zkSync/MinimalProxyZkSync.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | /// @custom:security-contact security@1inch.io 6 | contract MinimalProxyZkSync { 7 | address private immutable _IMPLEMENTATION; 8 | 9 | constructor(address implementation) payable { 10 | _IMPLEMENTATION = implementation; 11 | } 12 | 13 | // solhint-disable-next-line no-complex-fallback 14 | fallback() external payable { 15 | address _impl = _IMPLEMENTATION; 16 | assembly ("memory-safe") { 17 | calldatacopy(0, 0, calldatasize()) 18 | let result := delegatecall(gas(), _impl, 0, calldatasize(), 0, 0) 19 | returndatacopy(0, 0, returndatasize()) 20 | switch result 21 | case 0 { 22 | revert(0, returndatasize()) 23 | } 24 | default { 25 | return(0, returndatasize()) 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contracts/zkSync/ZkSyncLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | /** 6 | * @title Library for ZkSync contracts. 7 | * @custom:security-contact security@1inch.io 8 | */ 9 | library ZkSyncLib { 10 | // keccak256("zksyncCreate2") 11 | bytes32 constant private _CREATE2_PREFIX = 0x2020dba91b30cc0006188af794c2fb30dd8520db7e2c088b7fc7c103c00ca494; 12 | 13 | /** 14 | * @notice Returns the address of the contract deployed with CREATE2. 15 | * @param salt The salt used for the deployment. 16 | * @param bytecodeHash The hash of the bytecode. 17 | * @param deployer The address of the deployer. 18 | * @param inputHash The hash of the input. 19 | * @return addr The computed address. 20 | */ 21 | function computeAddressZkSync( 22 | bytes32 salt, 23 | bytes32 bytecodeHash, 24 | address deployer, 25 | bytes32 inputHash 26 | ) internal pure returns (address addr) { 27 | assembly ("memory-safe") { 28 | let ptr := mload(0x40) 29 | mstore(ptr, _CREATE2_PREFIX) 30 | mstore(add(ptr, 0x20), deployer) 31 | mstore(add(ptr, 0x40), salt) 32 | mstore(add(ptr, 0x60), bytecodeHash) 33 | mstore(add(ptr, 0x80), inputHash) 34 | addr := and(keccak256(ptr, 0xa0), 0xffffffffffffffffffffffffffffffffffffffff) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /deployments/arbitrum/ERC20True.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "0xDA0000d4000015A526378bB6faFc650Cea5966F8", 3 | "abi": [ 4 | { 5 | "inputs": [ 6 | { 7 | "internalType": "address", 8 | "name": "", 9 | "type": "address" 10 | }, 11 | { 12 | "internalType": "address", 13 | "name": "", 14 | "type": "address" 15 | } 16 | ], 17 | "name": "allowance", 18 | "outputs": [ 19 | { 20 | "internalType": "uint256", 21 | "name": "", 22 | "type": "uint256" 23 | } 24 | ], 25 | "stateMutability": "pure", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [ 30 | { 31 | "internalType": "address", 32 | "name": "", 33 | "type": "address" 34 | }, 35 | { 36 | "internalType": "uint256", 37 | "name": "", 38 | "type": "uint256" 39 | } 40 | ], 41 | "name": "approve", 42 | "outputs": [ 43 | { 44 | "internalType": "bool", 45 | "name": "", 46 | "type": "bool" 47 | } 48 | ], 49 | "stateMutability": "pure", 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [ 54 | { 55 | "internalType": "address", 56 | "name": "", 57 | "type": "address" 58 | } 59 | ], 60 | "name": "balanceOf", 61 | "outputs": [ 62 | { 63 | "internalType": "uint256", 64 | "name": "", 65 | "type": "uint256" 66 | } 67 | ], 68 | "stateMutability": "pure", 69 | "type": "function" 70 | }, 71 | { 72 | "inputs": [ 73 | { 74 | "internalType": "address", 75 | "name": "", 76 | "type": "address" 77 | }, 78 | { 79 | "internalType": "uint256", 80 | "name": "", 81 | "type": "uint256" 82 | } 83 | ], 84 | "name": "transfer", 85 | "outputs": [ 86 | { 87 | "internalType": "bool", 88 | "name": "", 89 | "type": "bool" 90 | } 91 | ], 92 | "stateMutability": "pure", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "address", 99 | "name": "", 100 | "type": "address" 101 | }, 102 | { 103 | "internalType": "address", 104 | "name": "", 105 | "type": "address" 106 | }, 107 | { 108 | "internalType": "uint256", 109 | "name": "", 110 | "type": "uint256" 111 | } 112 | ], 113 | "name": "transferFrom", 114 | "outputs": [ 115 | { 116 | "internalType": "bool", 117 | "name": "", 118 | "type": "bool" 119 | } 120 | ], 121 | "stateMutability": "pure", 122 | "type": "function" 123 | } 124 | ], 125 | "transactionHash": "0x447a078cc6c4b1ad4ab37fc507a3b9b7def553105b30ba09117af8494dba82b4", 126 | "receipt": { 127 | "to": "0xD935a2bb926019E0ed6fb31fbD5b1Bbb7c05bf65", 128 | "from": "0x56E44874F624EbDE6efCc783eFD685f0FBDC6dcF", 129 | "contractAddress": null, 130 | "transactionIndex": 4, 131 | "gasUsed": "216518", 132 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 133 | "blockHash": "0x2270133526c934cb496bc1f2f4cabd7405206b3e337171b7864d27ef2e3674ee", 134 | "transactionHash": "0x447a078cc6c4b1ad4ab37fc507a3b9b7def553105b30ba09117af8494dba82b4", 135 | "logs": [], 136 | "blockNumber": 247891354, 137 | "cumulativeGasUsed": "364029", 138 | "status": 1 139 | }, 140 | "args": [], 141 | "numDeployments": 1, 142 | "bytecode": "0x60808060405234610016576101da908161001b8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033", 143 | "deployedBytecode": "0x60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033" 144 | } -------------------------------------------------------------------------------- /deployments/aurora/ERC20True.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "0xDA0000d4000015A526378bB6faFc650Cea5966F8", 3 | "abi": [ 4 | { 5 | "inputs": [ 6 | { 7 | "internalType": "address", 8 | "name": "", 9 | "type": "address" 10 | }, 11 | { 12 | "internalType": "address", 13 | "name": "", 14 | "type": "address" 15 | } 16 | ], 17 | "name": "allowance", 18 | "outputs": [ 19 | { 20 | "internalType": "uint256", 21 | "name": "", 22 | "type": "uint256" 23 | } 24 | ], 25 | "stateMutability": "pure", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [ 30 | { 31 | "internalType": "address", 32 | "name": "", 33 | "type": "address" 34 | }, 35 | { 36 | "internalType": "uint256", 37 | "name": "", 38 | "type": "uint256" 39 | } 40 | ], 41 | "name": "approve", 42 | "outputs": [ 43 | { 44 | "internalType": "bool", 45 | "name": "", 46 | "type": "bool" 47 | } 48 | ], 49 | "stateMutability": "pure", 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [ 54 | { 55 | "internalType": "address", 56 | "name": "", 57 | "type": "address" 58 | } 59 | ], 60 | "name": "balanceOf", 61 | "outputs": [ 62 | { 63 | "internalType": "uint256", 64 | "name": "", 65 | "type": "uint256" 66 | } 67 | ], 68 | "stateMutability": "pure", 69 | "type": "function" 70 | }, 71 | { 72 | "inputs": [ 73 | { 74 | "internalType": "address", 75 | "name": "", 76 | "type": "address" 77 | }, 78 | { 79 | "internalType": "uint256", 80 | "name": "", 81 | "type": "uint256" 82 | } 83 | ], 84 | "name": "transfer", 85 | "outputs": [ 86 | { 87 | "internalType": "bool", 88 | "name": "", 89 | "type": "bool" 90 | } 91 | ], 92 | "stateMutability": "pure", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "address", 99 | "name": "", 100 | "type": "address" 101 | }, 102 | { 103 | "internalType": "address", 104 | "name": "", 105 | "type": "address" 106 | }, 107 | { 108 | "internalType": "uint256", 109 | "name": "", 110 | "type": "uint256" 111 | } 112 | ], 113 | "name": "transferFrom", 114 | "outputs": [ 115 | { 116 | "internalType": "bool", 117 | "name": "", 118 | "type": "bool" 119 | } 120 | ], 121 | "stateMutability": "pure", 122 | "type": "function" 123 | } 124 | ], 125 | "transactionHash": "0x8e6c5e3122e935ea4ac758af8e6b606fc3b5399ad8f1fe5838210614ec366819", 126 | "receipt": { 127 | "to": "0xD935a2bb926019E0ed6fb31fbD5b1Bbb7c05bf65", 128 | "from": "0x56E44874F624EbDE6efCc783eFD685f0FBDC6dcF", 129 | "contractAddress": null, 130 | "transactionIndex": 0, 131 | "gasUsed": "202293", 132 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 133 | "blockHash": "0x19e28512a747f067b5d7c6bbcce7115dc56d6c9fd66c18eaad360d3156f43e03", 134 | "transactionHash": "0x8e6c5e3122e935ea4ac758af8e6b606fc3b5399ad8f1fe5838210614ec366819", 135 | "logs": [], 136 | "blockNumber": 126809133, 137 | "cumulativeGasUsed": "0", 138 | "status": 1 139 | }, 140 | "args": [], 141 | "numDeployments": 1, 142 | "bytecode": "0x60808060405234610016576101da908161001b8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033", 143 | "deployedBytecode": "0x60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033" 144 | } -------------------------------------------------------------------------------- /deployments/base/ERC20True.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "0xDA0000d4000015A526378bB6faFc650Cea5966F8", 3 | "abi": [ 4 | { 5 | "inputs": [ 6 | { 7 | "internalType": "address", 8 | "name": "", 9 | "type": "address" 10 | }, 11 | { 12 | "internalType": "address", 13 | "name": "", 14 | "type": "address" 15 | } 16 | ], 17 | "name": "allowance", 18 | "outputs": [ 19 | { 20 | "internalType": "uint256", 21 | "name": "", 22 | "type": "uint256" 23 | } 24 | ], 25 | "stateMutability": "pure", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [ 30 | { 31 | "internalType": "address", 32 | "name": "", 33 | "type": "address" 34 | }, 35 | { 36 | "internalType": "uint256", 37 | "name": "", 38 | "type": "uint256" 39 | } 40 | ], 41 | "name": "approve", 42 | "outputs": [ 43 | { 44 | "internalType": "bool", 45 | "name": "", 46 | "type": "bool" 47 | } 48 | ], 49 | "stateMutability": "pure", 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [ 54 | { 55 | "internalType": "address", 56 | "name": "", 57 | "type": "address" 58 | } 59 | ], 60 | "name": "balanceOf", 61 | "outputs": [ 62 | { 63 | "internalType": "uint256", 64 | "name": "", 65 | "type": "uint256" 66 | } 67 | ], 68 | "stateMutability": "pure", 69 | "type": "function" 70 | }, 71 | { 72 | "inputs": [ 73 | { 74 | "internalType": "address", 75 | "name": "", 76 | "type": "address" 77 | }, 78 | { 79 | "internalType": "uint256", 80 | "name": "", 81 | "type": "uint256" 82 | } 83 | ], 84 | "name": "transfer", 85 | "outputs": [ 86 | { 87 | "internalType": "bool", 88 | "name": "", 89 | "type": "bool" 90 | } 91 | ], 92 | "stateMutability": "pure", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "address", 99 | "name": "", 100 | "type": "address" 101 | }, 102 | { 103 | "internalType": "address", 104 | "name": "", 105 | "type": "address" 106 | }, 107 | { 108 | "internalType": "uint256", 109 | "name": "", 110 | "type": "uint256" 111 | } 112 | ], 113 | "name": "transferFrom", 114 | "outputs": [ 115 | { 116 | "internalType": "bool", 117 | "name": "", 118 | "type": "bool" 119 | } 120 | ], 121 | "stateMutability": "pure", 122 | "type": "function" 123 | } 124 | ], 125 | "transactionHash": "0x2be38d1e847335a78bd8e0552c6c476152b03a2dbc88a5208f289bf4cf23ea05", 126 | "receipt": { 127 | "to": "0xD935a2bb926019E0ed6fb31fbD5b1Bbb7c05bf65", 128 | "from": "0x56E44874F624EbDE6efCc783eFD685f0FBDC6dcF", 129 | "contractAddress": null, 130 | "transactionIndex": 66, 131 | "gasUsed": "202293", 132 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 133 | "blockHash": "0x961bedab90215fece4a58df0ba51903fd4774eefbf9156f3cc438fa68b2a978b", 134 | "transactionHash": "0x2be38d1e847335a78bd8e0552c6c476152b03a2dbc88a5208f289bf4cf23ea05", 135 | "logs": [], 136 | "blockNumber": 19067150, 137 | "cumulativeGasUsed": "10764459", 138 | "status": 1 139 | }, 140 | "args": [], 141 | "numDeployments": 1, 142 | "bytecode": "0x60808060405234610016576101da908161001b8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033", 143 | "deployedBytecode": "0x60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033" 144 | } -------------------------------------------------------------------------------- /deployments/bsc/ERC20True.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "0xDA0000d4000015A526378bB6faFc650Cea5966F8", 3 | "abi": [ 4 | { 5 | "inputs": [ 6 | { 7 | "internalType": "address", 8 | "name": "", 9 | "type": "address" 10 | }, 11 | { 12 | "internalType": "address", 13 | "name": "", 14 | "type": "address" 15 | } 16 | ], 17 | "name": "allowance", 18 | "outputs": [ 19 | { 20 | "internalType": "uint256", 21 | "name": "", 22 | "type": "uint256" 23 | } 24 | ], 25 | "stateMutability": "pure", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [ 30 | { 31 | "internalType": "address", 32 | "name": "", 33 | "type": "address" 34 | }, 35 | { 36 | "internalType": "uint256", 37 | "name": "", 38 | "type": "uint256" 39 | } 40 | ], 41 | "name": "approve", 42 | "outputs": [ 43 | { 44 | "internalType": "bool", 45 | "name": "", 46 | "type": "bool" 47 | } 48 | ], 49 | "stateMutability": "pure", 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [ 54 | { 55 | "internalType": "address", 56 | "name": "", 57 | "type": "address" 58 | } 59 | ], 60 | "name": "balanceOf", 61 | "outputs": [ 62 | { 63 | "internalType": "uint256", 64 | "name": "", 65 | "type": "uint256" 66 | } 67 | ], 68 | "stateMutability": "pure", 69 | "type": "function" 70 | }, 71 | { 72 | "inputs": [ 73 | { 74 | "internalType": "address", 75 | "name": "", 76 | "type": "address" 77 | }, 78 | { 79 | "internalType": "uint256", 80 | "name": "", 81 | "type": "uint256" 82 | } 83 | ], 84 | "name": "transfer", 85 | "outputs": [ 86 | { 87 | "internalType": "bool", 88 | "name": "", 89 | "type": "bool" 90 | } 91 | ], 92 | "stateMutability": "pure", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "address", 99 | "name": "", 100 | "type": "address" 101 | }, 102 | { 103 | "internalType": "address", 104 | "name": "", 105 | "type": "address" 106 | }, 107 | { 108 | "internalType": "uint256", 109 | "name": "", 110 | "type": "uint256" 111 | } 112 | ], 113 | "name": "transferFrom", 114 | "outputs": [ 115 | { 116 | "internalType": "bool", 117 | "name": "", 118 | "type": "bool" 119 | } 120 | ], 121 | "stateMutability": "pure", 122 | "type": "function" 123 | } 124 | ], 125 | "transactionHash": "0x226a8e093b6399609774afb9228bec775461089a2e535d7ec48e905bb3a33445", 126 | "receipt": { 127 | "to": "0xD935a2bb926019E0ed6fb31fbD5b1Bbb7c05bf65", 128 | "from": "0x56E44874F624EbDE6efCc783eFD685f0FBDC6dcF", 129 | "contractAddress": null, 130 | "transactionIndex": 134, 131 | "gasUsed": "202293", 132 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 133 | "blockHash": "0x6ea6b7dd7ec8d5fef08c262f9fd33a9d7b80e2bb5e8672e588292b4b511cb396", 134 | "transactionHash": "0x226a8e093b6399609774afb9228bec775461089a2e535d7ec48e905bb3a33445", 135 | "logs": [], 136 | "blockNumber": 41783252, 137 | "cumulativeGasUsed": "10259545", 138 | "status": 1 139 | }, 140 | "args": [], 141 | "numDeployments": 1, 142 | "bytecode": "0x60808060405234610016576101da908161001b8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033", 143 | "deployedBytecode": "0x60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033" 144 | } -------------------------------------------------------------------------------- /deployments/gnosis/ERC20True.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "0xDA0000d4000015A526378bB6faFc650Cea5966F8", 3 | "abi": [ 4 | { 5 | "inputs": [ 6 | { 7 | "internalType": "address", 8 | "name": "", 9 | "type": "address" 10 | }, 11 | { 12 | "internalType": "address", 13 | "name": "", 14 | "type": "address" 15 | } 16 | ], 17 | "name": "allowance", 18 | "outputs": [ 19 | { 20 | "internalType": "uint256", 21 | "name": "", 22 | "type": "uint256" 23 | } 24 | ], 25 | "stateMutability": "pure", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [ 30 | { 31 | "internalType": "address", 32 | "name": "", 33 | "type": "address" 34 | }, 35 | { 36 | "internalType": "uint256", 37 | "name": "", 38 | "type": "uint256" 39 | } 40 | ], 41 | "name": "approve", 42 | "outputs": [ 43 | { 44 | "internalType": "bool", 45 | "name": "", 46 | "type": "bool" 47 | } 48 | ], 49 | "stateMutability": "pure", 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [ 54 | { 55 | "internalType": "address", 56 | "name": "", 57 | "type": "address" 58 | } 59 | ], 60 | "name": "balanceOf", 61 | "outputs": [ 62 | { 63 | "internalType": "uint256", 64 | "name": "", 65 | "type": "uint256" 66 | } 67 | ], 68 | "stateMutability": "pure", 69 | "type": "function" 70 | }, 71 | { 72 | "inputs": [ 73 | { 74 | "internalType": "address", 75 | "name": "", 76 | "type": "address" 77 | }, 78 | { 79 | "internalType": "uint256", 80 | "name": "", 81 | "type": "uint256" 82 | } 83 | ], 84 | "name": "transfer", 85 | "outputs": [ 86 | { 87 | "internalType": "bool", 88 | "name": "", 89 | "type": "bool" 90 | } 91 | ], 92 | "stateMutability": "pure", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "address", 99 | "name": "", 100 | "type": "address" 101 | }, 102 | { 103 | "internalType": "address", 104 | "name": "", 105 | "type": "address" 106 | }, 107 | { 108 | "internalType": "uint256", 109 | "name": "", 110 | "type": "uint256" 111 | } 112 | ], 113 | "name": "transferFrom", 114 | "outputs": [ 115 | { 116 | "internalType": "bool", 117 | "name": "", 118 | "type": "bool" 119 | } 120 | ], 121 | "stateMutability": "pure", 122 | "type": "function" 123 | } 124 | ], 125 | "transactionHash": "0x581d246f505b7296a5b7a1e0ef87aae279266d5a39826ed58b584426d17a5c92", 126 | "receipt": { 127 | "to": "0xD935a2bb926019E0ed6fb31fbD5b1Bbb7c05bf65", 128 | "from": "0x56E44874F624EbDE6efCc783eFD685f0FBDC6dcF", 129 | "contractAddress": null, 130 | "transactionIndex": 3, 131 | "gasUsed": "202293", 132 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 133 | "blockHash": "0x1947f5e845bd2f901fe4279da2b681f172f1b41269b2e5cb6153fe3748b2fb07", 134 | "transactionHash": "0x581d246f505b7296a5b7a1e0ef87aae279266d5a39826ed58b584426d17a5c92", 135 | "logs": [], 136 | "blockNumber": 35726102, 137 | "cumulativeGasUsed": "1883640", 138 | "status": 1 139 | }, 140 | "args": [], 141 | "numDeployments": 1, 142 | "bytecode": "0x60808060405234610016576101da908161001b8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033", 143 | "deployedBytecode": "0x60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033" 144 | } -------------------------------------------------------------------------------- /deployments/linea/.chainId: -------------------------------------------------------------------------------- 1 | 59144 -------------------------------------------------------------------------------- /deployments/mainnet/ERC20True.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "0xDA0000d4000015A526378bB6faFc650Cea5966F8", 3 | "abi": [ 4 | { 5 | "inputs": [ 6 | { 7 | "internalType": "address", 8 | "name": "", 9 | "type": "address" 10 | }, 11 | { 12 | "internalType": "address", 13 | "name": "", 14 | "type": "address" 15 | } 16 | ], 17 | "name": "allowance", 18 | "outputs": [ 19 | { 20 | "internalType": "uint256", 21 | "name": "", 22 | "type": "uint256" 23 | } 24 | ], 25 | "stateMutability": "pure", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [ 30 | { 31 | "internalType": "address", 32 | "name": "", 33 | "type": "address" 34 | }, 35 | { 36 | "internalType": "uint256", 37 | "name": "", 38 | "type": "uint256" 39 | } 40 | ], 41 | "name": "approve", 42 | "outputs": [ 43 | { 44 | "internalType": "bool", 45 | "name": "", 46 | "type": "bool" 47 | } 48 | ], 49 | "stateMutability": "pure", 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [ 54 | { 55 | "internalType": "address", 56 | "name": "", 57 | "type": "address" 58 | } 59 | ], 60 | "name": "balanceOf", 61 | "outputs": [ 62 | { 63 | "internalType": "uint256", 64 | "name": "", 65 | "type": "uint256" 66 | } 67 | ], 68 | "stateMutability": "pure", 69 | "type": "function" 70 | }, 71 | { 72 | "inputs": [ 73 | { 74 | "internalType": "address", 75 | "name": "", 76 | "type": "address" 77 | }, 78 | { 79 | "internalType": "uint256", 80 | "name": "", 81 | "type": "uint256" 82 | } 83 | ], 84 | "name": "transfer", 85 | "outputs": [ 86 | { 87 | "internalType": "bool", 88 | "name": "", 89 | "type": "bool" 90 | } 91 | ], 92 | "stateMutability": "pure", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "address", 99 | "name": "", 100 | "type": "address" 101 | }, 102 | { 103 | "internalType": "address", 104 | "name": "", 105 | "type": "address" 106 | }, 107 | { 108 | "internalType": "uint256", 109 | "name": "", 110 | "type": "uint256" 111 | } 112 | ], 113 | "name": "transferFrom", 114 | "outputs": [ 115 | { 116 | "internalType": "bool", 117 | "name": "", 118 | "type": "bool" 119 | } 120 | ], 121 | "stateMutability": "pure", 122 | "type": "function" 123 | } 124 | ], 125 | "transactionHash": "0x572f29f09b05a2e3d7b64dd9c55589667daadf7219cbd19445540e8cb7694346", 126 | "receipt": { 127 | "to": "0xD935a2bb926019E0ed6fb31fbD5b1Bbb7c05bf65", 128 | "from": "0x56E44874F624EbDE6efCc783eFD685f0FBDC6dcF", 129 | "contractAddress": null, 130 | "transactionIndex": 13, 131 | "gasUsed": "202293", 132 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 133 | "blockHash": "0xdb26e71b4a98416cb3f8b12b707022d9b699824c4e1e418652c9a83db92a3ae8", 134 | "transactionHash": "0x572f29f09b05a2e3d7b64dd9c55589667daadf7219cbd19445540e8cb7694346", 135 | "logs": [], 136 | "blockNumber": 20633364, 137 | "cumulativeGasUsed": "2487442", 138 | "status": 1 139 | }, 140 | "args": [], 141 | "numDeployments": 1, 142 | "bytecode": "0x60808060405234610016576101da908161001b8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033", 143 | "deployedBytecode": "0x60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033" 144 | } -------------------------------------------------------------------------------- /deployments/optimism/ERC20True.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "0xDA0000d4000015A526378bB6faFc650Cea5966F8", 3 | "abi": [ 4 | { 5 | "inputs": [ 6 | { 7 | "internalType": "address", 8 | "name": "", 9 | "type": "address" 10 | }, 11 | { 12 | "internalType": "address", 13 | "name": "", 14 | "type": "address" 15 | } 16 | ], 17 | "name": "allowance", 18 | "outputs": [ 19 | { 20 | "internalType": "uint256", 21 | "name": "", 22 | "type": "uint256" 23 | } 24 | ], 25 | "stateMutability": "pure", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [ 30 | { 31 | "internalType": "address", 32 | "name": "", 33 | "type": "address" 34 | }, 35 | { 36 | "internalType": "uint256", 37 | "name": "", 38 | "type": "uint256" 39 | } 40 | ], 41 | "name": "approve", 42 | "outputs": [ 43 | { 44 | "internalType": "bool", 45 | "name": "", 46 | "type": "bool" 47 | } 48 | ], 49 | "stateMutability": "pure", 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [ 54 | { 55 | "internalType": "address", 56 | "name": "", 57 | "type": "address" 58 | } 59 | ], 60 | "name": "balanceOf", 61 | "outputs": [ 62 | { 63 | "internalType": "uint256", 64 | "name": "", 65 | "type": "uint256" 66 | } 67 | ], 68 | "stateMutability": "pure", 69 | "type": "function" 70 | }, 71 | { 72 | "inputs": [ 73 | { 74 | "internalType": "address", 75 | "name": "", 76 | "type": "address" 77 | }, 78 | { 79 | "internalType": "uint256", 80 | "name": "", 81 | "type": "uint256" 82 | } 83 | ], 84 | "name": "transfer", 85 | "outputs": [ 86 | { 87 | "internalType": "bool", 88 | "name": "", 89 | "type": "bool" 90 | } 91 | ], 92 | "stateMutability": "pure", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "address", 99 | "name": "", 100 | "type": "address" 101 | }, 102 | { 103 | "internalType": "address", 104 | "name": "", 105 | "type": "address" 106 | }, 107 | { 108 | "internalType": "uint256", 109 | "name": "", 110 | "type": "uint256" 111 | } 112 | ], 113 | "name": "transferFrom", 114 | "outputs": [ 115 | { 116 | "internalType": "bool", 117 | "name": "", 118 | "type": "bool" 119 | } 120 | ], 121 | "stateMutability": "pure", 122 | "type": "function" 123 | } 124 | ], 125 | "transactionHash": "0xbcec37e3721a129c566a433c43575cc19d3e16b332672a78e6eccbe70e5321c4", 126 | "receipt": { 127 | "to": "0xD935a2bb926019E0ed6fb31fbD5b1Bbb7c05bf65", 128 | "from": "0x56E44874F624EbDE6efCc783eFD685f0FBDC6dcF", 129 | "contractAddress": null, 130 | "transactionIndex": 7, 131 | "gasUsed": "202293", 132 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 133 | "blockHash": "0xc29c7f3ce54af7f75372ca1c04c17a1fccedb51484ec31994f75a590be039558", 134 | "transactionHash": "0xbcec37e3721a129c566a433c43575cc19d3e16b332672a78e6eccbe70e5321c4", 135 | "logs": [], 136 | "blockNumber": 124662642, 137 | "cumulativeGasUsed": "2405739", 138 | "status": 1 139 | }, 140 | "args": [], 141 | "numDeployments": 1, 142 | "bytecode": "0x60808060405234610016576101da908161001b8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033", 143 | "deployedBytecode": "0x60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033" 144 | } -------------------------------------------------------------------------------- /deployments/unichain/ERC20True.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "0xDA0000d4000015A526378bB6faFc650Cea5966F8", 3 | "abi": [ 4 | { 5 | "inputs": [ 6 | { 7 | "internalType": "address", 8 | "name": "", 9 | "type": "address" 10 | }, 11 | { 12 | "internalType": "address", 13 | "name": "", 14 | "type": "address" 15 | } 16 | ], 17 | "name": "allowance", 18 | "outputs": [ 19 | { 20 | "internalType": "uint256", 21 | "name": "", 22 | "type": "uint256" 23 | } 24 | ], 25 | "stateMutability": "pure", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [ 30 | { 31 | "internalType": "address", 32 | "name": "", 33 | "type": "address" 34 | }, 35 | { 36 | "internalType": "uint256", 37 | "name": "", 38 | "type": "uint256" 39 | } 40 | ], 41 | "name": "approve", 42 | "outputs": [ 43 | { 44 | "internalType": "bool", 45 | "name": "", 46 | "type": "bool" 47 | } 48 | ], 49 | "stateMutability": "pure", 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [ 54 | { 55 | "internalType": "address", 56 | "name": "", 57 | "type": "address" 58 | } 59 | ], 60 | "name": "balanceOf", 61 | "outputs": [ 62 | { 63 | "internalType": "uint256", 64 | "name": "", 65 | "type": "uint256" 66 | } 67 | ], 68 | "stateMutability": "pure", 69 | "type": "function" 70 | }, 71 | { 72 | "inputs": [ 73 | { 74 | "internalType": "address", 75 | "name": "", 76 | "type": "address" 77 | }, 78 | { 79 | "internalType": "uint256", 80 | "name": "", 81 | "type": "uint256" 82 | } 83 | ], 84 | "name": "transfer", 85 | "outputs": [ 86 | { 87 | "internalType": "bool", 88 | "name": "", 89 | "type": "bool" 90 | } 91 | ], 92 | "stateMutability": "pure", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "address", 99 | "name": "", 100 | "type": "address" 101 | }, 102 | { 103 | "internalType": "address", 104 | "name": "", 105 | "type": "address" 106 | }, 107 | { 108 | "internalType": "uint256", 109 | "name": "", 110 | "type": "uint256" 111 | } 112 | ], 113 | "name": "transferFrom", 114 | "outputs": [ 115 | { 116 | "internalType": "bool", 117 | "name": "", 118 | "type": "bool" 119 | } 120 | ], 121 | "stateMutability": "pure", 122 | "type": "function" 123 | } 124 | ], 125 | "transactionHash": "0x9c129f82f8f332a43c557b3a9fb660d01fc0269a3e18b36bb05027fe2744e924", 126 | "receipt": { 127 | "to": "0xD935a2bb926019E0ed6fb31fbD5b1Bbb7c05bf65", 128 | "from": "0x56E44874F624EbDE6efCc783eFD685f0FBDC6dcF", 129 | "contractAddress": null, 130 | "transactionIndex": 16, 131 | "gasUsed": "202280", 132 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 133 | "blockHash": "0x27ac75378bf79046c03f9f4e968a6cc319103e3d7b4cf0d5a800b98dd7b2eec5", 134 | "transactionHash": "0x9c129f82f8f332a43c557b3a9fb660d01fc0269a3e18b36bb05027fe2744e924", 135 | "logs": [], 136 | "blockNumber": 16479046, 137 | "cumulativeGasUsed": "8160447", 138 | "status": 1 139 | }, 140 | "args": [], 141 | "numDeployments": 1, 142 | "bytecode": "0x60808060405234610016576101da908161001b8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033", 143 | "deployedBytecode": "0x60806040526004361015610011575f80fd5b5f3560e01c8063095ea7b31461009f57806323b872dd146100db57806370a08231146100a4578063a9059cbb1461009f5763dd62ed3e14610050575f80fd5b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610087610127565b5061009061014a565b5060206040515f8152f35b5f80fd5b61016d565b3461009b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610090610127565b3461009b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b57610112610127565b5061011b61014a565b50602060405160018152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361009b57565b3461009b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261009b5761011b61012756fea2646970667358221220b9f54a192e44e1c4f4b231ddf080441810dc4e2d317e3c2cedcaac4306de7bcd64736f6c63430008170033" 144 | } -------------------------------------------------------------------------------- /documentation/.gitignore: -------------------------------------------------------------------------------- 1 | book/ -------------------------------------------------------------------------------- /documentation/book.css: -------------------------------------------------------------------------------- 1 | table { 2 | margin: 0 auto; 3 | border-collapse: collapse; 4 | width: 100%; 5 | } 6 | 7 | table td:first-child { 8 | width: 15%; 9 | } 10 | 11 | table td:nth-child(2) { 12 | width: 25%; 13 | } -------------------------------------------------------------------------------- /documentation/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | src = "src" 3 | title = "" 4 | 5 | [output.html] 6 | no-section-label = true 7 | additional-js = ["solidity.min.js"] 8 | additional-css = ["book.css"] 9 | git-repository-url = "https://github.com/1inch/cross-chain-swap" 10 | 11 | [output.html.fold] 12 | enable = true 13 | -------------------------------------------------------------------------------- /documentation/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | - [Home](README.md) 3 | # contracts 4 | - [❱ interfaces](contracts/interfaces/README.md) 5 | - [IEscrow](contracts/interfaces/IEscrow.sol/interface.IEscrow.md) 6 | - [IEscrowFactory](contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md) 7 | - [IEscrowSrc](contracts/interfaces/IEscrowSrc.sol/interface.IEscrowSrc.md) 8 | - [❱ libraries](contracts/libraries/README.md) 9 | - [Clones](contracts/libraries/Clones.sol/library.Clones.md) 10 | - [ImmutablesLib](contracts/libraries/ImmutablesLib.sol/library.ImmutablesLib.md) 11 | - [Timelocks](contracts/libraries/TimelocksLib.sol/type.Timelocks.md) 12 | - [TimelocksLib](contracts/libraries/TimelocksLib.sol/library.TimelocksLib.md) 13 | - [❱ mocks](contracts/mocks/README.md) 14 | - [ERC20True](contracts/mocks/ERC20True.sol/contract.ERC20True.md) 15 | - [Escrow](contracts/Escrow.sol/abstract.Escrow.md) 16 | - [EscrowDst](contracts/EscrowDst.sol/contract.EscrowDst.md) 17 | - [EscrowFactory](contracts/EscrowFactory.sol/contract.EscrowFactory.md) 18 | - [EscrowSrc](contracts/EscrowSrc.sol/contract.EscrowSrc.md) 19 | -------------------------------------------------------------------------------- /documentation/src/contracts/Escrow.sol/abstract.Escrow.md: -------------------------------------------------------------------------------- 1 | # Escrow 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/953335457652894d3aa7caf6353d8c55f2e2a675/contracts/Escrow.sol) 3 | 4 | **Inherits:** 5 | [IEscrow](/contracts/interfaces/IEscrow.sol/interface.IEscrow.md) 6 | 7 | 8 | ## State Variables 9 | ### RESCUE_DELAY 10 | 11 | ```solidity 12 | uint256 public immutable RESCUE_DELAY; 13 | ``` 14 | 15 | 16 | ### FACTORY 17 | 18 | ```solidity 19 | address public immutable FACTORY = msg.sender; 20 | ``` 21 | 22 | 23 | ### PROXY_BYTECODE_HASH 24 | 25 | ```solidity 26 | bytes32 public immutable PROXY_BYTECODE_HASH = Clones.computeProxyBytecodeHash(address(this)); 27 | ``` 28 | 29 | 30 | ## Functions 31 | ### constructor 32 | 33 | 34 | ```solidity 35 | constructor(uint32 rescueDelay); 36 | ``` 37 | 38 | ### onlyValidImmutables 39 | 40 | 41 | ```solidity 42 | modifier onlyValidImmutables(Immutables calldata immutables); 43 | ``` 44 | 45 | ### rescueFunds 46 | 47 | See [IEscrow-rescueFunds](/contracts/interfaces/IEscrow.sol/interface.IEscrow.md#rescuefunds). 48 | 49 | 50 | ```solidity 51 | function rescueFunds(address token, uint256 amount, Immutables calldata immutables) external onlyValidImmutables(immutables); 52 | ``` 53 | 54 | ### _isValidSecret 55 | 56 | 57 | ```solidity 58 | function _isValidSecret(bytes32 secret, bytes32 hashlock) internal pure returns (bool); 59 | ``` 60 | 61 | ### _checkSecretAndTransfer 62 | 63 | Checks the secret and transfers tokens to the recipient. 64 | 65 | *The secret is valid if its hash matches the hashlock.* 66 | 67 | 68 | ```solidity 69 | function _checkSecretAndTransfer(bytes32 secret, bytes32 hashlock, address recipient, address token, uint256 amount) internal; 70 | ``` 71 | **Parameters** 72 | 73 | |Name|Type|Description| 74 | |----|----|-----------| 75 | |`secret`|`bytes32`|Provided secret to verify.| 76 | |`hashlock`|`bytes32`|Hashlock to compare with.| 77 | |`recipient`|`address`|Address to transfer tokens to.| 78 | |`token`|`address`|Address of the token to transfer.| 79 | |`amount`|`uint256`|Amount of tokens to transfer.| 80 | 81 | 82 | ### _rescueFunds 83 | 84 | 85 | ```solidity 86 | function _rescueFunds(Timelocks timelocks, address token, uint256 amount) internal; 87 | ``` 88 | 89 | ### _uniTransfer 90 | 91 | 92 | ```solidity 93 | function _uniTransfer(address token, address to, uint256 amount) internal; 94 | ``` 95 | 96 | ### _ethTransfer 97 | 98 | 99 | ```solidity 100 | function _ethTransfer(address to, uint256 amount) internal; 101 | ``` 102 | 103 | ### _validateImmutables 104 | 105 | 106 | ```solidity 107 | function _validateImmutables(Immutables calldata immutables) private view; 108 | ``` 109 | 110 | -------------------------------------------------------------------------------- /documentation/src/contracts/EscrowDst.sol/contract.EscrowDst.md: -------------------------------------------------------------------------------- 1 | # EscrowDst 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/953335457652894d3aa7caf6353d8c55f2e2a675/contracts/EscrowDst.sol) 3 | 4 | **Inherits:** 5 | [Escrow](/contracts/Escrow.sol/abstract.Escrow.md) 6 | 7 | Contract to initially lock funds and then unlock them with verification of the secret presented. 8 | 9 | *Funds are locked in at the time of contract deployment. For this taker calls the `EscrowFactory.createDstEscrow` function. 10 | To perform any action, the caller must provide the same Immutables values used to deploy the clone contract.* 11 | 12 | 13 | ## Functions 14 | ### constructor 15 | 16 | 17 | ```solidity 18 | constructor(uint32 rescueDelay) Escrow(rescueDelay); 19 | ``` 20 | 21 | ### withdraw 22 | 23 | See [IEscrow-withdraw](/contracts/interfaces/IEscrow.sol/interface.IEscrow.md#withdraw). 24 | 25 | *The function works on the time intervals highlighted with capital letters: 26 | ---- contract deployed --/-- finality --/-- PRIVATE WITHDRAWAL --/-- PUBLIC WITHDRAWAL --/-- private cancellation ----* 27 | 28 | 29 | ```solidity 30 | function withdraw(bytes32 secret, Immutables calldata immutables) external onlyValidImmutables(immutables); 31 | ``` 32 | 33 | ### cancel 34 | 35 | See [IEscrow-cancel](/contracts/interfaces/IEscrow.sol/interface.IEscrow.md#cancel). 36 | 37 | *The function works on the time interval highlighted with capital letters: 38 | ---- contract deployed --/-- finality --/-- private withdrawal --/-- public withdrawal --/-- PRIVATE CANCELLATION ----* 39 | 40 | 41 | ```solidity 42 | function cancel(Immutables calldata immutables) external onlyValidImmutables(immutables); 43 | ``` 44 | 45 | -------------------------------------------------------------------------------- /documentation/src/contracts/EscrowFactory.sol/contract.EscrowFactory.md: -------------------------------------------------------------------------------- 1 | # EscrowFactory 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/953335457652894d3aa7caf6353d8c55f2e2a675/contracts/EscrowFactory.sol) 3 | 4 | **Inherits:** 5 | [IEscrowFactory](/contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md), WhitelistExtension, ResolverFeeExtension 6 | 7 | Contract to create escrow contracts for cross-chain atomic swap. 8 | 9 | 10 | ## State Variables 11 | ### _SRC_IMMUTABLES_LENGTH 12 | 13 | ```solidity 14 | uint256 private constant _SRC_IMMUTABLES_LENGTH = 160; 15 | ``` 16 | 17 | 18 | ### ESCROW_SRC_IMPLEMENTATION 19 | 20 | ```solidity 21 | address public immutable ESCROW_SRC_IMPLEMENTATION; 22 | ``` 23 | 24 | 25 | ### ESCROW_DST_IMPLEMENTATION 26 | 27 | ```solidity 28 | address public immutable ESCROW_DST_IMPLEMENTATION; 29 | ``` 30 | 31 | 32 | ### _PROXY_SRC_BYTECODE_HASH 33 | 34 | ```solidity 35 | bytes32 private immutable _PROXY_SRC_BYTECODE_HASH; 36 | ``` 37 | 38 | 39 | ### _PROXY_DST_BYTECODE_HASH 40 | 41 | ```solidity 42 | bytes32 private immutable _PROXY_DST_BYTECODE_HASH; 43 | ``` 44 | 45 | 46 | ## Functions 47 | ### constructor 48 | 49 | 50 | ```solidity 51 | constructor( 52 | address limitOrderProtocol, 53 | IERC20 token, 54 | uint32 rescueDelaySrc, 55 | uint32 rescueDelayDst 56 | ) BaseExtension(limitOrderProtocol) ResolverFeeExtension(token); 57 | ``` 58 | 59 | ### _postInteraction 60 | 61 | Creates a new escrow contract for maker on the source chain. 62 | 63 | *The caller must be whitelisted and pre-send the safety deposit in a native token 64 | to a pre-computed deterministic address of the created escrow. 65 | The external postInteraction function call will be made from the Limit Order Protocol 66 | after all funds have been transferred. See [IPostInteraction-postInteraction](/lib/limit-order-protocol/contracts/mocks/InteractionMock.sol/contract.InteractionMock.md#postinteraction). 67 | `extraData` consists of: 68 | - ExtraDataImmutables struct 69 | - whitelist 70 | - 0 / 4 bytes for the fee 71 | - 1 byte for the bitmap* 72 | 73 | 74 | ```solidity 75 | function _postInteraction( 76 | IOrderMixin.Order calldata order, 77 | bytes calldata extension, 78 | bytes32 orderHash, 79 | address taker, 80 | uint256 makingAmount, 81 | uint256 takingAmount, 82 | uint256 remainingMakingAmount, 83 | bytes calldata extraData 84 | ) internal override(WhitelistExtension, ResolverFeeExtension); 85 | ``` 86 | 87 | ### createDstEscrow 88 | 89 | See [IEscrowFactory-createDstEscrow](/contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md#createdstescrow). 90 | 91 | 92 | ```solidity 93 | function createDstEscrow(IEscrow.Immutables calldata dstImmutables, uint256 srcCancellationTimestamp) external payable; 94 | ``` 95 | 96 | ### addressOfEscrowSrc 97 | 98 | See [IEscrowFactory-addressOfEscrowSrc](/contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md#addressofescrowsrc). 99 | 100 | 101 | ```solidity 102 | function addressOfEscrowSrc(IEscrow.Immutables calldata immutables) external view returns (address); 103 | ``` 104 | 105 | ### addressOfEscrowDst 106 | 107 | See [IEscrowFactory-addressOfEscrowDst](/contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md#addressofescrowdst). 108 | 109 | 110 | ```solidity 111 | function addressOfEscrowDst(IEscrow.Immutables calldata immutables) external view returns (address); 112 | ``` 113 | 114 | -------------------------------------------------------------------------------- /documentation/src/contracts/EscrowSrc.sol/contract.EscrowSrc.md: -------------------------------------------------------------------------------- 1 | # EscrowSrc 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/953335457652894d3aa7caf6353d8c55f2e2a675/contracts/EscrowSrc.sol) 3 | 4 | **Inherits:** 5 | [Escrow](/contracts/Escrow.sol/abstract.Escrow.md), [IEscrowSrc](/contracts/interfaces/IEscrowSrc.sol/interface.IEscrowSrc.md) 6 | 7 | Contract to initially lock funds and then unlock them with verification of the secret presented. 8 | 9 | *Funds are locked in at the time of contract deployment. For this Limit Order Protocol 10 | calls the `EscrowFactory.postInteraction` function. 11 | To perform any action, the caller must provide the same Immutables values used to deploy the clone contract.* 12 | 13 | 14 | ## Functions 15 | ### constructor 16 | 17 | 18 | ```solidity 19 | constructor(uint32 rescueDelay) Escrow(rescueDelay); 20 | ``` 21 | 22 | ### withdraw 23 | 24 | See [IEscrow-withdraw](/contracts/EscrowDst.sol/contract.EscrowDst.md#withdraw). 25 | 26 | *The function works on the time interval highlighted with capital letters: 27 | ---- contract deployed --/-- finality --/-- PRIVATE WITHDRAWAL --/-- private cancellation --/-- public cancellation ----* 28 | 29 | 30 | ```solidity 31 | function withdraw(bytes32 secret, Immutables calldata immutables) external onlyValidImmutables(immutables); 32 | ``` 33 | 34 | ### withdrawTo 35 | 36 | See [IEscrowSrc-withdrawTo](/contracts/interfaces/IEscrowSrc.sol/interface.IEscrowSrc.md#withdrawto). 37 | 38 | *The function works on the time interval highlighted with capital letters: 39 | ---- contract deployed --/-- finality --/-- PRIVATE WITHDRAWAL --/-- private cancellation --/-- public cancellation ----* 40 | 41 | 42 | ```solidity 43 | function withdrawTo(bytes32 secret, address target, Immutables calldata immutables) external onlyValidImmutables(immutables); 44 | ``` 45 | 46 | ### cancel 47 | 48 | See [IEscrow-cancel](/contracts/EscrowDst.sol/contract.EscrowDst.md#cancel). 49 | 50 | *The function works on the time intervals highlighted with capital letters: 51 | ---- contract deployed --/-- finality --/-- private withdrawal --/-- PRIVATE CANCELLATION --/-- PUBLIC CANCELLATION ----* 52 | 53 | 54 | ```solidity 55 | function cancel(Immutables calldata immutables) external onlyValidImmutables(immutables); 56 | ``` 57 | 58 | ### _withdrawTo 59 | 60 | 61 | ```solidity 62 | function _withdrawTo(bytes32 secret, address target, Immutables calldata immutables) internal; 63 | ``` 64 | 65 | -------------------------------------------------------------------------------- /documentation/src/contracts/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Contents 4 | - [interfaces](/contracts/interfaces) 5 | - [libraries](/contracts/libraries) 6 | - [mocks](/contracts/mocks) 7 | - [Escrow](Escrow.sol/abstract.Escrow.md) 8 | - [EscrowDst](EscrowDst.sol/contract.EscrowDst.md) 9 | - [EscrowFactory](EscrowFactory.sol/contract.EscrowFactory.md) 10 | - [EscrowSrc](EscrowSrc.sol/contract.EscrowSrc.md) 11 | -------------------------------------------------------------------------------- /documentation/src/contracts/interfaces/IEscrow.sol/interface.IEscrow.md: -------------------------------------------------------------------------------- 1 | # IEscrow 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/953335457652894d3aa7caf6353d8c55f2e2a675/contracts/interfaces/IEscrow.sol) 3 | 4 | Interface implies locking funds initially and then unlocking them with verification of the secret presented. 5 | 6 | 7 | ## Functions 8 | ### RESCUE_DELAY 9 | 10 | 11 | ```solidity 12 | function RESCUE_DELAY() external view returns (uint256); 13 | ``` 14 | 15 | ### FACTORY 16 | 17 | 18 | ```solidity 19 | function FACTORY() external view returns (address); 20 | ``` 21 | 22 | ### PROXY_BYTECODE_HASH 23 | 24 | 25 | ```solidity 26 | function PROXY_BYTECODE_HASH() external view returns (bytes32); 27 | ``` 28 | 29 | ### withdraw 30 | 31 | Withdraws funds to a predetermined recipient. 32 | 33 | *Withdrawal can only be made during the withdrawal period and with secret with hash matches the hashlock. 34 | The safety deposit is sent to the caller.* 35 | 36 | 37 | ```solidity 38 | function withdraw(bytes32 secret, IEscrow.Immutables calldata immutables) external; 39 | ``` 40 | **Parameters** 41 | 42 | |Name|Type|Description| 43 | |----|----|-----------| 44 | |`secret`|`bytes32`|The secret that unlocks the escrow.| 45 | |`immutables`|`IEscrow.Immutables`|| 46 | 47 | 48 | ### cancel 49 | 50 | Cancels the escrow and returns tokens to a predetermined recipient. 51 | 52 | *The escrow can only be cancelled during the cancellation period. 53 | The safety deposit is sent to the caller.* 54 | 55 | 56 | ```solidity 57 | function cancel(IEscrow.Immutables calldata immutables) external; 58 | ``` 59 | 60 | ### rescueFunds 61 | 62 | Rescues funds from the escrow. 63 | 64 | *Funds can only be rescued by the taker after the rescue delay.* 65 | 66 | 67 | ```solidity 68 | function rescueFunds(address token, uint256 amount, IEscrow.Immutables calldata immutables) external; 69 | ``` 70 | **Parameters** 71 | 72 | |Name|Type|Description| 73 | |----|----|-----------| 74 | |`token`|`address`|The address of the token to rescue. Zero address for native token.| 75 | |`amount`|`uint256`|The amount of tokens to rescue.| 76 | |`immutables`|`IEscrow.Immutables`|| 77 | 78 | 79 | ## Errors 80 | ### InvalidCaller 81 | 82 | ```solidity 83 | error InvalidCaller(); 84 | ``` 85 | 86 | ### InvalidCancellationTime 87 | 88 | ```solidity 89 | error InvalidCancellationTime(); 90 | ``` 91 | 92 | ### InvalidImmutables 93 | 94 | ```solidity 95 | error InvalidImmutables(); 96 | ``` 97 | 98 | ### InvalidRescueTime 99 | 100 | ```solidity 101 | error InvalidRescueTime(); 102 | ``` 103 | 104 | ### InvalidSecret 105 | 106 | ```solidity 107 | error InvalidSecret(); 108 | ``` 109 | 110 | ### InvalidWithdrawalTime 111 | 112 | ```solidity 113 | error InvalidWithdrawalTime(); 114 | ``` 115 | 116 | ### NativeTokenSendingFailure 117 | 118 | ```solidity 119 | error NativeTokenSendingFailure(); 120 | ``` 121 | 122 | ## Structs 123 | ### Immutables 124 | 125 | ```solidity 126 | struct Immutables { 127 | bytes32 orderHash; 128 | bytes32 hashlock; 129 | Address maker; 130 | Address taker; 131 | Address token; 132 | uint256 amount; 133 | uint256 safetyDeposit; 134 | Timelocks timelocks; 135 | } 136 | ``` 137 | 138 | -------------------------------------------------------------------------------- /documentation/src/contracts/interfaces/IEscrowDst.sol/interface.IEscrowDst.md: -------------------------------------------------------------------------------- 1 | # IEscrowDst 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/ebb85c41907258c27b301dda207e13dd189a6048/contracts/interfaces/IEscrowDst.sol) 3 | 4 | Interface implies locking funds initially and then unlocking them with verification of the secret presented. 5 | 6 | 7 | ## Functions 8 | ### escrowImmutables 9 | 10 | Returns the immutable parameters of the escrow contract. 11 | 12 | *The immutables are stored at the end of the proxy clone contract bytecode and 13 | are added to the calldata each time the proxy clone function is called.* 14 | 15 | 16 | ```solidity 17 | function escrowImmutables() external pure returns (EscrowImmutables calldata); 18 | ``` 19 | **Returns** 20 | 21 | |Name|Type|Description| 22 | |----|----|-----------| 23 | |``|`EscrowImmutables`|The immutables of the escrow contract.| 24 | 25 | 26 | ## Structs 27 | ### EscrowImmutables 28 | Data for the order immutables. 29 | token, amount and safetyDeposit are related to the destination chain. 30 | 31 | 32 | ```solidity 33 | struct EscrowImmutables { 34 | bytes32 orderHash; 35 | bytes32 hashlock; 36 | PackedAddresses packedAddresses; 37 | uint256 amount; 38 | uint256 safetyDeposit; 39 | Timelocks timelocks; 40 | } 41 | ``` 42 | 43 | -------------------------------------------------------------------------------- /documentation/src/contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md: -------------------------------------------------------------------------------- 1 | # IEscrowFactory 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/953335457652894d3aa7caf6353d8c55f2e2a675/contracts/interfaces/IEscrowFactory.sol) 3 | 4 | Interface to deploy escrow contracts for the destination chain and to get the deterministic address of escrow on both chains. 5 | 6 | 7 | ## Functions 8 | ### createDstEscrow 9 | 10 | Creates a new escrow contract for taker on the destination chain. 11 | 12 | *The caller must send the safety deposit in the native token along with the function call 13 | and approve the destination token to be transferred to the created escrow.* 14 | 15 | 16 | ```solidity 17 | function createDstEscrow(IEscrow.Immutables calldata dstImmutables, uint256 srcCancellationTimestamp) external payable; 18 | ``` 19 | **Parameters** 20 | 21 | |Name|Type|Description| 22 | |----|----|-----------| 23 | |`dstImmutables`|`IEscrow.Immutables`|The immutables of the escrow contract that are used in deployment.| 24 | |`srcCancellationTimestamp`|`uint256`|The start of the cancellation period for the source chain.| 25 | 26 | 27 | ### addressOfEscrowSrc 28 | 29 | Returns the deterministic address of the source escrow based on the salt. 30 | 31 | 32 | ```solidity 33 | function addressOfEscrowSrc(IEscrow.Immutables calldata immutables) external view returns (address); 34 | ``` 35 | **Parameters** 36 | 37 | |Name|Type|Description| 38 | |----|----|-----------| 39 | |`immutables`|`IEscrow.Immutables`|The immutable arguments used to compute salt for escrow deployment.| 40 | 41 | **Returns** 42 | 43 | |Name|Type|Description| 44 | |----|----|-----------| 45 | |``|`address`|The computed address of the escrow.| 46 | 47 | 48 | ### addressOfEscrowDst 49 | 50 | Returns the deterministic address of the destination escrow based on the salt. 51 | 52 | 53 | ```solidity 54 | function addressOfEscrowDst(IEscrow.Immutables calldata immutables) external view returns (address); 55 | ``` 56 | **Parameters** 57 | 58 | |Name|Type|Description| 59 | |----|----|-----------| 60 | |`immutables`|`IEscrow.Immutables`|The immutable arguments used to compute salt for escrow deployment.| 61 | 62 | **Returns** 63 | 64 | |Name|Type|Description| 65 | |----|----|-----------| 66 | |``|`address`|The computed address of the escrow.| 67 | 68 | 69 | ## Events 70 | ### CrosschainSwap 71 | 72 | ```solidity 73 | event CrosschainSwap(IEscrow.Immutables srcImmutables, DstImmutablesComplement dstImmutablesComplement); 74 | ``` 75 | 76 | ## Errors 77 | ### InsufficientEscrowBalance 78 | 79 | ```solidity 80 | error InsufficientEscrowBalance(); 81 | ``` 82 | 83 | ### InvalidCreationTime 84 | 85 | ```solidity 86 | error InvalidCreationTime(); 87 | ``` 88 | 89 | ## Structs 90 | ### ExtraDataImmutables 91 | 92 | ```solidity 93 | struct ExtraDataImmutables { 94 | bytes32 hashlock; 95 | uint256 dstChainId; 96 | Address dstToken; 97 | uint256 deposits; 98 | Timelocks timelocks; 99 | } 100 | ``` 101 | 102 | ### DstImmutablesComplement 103 | 104 | ```solidity 105 | struct DstImmutablesComplement { 106 | uint256 amount; 107 | Address token; 108 | uint256 safetyDeposit; 109 | uint256 chainId; 110 | } 111 | ``` 112 | 113 | -------------------------------------------------------------------------------- /documentation/src/contracts/interfaces/IEscrowSrc.sol/interface.IEscrowSrc.md: -------------------------------------------------------------------------------- 1 | # IEscrowSrc 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/953335457652894d3aa7caf6353d8c55f2e2a675/contracts/interfaces/IEscrowSrc.sol) 3 | 4 | Interface implies locking funds initially and then unlocking them with verification of the secret presented. 5 | 6 | 7 | ## Functions 8 | ### withdrawTo 9 | 10 | Withdraws funds to a specified target. 11 | 12 | *Withdrawal can only be made during the withdrawal period and with secret with hash matches the hashlock. 13 | The safety deposit is sent to the caller.* 14 | 15 | 16 | ```solidity 17 | function withdrawTo(bytes32 secret, address target, IEscrow.Immutables calldata immutables) external; 18 | ``` 19 | **Parameters** 20 | 21 | |Name|Type|Description| 22 | |----|----|-----------| 23 | |`secret`|`bytes32`|The secret that unlocks the escrow.| 24 | |`target`|`address`|| 25 | |`immutables`|`IEscrow.Immutables`|| 26 | 27 | 28 | -------------------------------------------------------------------------------- /documentation/src/contracts/interfaces/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Contents 4 | - [IEscrow](IEscrow.sol/interface.IEscrow.md) 5 | - [IEscrowFactory](IEscrowFactory.sol/interface.IEscrowFactory.md) 6 | - [IEscrowSrc](IEscrowSrc.sol/interface.IEscrowSrc.md) 7 | -------------------------------------------------------------------------------- /documentation/src/contracts/libraries/Clones.sol/library.Clones.md: -------------------------------------------------------------------------------- 1 | # Clones 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/953335457652894d3aa7caf6353d8c55f2e2a675/contracts/libraries/Clones.sol) 3 | 4 | *https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for 5 | deploying minimal proxy contracts, also known as "clones". 6 | > To simply and cheaply clone contract functionality in an immutable way, this standard specifies 7 | > a minimal bytecode implementation that delegates all calls to a known, fixed address. 8 | The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` 9 | (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the 10 | deterministic method.* 11 | 12 | 13 | ## Functions 14 | ### cloneDeterministic 15 | 16 | *Deploys and returns the address of a clone that mimics the behaviour of `implementation`. 17 | This function uses the create2 opcode and a `salt` to deterministically deploy 18 | the clone. Using the same `implementation` and `salt` multiple time will revert, since 19 | the clones cannot be deployed twice at the same address.* 20 | 21 | 22 | ```solidity 23 | function cloneDeterministic(address implementation, bytes32 salt, uint256 value) internal returns (address instance); 24 | ``` 25 | 26 | ### computeProxyBytecodeHash 27 | 28 | 29 | ```solidity 30 | function computeProxyBytecodeHash(address implementation) internal pure returns (bytes32 bytecodeHash); 31 | ``` 32 | 33 | ## Errors 34 | ### ERC1167FailedCreateClone 35 | *A clone instance deployment failed.* 36 | 37 | 38 | ```solidity 39 | error ERC1167FailedCreateClone(); 40 | ``` 41 | 42 | -------------------------------------------------------------------------------- /documentation/src/contracts/libraries/ImmutablesLib.sol/library.ImmutablesLib.md: -------------------------------------------------------------------------------- 1 | # ImmutablesLib 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/953335457652894d3aa7caf6353d8c55f2e2a675/contracts/libraries/ImmutablesLib.sol) 3 | 4 | 5 | ## State Variables 6 | ### ESCROW_IMMUTABLES_SIZE 7 | 8 | ```solidity 9 | uint256 internal constant ESCROW_IMMUTABLES_SIZE = 0x100; 10 | ``` 11 | 12 | 13 | ## Functions 14 | ### hash 15 | 16 | 17 | ```solidity 18 | function hash(IEscrow.Immutables calldata immutables) internal pure returns (bytes32 ret); 19 | ``` 20 | 21 | ### hashMem 22 | 23 | 24 | ```solidity 25 | function hashMem(IEscrow.Immutables memory immutables) internal pure returns (bytes32 ret); 26 | ``` 27 | 28 | -------------------------------------------------------------------------------- /documentation/src/contracts/libraries/PackedAddressesLib.sol/library.PackedAddressesLib.md: -------------------------------------------------------------------------------- 1 | # PackedAddressesLib 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/ebb85c41907258c27b301dda207e13dd189a6048/contracts/libraries/PackedAddressesLib.sol) 3 | 4 | Library to pack 3 addresses into 2 uint256 values. 5 | 6 | 7 | ## Functions 8 | ### maker 9 | 10 | Returns the maker address from the packed addresses. 11 | 12 | 13 | ```solidity 14 | function maker(PackedAddresses calldata packedAddresses) internal pure returns (address); 15 | ``` 16 | **Parameters** 17 | 18 | |Name|Type|Description| 19 | |----|----|-----------| 20 | |`packedAddresses`|`PackedAddresses`|Packed addresses.| 21 | 22 | **Returns** 23 | 24 | |Name|Type|Description| 25 | |----|----|-----------| 26 | |``|`address`|The maker address.| 27 | 28 | 29 | ### taker 30 | 31 | Returns the taker address from the packed addresses. 32 | 33 | 34 | ```solidity 35 | function taker(PackedAddresses calldata packedAddresses) internal pure returns (address); 36 | ``` 37 | **Parameters** 38 | 39 | |Name|Type|Description| 40 | |----|----|-----------| 41 | |`packedAddresses`|`PackedAddresses`|Packed addresses.| 42 | 43 | **Returns** 44 | 45 | |Name|Type|Description| 46 | |----|----|-----------| 47 | |``|`address`|The taker address.| 48 | 49 | 50 | ### token 51 | 52 | Returns the taker address from the packed addresses. 53 | 54 | 55 | ```solidity 56 | function token(PackedAddresses calldata packedAddresses) internal pure returns (address); 57 | ``` 58 | **Parameters** 59 | 60 | |Name|Type|Description| 61 | |----|----|-----------| 62 | |`packedAddresses`|`PackedAddresses`|Packed addresses.| 63 | 64 | **Returns** 65 | 66 | |Name|Type|Description| 67 | |----|----|-----------| 68 | |``|`address`|The taker address.| 69 | 70 | 71 | ### _maker 72 | 73 | 74 | ```solidity 75 | function _maker(uint256 addressesPart1) internal pure returns (address); 76 | ``` 77 | 78 | ### _taker 79 | 80 | 81 | ```solidity 82 | function _taker(uint256 addressesPart1, uint256 addressesPart2) internal pure returns (address); 83 | ``` 84 | 85 | ### _token 86 | 87 | 88 | ```solidity 89 | function _token(uint256 addressesPart2) internal pure returns (address); 90 | ``` 91 | 92 | -------------------------------------------------------------------------------- /documentation/src/contracts/libraries/PackedAddressesLib.sol/struct.PackedAddresses.md: -------------------------------------------------------------------------------- 1 | # PackedAddresses 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/ebb85c41907258c27b301dda207e13dd189a6048/contracts/libraries/PackedAddressesLib.sol) 3 | 4 | 5 | ```solidity 6 | struct PackedAddresses { 7 | uint256 addressesPart1; 8 | uint256 addressesPart2; 9 | } 10 | ``` 11 | 12 | -------------------------------------------------------------------------------- /documentation/src/contracts/libraries/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Contents 4 | - [Clones](Clones.sol/library.Clones.md) 5 | - [ImmutablesLib](ImmutablesLib.sol/library.ImmutablesLib.md) 6 | - [Timelocks](TimelocksLib.sol/type.Timelocks.md) 7 | - [TimelocksLib](TimelocksLib.sol/library.TimelocksLib.md) 8 | -------------------------------------------------------------------------------- /documentation/src/contracts/libraries/TimelocksLib.sol/library.TimelocksLib.md: -------------------------------------------------------------------------------- 1 | # TimelocksLib 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/953335457652894d3aa7caf6353d8c55f2e2a675/contracts/libraries/TimelocksLib.sol) 3 | 4 | 5 | ## State Variables 6 | ### _TIMELOCK_MASK 7 | 8 | ```solidity 9 | uint256 internal constant _TIMELOCK_MASK = type(uint32).max; 10 | ``` 11 | 12 | 13 | ### _SRC_FINALITY_OFFSET 14 | 15 | ```solidity 16 | uint256 internal constant _SRC_FINALITY_OFFSET = 224; 17 | ``` 18 | 19 | 20 | ### _SRC_WITHDRAWAL_OFFSET 21 | 22 | ```solidity 23 | uint256 internal constant _SRC_WITHDRAWAL_OFFSET = 192; 24 | ``` 25 | 26 | 27 | ### _SRC_CANCELLATION_OFFSET 28 | 29 | ```solidity 30 | uint256 internal constant _SRC_CANCELLATION_OFFSET = 160; 31 | ``` 32 | 33 | 34 | ### _DST_FINALITY_OFFSET 35 | 36 | ```solidity 37 | uint256 internal constant _DST_FINALITY_OFFSET = 128; 38 | ``` 39 | 40 | 41 | ### _DST_WITHDRAWAL_OFFSET 42 | 43 | ```solidity 44 | uint256 internal constant _DST_WITHDRAWAL_OFFSET = 96; 45 | ``` 46 | 47 | 48 | ### _DST_PUB_WITHDRAWAL_OFFSET 49 | 50 | ```solidity 51 | uint256 internal constant _DST_PUB_WITHDRAWAL_OFFSET = 64; 52 | ``` 53 | 54 | 55 | ## Functions 56 | ### setDeployedAt 57 | 58 | Sets the Escrow deployment timestamp. 59 | 60 | 61 | ```solidity 62 | function setDeployedAt(Timelocks timelocks, uint256 value) internal pure returns (Timelocks); 63 | ``` 64 | **Parameters** 65 | 66 | |Name|Type|Description| 67 | |----|----|-----------| 68 | |`timelocks`|`Timelocks`|The timelocks to set the deployment timestamp to.| 69 | |`value`|`uint256`|The new Escrow deployment timestamp.| 70 | 71 | **Returns** 72 | 73 | |Name|Type|Description| 74 | |----|----|-----------| 75 | |``|`Timelocks`|The timelocks with the deployment timestamp set.| 76 | 77 | 78 | ### rescueStart 79 | 80 | Returns the start of the rescue period. 81 | 82 | 83 | ```solidity 84 | function rescueStart(Timelocks timelocks, uint256 rescueDelay) internal pure returns (uint256); 85 | ``` 86 | **Parameters** 87 | 88 | |Name|Type|Description| 89 | |----|----|-----------| 90 | |`timelocks`|`Timelocks`|The timelocks to get the rescue delay from.| 91 | |`rescueDelay`|`uint256`|| 92 | 93 | **Returns** 94 | 95 | |Name|Type|Description| 96 | |----|----|-----------| 97 | |``|`uint256`|The start of the rescue period.| 98 | 99 | 100 | ### srcWithdrawalStart 101 | 102 | Returns the start of the private withdrawal period on the source chain. 103 | 104 | 105 | ```solidity 106 | function srcWithdrawalStart(Timelocks timelocks) internal pure returns (uint256); 107 | ``` 108 | **Parameters** 109 | 110 | |Name|Type|Description| 111 | |----|----|-----------| 112 | |`timelocks`|`Timelocks`|The timelocks to get the finality duration from.| 113 | 114 | **Returns** 115 | 116 | |Name|Type|Description| 117 | |----|----|-----------| 118 | |``|`uint256`|The start of the private withdrawal period.| 119 | 120 | 121 | ### srcCancellationStart 122 | 123 | Returns the start of the private cancellation period on the source chain. 124 | 125 | 126 | ```solidity 127 | function srcCancellationStart(Timelocks timelocks) internal pure returns (uint256); 128 | ``` 129 | **Parameters** 130 | 131 | |Name|Type|Description| 132 | |----|----|-----------| 133 | |`timelocks`|`Timelocks`|The timelocks to get the private withdrawal duration from.| 134 | 135 | **Returns** 136 | 137 | |Name|Type|Description| 138 | |----|----|-----------| 139 | |``|`uint256`|The start of the private cancellation period.| 140 | 141 | 142 | ### srcPubCancellationStart 143 | 144 | Returns the start of the public cancellation period on the source chain. 145 | 146 | 147 | ```solidity 148 | function srcPubCancellationStart(Timelocks timelocks) internal pure returns (uint256); 149 | ``` 150 | **Parameters** 151 | 152 | |Name|Type|Description| 153 | |----|----|-----------| 154 | |`timelocks`|`Timelocks`|The timelocks to get the private cancellation duration from.| 155 | 156 | **Returns** 157 | 158 | |Name|Type|Description| 159 | |----|----|-----------| 160 | |``|`uint256`|The start of the public cancellation period.| 161 | 162 | 163 | ### dstWithdrawalStart 164 | 165 | Returns the start of the private withdrawal period on the destination chain. 166 | 167 | 168 | ```solidity 169 | function dstWithdrawalStart(Timelocks timelocks) internal pure returns (uint256); 170 | ``` 171 | **Parameters** 172 | 173 | |Name|Type|Description| 174 | |----|----|-----------| 175 | |`timelocks`|`Timelocks`|The timelocks to get the finality duration from.| 176 | 177 | **Returns** 178 | 179 | |Name|Type|Description| 180 | |----|----|-----------| 181 | |``|`uint256`|The start of the private withdrawal period.| 182 | 183 | 184 | ### dstPubWithdrawalStart 185 | 186 | Returns the start of the public withdrawal period on the destination chain. 187 | 188 | 189 | ```solidity 190 | function dstPubWithdrawalStart(Timelocks timelocks) internal pure returns (uint256); 191 | ``` 192 | **Parameters** 193 | 194 | |Name|Type|Description| 195 | |----|----|-----------| 196 | |`timelocks`|`Timelocks`|The timelocks to get the private withdrawal duration from.| 197 | 198 | **Returns** 199 | 200 | |Name|Type|Description| 201 | |----|----|-----------| 202 | |``|`uint256`|The start of the public withdrawal period.| 203 | 204 | 205 | ### dstCancellationStart 206 | 207 | Returns the start of the private cancellation period on the destination chain. 208 | 209 | 210 | ```solidity 211 | function dstCancellationStart(Timelocks timelocks) internal pure returns (uint256); 212 | ``` 213 | **Parameters** 214 | 215 | |Name|Type|Description| 216 | |----|----|-----------| 217 | |`timelocks`|`Timelocks`|The timelocks to get the public withdrawal duration from.| 218 | 219 | **Returns** 220 | 221 | |Name|Type|Description| 222 | |----|----|-----------| 223 | |``|`uint256`|The start of the private cancellation period.| 224 | 225 | 226 | ### _get 227 | 228 | 229 | ```solidity 230 | function _get(Timelocks timelocks, uint256 offset) private pure returns (uint256); 231 | ``` 232 | 233 | -------------------------------------------------------------------------------- /documentation/src/contracts/libraries/TimelocksLib.sol/type.Timelocks.md: -------------------------------------------------------------------------------- 1 | # Timelocks 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/953335457652894d3aa7caf6353d8c55f2e2a675/contracts/libraries/TimelocksLib.sol) 3 | 4 | *Timelocks for the source and the destination chains plus the deployment timestamp. 5 | For illustrative purposes, it is possible to describe timelocks by two structures: 6 | struct SrcTimelocks { 7 | uint256 finality; 8 | uint256 withdrawal; 9 | uint256 cancellation; 10 | } 11 | struct DstTimelocks { 12 | uint256 finality; 13 | uint256 withdrawal; 14 | uint256 publicWithdrawal; 15 | } 16 | finality: The duration of the chain finality period. 17 | withdrawal: The duration of the period when only the taker with a secret can withdraw tokens for taker (source chain) 18 | or maker (destination chain). 19 | publicWithdrawal: The duration of the period when anyone with a secret can withdraw tokens for taker (source chain) 20 | or maker (destination chain). 21 | cancellation: The duration of the period when escrow can only be cancelled by the taker.* 22 | 23 | 24 | ```solidity 25 | type Timelocks is uint256; 26 | ``` 27 | 28 | -------------------------------------------------------------------------------- /documentation/src/contracts/mocks/ERC20True.sol/contract.ERC20True.md: -------------------------------------------------------------------------------- 1 | # ERC20True 2 | [Git Source](https://github.com/1inch/cross-chain-swap/blob/953335457652894d3aa7caf6353d8c55f2e2a675/contracts/mocks/ERC20True.sol) 3 | 4 | 5 | ## Functions 6 | ### transfer 7 | 8 | 9 | ```solidity 10 | function transfer(address, uint256) public pure returns (bool); 11 | ``` 12 | 13 | ### transferFrom 14 | 15 | 16 | ```solidity 17 | function transferFrom(address, address, uint256) public pure returns (bool); 18 | ``` 19 | 20 | ### approve 21 | 22 | 23 | ```solidity 24 | function approve(address, uint256) public pure returns (bool); 25 | ``` 26 | 27 | ### balanceOf 28 | 29 | 30 | ```solidity 31 | function balanceOf(address) public pure returns (uint256); 32 | ``` 33 | 34 | ### allowance 35 | 36 | 37 | ```solidity 38 | function allowance(address, address) public pure returns (uint256); 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /documentation/src/contracts/mocks/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Contents 4 | - [ERC20True](ERC20True.sol/contract.ERC20True.md) 5 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Running create_order.sh 2 | 3 | This guide explains how to use the `create_order.sh` script to automate the deployment and management of cross-chain escrow contracts using Foundry, Anvil, and your project configuration. 4 | 5 | ## Prerequisites 6 | 7 | - [Foundry](https://book.getfoundry.sh/) installed (`anvil`, `forge`, `cast` in your PATH) 8 | - [jq](https://stedolan.github.io/jq/) installed for JSON parsing 9 | - A valid `config.json` in `examples/config/` with all required fields (see below) 10 | - .env file with envirinment variables 11 | - (Optional) A working Ethereum RPC endpoint for forking 12 | 13 | ## Environment Variables 14 | 15 | In addition to the configuration file, you must create a `.env` file in the project root with the following variables: 16 | 17 | - `DEPLOYER_PRIVATE_KEY`: Private key of the deployer account (used for contract deployment and transactions). 18 | - `MAKER_PRIVATE_KEY`: Private key of the maker account (used for order creation and signing). 19 | - `CHAIN_ID`: The chain ID to use for deployment (e.g., `31337` for local Anvil, or the target network's chain ID). 20 | - `RPC_URL`: The Ethereum RPC endpoint URL (used for forking or connecting to the network). 21 | 22 | These variables are required for the script to authenticate and interact with the blockchain. Do **not** share your private keys or commit your `.env` file to version control. 23 | 24 | ## Configuration 25 | 26 | Edit `examples/config/config.json` to set up your deployment parameters. Example: 27 | 28 | ```json 29 | { 30 | "escrowFactory": "0x...", // address of escrow factory contract 31 | "limitOrderProtocol": "0x...", // address of limit order protocol contract 32 | "deployer": "0x...", // deployer address 33 | "maker": "0x...", // maker address 34 | "srcToken": "0x...", // source chain token address 35 | "dstToken": "0x...", // destination chain token address 36 | "resolver": "0x...", // resolver address 37 | "srcAmount": 1, // source chain amount of srcToken 38 | "dstAmount": 1, // destination chain amount of dstToken 39 | "safetyDeposit": 1, // safety deposit (same for src and dst chains) 40 | "withdrawalSrcTimelock": 300, 41 | "publicWithdrawalSrcTimelock": 600, 42 | "cancellationSrcTimelock": 900, 43 | "publicCancellationSrcTimelock": 1200, 44 | "withdrawalDstTimelock": 300, 45 | "publicWithdrawalDstTimelock": 600, 46 | "cancellationDstTimelock": 900, 47 | "secret": "secret1", 48 | "stages": [ 49 | "deployMocks", // stage for deployment mock resolver, src and dst tokens (only for chainId == 31337) 50 | // Eliminate any stages from the remaining list that are not required 51 | "deployEscrowSrc", // fill order by resolver (deploy escrow contract on source chain) 52 | "deployEscrowDst", // deploy escrow on destination chain 53 | "withdrawSrc", // withdraw tokens on source chain 54 | "withdrawDst", // withdraw tokens on destination chain 55 | "cancelSrc", // cancel order on source chain 56 | "cancelDst" // cancel order on destination chain 57 | ] 58 | } 59 | ``` 60 | 61 | ## Usage 62 | 63 | 1. **Make the script executable:** 64 | ```zsh 65 | chmod +x create_order.sh 66 | ``` 67 | 68 | 2. **Run the script:** 69 | ```zsh 70 | ./create_order.sh 71 | ``` 72 | 73 | The script will: 74 | - Read your config and stages 75 | - Start Anvil with rpcUrl fork if `chainId` is 31337 76 | - Sequentially run each stage (deploy, withdraw, cancel, etc.) 77 | - For time-dependent stages, set the next block timestamp according to your config if `chainId` is 31337 78 | - Kill Anvil after all stages are complete if `chainId` is 31337 79 | 80 | ## Notes 81 | 82 | - If you use a public RPC endpoint, ensure it is reliable and not rate-limited. 83 | - You can customize the `stages` array in your config to run only specific steps. 84 | - All logs and errors will be shown in your terminal. Check `anvil.log` for Anvil output. 85 | 86 | ## Troubleshooting 87 | 88 | For more details, see the comments in `create_order.sh` or contact the project maintainers. 89 | -------------------------------------------------------------------------------- /examples/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "escrowFactory": "0xa7bCb4EAc8964306F9e3764f67Db6A7af6DdF99A", 3 | "limitOrderProtocol": "0x111111125421cA6dc452d289314280a0f8842A65", 4 | "deployer": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 5 | "maker": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", 6 | "srcToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", 7 | "dstToken": "0x0000000000000000000000000000000000000000", 8 | "resolver": "0x6c9a2f9a94770336403e69e9ea5d88c97ef3b78a", 9 | "srcAmount": 100, 10 | "dstAmount": 300, 11 | "safetyDeposit": 1, 12 | "withdrawalSrcTimelock": 300, 13 | "publicWithdrawalSrcTimelock": 600, 14 | "cancellationSrcTimelock": 900, 15 | "publicCancellationSrcTimelock": 1200, 16 | "withdrawalDstTimelock": 300, 17 | "publicWithdrawalDstTimelock": 600, 18 | "cancellationDstTimelock": 900, 19 | "secret": "secret1", 20 | "stages": [ 21 | "deployMocks", 22 | "deployEscrowSrc", 23 | "deployEscrowDst", 24 | "withdrawSrc", 25 | "withdrawDst" 26 | ] 27 | } -------------------------------------------------------------------------------- /examples/script/utils/ConfigLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { Vm } from "forge-std/Vm.sol"; 6 | 7 | struct Config { 8 | uint32 cancellationDstTimelock; 9 | uint32 cancellationSrcTimelock; 10 | address deployer; 11 | uint256 dstAmount; 12 | address dstToken; 13 | address escrowFactory; 14 | address limitOrderProtocol; 15 | address maker; 16 | uint32 publicCancellationSrcTimelock; 17 | uint32 publicWithdrawalDstTimelock; 18 | uint32 publicWithdrawalSrcTimelock; 19 | address resolver; 20 | uint256 safetyDeposit; 21 | string secret; 22 | uint256 srcAmount; 23 | address srcToken; 24 | string[] stages; 25 | uint32 withdrawalDstTimelock; 26 | uint32 withdrawalSrcTimelock; 27 | } 28 | 29 | library ConfigLib { 30 | function getConfig(Vm vm, string memory fileName) internal view returns (Config memory) { 31 | string memory json = vm.readFile(fileName); 32 | bytes memory data = vm.parseJson(json); 33 | 34 | Config memory config = abi.decode(data, (Config)); 35 | 36 | return config; 37 | } 38 | } -------------------------------------------------------------------------------- /examples/script/utils/EscrowDevOpsTools.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { ERC20 } from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; 6 | 7 | import { Timelocks } from "contracts/libraries/TimelocksLib.sol"; 8 | 9 | import { DevOpsTools } from "./DevOpsTools.sol"; 10 | import { Config } from "./ConfigLib.sol"; 11 | 12 | library EscrowDevOpsTools { 13 | error NoSrcEscrowCreatedEventFound(); 14 | error NoDstEscrowCreatedEventFound(); 15 | error NoTransferEventFoundForSrcToken(); 16 | error NoOrderFilledEventFound(); 17 | error OutOfBounds(); 18 | 19 | string public constant RELATIVE_BROADCAST_PATH = "./broadcast/CreateOrder.s.sol"; 20 | 21 | bytes32 public constant ORDER_FILLED_EVENT_SIGNATURE = 0xfec331350fce78ba658e082a71da20ac9f8d798a99b3c79681c8440cbfe77e07; 22 | bytes32 public constant TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; 23 | bytes32 public constant SRC_ESCROW_CREATED_EVENT_SIGNATURE = 0x0e534c62f0afd2fa0f0fa71198e8aa2d549f24daf2bb47de0d5486c7ce9288ca; 24 | bytes32 public constant DST_ESCROW_CREATED_EVENT_SIGNATURE = 0xc30e111dcc74fddc2c3a4d98ffb97adec4485c0a687946bf5b22c2a99c7ff96d; 25 | 26 | function getResolver(Config memory config) internal view returns(address) { 27 | if (block.chainid != 31337) { 28 | return config.resolver; 29 | } 30 | 31 | address contractAddress = DevOpsTools.getMostRecentDeployment( 32 | "ResolverExample", "", block.chainid, RELATIVE_BROADCAST_PATH); 33 | return contractAddress; 34 | } 35 | 36 | function getSrcToken(Config memory config) internal view returns(address) { 37 | return getToken(config.srcToken); 38 | } 39 | 40 | function getDstToken(Config memory config) internal view returns(address) { 41 | return getToken(config.dstToken); 42 | } 43 | 44 | function getToken(address token) internal view returns(address) { 45 | if (block.chainid != 31337 || token == address(0)) { 46 | return token; 47 | } 48 | 49 | address contractAddress = DevOpsTools.getMostRecentDeployment( 50 | "TokenCustomDecimalsMock", ERC20(token).name(), block.chainid, RELATIVE_BROADCAST_PATH); 51 | return contractAddress; 52 | } 53 | 54 | function getEscrowSrcAddressAndTimestamp(address srcToken) internal view returns(address, uint256) { 55 | DevOpsTools.Receipt memory receipt = DevOpsTools.getMostRecentLog( 56 | srcToken, 57 | TRANSFER_EVENT_SIGNATURE, 58 | block.chainid, 59 | RELATIVE_BROADCAST_PATH 60 | ); 61 | 62 | if (receipt.topics.length < 3) { 63 | revert NoTransferEventFoundForSrcToken(); 64 | } 65 | 66 | return (address(uint160(uint256(receipt.topics[2]))), receipt.timestamp); 67 | } 68 | 69 | function getOrderHashAndTimelocksFromSrcEscrowCreatedEvent(Config memory config) internal view returns(bytes32 orderHash, Timelocks) { 70 | DevOpsTools.Receipt memory receipt = DevOpsTools.getMostRecentLog( 71 | config.escrowFactory, 72 | SRC_ESCROW_CREATED_EVENT_SIGNATURE, 73 | block.chainid, 74 | RELATIVE_BROADCAST_PATH 75 | ); 76 | 77 | if (receipt.data.length < 256) { 78 | revert NoSrcEscrowCreatedEventFound(); 79 | } 80 | 81 | return (toBytes32(receipt.data, 0), Timelocks.wrap(uint256(toBytes32(receipt.data, 224)))); 82 | } 83 | 84 | function getEscrowDstAddressAndDeployTimeFromDstEscrowCreatedEvent(Config memory config) internal view returns(address, uint256) { 85 | DevOpsTools.Receipt memory receipt = DevOpsTools.getMostRecentLog( 86 | config.escrowFactory, 87 | DST_ESCROW_CREATED_EVENT_SIGNATURE, 88 | block.chainid, 89 | RELATIVE_BROADCAST_PATH 90 | ); 91 | 92 | if (receipt.data.length < 96) { 93 | revert NoDstEscrowCreatedEventFound(); 94 | } 95 | 96 | return (address(uint160(uint256(toBytes32(receipt.data, 0)))), receipt.timestamp); 97 | } 98 | 99 | function getOrderHash(Config memory config) internal view returns(bytes32) { 100 | DevOpsTools.Receipt memory receipt = DevOpsTools.getMostRecentLog( 101 | config.limitOrderProtocol, 102 | ORDER_FILLED_EVENT_SIGNATURE, 103 | block.chainid, 104 | RELATIVE_BROADCAST_PATH 105 | ); 106 | 107 | if (receipt.data.length < 32) { 108 | revert NoOrderFilledEventFound(); 109 | } 110 | 111 | return toBytes32(receipt.data, 0); 112 | } 113 | 114 | function toBytes32(bytes memory data, uint256 offset) internal pure returns (bytes32 result) { 115 | if (data.length < offset + 32) { 116 | revert OutOfBounds(); 117 | } 118 | assembly { 119 | result := mload(add(add(data, 32), offset)) 120 | } 121 | } 122 | } -------------------------------------------------------------------------------- /examples/script/utils/StringUtils.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | library StringUtils { 6 | function isEqualTo(string memory str1, string memory str2) internal pure returns (bool) { 7 | return keccak256(abi.encodePacked(str1)) == keccak256(abi.encodePacked(str2)); 8 | } 9 | 10 | function contains(string memory str, string memory substr) internal pure returns (bool) { 11 | bytes memory strBytes = bytes(str); 12 | bytes memory substrBytes = bytes(substr); 13 | if (strBytes.length < substrBytes.length || strBytes.length == 0) { 14 | return false; 15 | } 16 | 17 | for (uint256 i = 0; i <= strBytes.length - substrBytes.length; i++) { 18 | bool isEqual = true; 19 | for (uint256 j = 0; j < substrBytes.length; j++) { 20 | if (strBytes[i + j] != substrBytes[j]) { 21 | isEqual = false; 22 | break; 23 | } 24 | } 25 | if (isEqual) return true; 26 | } 27 | return false; 28 | } 29 | } -------------------------------------------------------------------------------- /examples/scripts/create_order.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | source .env 4 | 5 | CURRENT_DIR=$(dirname "$0") 6 | CONFIG_PATH="${CURRENT_DIR}/../config/config.json" 7 | SCRIPT_PATH="${CURRENT_DIR}/../script/CreateOrder.s.sol:CreateOrder" 8 | 9 | # Read config values 10 | if [[ -z "$CHAIN_ID" ]]; then 11 | CHAIN_ID=31337 12 | fi 13 | 14 | # Timelocks 15 | WITHDRAWAL_SRC_TIMELOCK=$(jq -r '.withdrawalSrcTimelock' "$CONFIG_PATH") 16 | WITHDRAWAL_DST_TIMELOCK=$(jq -r '.withdrawalDstTimelock' "$CONFIG_PATH") 17 | CANCELLATION_SRC_TIMELOCK=$(jq -r '.cancellationSrcTimelock' "$CONFIG_PATH") 18 | CANCELLATION_DST_TIMELOCK=$(jq -r '.cancellationDstTimelock' "$CONFIG_PATH") 19 | 20 | echo -n "Do you want to rebuild project? Otherwise it will rebuild automatically if necessary [y/n]: " 21 | read response 22 | if [[ "$response" == "y" || "$response" == "Y" ]]; then 23 | forge clean 24 | forge build 25 | fi 26 | 27 | # Start anvil if local 28 | if [[ "$CHAIN_ID" == "31337" ]]; then 29 | echo "Launching anvil with fork from $RPC_URL and block-time 1..." 30 | anvil --fork-url "$RPC_URL" --block-time 1 --chain-id 31337 --steps-tracing --host 127.0.0.1 --port 8545 -vvvvv > anvil.log 2>&1 & 31 | ANVIL_PID=$! 32 | sleep 15 33 | # Get anvil start timestamp 34 | ANVIL_START_TIMESTAMP=$(cast block latest --rpc-url http://localhost:8545 | grep timestamp | awk '{print $2}') 35 | echo "Anvil start timestamp: $ANVIL_START_TIMESTAMP" 36 | RPC_URL="http://localhost:8545" 37 | fi 38 | 39 | # Read stages array from config.json 40 | STAGES=($(jq -r '.stages[]' "$CONFIG_PATH")) 41 | 42 | ANVIL_DEPLOY_SRC_TIMESTAMP=$ANVIL_START_TIMESTAMP 43 | ANVIL_DEPLOY_DST_TIMESTAMP=$ANVIL_START_TIMESTAMP 44 | TIME_DELTA=5 # Time delta in seconds 45 | 46 | for STAGE in "${STAGES[@]}"; do 47 | # Set next block timestamp for time-dependent stages 48 | if [[ "$CHAIN_ID" == "31337" ]]; then 49 | case "$STAGE" in 50 | withdrawSrc) 51 | NEXT_TS=$((ANVIL_DEPLOY_SRC_TIMESTAMP + WITHDRAWAL_SRC_TIMELOCK + TIME_DELTA)) 52 | echo "Setting next block timestamp for withdrawSrc: $NEXT_TS" 53 | cast rpc anvil_setNextBlockTimestamp "$NEXT_TS" --rpc-url "$RPC_URL" 54 | ;; 55 | withdrawDst) 56 | NEXT_TS=$((ANVIL_DEPLOY_DST_TIMESTAMP + WITHDRAWAL_DST_TIMELOCK + TIME_DELTA)) 57 | echo "Setting next block timestamp for withdrawDst: $NEXT_TS" 58 | cast rpc anvil_setNextBlockTimestamp "$NEXT_TS" --rpc-url "$RPC_URL" 59 | ;; 60 | cancelSrc) 61 | NEXT_TS=$((ANVIL_DEPLOY_SRC_TIMESTAMP + CANCELLATION_SRC_TIMELOCK + TIME_DELTA)) 62 | echo "Setting next block timestamp for cancelSrc: $NEXT_TS" 63 | cast rpc anvil_setNextBlockTimestamp "$NEXT_TS" --rpc-url "$RPC_URL" 64 | ;; 65 | cancelDst) 66 | NEXT_TS=$((ANVIL_DEPLOY_DST_TIMESTAMP + CANCELLATION_DST_TIMELOCK + TIME_DELTA)) 67 | echo "Setting next block timestamp for cancelDst: $NEXT_TS" 68 | cast rpc anvil_setNextBlockTimestamp "$NEXT_TS" --rpc-url "$RPC_URL" 69 | ;; 70 | esac 71 | fi 72 | 73 | echo "=== Running stage: $STAGE ===" 74 | MODE=$STAGE forge script "$SCRIPT_PATH" --broadcast --rpc-url "$RPC_URL" 75 | 76 | case "$STAGE" in 77 | deployEscrowSrc) 78 | ANVIL_DEPLOY_SRC_TIMESTAMP=$(cast block latest --rpc-url "$RPC_URL" | grep timestamp | awk '{print $2}') 79 | echo "New anvil deploy src timestamp: $ANVIL_DEPLOY_SRC_TIMESTAMP" 80 | ;; 81 | deployEscrowDst) 82 | ANVIL_DEPLOY_DST_TIMESTAMP=$(cast block latest --rpc-url "$RPC_URL" | grep timestamp | awk '{print $2}') 83 | echo "New anvil deploy dst timestamp: $ANVIL_DEPLOY_DST_TIMESTAMP" 84 | ;; 85 | esac 86 | 87 | echo -n "Continue to the next stage? [y/n]:" 88 | read answer 89 | if [[ "$answer" == "n" || "$answer" == "N" ]]; then 90 | echo "Exiting script." 91 | break 92 | fi 93 | 94 | sleep 1 95 | done 96 | 97 | # Cleanup 98 | if [[ "$CHAIN_ID" == "31337" ]]; then 99 | echo -n "Cleanup anvil instance? [y/n]:" 100 | read answer 101 | if [[ "$answer" == "y" || "$answer" == "Y" ]]; then 102 | echo "Killing anvil..." 103 | kill $ANVIL_PID 104 | else 105 | echo "Don't forget to kill anvil manually by running 'kill $ANVIL_PID' if you want to stop it." 106 | fi 107 | fi 108 | 109 | echo "=== All stages completed ===" -------------------------------------------------------------------------------- /foundry.lock: -------------------------------------------------------------------------------- 1 | { 2 | "lib/murky": { 3 | "rev": "991e371eb1dfa9f86701869eb08ec4e98c3cc0b0" 4 | }, 5 | "lib/limit-order-settlement": { 6 | "rev": "78a5a68f4814361332e347071513b3d191a630e1" 7 | }, 8 | "lib/openzeppelin-contracts": { 9 | "rev": "6ef73e33866527291e81cf98ddd1ec8b60d7aac8" 10 | }, 11 | "lib/solidity-utils": { 12 | "rev": "94611cc4ddb6c7c55f9d20f3093074ecca5440ba" 13 | }, 14 | "lib/limit-order-protocol": { 15 | "rev": "b655e74665559450ebf3500c2149b805db8ee229" 16 | }, 17 | "lib/forge-std": { 18 | "rev": "60acb7aaadcce2d68e52986a0a66fe79f07d138f" 19 | } 20 | } -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'contracts' 3 | out = 'out' 4 | libs = ['lib'] 5 | test = 'test' 6 | optimizer_runs = 1000000 7 | via-ir = true 8 | evm_version = 'shanghai' 9 | solc_version = '0.8.23' 10 | gas_reports = ["EscrowSrc", "EscrowDst", "EscrowFactory", "MerkleStorageInvalidator"] 11 | 12 | fs_permissions = [ 13 | { access = "read", path = "./examples/config/config.json" }, 14 | { access = "read", path = "./broadcast" }, 15 | { access = "read", path = "./reports" }, 16 | ] 17 | 18 | [profile.lite.optimizer_details.yulDetails] 19 | optimizerSteps = '' 20 | 21 | [fmt] 22 | line_length = 140 23 | bracket_spacing = true 24 | multiline_func_header = 'params_first' 25 | wrap_comments = true 26 | 27 | [fuzz] 28 | runs = 1024 29 | 30 | [profile.zksync] 31 | src = 'contracts' 32 | libs = ['lib'] 33 | fallback_oz = true 34 | is_system = false 35 | mode = "3" 36 | -------------------------------------------------------------------------------- /hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RED='\033[0;31m' 4 | GREEN='\033[0;32m' 5 | NC='\033[0m' 6 | 7 | printf "Running yarn lint... \n" 8 | if yarn lint &>/dev/null; then 9 | printf "${GREEN}Solidity code is valid${NC} \n" 10 | else 11 | printf "${RED}Solidity code is invalid${NC} Please run yarn lint and fix problems \n" 12 | exit 1 13 | fi 14 | 15 | printf "Checking forge version... \n" 16 | local_version=$(forge --version | cut -w -f 3 | cut -c 2-8) 17 | remote_version=$(curl -s https://api.github.com/repos/foundry-rs/foundry/git/refs/tags | jq '.[] | select(.ref == "refs/tags/nightly") | .object.sha' | cut -c 2-8) 18 | if [ "$local_version" == "$remote_version" ]; then 19 | printf "${GREEN}Forge version is up to date${NC} \n" 20 | else 21 | printf "${RED}Forge version is outdated${NC} Please update forge to the latest version \n" 22 | printf "Local version: ${local_version} \n" 23 | printf "Remote version: ${remote_version} \n" 24 | exit 1 25 | fi 26 | 27 | printf "Running forge snapshot --diff... \n" 28 | if FOUNDRY_PROFILE=default forge snapshot --check --no-match-test "testFuzz_*" &>/dev/null; then 29 | printf "${GREEN}No gas difference${NC} \n" 30 | else 31 | printf "${RED}Gas difference${NC} Please run forge snapshot and add changes to the commit. \n" 32 | exit 1 33 | fi 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@1inch/cross-chain-swap", 3 | "version": "1.0.0", 4 | "description": "", 5 | "repository": { 6 | "type": "git", 7 | "url": "git@github.com:1inch/cross-chain-swap.git" 8 | }, 9 | "license": "MIT", 10 | "devDependencies": { 11 | "eslint": "8.56.0", 12 | "rimraf": "5.0.5", 13 | "solc": "0.8.23", 14 | "solhint": "5.0.1" 15 | }, 16 | "scripts": { 17 | "clean": "rimraf coverage && forge clean", 18 | "coverage": "mkdir -p coverage && FOUNDRY_PROFILE=default forge coverage --report lcov --ir-minimum --report-file coverage/lcov.info", 19 | "coverage:zksync": "mkdir -p coverage && FOUNDRY_PROFILE=zksync forge coverage --zksync --report lcov --ir-minimum --report-file coverage/lcov.info", 20 | "coverage:html": "bash scripts/coverage.sh", 21 | "deploy": "./scripts/deploy.sh", 22 | "doc": "forge doc --build --out documentation", 23 | "gasreport": "FOUNDRY_PROFILE=default forge test -vvv --gas-report", 24 | "lint": "solhint --max-warnings 0 \"contracts/**/*.sol\" \"test/**/*.sol\" \"script/**/*.sol\" \"examples/**/*.sol\"", 25 | "lint:fix": "solhint --max-warnings 0 \"contracts/**/*.sol\" \"test/**/*.sol\" --fix", 26 | "test": "FOUNDRY_PROFILE=default forge snapshot --no-match-test \"testFuzz_*\"", 27 | "test:lite": "FOUNDRY_PROFILE=lite forge test -vvv", 28 | "test:zksync": "FOUNDRY_PROFILE=zksync forge test -vvv --zksync --force" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /release.md: -------------------------------------------------------------------------------- 1 | # Changes from Version 1.0.0 to 1.1.0 2 | 3 | Based on my analysis of the git history and file changes, here's a comprehensive overview of what's new in the cross-chain swap project since version 1.0.0: 4 | 5 | ## Major Features and Enhancements 6 | 7 | ### 1. Settlement Extension with Fee Support (PR #131) 8 | 9 | - **Fee Structure Implementation**: Added comprehensive fee support with integrator fees, protocol fees, and resolver fees 10 | - **SimpleSettlement Integration**: Replaced `ResolverValidationExtension` with `SimpleSettlement` from limit-order-settlement 11 | - **Fee Recipients**: Added support for integrator and protocol fee recipients in the extraData structure 12 | - **Whitelist Discount**: Implemented whitelist discount numerator for fee calculations 13 | 14 | ### 2. Demo Script and Examples 15 | 16 | - **Complete Lifecycle Demo**: Added comprehensive demo script showing the full cross-chain swap lifecycle 17 | - **Automated Testing**: Created `create_order.sh` script for automated deployment and testing 18 | - **Configuration Management**: Moved sensitive parameters (private keys, RPC URLs) from config.json to .env file 19 | - **Stage-based Execution**: Supports configurable stages including deployment, withdrawal, and cancellation 20 | 21 | ### 3. Gas Optimizations 22 | 23 | - **Assembly Optimization**: Implemented assembly code for hash computation, improving gas efficiency by ~500 gas (median) 24 | - **Immutables Library Enhancement**: Optimized the ImmutablesLib contract for better performance 25 | 26 | ### 4. Testing Enhancements 27 | 28 | - **Taking Amount Tests**: Added tests to verify orders with taking amount set (PR #133) 29 | - **Fee Calculation Tests**: New test suite for fee calculations 30 | - **Escrow Cancel Tests**: Separated cancel functionality tests into dedicated test file 31 | - **Integration Tests**: Expanded integration tests for getters and rescue funds functionality 32 | 33 | ## Infrastructure and Development Experience 34 | 35 | ### 1. Build Automation 36 | 37 | - **Makefile Addition**: Added comprehensive Makefile to simplify script execution 38 | - **Common Commands**: Includes targets for testing, coverage, deployment, and more 39 | 40 | ### 2. Documentation and Templates 41 | 42 | - **Pull Request Template**: Added GitHub PR template for better contribution management 43 | - **Disclaimer**: Added disclaimer for ResolverExample mock contract 44 | - **Enhanced README**: Updated with partial fills documentation 45 | 46 | ### 3. CI/CD Improvements 47 | 48 | - **Fixed CI Pipeline**: Resolved issues with the CI workflow 49 | - **Removed zkSync Coverage**: Temporarily removed coverage-zk stage due to unresolved forge issues 50 | 51 | ## Technical Changes 52 | 53 | ### 1. Contract Updates 54 | 55 | - **BaseEscrowFactory**: Major refactoring to support fees and SimpleSettlement 56 | - **Escrow Contracts**: Updated to handle new fee parameters and immutable structures 57 | - **ImmutablesLib**: Reunified immutable structures and optimized with assembly 58 | 59 | ### 2. Test Refactoring 60 | 61 | - **Unit Test Split**: Separated Escrow.t.sol into focused test files (reduced from 534 to more manageable sizes) 62 | - **New Test Utilities**: Added FeeCalcLib, CustomPostInteraction, and NoReceive mocks 63 | 64 | ### 3. Dependency Updates 65 | 66 | - Updated all git submodules (forge-std, limit-order-protocol, limit-order-settlement, murky, openzeppelin-contracts, solidity-utils) 67 | -------------------------------------------------------------------------------- /remappings.txt: -------------------------------------------------------------------------------- 1 | @1inch/limit-order-protocol-contract/=lib/limit-order-protocol/ 2 | @1inch/limit-order-settlement/=lib/limit-order-settlement/ 3 | @1inch/solidity-utils/=lib/solidity-utils/ 4 | solidity-utils/=lib/solidity-utils/ 5 | limit-order-protocol/=lib/limit-order-protocol/ 6 | limit-order-settlement/=lib/limit-order-settlement/ 7 | -------------------------------------------------------------------------------- /script/DeployEscrowFactory.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { Script } from "forge-std/Script.sol"; 6 | 7 | import { ICreate3Deployer } from "solidity-utils/contracts/interfaces/ICreate3Deployer.sol"; 8 | 9 | import { EscrowFactory } from "contracts/EscrowFactory.sol"; 10 | 11 | // solhint-disable no-console 12 | import { console } from "forge-std/console.sol"; 13 | 14 | contract DeployEscrowFactory is Script { 15 | uint32 public constant RESCUE_DELAY = 691200; // 8 days 16 | bytes32 public constant CROSSCHAIN_SALT = keccak256("1inch EscrowFactory"); 17 | 18 | address public constant LOP = 0x111111125421cA6dc452d289314280a0f8842A65; // All chains 19 | address public constant ACCESS_TOKEN = 0xACCe550000159e70908C0499a1119D04e7039C28; // All chains 20 | ICreate3Deployer public constant CREATE3_DEPLOYER = ICreate3Deployer(0x65B3Db8bAeF0215A1F9B14c506D2a3078b2C84AE); // All chains 21 | 22 | function run() external { 23 | address deployer = vm.envAddress("DEPLOYER_ADDRESS"); 24 | address owner = deployer; 25 | 26 | vm.startBroadcast(); 27 | address escrowFactory = CREATE3_DEPLOYER.deploy( 28 | CROSSCHAIN_SALT, 29 | abi.encodePacked( 30 | type(EscrowFactory).creationCode, 31 | abi.encode(LOP, ACCESS_TOKEN, owner, RESCUE_DELAY, RESCUE_DELAY) 32 | ) 33 | ); 34 | vm.stopBroadcast(); 35 | 36 | console.log("Escrow Factory deployed at: ", escrowFactory); 37 | } 38 | } 39 | // solhint-enable no-console 40 | -------------------------------------------------------------------------------- /script/DeployEscrowFactoryZkSync.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { Script } from "forge-std/Script.sol"; 6 | import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; 7 | 8 | import { EscrowFactoryZkSync } from "contracts/zkSync/EscrowFactoryZkSync.sol"; 9 | 10 | // solhint-disable no-console 11 | import { console } from "forge-std/console.sol"; 12 | 13 | contract DeployEscrowFactoryZkSync is Script { 14 | uint32 public constant RESCUE_DELAY = 691200; // 8 days 15 | address public constant LOP = 0x6fd4383cB451173D5f9304F041C7BCBf27d561fF; 16 | IERC20 public constant ACCESS_TOKEN = IERC20(0xC2c4fE863EC835D7DdbFE91Fe33cf1C7Df45Fa7C); 17 | 18 | function run() external { 19 | address deployer = vm.envAddress("DEPLOYER_ADDRESS"); 20 | address owner = deployer; 21 | 22 | vm.startBroadcast(); 23 | EscrowFactoryZkSync escrowFactory = new EscrowFactoryZkSync( 24 | LOP, 25 | ACCESS_TOKEN, 26 | owner, 27 | RESCUE_DELAY, 28 | RESCUE_DELAY 29 | ); 30 | vm.stopBroadcast(); 31 | 32 | console.log("Escrow Factory deployed at: ", address(escrowFactory)); 33 | } 34 | } 35 | // solhint-enable no-console 36 | -------------------------------------------------------------------------------- /script/txn_example/CancelDst.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { Script } from "forge-std/Script.sol"; 6 | import { Address } from "solidity-utils/contracts/libraries/AddressLib.sol"; 7 | 8 | import { IBaseEscrow } from "contracts/interfaces/IBaseEscrow.sol"; 9 | import { IResolverExample } from "contracts/interfaces/IResolverExample.sol"; 10 | import { Timelocks, TimelocksLib } from "contracts/libraries/TimelocksLib.sol"; 11 | 12 | import { FeeCalcLib } from "test/utils/libraries/FeeCalcLib.sol"; 13 | 14 | contract CancelDst is Script { 15 | function run() external { 16 | address deployer = vm.envAddress("DEPLOYER_ADDRESS"); 17 | uint256 deployerPK = vm.envUint("DEPLOYER_PRIVATE_KEY"); 18 | IResolverExample resolver = IResolverExample(vm.envAddress("RESOLVER")); 19 | address dstToken = address(0); // ETH 20 | bytes32 orderHash = vm.envBytes32("ORDER_HASH"); 21 | Timelocks timelocks = Timelocks.wrap(vm.envUint("TIMELOCKS")); 22 | uint256 deployedAt = vm.envUint("DEPLOYED_AT"); 23 | address protocolFeeRecipient = vm.envAddress("PROTOCOL_FEE_RECIPIENT"); 24 | address integratorFeeRecipient = vm.envAddress("INTEGRATOR_FEE_RECIPIENT"); 25 | uint256 protocolFee = vm.envUint("PROTOCOL_FEE"); 26 | uint256 integratorFee = vm.envUint("INTEGRATOR_FEE"); 27 | uint256 integratorShare = vm.envUint("INTEGRATOR_SHARE"); 28 | 29 | timelocks = TimelocksLib.setDeployedAt(timelocks, deployedAt); 30 | bytes32 secret = keccak256(abi.encodePacked("secret")); 31 | bytes32 hashlock = keccak256(abi.encode(secret)); 32 | uint256 dstAmount = 1; // 1 USDC 33 | uint256 safetyDeposit = 1; 34 | 35 | (uint256 integratorFeeAmount, uint256 protocolFeeAmount) = FeeCalcLib.getFeeAmounts( 36 | dstAmount, 37 | protocolFee, 38 | integratorFee, 39 | integratorShare 40 | ); 41 | 42 | IBaseEscrow.Immutables memory immutables = IBaseEscrow.Immutables({ 43 | orderHash: orderHash, 44 | amount: dstAmount, 45 | maker: Address.wrap(uint160(deployer)), 46 | taker: Address.wrap(uint160(address(resolver))), 47 | token: Address.wrap(uint160(dstToken)), 48 | hashlock: hashlock, 49 | safetyDeposit: safetyDeposit, 50 | timelocks: timelocks, 51 | parameters: abi.encode( 52 | protocolFeeAmount, 53 | integratorFeeAmount, 54 | Address.wrap(uint160(protocolFeeRecipient)), 55 | Address.wrap(uint160(integratorFeeRecipient)) 56 | ) 57 | }); 58 | 59 | address escrow = vm.envAddress("ESCROW_DST"); 60 | // address escrow = IEscrowFactory(escrowFactory).addressOfEscrowDst(immutables); 61 | 62 | address[] memory targets = new address[](1); 63 | bytes[] memory data = new bytes[](1); 64 | targets[0] = escrow; 65 | data[0] = abi.encodeWithSelector(IBaseEscrow(escrow).cancel.selector, immutables); 66 | 67 | vm.startBroadcast(deployerPK); 68 | resolver.arbitraryCalls(targets, data); 69 | vm.stopBroadcast(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /script/txn_example/CancelSrc.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { Script } from "forge-std/Script.sol"; 6 | import { Address } from "solidity-utils/contracts/libraries/AddressLib.sol"; 7 | 8 | import { IBaseEscrow } from "contracts/interfaces/IBaseEscrow.sol"; 9 | import { IEscrowFactory } from "contracts/interfaces/IEscrowFactory.sol"; 10 | import { IResolverExample } from "contracts/interfaces/IResolverExample.sol"; 11 | import { Timelocks, TimelocksLib } from "contracts/libraries/TimelocksLib.sol"; 12 | 13 | 14 | contract CancelSrc is Script { 15 | function run() external { 16 | address deployer = vm.envAddress("DEPLOYER_ADDRESS"); 17 | uint256 deployerPK = vm.envUint("DEPLOYER_PRIVATE_KEY"); 18 | IResolverExample resolver = IResolverExample(vm.envAddress("RESOLVER")); 19 | address escrowFactory = vm.envAddress("ESCROW_FACTORY"); 20 | address srcToken = vm.envAddress("TOKEN_SRC"); 21 | bytes32 orderHash = vm.envBytes32("ORDER_HASH"); 22 | Timelocks timelocks = Timelocks.wrap(vm.envUint("TIMELOCKS")); 23 | uint256 deployedAt = vm.envUint("DEPLOYED_AT"); 24 | 25 | timelocks = TimelocksLib.setDeployedAt(timelocks, deployedAt); 26 | bytes32 secret = keccak256(abi.encodePacked("secret")); 27 | bytes32 hashlock = keccak256(abi.encode(secret)); 28 | uint256 srcAmount = 1; // 1 USDC 29 | uint256 safetyDeposit = 1; 30 | 31 | IBaseEscrow.Immutables memory immutables = IBaseEscrow.Immutables({ 32 | orderHash: orderHash, 33 | amount: srcAmount, 34 | maker: Address.wrap(uint160(deployer)), 35 | taker: Address.wrap(uint160(address(resolver))), 36 | token: Address.wrap(uint160(srcToken)), 37 | hashlock: hashlock, 38 | safetyDeposit: safetyDeposit, 39 | timelocks: timelocks, 40 | parameters: "" // Must skip params due only EscrowDst.withdraw() using it. 41 | }); 42 | 43 | // address escrow = vm.envAddress("ESCROW_SRC"); 44 | address escrow = IEscrowFactory(escrowFactory).addressOfEscrowSrc(immutables); 45 | 46 | address[] memory targets = new address[](1); 47 | bytes[] memory data = new bytes[](1); 48 | targets[0] = escrow; 49 | data[0] = abi.encodeWithSelector(IBaseEscrow(escrow).cancel.selector, immutables); 50 | 51 | vm.startBroadcast(deployerPK); 52 | resolver.arbitraryCalls(targets, data); 53 | vm.stopBroadcast(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /script/txn_example/DeployEscrowDst.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { Script } from "forge-std/Script.sol"; 6 | 7 | import { Timelocks } from "contracts/libraries/TimelocksLib.sol"; 8 | import { IBaseEscrow } from "contracts/interfaces/IBaseEscrow.sol"; 9 | import { IResolverExample } from "contracts/interfaces/IResolverExample.sol"; 10 | 11 | import { FeeCalcLib } from "test/utils/libraries/FeeCalcLib.sol"; 12 | 13 | import { CrossChainTestLib } from "test/utils/libraries/CrossChainTestLib.sol"; 14 | 15 | contract DeployEscrowDst is Script { 16 | function run() external { 17 | address deployer = vm.envAddress("DEPLOYER_ADDRESS"); 18 | uint256 deployerPK = vm.envUint("DEPLOYER_PRIVATE_KEY"); 19 | IResolverExample resolver = IResolverExample(vm.envAddress("RESOLVER")); 20 | bytes32 orderHash = vm.envBytes32("ORDER_HASH"); 21 | Timelocks timelocks = Timelocks.wrap(vm.envUint("TIMELOCKS")); 22 | address protocolFeeRecipient = vm.envAddress("PROTOCOL_FEE_RECIPIENT"); 23 | address integratorFeeRecipient = vm.envAddress("INTEGRATOR_FEE_RECIPIENT"); 24 | uint256 protocolFee = vm.envUint("PROTOCOL_FEE"); 25 | uint256 integratorFee = vm.envUint("INTEGRATOR_FEE"); 26 | uint256 integratorShare = vm.envUint("INTEGRATOR_SHARE"); 27 | 28 | // Prepare data to deploy escrow 29 | address maker = deployer; 30 | address dstToken = address(0); // ETH 31 | uint256 dstAmount = 1; // ETH 32 | uint256 safetyDeposit = 1; 33 | bytes32 secret = keccak256(abi.encodePacked("secret")); 34 | bytes32 hashlock = keccak256(abi.encode(secret)); 35 | 36 | (uint256 integratorFeeAmount, uint256 protocolFeeAmount) = FeeCalcLib.getFeeAmounts( 37 | dstAmount, 38 | protocolFee, 39 | integratorFee, 40 | integratorShare 41 | ); 42 | 43 | IBaseEscrow.Immutables memory escrowImmutables = CrossChainTestLib.buildDstEscrowImmutables( 44 | orderHash, 45 | hashlock, 46 | dstAmount, 47 | maker, 48 | address(resolver), 49 | dstToken, 50 | safetyDeposit, 51 | timelocks, 52 | protocolFeeRecipient, 53 | integratorFeeRecipient, 54 | protocolFeeAmount, 55 | integratorFeeAmount 56 | ); 57 | 58 | uint256 srcCancellationTimestamp = type(uint32).max; 59 | 60 | { 61 | vm.startBroadcast(deployerPK); 62 | resolver.deployDst{ value: dstAmount + safetyDeposit }( 63 | escrowImmutables, 64 | srcCancellationTimestamp 65 | ); 66 | vm.stopBroadcast(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /script/txn_example/WithdrawDst.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { Script } from "forge-std/Script.sol"; 6 | import { Address } from "solidity-utils/contracts/libraries/AddressLib.sol"; 7 | 8 | import { IBaseEscrow } from "contracts/interfaces/IBaseEscrow.sol"; 9 | import { IResolverExample } from "contracts/interfaces/IResolverExample.sol"; 10 | import { Timelocks, TimelocksLib } from "contracts/libraries/TimelocksLib.sol"; 11 | 12 | import { FeeCalcLib } from "test/utils/libraries/FeeCalcLib.sol"; 13 | 14 | contract WithdrawDst is Script { 15 | function run() external { 16 | address deployer = vm.envAddress("DEPLOYER_ADDRESS"); 17 | uint256 deployerPK = vm.envUint("DEPLOYER_PRIVATE_KEY"); 18 | IResolverExample resolver = IResolverExample(vm.envAddress("RESOLVER")); 19 | address dstToken = address(0); // ETH 20 | bytes32 orderHash = vm.envBytes32("ORDER_HASH"); 21 | Timelocks timelocks = Timelocks.wrap(vm.envUint("TIMELOCKS")); 22 | uint256 deployedAt = vm.envUint("DEPLOYED_AT"); 23 | address protocolFeeRecipient = vm.envAddress("PROTOCOL_FEE_RECIPIENT"); 24 | address integratorFeeRecipient = vm.envAddress("INTEGRATOR_FEE_RECIPIENT"); 25 | uint256 protocolFee = vm.envUint("PROTOCOL_FEE"); 26 | uint256 integratorFee = vm.envUint("INTEGRATOR_FEE"); 27 | uint256 integratorShare = vm.envUint("INTEGRATOR_SHARE"); 28 | 29 | timelocks = TimelocksLib.setDeployedAt(timelocks, deployedAt); 30 | bytes32 secret = keccak256(abi.encodePacked("secret")); 31 | bytes32 hashlock = keccak256(abi.encode(secret)); 32 | uint256 dstAmount = 1; // 1 USDC 33 | uint256 safetyDeposit = 1; 34 | 35 | (uint256 integratorFeeAmount, uint256 protocolFeeAmount) = FeeCalcLib.getFeeAmounts( 36 | dstAmount, 37 | protocolFee, 38 | integratorFee, 39 | integratorShare 40 | ); 41 | 42 | IBaseEscrow.Immutables memory immutables = IBaseEscrow.Immutables({ 43 | orderHash: orderHash, 44 | amount: dstAmount, 45 | maker: Address.wrap(uint160(deployer)), 46 | taker: Address.wrap(uint160(address(resolver))), 47 | token: Address.wrap(uint160(dstToken)), 48 | hashlock: hashlock, 49 | safetyDeposit: safetyDeposit, 50 | timelocks: timelocks, 51 | parameters: abi.encode( 52 | protocolFeeAmount, 53 | integratorFeeAmount, 54 | Address.wrap(uint160(protocolFeeRecipient)), 55 | Address.wrap(uint160(integratorFeeRecipient)) 56 | ) 57 | }); 58 | 59 | address escrow = vm.envAddress("ESCROW_DST"); 60 | // address escrow = IEscrowFactory(escrowFactory).addressOfEscrowDst(immutables); 61 | 62 | address[] memory targets = new address[](1); 63 | bytes[] memory data = new bytes[](1); 64 | targets[0] = escrow; 65 | data[0] = abi.encodeWithSelector(IBaseEscrow(escrow).withdraw.selector, secret, immutables); 66 | 67 | vm.startBroadcast(deployerPK); 68 | // IBaseEscrow(escrow).withdraw(secret, immutables); 69 | resolver.arbitraryCalls(targets, data); 70 | vm.stopBroadcast(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /script/txn_example/WithdrawSrc.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { Script } from "forge-std/Script.sol"; 6 | import { Address } from "solidity-utils/contracts/libraries/AddressLib.sol"; 7 | 8 | import { IBaseEscrow } from "contracts/interfaces/IBaseEscrow.sol"; 9 | import { IEscrowFactory } from "contracts/interfaces/IEscrowFactory.sol"; 10 | import { IResolverExample } from "contracts/interfaces/IResolverExample.sol"; 11 | import { Timelocks, TimelocksLib } from "contracts/libraries/TimelocksLib.sol"; 12 | 13 | contract WithdrawSrc is Script { 14 | function run() external { 15 | address deployer = vm.envAddress("DEPLOYER_ADDRESS"); 16 | uint256 deployerPK = vm.envUint("DEPLOYER_PRIVATE_KEY"); 17 | IResolverExample resolver = IResolverExample(vm.envAddress("RESOLVER")); 18 | address escrowFactory = vm.envAddress("ESCROW_FACTORY"); 19 | address srcToken = vm.envAddress("TOKEN_SRC"); 20 | bytes32 orderHash = vm.envBytes32("ORDER_HASH"); 21 | Timelocks timelocks = Timelocks.wrap(vm.envUint("TIMELOCKS")); 22 | uint256 deployedAt = vm.envUint("DEPLOYED_AT"); 23 | 24 | timelocks = TimelocksLib.setDeployedAt(timelocks, deployedAt); 25 | bytes32 secret = keccak256(abi.encodePacked("secret")); 26 | bytes32 hashlock = keccak256(abi.encode(secret)); 27 | uint256 srcAmount = 1; // 1 USDC 28 | uint256 safetyDeposit = 1; 29 | 30 | IBaseEscrow.Immutables memory immutables = IBaseEscrow.Immutables({ 31 | orderHash: orderHash, 32 | amount: srcAmount, 33 | maker: Address.wrap(uint160(deployer)), 34 | taker: Address.wrap(uint160(address(resolver))), 35 | token: Address.wrap(uint160(srcToken)), 36 | hashlock: hashlock, 37 | safetyDeposit: safetyDeposit, 38 | timelocks: timelocks, 39 | parameters: "" // Must skip params due only EscrowDst.withdraw() using it. 40 | }); 41 | 42 | address escrow = IEscrowFactory(escrowFactory).addressOfEscrowSrc(immutables); 43 | 44 | address[] memory targets = new address[](1); 45 | bytes[] memory data = new bytes[](1); 46 | targets[0] = escrow; 47 | data[0] = abi.encodeWithSelector(IBaseEscrow(escrow).withdraw.selector, secret, immutables); 48 | 49 | vm.startBroadcast(deployerPK); 50 | // IBaseEscrow(escrow).withdraw(secret, immutables); 51 | resolver.arbitraryCalls(targets, data); 52 | vm.stopBroadcast(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/coverage.sh: -------------------------------------------------------------------------------- 1 | set -e # exit on error 2 | 3 | mkdir -p coverage 4 | 5 | # generates lcov.info 6 | forge coverage --report lcov --ir-minimum --report-file coverage/lcov.info 7 | 8 | # Filter out node_modules, test, and mock files 9 | lcov \ 10 | --rc branch_coverage=1 \ 11 | --remove coverage/lcov.info \ 12 | --output-file coverage/filtered-lcov.info \ 13 | "*test*" "contracts/mocks/*" 14 | 15 | # Generate summary 16 | lcov \ 17 | --rc branch_coverage=1 \ 18 | --list coverage/filtered-lcov.info 19 | 20 | # Generate html report 21 | if [ "$CI" != "true" ] 22 | then 23 | genhtml \ 24 | --rc branch_coverage=1 \ 25 | --keep-going \ 26 | --output-directory coverage \ 27 | coverage/filtered-lcov.info 28 | fi 29 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | set -e # exit on error 4 | 5 | # Source the .env file to load the variables 6 | if [ -f .env ]; then 7 | source .env 8 | else 9 | echo "Error: .env file not found" 10 | exit 1 11 | fi 12 | 13 | # Define the chain configurations 14 | typeset -A chains 15 | chains["mainnet"]="$MAINNET_RPC_URL" 16 | chains["bsc"]="$BSC_RPC_URL" 17 | chains["polygon"]="$POLYGON_RPC_URL" 18 | chains["avalanche"]="$AVALANCHE_RPC_URL" 19 | chains["gnosis"]="$GNOSIS_RPC_URL" 20 | chains["arbitrum"]="$ARBITRUM_RPC_URL" 21 | chains["optimism"]="$OPTIMISM_RPC_URL" 22 | chains["base"]="$BASE_RPC_URL" 23 | chains["zksync"]="$ZKSYNC_RPC_URL" 24 | chains["linea"]="$LINEA_RPC_URL" 25 | chains["sonic"]="$SONIC_RPC_URL" 26 | chains["unichain"]="$UNICHAIN_RPC_URL" 27 | 28 | rpc_url="${chains["$1"]}" 29 | if [ -z "$rpc_url" ]; then 30 | echo "Chain not found" 31 | exit 1 32 | fi 33 | echo "Provided chain: $1" 34 | echo "RPC URL: $rpc_url" 35 | 36 | keystore="$HOME/.foundry/keystores/$2" 37 | echo "Keystore: $keystore" 38 | if [ -e "$keystore" ]; then 39 | echo "Keystore provided" 40 | else 41 | echo "Keystore not provided" 42 | exit 1 43 | fi 44 | 45 | if [ "$1" = "zksync" ]; then 46 | forge script script/DeployEscrowFactoryZkSync.s.sol --zksync --fork-url $rpc_url --keystore $keystore --broadcast -vvvv 47 | else 48 | forge script script/DeployEscrowFactory.s.sol --fork-url $rpc_url --keystore $keystore --broadcast -vvvv 49 | fi 50 | -------------------------------------------------------------------------------- /test/libraries/FeeCalcLib.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.23; 3 | 4 | import { IBaseEscrow } from "contracts/interfaces/IBaseEscrow.sol"; 5 | 6 | import { ImmutablesLib } from "contracts/libraries/ImmutablesLib.sol"; 7 | import { BaseSetup } from "../utils/BaseSetup.sol"; 8 | 9 | contract FeeCalcLibTest is BaseSetup { 10 | using ImmutablesLib for IBaseEscrow.Immutables; 11 | 12 | function setUp() public virtual override { 13 | BaseSetup.setUp(); 14 | } 15 | 16 | /* solhint-disable func-name-mixedcase */ 17 | function test_getFeeAmounts() public view { 18 | (IBaseEscrow.Immutables memory immutables,,) = _prepareDataDst(); 19 | 20 | assertEq(FEES_AMOUNT, immutables.integratorFeeAmount() + immutables.protocolFeeAmount()); 21 | assertEq(PROTOCOL_FEE_AMOUNT, immutables.protocolFeeAmount()); 22 | } 23 | /* solhint-enable func-name-mixedcase */ 24 | } 25 | -------------------------------------------------------------------------------- /test/libraries/TimelocksLib.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.23; 3 | 4 | import { IBaseEscrow } from "contracts/interfaces/IBaseEscrow.sol"; 5 | import { EscrowDst } from "contracts/EscrowDst.sol"; 6 | 7 | import { Timelocks } from "contracts/libraries/TimelocksLib.sol"; 8 | import { TimelocksSettersLib } from "../utils/libraries/TimelocksSettersLib.sol"; 9 | import { AddressLib, Address } from "solidity-utils/contracts/libraries/AddressLib.sol"; 10 | 11 | import { BaseSetup } from "../utils/BaseSetup.sol"; 12 | import { CrossChainTestLib } from "../utils/libraries/CrossChainTestLib.sol"; 13 | import { TimelocksLibMock } from "../utils/mocks/TimelocksLibMock.sol"; 14 | 15 | contract TimelocksLibTest is BaseSetup { 16 | using AddressLib for Address; 17 | 18 | TimelocksLibMock public timelocksLibMock; 19 | 20 | function setUp() public virtual override { 21 | BaseSetup.setUp(); 22 | timelocksLibMock = new TimelocksLibMock(); 23 | } 24 | 25 | /* solhint-disable func-name-mixedcase */ 26 | 27 | function test_getStartTimestamps() public view { 28 | uint256 timestamp = block.timestamp; 29 | Timelocks timelocksTest = TimelocksSettersLib.init( 30 | srcTimelocks.withdrawal, 31 | srcTimelocks.publicWithdrawal, 32 | srcTimelocks.cancellation, 33 | srcTimelocks.publicCancellation, 34 | dstTimelocks.withdrawal, 35 | dstTimelocks.publicWithdrawal, 36 | dstTimelocks.cancellation, 37 | uint32(timestamp) 38 | ); 39 | 40 | assertEq(timelocksLibMock.rescueStart(timelocksTest, RESCUE_DELAY), timestamp + RESCUE_DELAY); 41 | assertEq(timelocksLibMock.srcWithdrawal(timelocksTest), timestamp + srcTimelocks.withdrawal); 42 | assertEq(timelocksLibMock.srcCancellation(timelocksTest), timestamp + srcTimelocks.cancellation); 43 | assertEq(timelocksLibMock.srcPublicCancellation(timelocksTest), timestamp + srcTimelocks.publicCancellation); 44 | assertEq(timelocksLibMock.dstWithdrawal(timelocksTest), timestamp + dstTimelocks.withdrawal); 45 | assertEq(timelocksLibMock.dstPublicWithdrawal(timelocksTest), timestamp + dstTimelocks.publicWithdrawal); 46 | assertEq(timelocksLibMock.dstCancellation(timelocksTest), timestamp + dstTimelocks.cancellation); 47 | } 48 | 49 | function test_setDeployedAt() public view { 50 | uint256 timestamp = block.timestamp; 51 | assertEq(Timelocks.unwrap(timelocksLibMock.setDeployedAt(Timelocks.wrap(0), timestamp)), timestamp << 224); 52 | } 53 | 54 | function test_NoTimelocksOverflow() public { 55 | vm.warp(1710159521); // make it real, it's 0 in foundry 56 | 57 | srcTimelocks = CrossChainTestLib.SrcTimelocks({ 58 | withdrawal: 2584807817, 59 | publicWithdrawal: 2584807817, 60 | cancellation: 2584807820, 61 | publicCancellation: 62 | 2584807820 63 | }); 64 | dstTimelocks = CrossChainTestLib.DstTimelocks({ withdrawal: 2584807817, publicWithdrawal: 2584807817, cancellation: 2584807820 }); 65 | (timelocks, timelocksDst) = CrossChainTestLib.setTimelocks(srcTimelocks, dstTimelocks); 66 | 67 | (IBaseEscrow.Immutables memory immutablesDst, uint256 srcCancellationTimestamp, EscrowDst dstClone) = _prepareDataDst(); 68 | 69 | // deploy escrow 70 | vm.prank(bob.addr); 71 | escrowFactory.createDstEscrow{ value: DST_SAFETY_DEPOSIT }(immutablesDst, srcCancellationTimestamp); 72 | 73 | // withdraw 74 | vm.warp(block.timestamp + dstTimelocks.publicWithdrawal); 75 | uint256 balanceAlice = dai.balanceOf(alice.addr); 76 | accessToken.mint(alice.addr, 1); 77 | vm.startPrank(alice.addr); 78 | dstClone.publicWithdraw(SECRET, immutablesDst); 79 | assertEq(dai.balanceOf(address(dstClone)), 0); 80 | assertEq(dai.balanceOf(alice.addr), balanceAlice + TAKING_AMOUNT - FEES_AMOUNT); 81 | assertEq(dai.balanceOf(protocolFeeReceiver), PROTOCOL_FEE_AMOUNT); 82 | assertEq(dai.balanceOf(integratorFeeReceiver), FEES_AMOUNT - PROTOCOL_FEE_AMOUNT); 83 | } 84 | 85 | /* solhint-enable func-name-mixedcase */ 86 | } 87 | -------------------------------------------------------------------------------- /test/unit/MerkleStorageInvalidator.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.23; 3 | 4 | import { Merkle } from "murky/src/Merkle.sol"; 5 | 6 | import { ITakerInteraction } from "limit-order-protocol/contracts/interfaces/ITakerInteraction.sol"; 7 | 8 | import { IMerkleStorageInvalidator } from "contracts/interfaces/IMerkleStorageInvalidator.sol"; 9 | 10 | import { BaseSetup } from "../utils/BaseSetup.sol"; 11 | import { CrossChainTestLib } from "../utils/libraries/CrossChainTestLib.sol"; 12 | 13 | contract MerkleStorageInvalidatorTest is BaseSetup { 14 | 15 | Merkle public merkle; 16 | bytes32 public root; 17 | 18 | function setUp() public virtual override { 19 | merkle = new Merkle(); 20 | root = bytes32(0); 21 | BaseSetup.setUp(); 22 | } 23 | 24 | /* solhint-disable func-name-mixedcase */ 25 | 26 | function testFuzz_ValidateProof(uint256 secretsAmount, uint256 idx) public { 27 | secretsAmount = bound(secretsAmount, 2, 1000); 28 | idx = bound(idx, 0, secretsAmount - 1); 29 | bytes32[] memory hashedSecrets = new bytes32[](secretsAmount); 30 | bytes32[] memory hashedPairs = new bytes32[](secretsAmount); 31 | 32 | // Note: This is not production-ready code. Use cryptographically secure random to generate secrets. 33 | for (uint64 i = 0; i < secretsAmount; i++) { 34 | hashedSecrets[i] = keccak256(abi.encodePacked(i)); 35 | hashedPairs[i] = keccak256(abi.encodePacked(i, hashedSecrets[i])); 36 | } 37 | root = merkle.getRoot(hashedPairs); 38 | 39 | bytes32[] memory proof = merkle.getProof(hashedPairs, idx); 40 | assert(merkle.verifyProof(root, proof, hashedPairs[idx])); 41 | 42 | CrossChainTestLib.SwapData memory swapData = _prepareDataSrcHashlock(root, false, true); 43 | 44 | vm.prank(address(limitOrderProtocol)); 45 | ITakerInteraction(escrowFactory).takerInteraction( 46 | swapData.order, 47 | swapData.extension, 48 | swapData.orderHash, 49 | bob.addr, 50 | MAKING_AMOUNT, 51 | TAKING_AMOUNT, 52 | 0, 53 | abi.encode(proof, idx, hashedSecrets[idx]) 54 | ); 55 | (uint256 storedIndex, bytes32 storedLeaf) = IMerkleStorageInvalidator(escrowFactory).lastValidated( 56 | keccak256(abi.encodePacked(swapData.orderHash, uint240(uint256(root)))) 57 | ); 58 | assertEq(storedIndex, idx + 1); 59 | assertEq(storedLeaf, hashedSecrets[idx]); 60 | } 61 | 62 | function testFuzz_NoInvalidProofValidation(uint256 secretsAmount, uint256 idx) public { 63 | secretsAmount = bound(secretsAmount, 2, 1000); 64 | idx = bound(idx, 0, secretsAmount - 1); 65 | bytes32[] memory hashedSecrets = new bytes32[](secretsAmount); 66 | bytes32[] memory hashedPairs = new bytes32[](secretsAmount); 67 | 68 | // Note: This is not production-ready code. Use cryptographically secure random to generate secrets. 69 | for (uint64 i = 0; i < secretsAmount; i++) { 70 | hashedSecrets[i] = keccak256(abi.encodePacked(i)); 71 | hashedPairs[i] = keccak256(abi.encodePacked(i, hashedSecrets[i])); 72 | } 73 | root = merkle.getRoot(hashedPairs); 74 | 75 | bytes32[] memory proof = merkle.getProof(hashedPairs, idx); 76 | 77 | CrossChainTestLib.SwapData memory swapData = _prepareDataSrcHashlock(root, false, true); 78 | 79 | uint256 wrongIndex = idx + 1 < secretsAmount ? idx + 1 : idx - 1; 80 | 81 | vm.prank(address(limitOrderProtocol)); 82 | vm.expectRevert(IMerkleStorageInvalidator.InvalidProof.selector); 83 | ITakerInteraction(escrowFactory).takerInteraction( 84 | swapData.order, 85 | swapData.extension, 86 | swapData.orderHash, 87 | bob.addr, 88 | MAKING_AMOUNT, 89 | TAKING_AMOUNT, 90 | 0, 91 | abi.encode(proof, wrongIndex, hashedSecrets[wrongIndex]) 92 | ); 93 | } 94 | 95 | function test_ShortenedProofIsNotValid() public { 96 | uint256 secretsAmount = 8; 97 | uint256 idx = 0; 98 | 99 | bytes32[] memory hashedSecrets = new bytes32[](secretsAmount); 100 | bytes32[] memory hashedPairs = new bytes32[](secretsAmount); 101 | 102 | // Note: This is not production-ready code. Use cryptographically secure random to generate secrets. 103 | for (uint64 i = 0; i < secretsAmount; i++) { 104 | hashedSecrets[i] = keccak256(abi.encodePacked(i)); 105 | hashedPairs[i] = keccak256(abi.encodePacked(i, hashedSecrets[i])); 106 | } 107 | root = merkle.getRoot(hashedPairs); 108 | 109 | // Valid proof 110 | bytes32[] memory proof = merkle.getProof(hashedPairs, idx); 111 | 112 | // Calculate the intermediate node to pass as a value 113 | bytes32 firstInterNode = merkle.hashLeafPairs(hashedPairs[idx], proof[0]); 114 | 115 | (uint256 fakeIdx, bytes32 fakeSecretHash) = 116 | uint256(firstInterNode) > uint256(proof[1]) ? (uint256(proof[1]), firstInterNode) : (uint256(firstInterNode), proof[1]); 117 | 118 | bytes32[] memory shortenedProof = new bytes32[](1); 119 | shortenedProof[0] = proof[proof.length - 1]; 120 | 121 | CrossChainTestLib.SwapData memory swapData = _prepareDataSrcHashlock(root, false, true); 122 | 123 | vm.prank(address(limitOrderProtocol)); 124 | vm.expectRevert(IMerkleStorageInvalidator.InvalidProof.selector); 125 | ITakerInteraction(escrowFactory).takerInteraction( 126 | swapData.order, 127 | swapData.extension, 128 | swapData.orderHash, 129 | bob.addr, 130 | MAKING_AMOUNT, 131 | TAKING_AMOUNT, 132 | 0, 133 | abi.encode(shortenedProof, fakeIdx, fakeSecretHash) 134 | ); 135 | } 136 | 137 | /* solhint-enable func-name-mixedcase */ 138 | } 139 | -------------------------------------------------------------------------------- /test/utils/Utils.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { CommonBase } from "forge-std/Base.sol"; 6 | 7 | contract Utils is CommonBase { 8 | struct Wallet { 9 | address addr; 10 | uint256 privateKey; 11 | } 12 | 13 | /* solhint-disable private-vars-leading-underscore */ 14 | Wallet[] internal users; 15 | uint256 internal nextUser = uint256(keccak256(abi.encodePacked("user address"))); 16 | /* solhint-enable private-vars-leading-underscore */ 17 | 18 | function _getNextUserAddress() internal returns (Wallet memory) { 19 | address addr = vm.addr(nextUser); 20 | Wallet memory user = Wallet(addr, nextUser); 21 | nextUser = uint256(keccak256(abi.encodePacked(nextUser))); 22 | return user; 23 | } 24 | 25 | // create users with 100 ETH balance each 26 | function _createUsers(uint256 userNum) internal { 27 | users = new Wallet[](userNum); 28 | for (uint256 i = 0; i < userNum; i++) { 29 | Wallet memory user = _getNextUserAddress(); 30 | vm.deal(user.addr, 100 ether); 31 | users[i] = user; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/utils/libraries/FeeCalcLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.23; 4 | 5 | import { Math } from "openzeppelin-contracts/contracts/utils/math/Math.sol"; 6 | 7 | library FeeCalcLib { 8 | using Math for uint256; 9 | 10 | /// @dev Allows fees in range [1e-5, 0.65535] 11 | uint256 internal constant _BASE_1E5 = 1e5; 12 | uint256 internal constant _BASE_1E2 = 100; 13 | 14 | /** 15 | * @notice Calculates the actual integrator and protocol fee amounts from the given order parameters. 16 | * @dev Assumes: 17 | * - `integratorFee` and `protocolFee` are expressed in basis points (1e5 = 100%), 18 | * - `integratorShare` is expressed in percentage (1e2 = 100%). 19 | * 20 | * The total fee is split proportionally between the protocol and integrator, 21 | * based on the fee configuration. The integrator receives a share of their allocated fee, 22 | * and the remainder is added to the protocol's fee. 23 | * 24 | * protocolFeeAmount = protocol's portion + (1 - integratorShare) of integrator fee 25 | * integratorFeeAmount = integratorShare of integrator fee 26 | * 27 | * @param amount The order amount used to calculate fees, 28 | * @param protocolFee Protocol fee (in basis points), 29 | * @param integratorFee Integrator fee (in basis points), 30 | * @param integratorShare Share (%) of integratorFee the integrator retains. 31 | * @return integratorFeeAmount The final amount retained by the integrator. 32 | * @return protocolFeeAmount The final amount allocated to the protocol, 33 | * including its own fee and the leftover part of the integrator's fee. 34 | */ 35 | function getFeeAmounts( 36 | uint256 amount, 37 | uint256 protocolFee, 38 | uint256 integratorFee, 39 | uint256 integratorShare 40 | ) internal pure returns (uint256 integratorFeeAmount, uint256 protocolFeeAmount) { 41 | uint256 denominator = _BASE_1E5 + integratorFee + protocolFee; 42 | uint256 integratorFeeTotal = amount.mulDiv(integratorFee, denominator); 43 | integratorFeeAmount = integratorFeeTotal.mulDiv(integratorShare, _BASE_1E2); 44 | protocolFeeAmount = amount.mulDiv(protocolFee, denominator) + integratorFeeTotal - integratorFeeAmount; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/utils/libraries/TimelocksSettersLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { Timelocks, TimelocksLib } from "../../../contracts/libraries/TimelocksLib.sol"; 6 | 7 | /** 8 | * @title Library with setters for Timelocks. 9 | */ 10 | library TimelocksSettersLib { 11 | /** 12 | * @notice Initializes the timelocks. 13 | * @param srcWithdrawal Seconds between `deployedAt` and the start of the withdrawal period on the source chain. 14 | * @param srcCancellation Seconds between `deployedAt` and the start of the cancellation period on the source chain. 15 | * @param srcPublicCancellation Seconds between `deployedAt` and the start of the public cancellation period on the source chain. 16 | * @param dstWithdrawal Seconds between `deployedAt` and the start of the withdrawal period on the destination chain. 17 | * @param dstPublicWithdrawal Seconds between `deployedAt` and the start of the public withdrawal period on the destination chain. 18 | * @param dstCancellation Seconds between `deployedAt` and the start of the cancellation period on the destination chain. 19 | * @param deployedAt Deployment timestamp. 20 | * @return The initialized Timelocks. 21 | */ 22 | function init( 23 | uint32 srcWithdrawal, 24 | uint32 srcPublicWithdrawal, 25 | uint32 srcCancellation, 26 | uint32 srcPublicCancellation, 27 | uint32 dstWithdrawal, 28 | uint32 dstPublicWithdrawal, 29 | uint32 dstCancellation, 30 | uint32 deployedAt 31 | ) internal pure returns (Timelocks) { 32 | return Timelocks.wrap( 33 | (uint256(deployedAt) << 224) 34 | | (uint256(srcWithdrawal) << (uint256(TimelocksLib.Stage.SrcWithdrawal) * 32)) 35 | | (uint256(srcPublicWithdrawal) << (uint256(TimelocksLib.Stage.SrcPublicWithdrawal) * 32)) 36 | | (uint256(srcCancellation) << (uint256(TimelocksLib.Stage.SrcCancellation) * 32)) 37 | | (uint256(srcPublicCancellation) << (uint256(TimelocksLib.Stage.SrcPublicCancellation) * 32)) 38 | | (uint256(dstWithdrawal) << (uint256(TimelocksLib.Stage.DstWithdrawal) * 32)) 39 | | (uint256(dstPublicWithdrawal) << (uint256(TimelocksLib.Stage.DstPublicWithdrawal) * 32)) 40 | | (uint256(dstCancellation) << (uint256(TimelocksLib.Stage.DstCancellation) * 32)) 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/utils/mocks/CustomPostInteraction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { IOrderMixin } from "limit-order-protocol/contracts/interfaces/IOrderMixin.sol"; 6 | import { IPostInteraction } from "limit-order-protocol/contracts/interfaces/IPostInteraction.sol"; 7 | 8 | contract CustomPostInteraction is IPostInteraction { 9 | event Invoked(bytes extraData); 10 | 11 | function postInteraction( 12 | IOrderMixin.Order calldata /* order */, 13 | bytes calldata /* extension */, 14 | bytes32 /* orderHash */, 15 | address /* taker */, 16 | uint256 /* makingAmount */, 17 | uint256 /* takingAmount */, 18 | uint256 /* remainingMakingAmount */, 19 | bytes calldata extraData 20 | ) external { 21 | emit Invoked(extraData); 22 | } 23 | } -------------------------------------------------------------------------------- /test/utils/mocks/NoReceive.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | contract NoReceive { 6 | error NativeTokenCantBeReceived(); 7 | 8 | receive() external payable { 9 | revert NativeTokenCantBeReceived(); 10 | } 11 | } -------------------------------------------------------------------------------- /test/utils/mocks/ResolverReentrancy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { Ownable } from "openzeppelin-contracts/contracts/access/Ownable.sol"; 6 | 7 | import { IOrderMixin } from "limit-order-protocol/contracts/interfaces/IOrderMixin.sol"; 8 | import { TakerTraits } from "limit-order-protocol/contracts/libraries/TakerTraitsLib.sol"; 9 | 10 | import { IBaseEscrow } from "../../../contracts/interfaces/IBaseEscrow.sol"; 11 | import { IEscrowFactory } from "../../../contracts/interfaces/IEscrowFactory.sol"; 12 | import { TimelocksLib } from "../../../contracts/libraries/TimelocksLib.sol"; 13 | 14 | contract ResolverReentrancy is Ownable { 15 | uint256 private constant _ARGS_INTERACTION_LENGTH_OFFSET = 200; 16 | IEscrowFactory private immutable _FACTORY; 17 | IOrderMixin private immutable _LOP; 18 | bytes32 private _r; 19 | bytes32 private _vs; 20 | TakerTraits private _takerTraits; 21 | IBaseEscrow.Immutables private _immutables; 22 | 23 | error AccessDenied(); 24 | 25 | /// @notice Only limit order protocol can call this contract. 26 | modifier onlyLOP() { 27 | if (msg.sender != address(_LOP)) { 28 | revert AccessDenied(); 29 | } 30 | _; 31 | } 32 | 33 | constructor(IEscrowFactory factory, IOrderMixin lop, address initialOwner) Ownable(initialOwner) { 34 | _FACTORY = factory; 35 | _LOP = lop; 36 | } 37 | 38 | receive() external payable {} // solhint-disable-line no-empty-blocks 39 | 40 | /** 41 | * @notice See {IResolverExample-deploySrc}. 42 | */ 43 | function deploySrc( 44 | IBaseEscrow.Immutables calldata immutables, 45 | IOrderMixin.Order calldata order, 46 | bytes32 r, 47 | bytes32 vs, 48 | uint256 amount, 49 | TakerTraits takerTraits, 50 | bytes calldata args 51 | ) external onlyOwner { 52 | IBaseEscrow.Immutables memory immutablesMem = immutables; 53 | immutablesMem.timelocks = TimelocksLib.setDeployedAt(immutables.timelocks, block.timestamp); 54 | address computed = _FACTORY.addressOfEscrowSrc(immutablesMem); 55 | (bool success,) = address(computed).call{ value: immutablesMem.safetyDeposit }(""); 56 | if (!success) revert IBaseEscrow.NativeTokenSendingFailure(); 57 | 58 | // _ARGS_HAS_TARGET = 1 << 251 59 | takerTraits = TakerTraits.wrap(TakerTraits.unwrap(takerTraits) | uint256(1 << 251)); 60 | bytes memory argsMem = abi.encodePacked(computed, args); 61 | _immutables = immutables; 62 | _r = r; 63 | _vs = vs; 64 | _takerTraits = takerTraits; 65 | _LOP.fillOrderArgs(order, r, vs, amount, takerTraits, argsMem); 66 | } 67 | 68 | function takerInteraction( 69 | IOrderMixin.Order calldata order, 70 | bytes calldata extension, 71 | bytes32 /* orderHash */, 72 | address /* taker */, 73 | uint256 /* makingAmount */, 74 | uint256 /* takingAmount */, 75 | uint256 /* remainingMakingAmount */, 76 | bytes calldata extraData 77 | ) external onlyLOP { 78 | _immutables.amount = 1; 79 | address computed = _FACTORY.addressOfEscrowSrc(_immutables); 80 | (bool success,) = address(computed).call{ value: _immutables.safetyDeposit }(""); 81 | if (!success) revert IBaseEscrow.NativeTokenSendingFailure(); 82 | 83 | _takerTraits = TakerTraits.wrap( 84 | TakerTraits.unwrap(_takerTraits) & 85 | ~(uint256(type(uint24).max) << _ARGS_INTERACTION_LENGTH_OFFSET) | 86 | (extraData.length << _ARGS_INTERACTION_LENGTH_OFFSET) 87 | ); 88 | bytes memory argsMem = abi.encodePacked(computed, extension, extraData); 89 | _LOP.fillOrderArgs(order, _r, _vs, 1, _takerTraits, argsMem); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /test/utils/mocks/TimelocksLibMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.23; 4 | 5 | import { Timelocks, TimelocksLib } from "contracts/libraries/TimelocksLib.sol"; 6 | 7 | contract TimelocksLibMock { 8 | using TimelocksLib for Timelocks; 9 | 10 | function setDeployedAt(Timelocks timelocks, uint256 value) external pure returns (Timelocks) { 11 | return TimelocksLib.setDeployedAt(timelocks, value); 12 | } 13 | 14 | function rescueStart(Timelocks timelocks, uint256 rescueDelay) external pure returns (uint256) { 15 | return TimelocksLib.rescueStart(timelocks, rescueDelay); 16 | } 17 | 18 | function srcWithdrawal(Timelocks timelocks) external pure returns (uint256) { 19 | return timelocks.get(TimelocksLib.Stage.SrcWithdrawal); 20 | } 21 | 22 | function srcCancellation(Timelocks timelocks) external pure returns (uint256) { 23 | return timelocks.get(TimelocksLib.Stage.SrcCancellation); 24 | } 25 | 26 | function srcPublicCancellation(Timelocks timelocks) external pure returns (uint256) { 27 | return timelocks.get(TimelocksLib.Stage.SrcPublicCancellation); 28 | } 29 | 30 | function dstWithdrawal(Timelocks timelocks) external pure returns (uint256) { 31 | return timelocks.get(TimelocksLib.Stage.DstWithdrawal); 32 | } 33 | 34 | function dstPublicWithdrawal(Timelocks timelocks) external pure returns (uint256) { 35 | return timelocks.get(TimelocksLib.Stage.DstPublicWithdrawal); 36 | } 37 | 38 | function dstCancellation(Timelocks timelocks) external pure returns (uint256) { 39 | return timelocks.get(TimelocksLib.Stage.DstCancellation); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /timelocks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1inch/cross-chain-swap/faf629a3a897708942dbdeecb5c562137f5eaba7/timelocks.png --------------------------------------------------------------------------------