diff --git a/.gas-snapshot b/.gas-snapshot index cdca3a9..2991854 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,5 +1,5 @@ -EscrowFactoryTest:testFuzz_DeployCloneForMaker(bytes32,uint56,uint56) (runs: 256, μ: 318009, ~: 321353) -EscrowFactoryTest:testFuzz_DeployCloneForTaker(bytes32,uint56) (runs: 256, μ: 244285, ~: 247826) +EscrowFactoryTest:testFuzz_DeployCloneForMaker(bytes32,uint56,uint56) (runs: 256, μ: 317514, ~: 321353) +EscrowFactoryTest:testFuzz_DeployCloneForTaker(bytes32,uint56) (runs: 256, μ: 243672, ~: 247826) EscrowFactoryTest:test_NoDeploymentForNotResolver() (gas: 112084) EscrowFactoryTest:test_NoInsufficientBalanceDeploymentForMaker() (gas: 281570) EscrowFactoryTest:test_NoInsufficientBalanceDeploymentForTaker() (gas: 30637) @@ -14,16 +14,16 @@ EscrowTest:test_NoCancelDuringResolverUnlockDst() (gas: 237840) EscrowTest:test_NoCancelDuringUnlockSrc() (gas: 319525) EscrowTest:test_NoFailedNativeTokenTransferCancelDst() (gas: 249083) EscrowTest:test_NoFailedNativeTokenTransferCancelSrc() (gas: 335638) -EscrowTest:test_NoFailedNativeTokenTransferWithdrawalDst() (gas: 271091) -EscrowTest:test_NoFailedNativeTokenTransferWithdrawalSrc() (gas: 352888) -EscrowTest:test_NoWithdrawalByNonResolverDst() (gas: 238107) +EscrowTest:test_NoFailedNativeTokenTransferWithdrawalDst() (gas: 271094) +EscrowTest:test_NoFailedNativeTokenTransferWithdrawalSrc() (gas: 352891) +EscrowTest:test_NoWithdrawalByNonResolverDst() (gas: 238110) EscrowTest:test_NoWithdrawalDuringFinalityLockDst() (gas: 237218) EscrowTest:test_NoWithdrawalDuringFinalityLockSrc() (gas: 319286) -EscrowTest:test_NoWithdrawalWithWrongSecretDst() (gas: 238982) -EscrowTest:test_NoWithdrawalWithWrongSecretSrc() (gas: 319933) -EscrowTest:test_WithdrawByAnyoneDst() (gas: 255281) -EscrowTest:test_WithdrawByResolverDst() (gas: 255927) -EscrowTest:test_WithdrawByResolverPublicDst() (gas: 255644) -EscrowTest:test_WithdrawSrc() (gas: 336713) +EscrowTest:test_NoWithdrawalWithWrongSecretDst() (gas: 238985) +EscrowTest:test_NoWithdrawalWithWrongSecretSrc() (gas: 319936) +EscrowTest:test_WithdrawByAnyoneDst() (gas: 255284) +EscrowTest:test_WithdrawByResolverDst() (gas: 255930) +EscrowTest:test_WithdrawByResolverPublicDst() (gas: 255647) +EscrowTest:test_WithdrawSrc() (gas: 336716) IntegrationEscrowFactoryTest:testFuzz_DeployCloneForMakerInt(bytes32,uint56,uint56) (runs: 256, μ: 397861, ~: 401576) IntegrationEscrowFactoryTest:test_NoInsufficientBalanceDeploymentForMakerInt() (gas: 382262) \ No newline at end of file diff --git a/contracts/Escrow.sol b/contracts/Escrow.sol index dc7a4d9..dfcb07c 100644 --- a/contracts/Escrow.sol +++ b/contracts/Escrow.sol @@ -9,15 +9,27 @@ import { SafeERC20 } from "solidity-utils/libraries/SafeERC20.sol"; import { IEscrow } from "./interfaces/IEscrow.sol"; +/** + * @title Escrow contract for cross-chain atomic swap. + * @notice Contract to initially lock funds on both chains and then unlock with verification of the secret presented. + * @dev Funds are locked in at the time of contract deployment. On both chains this is done by calling `EscrowFactory` + * functions. On the source chain Limit Order Protocol calls the `postInteraction` function and on the destination + * chain taker calls the `createEscrow` function. + * Withdrawal and cancellation functions for the source and destination chains are implemented separately. + */ contract Escrow is Clone, IEscrow { using SafeERC20 for IERC20; + /** + * @notice See {IEscrow-withdrawSrc}. + */ function withdrawSrc(bytes32 secret) external { SrcEscrowImmutables calldata escrowImmutables = srcEscrowImmutables(); - uint256 finalityTimestamp = escrowImmutables.deployedAt + escrowImmutables.extraDataParams.srcTimelocks.finality; + uint256 finalisedTimestamp = escrowImmutables.deployedAt + escrowImmutables.extraDataParams.srcTimelocks.finality; + // Check that it's public unlock period. if ( - block.timestamp < finalityTimestamp || - block.timestamp > finalityTimestamp + escrowImmutables.extraDataParams.srcTimelocks.publicUnlock + block.timestamp < finalisedTimestamp || + block.timestamp >= finalisedTimestamp + escrowImmutables.extraDataParams.srcTimelocks.publicUnlock ) revert InvalidWithdrawalTime(); _checkSecretAndTransfer( @@ -27,18 +39,25 @@ contract Escrow is Clone, IEscrow { escrowImmutables.interactionParams.srcToken, escrowImmutables.interactionParams.srcAmount ); + + // Send the safety deposit to the caller. (bool success, ) = msg.sender.call{value: escrowImmutables.extraDataParams.srcSafetyDeposit}(""); if (!success) revert NativeTokenSendingFailure(); } + /** + * @notice See {IEscrow-cancelSrc}. + */ function cancelSrc() external { SrcEscrowImmutables calldata escrowImmutables = srcEscrowImmutables(); - uint256 finalityTimestamp = escrowImmutables.deployedAt + escrowImmutables.extraDataParams.srcTimelocks.finality; - uint256 cancellationTimestamp = finalityTimestamp + escrowImmutables.extraDataParams.srcTimelocks.publicUnlock; + uint256 finalisedTimestamp = escrowImmutables.deployedAt + escrowImmutables.extraDataParams.srcTimelocks.finality; + uint256 cancellationTimestamp = finalisedTimestamp + escrowImmutables.extraDataParams.srcTimelocks.publicUnlock; + // Check that it's cancellation period. if (block.timestamp < cancellationTimestamp) { revert InvalidCancellationTime(); } + // Check that the caller is a taker if it's the private cancellation period. if ( block.timestamp < cancellationTimestamp + escrowImmutables.extraDataParams.srcTimelocks.cancel && msg.sender != escrowImmutables.interactionParams.taker @@ -50,20 +69,27 @@ contract Escrow is Clone, IEscrow { escrowImmutables.interactionParams.maker, escrowImmutables.interactionParams.srcAmount ); + + // Send the safety deposit to the caller. (bool success, ) = msg.sender.call{value: escrowImmutables.extraDataParams.srcSafetyDeposit}(""); if (!success) revert NativeTokenSendingFailure(); } + /** + * @notice See {IEscrow-withdrawDst}. + */ function withdrawDst(bytes32 secret) external { DstEscrowImmutables calldata escrowImmutables = dstEscrowImmutables(); - uint256 finalityTimestamp = escrowImmutables.deployedAt + escrowImmutables.timelocks.finality; - uint256 unlockTimestamp = finalityTimestamp + escrowImmutables.timelocks.unlock; + uint256 finalisedTimestamp = escrowImmutables.deployedAt + escrowImmutables.timelocks.finality; + uint256 publicUnlockTimestamp = finalisedTimestamp + escrowImmutables.timelocks.unlock; + // Check that it's an unlock period. if ( - block.timestamp < finalityTimestamp || - block.timestamp > unlockTimestamp + escrowImmutables.timelocks.publicUnlock + block.timestamp < finalisedTimestamp || + block.timestamp >= publicUnlockTimestamp + escrowImmutables.timelocks.publicUnlock ) revert InvalidWithdrawalTime(); - if (block.timestamp < unlockTimestamp && msg.sender != escrowImmutables.taker) revert InvalidCaller(); + // Check that the caller is a taker if it's the private unlock period. + if (block.timestamp < publicUnlockTimestamp && msg.sender != escrowImmutables.taker) revert InvalidCaller(); _checkSecretAndTransfer( secret, @@ -72,14 +98,23 @@ contract Escrow is Clone, IEscrow { escrowImmutables.token, escrowImmutables.amount ); + + // Send the safety deposit to the caller. (bool success, ) = msg.sender.call{value: escrowImmutables.safetyDeposit}(""); if (!success) revert NativeTokenSendingFailure(); } + /** + * @notice See {IEscrow-cancelDst}. + */ function cancelDst() external { DstEscrowImmutables calldata escrowImmutables = dstEscrowImmutables(); - uint256 finalityTimestamp = escrowImmutables.deployedAt + escrowImmutables.timelocks.finality; - if (block.timestamp < finalityTimestamp + escrowImmutables.timelocks.unlock + escrowImmutables.timelocks.publicUnlock) { + uint256 finalisedTimestamp = escrowImmutables.deployedAt + escrowImmutables.timelocks.finality; + // Check that it's a cancellation period. + if ( + block.timestamp < + finalisedTimestamp + escrowImmutables.timelocks.unlock + escrowImmutables.timelocks.publicUnlock + ) { revert InvalidCancellationTime(); } @@ -88,27 +123,58 @@ contract Escrow is Clone, IEscrow { escrowImmutables.amount ); + // Send the safety deposit to the caller. (bool success, ) = msg.sender.call{value: escrowImmutables.safetyDeposit}(""); if (!success) revert NativeTokenSendingFailure(); } + /** + * @notice See {IEscrow-srcEscrowImmutables}. + */ function srcEscrowImmutables() public pure returns (SrcEscrowImmutables calldata data) { + // Get the offset of the immutable args in calldata. uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { data := offset } } + /** + * @notice See {IEscrow-dstEscrowImmutables}. + */ function dstEscrowImmutables() public pure returns (DstEscrowImmutables calldata data) { + // Get the offset of the immutable args in calldata. uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { data := offset } } + /** + * @notice Verifies the provided secret. + * @dev The secret is valid if its hash matches the hashlock. + * @param secret Provided secret to verify. + * @param hashlock Hashlock to compare with. + * @return True if the secret is valid, false otherwise. + */ function _isValidSecret(bytes32 secret, bytes32 hashlock) internal pure returns (bool) { return keccak256(abi.encode(secret)) == hashlock; } - function _checkSecretAndTransfer(bytes32 secret, bytes32 hashlock, address recipient, address token, uint256 amount) internal { + /** + * @notice Checks the secret and transfers tokens to the recipient. + * @dev The secret is valid if its hash matches the hashlock. + * @param secret Provided secret to verify. + * @param hashlock Hashlock to compare with. + * @param recipient Address to transfer tokens to. + * @param token Address of the token to transfer. + * @param amount Amount of tokens to transfer. + */ + function _checkSecretAndTransfer( + bytes32 secret, + bytes32 hashlock, + address recipient, + address token, + uint256 amount + ) internal { if (!_isValidSecret(secret, hashlock)) revert InvalidSecret(); IERC20(token).safeTransfer(recipient, amount); } diff --git a/contracts/EscrowFactory.sol b/contracts/EscrowFactory.sol index 713f714..c399415 100644 --- a/contracts/EscrowFactory.sol +++ b/contracts/EscrowFactory.sol @@ -13,11 +13,17 @@ import { ClonesWithImmutableArgs } from "clones-with-immutable-args/ClonesWithIm import { IEscrow } from "./interfaces/IEscrow.sol"; import { IEscrowFactory } from "./interfaces/IEscrowFactory.sol"; + +/** + * @title Escrow Factory contract + * @notice Contract to create escrow contracts for cross-chain atomic swap. + */ contract EscrowFactory is IEscrowFactory, SimpleSettlementExtension { using AddressLib for Address; using ClonesWithImmutableArgs for address; using SafeERC20 for IERC20; + // Address of the escrow contract implementation to clone. address public immutable IMPLEMENTATION; constructor(address implementation, address limitOrderProtocol, IERC20 token) @@ -26,7 +32,11 @@ contract EscrowFactory is IEscrowFactory, SimpleSettlementExtension { } /** - * @dev Creates a new escrow contract for maker. + * @notice Creates a new escrow contract for maker on the source chain. + * @dev The caller must be whitelisted and pre-send the safety deposit in a native token + * to a pre-computed deterministic address of the created escrow. + * The external postInteraction function call will be made from the Limit Order Protocol + * after all funds have been transferred. See {IPostInteraction-postInteraction}. */ function _postInteraction( IOrderMixin.Order calldata order, @@ -43,9 +53,10 @@ contract EscrowFactory is IEscrowFactory, SimpleSettlementExtension { bytes calldata extraDataParams = extraData[:352]; bytes calldata whitelist = extraData[352:]; - + if (!_isWhitelisted(whitelist, taker)) revert ResolverIsNotWhitelisted(); + // Prepare immutables for the escrow contract. bytes memory interactionParams = abi.encode( order.maker, taker, @@ -59,6 +70,7 @@ contract EscrowFactory is IEscrowFactory, SimpleSettlementExtension { interactionParams, extraDataParams ); + // Salt is orderHash address escrow = _createEscrow(data, orderHash, 0); uint256 safetyDeposit = abi.decode(extraDataParams, (IEscrow.ExtraDataParams)).srcSafetyDeposit; @@ -71,7 +83,7 @@ contract EscrowFactory is IEscrowFactory, SimpleSettlementExtension { } /** - * @dev Creates a new escrow contract for taker. + * @notice See {IEscrowFactory-createEscrow}. */ function createEscrow(DstEscrowImmutablesCreation calldata dstEscrowImmutables) external payable { if (msg.value < dstEscrowImmutables.safetyDeposit) revert InsufficientEscrowBalance(); @@ -104,10 +116,20 @@ contract EscrowFactory is IEscrowFactory, SimpleSettlementExtension { ); } + /** + * @notice See {IEscrowFactory-addressOfEscrow}. + */ function addressOfEscrow(bytes32 salt) public view returns (address) { return address(uint160(ClonesWithImmutableArgs.addressOfClone3(salt))); } + /** + * @notice Creates a new escrow contract with immutable arguments. + * @dev The escrow contract is a proxy clone created using the create3 pattern. + * @param data Encoded immutable args. + * @param salt The salt that influences the contract address in deterministic deployment. + * @return clone The address of the created escrow contract. + */ function _createEscrow( bytes memory data, bytes32 salt, diff --git a/contracts/interfaces/IEscrow.sol b/contracts/interfaces/IEscrow.sol index 40ecfc5..57d0c0d 100644 --- a/contracts/interfaces/IEscrow.sol +++ b/contracts/interfaces/IEscrow.sol @@ -27,6 +27,8 @@ interface IEscrow { uint256 unlock; uint256 publicUnlock; } + + // Data for the immutables from the order post interacton. struct InteractionParams { address maker; address taker; @@ -36,7 +38,9 @@ interface IEscrow { uint256 dstAmount; } + // Data for the immutables from the order extension. struct ExtraDataParams { + // Hash of the secret. bytes32 hashlock; uint256 dstChainId; address dstToken; @@ -46,14 +50,20 @@ interface IEscrow { DstTimelocks dstTimelocks; } + // Data for the source chain order immutables. struct SrcEscrowImmutables { uint256 deployedAt; InteractionParams interactionParams; ExtraDataParams extraDataParams; } + /** + * Data for the destination chain order immutables. + * chainId, token, amount and safetyDeposit relate to the destination chain. + */ struct DstEscrowImmutables { uint256 deployedAt; + // Hash of the secret. bytes32 hashlock; address maker; address taker; @@ -69,4 +79,53 @@ interface IEscrow { error InvalidSecret(); error InvalidWithdrawalTime(); error NativeTokenSendingFailure(); + + /** + * @notice Withdraws funds to the taker on the source chain. + * @dev Withdrawal can only be made during the public unlock period and with secret + * with hash matches the hashlock. + * The safety deposit is sent to the caller. + * @param secret The secret that unlocks the escrow. + */ + function withdrawSrc(bytes32 secret) external; + + /** + * @notice Cancels the escrow on the source chain and returns tokens to the maker. + * @dev The escrow can only be cancelled by taker during the private cancel period or + * by anyone during the public cancel period. + * The safety deposit is sent to the caller. + */ + function cancelSrc() external; + + /** + * @notice Withdraws funds to the maker on the destination chain. + * @dev Withdrawal can only be made by taker during the private unlock period or by anyone + * during the public unlock period. In both cases, a secret with hash matching the hashlock must be provided. + * The safety deposit is sent to the caller. + * @param secret The secret that unlocks the escrow. + */ + function withdrawDst(bytes32 secret) external; + + /** + * @notice Cancels the escrow on the destination chain and returns tokens to the taker. + * @dev The escrow can only be cancelled during the cancel period. + * The safety deposit is sent to the caller. + */ + function cancelDst() external; + + /** + * @notice Returns the immutable parameters of the escrow contract on the source chain. + * @dev The immutables are stored at the end of the proxy clone contract bytecode and + * are added to the calldata each time the proxy clone function is called. + * @return The immutables of the escrow contract. + */ + function srcEscrowImmutables() external pure returns (SrcEscrowImmutables calldata); + + /** + * @notice Returns the immutable parameters of the escrow contract on the destination chain. + * @dev The immutables are stored at the end of the proxy clone contract bytecode and + * are added to the calldata each time the proxy clone function is called. + * @return The immutables of the escrow contract. + */ + function dstEscrowImmutables() external pure returns (DstEscrowImmutables calldata); } diff --git a/contracts/interfaces/IEscrowFactory.sol b/contracts/interfaces/IEscrowFactory.sol index f903cef..c2bd87d 100644 --- a/contracts/interfaces/IEscrowFactory.sol +++ b/contracts/interfaces/IEscrowFactory.sol @@ -5,7 +5,11 @@ pragma solidity ^0.8.0; import { IEscrow } from "./IEscrow.sol"; interface IEscrowFactory { + /** + * token, amount and safetyDeposit are related to the destination chain. + */ struct DstEscrowImmutablesCreation { + // Hash of the secret. bytes32 hashlock; address maker; address taker; @@ -13,9 +17,25 @@ interface IEscrowFactory { uint256 amount; uint256 safetyDeposit; IEscrow.DstTimelocks timelocks; + // Start of the cancellation period for the source chain. uint256 srcCancellationTimestamp; } error InsufficientEscrowBalance(); error InvalidCreationTime(); + + /** + * @notice Creates a new escrow contract for taker on the destination chain. + * @dev The caller must send the safety deposit in the native token along with the function call + * and approve the destination token to be transferred to the created escrow. + * @param dstEscrowImmutables The immutables of the escrow contract that are used in deployment. + */ + function createEscrow(DstEscrowImmutablesCreation calldata dstEscrowImmutables) external payable; + + /** + * @notice Returns the deterministic address of the escrow based on the salt. + * @param salt The salt used to deploy escrow. + * @return The computed address of the escrow. + */ + function addressOfEscrow(bytes32 salt) external view returns (address); } diff --git a/documentation/book.toml b/documentation/book.toml index f9ecd21..b4d17d3 100644 --- a/documentation/book.toml +++ b/documentation/book.toml @@ -6,7 +6,7 @@ title = "" no-section-label = true additional-js = ["solidity.min.js"] additional-css = ["book.css"] -git-repository-url = "https://github.com/byshape/cross-chain-swap" +git-repository-url = "https://github.com/1inch/cross-chain-swap" [output.html.fold] enable = true diff --git a/documentation/src/contracts/Escrow.sol/contract.Escrow.md b/documentation/src/contracts/Escrow.sol/contract.Escrow.md index 637dd30..70f9c3f 100644 --- a/documentation/src/contracts/Escrow.sol/contract.Escrow.md +++ b/documentation/src/contracts/Escrow.sol/contract.Escrow.md @@ -1,13 +1,22 @@ # Escrow -[Git Source](https://github.com/byshape/cross-chain-swap/blob/c49176f8473d9a06db920990a07a4d8464dd4dd4/contracts/Escrow.sol) +[Git Source](https://github.com/1inch/cross-chain-swap/blob/f45e33f855d5dd79428a1ba540d9f8df14bbb794/contracts/Escrow.sol) **Inherits:** Clone, [IEscrow](/contracts/interfaces/IEscrow.sol/interface.IEscrow.md) +Contract to initially lock funds on both chains and then unlock with verification of the secret presented. + +*Funds are locked in at the time of contract deployment. On both chains this is done by calling `EscrowFactory` +functions. On the source chain Limit Order Protocol calls the `postInteraction` function and on the destination +chain taker calls the `createEscrow` function. +Withdrawal and cancellation functions for the source and destination chains are implemented separately.* + ## Functions ### withdrawSrc +See [IEscrow-withdrawSrc](/contracts/interfaces/IEscrow.sol/interface.IEscrow.md#withdrawsrc). + ```solidity function withdrawSrc(bytes32 secret) external; @@ -15,6 +24,8 @@ function withdrawSrc(bytes32 secret) external; ### cancelSrc +See [IEscrow-cancelSrc](/contracts/interfaces/IEscrow.sol/interface.IEscrow.md#cancelsrc). + ```solidity function cancelSrc() external; @@ -22,6 +33,8 @@ function cancelSrc() external; ### withdrawDst +See [IEscrow-withdrawDst](/contracts/interfaces/IEscrow.sol/interface.IEscrow.md#withdrawdst). + ```solidity function withdrawDst(bytes32 secret) external; @@ -29,6 +42,8 @@ function withdrawDst(bytes32 secret) external; ### cancelDst +See [IEscrow-cancelDst](/contracts/interfaces/IEscrow.sol/interface.IEscrow.md#canceldst). + ```solidity function cancelDst() external; @@ -36,30 +51,65 @@ function cancelDst() external; ### srcEscrowImmutables +See [IEscrow-srcEscrowImmutables](/contracts/interfaces/IEscrow.sol/interface.IEscrow.md#srcescrowimmutables). + ```solidity -function srcEscrowImmutables() public pure returns (SrcEscrowImmutables calldata); +function srcEscrowImmutables() public pure returns (SrcEscrowImmutables calldata data); ``` ### dstEscrowImmutables +See [IEscrow-dstEscrowImmutables](/contracts/interfaces/IEscrow.sol/interface.IEscrow.md#dstescrowimmutables). + ```solidity -function dstEscrowImmutables() public pure returns (DstEscrowImmutables calldata); +function dstEscrowImmutables() public pure returns (DstEscrowImmutables calldata data); ``` ### _isValidSecret +Verifies the provided secret. + +*The secret is valid if its hash matches the hashlock.* + ```solidity -function _isValidSecret(bytes32 secret, uint256 hashlock) internal pure returns (bool); +function _isValidSecret(bytes32 secret, bytes32 hashlock) internal pure returns (bool); ``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`secret`|`bytes32`|Provided secret to verify.| +|`hashlock`|`bytes32`|Hashlock to compare with.| + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|``|`bool`|True if the secret is valid, false otherwise.| + ### _checkSecretAndTransfer +Checks the secret and transfers tokens to the recipient. + +*The secret is valid if its hash matches the hashlock.* + ```solidity -function _checkSecretAndTransfer(bytes32 secret, uint256 hashlock, address recipient, address token, uint256 amount) +function _checkSecretAndTransfer(bytes32 secret, bytes32 hashlock, address recipient, address token, uint256 amount) internal; ``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`secret`|`bytes32`|Provided secret to verify.| +|`hashlock`|`bytes32`|Hashlock to compare with.| +|`recipient`|`address`|Address to transfer tokens to.| +|`token`|`address`|Address of the token to transfer.| +|`amount`|`uint256`|Amount of tokens to transfer.| + diff --git a/documentation/src/contracts/EscrowFactory.sol/contract.EscrowFactory.md b/documentation/src/contracts/EscrowFactory.sol/contract.EscrowFactory.md index c3e0b62..b34a818 100644 --- a/documentation/src/contracts/EscrowFactory.sol/contract.EscrowFactory.md +++ b/documentation/src/contracts/EscrowFactory.sol/contract.EscrowFactory.md @@ -1,8 +1,10 @@ # EscrowFactory -[Git Source](https://github.com/byshape/cross-chain-swap/blob/c49176f8473d9a06db920990a07a4d8464dd4dd4/contracts/EscrowFactory.sol) +[Git Source](https://github.com/1inch/cross-chain-swap/blob/f45e33f855d5dd79428a1ba540d9f8df14bbb794/contracts/EscrowFactory.sol) **Inherits:** -[IEscrowFactory](/contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md), ExtensionBase +[IEscrowFactory](/contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md), SimpleSettlementExtension + +Contract to create escrow contracts for cross-chain atomic swap. ## State Variables @@ -18,12 +20,18 @@ address public immutable IMPLEMENTATION; ```solidity -constructor(address implementation, address limitOrderProtocol) ExtensionBase(limitOrderProtocol); +constructor(address implementation, address limitOrderProtocol, IERC20 token) + SimpleSettlementExtension(limitOrderProtocol, token); ``` ### _postInteraction -*Creates a new escrow contract for maker.* +Creates a new escrow contract for maker on the source chain. + +*The caller must be whitelisted and pre-send the safety deposit in a native token +to a pre-computed deterministic address of the created escrow. +The external postInteraction function call will be made from the Limit Order Protocol +after all funds have been transferred. See [IPostInteraction-postInteraction](/lib/limit-order-protocol/contracts/mocks/InteractionMock.sol/contract.InteractionMock.md#postinteraction).* ```solidity @@ -41,24 +49,44 @@ function _postInteraction( ### createEscrow -*Creates a new escrow contract for taker.* +See [IEscrowFactory-createEscrow](/contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md#createescrow). ```solidity -function createEscrow(DstEscrowImmutablesCreation calldata dstEscrowImmutables) external; +function createEscrow(DstEscrowImmutablesCreation calldata dstEscrowImmutables) external payable; ``` ### addressOfEscrow +See [IEscrowFactory-addressOfEscrow](/contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md#addressofescrow). + ```solidity -function addressOfEscrow(bytes32 salt) external view returns (address); +function addressOfEscrow(bytes32 salt) public view returns (address); ``` ### _createEscrow +Creates a new escrow contract with immutable arguments. + +*The escrow contract is a proxy clone created using the create3 pattern.* + ```solidity -function _createEscrow(bytes memory data, bytes32 salt) private returns (address clone); +function _createEscrow(bytes memory data, bytes32 salt, uint256 value) private returns (address clone); ``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`data`|`bytes`|Encoded immutable args.| +|`salt`|`bytes32`|The salt that influences the contract address in deterministic deployment.| +|`value`|`uint256`|| + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|`clone`|`address`|The address of the created escrow contract.| + diff --git a/documentation/src/contracts/interfaces/IEscrow.sol/interface.IEscrow.md b/documentation/src/contracts/interfaces/IEscrow.sol/interface.IEscrow.md index 8ccc2bb..4dd8bc3 100644 --- a/documentation/src/contracts/interfaces/IEscrow.sol/interface.IEscrow.md +++ b/documentation/src/contracts/interfaces/IEscrow.sol/interface.IEscrow.md @@ -1,5 +1,105 @@ # IEscrow -[Git Source](https://github.com/byshape/cross-chain-swap/blob/c49176f8473d9a06db920990a07a4d8464dd4dd4/contracts/interfaces/IEscrow.sol) +[Git Source](https://github.com/1inch/cross-chain-swap/blob/f45e33f855d5dd79428a1ba540d9f8df14bbb794/contracts/interfaces/IEscrow.sol) + + +## Functions +### withdrawSrc + +Withdraws funds to the taker on the source chain. + +*Withdrawal can only be made during the public unlock period and with secret +with hash matches the hashlock. +The safety deposit is sent to the caller.* + + +```solidity +function withdrawSrc(bytes32 secret) external; +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`secret`|`bytes32`|The secret that unlocks the escrow.| + + +### cancelSrc + +Cancels the escrow on the source chain and returns tokens to the maker. + +*The escrow can only be cancelled by taker during the private cancel period or +by anyone during the public cancel period. +The safety deposit is sent to the caller.* + + +```solidity +function cancelSrc() external; +``` + +### withdrawDst + +Withdraws funds to the maker on the destination chain. + +*Withdrawal can only be made by taker during the private unlock period or by anyone +during the public unlock period. In both cases, a secret with hash matching the hashlock must be provided. +The safety deposit is sent to the caller.* + + +```solidity +function withdrawDst(bytes32 secret) external; +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`secret`|`bytes32`|The secret that unlocks the escrow.| + + +### cancelDst + +Cancels the escrow on the destination chain and returns tokens to the taker. + +*The escrow can only be cancelled during the cancel period. +The safety deposit is sent to the caller.* + + +```solidity +function cancelDst() external; +``` + +### srcEscrowImmutables + +Returns the immutable parameters of the escrow contract on the source chain. + +*The immutables are stored at the end of the proxy clone contract bytecode and +are added to the calldata each time the proxy clone function is called.* + + +```solidity +function srcEscrowImmutables() external pure returns (SrcEscrowImmutables calldata); +``` +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|``|`SrcEscrowImmutables`|The immutables of the escrow contract.| + + +### dstEscrowImmutables + +Returns the immutable parameters of the escrow contract on the destination chain. + +*The immutables are stored at the end of the proxy clone contract bytecode and +are added to the calldata each time the proxy clone function is called.* + + +```solidity +function dstEscrowImmutables() external pure returns (DstEscrowImmutables calldata); +``` +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|``|`DstEscrowImmutables`|The immutables of the escrow contract.| ## Errors @@ -27,17 +127,34 @@ error InvalidSecret(); error InvalidWithdrawalTime(); ``` +### NativeTokenSendingFailure + +```solidity +error NativeTokenSendingFailure(); +``` + ## Structs ### SrcTimelocks +Timelocks for the source chain. +finality: The duration of the chain finality period. +publicUnlock: The duration of the period when anyone with a secret can withdraw tokens for the taker. +cancel: The duration of the period when escrow can only be cancelled by the taker. + ```solidity struct SrcTimelocks { uint256 finality; uint256 publicUnlock; + uint256 cancel; } ``` ### DstTimelocks +Timelocks for the destination chain. +finality: The duration of the chain finality period. +unlock: The duration of the period when only the taker with a secret can withdraw tokens for the maker. +publicUnlock publicUnlock: The duration of the period when anyone with a secret can withdraw tokens for the maker. + ```solidity struct DstTimelocks { @@ -64,10 +181,11 @@ struct InteractionParams { ```solidity struct ExtraDataParams { - uint256 hashlock; + bytes32 hashlock; uint256 dstChainId; address dstToken; - uint256 safetyDeposit; + uint256 srcSafetyDeposit; + uint256 dstSafetyDeposit; SrcTimelocks srcTimelocks; DstTimelocks dstTimelocks; } @@ -84,11 +202,14 @@ struct SrcEscrowImmutables { ``` ### DstEscrowImmutables +Data for the destination chain order immutables. +chainId, token, amount and safetyDeposit relate to the destination chain. + ```solidity struct DstEscrowImmutables { uint256 deployedAt; - uint256 hashlock; + bytes32 hashlock; address maker; address taker; uint256 chainId; diff --git a/documentation/src/contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md b/documentation/src/contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md index 66f18cb..8f1e24d 100644 --- a/documentation/src/contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md +++ b/documentation/src/contracts/interfaces/IEscrowFactory.sol/interface.IEscrowFactory.md @@ -1,5 +1,45 @@ # IEscrowFactory -[Git Source](https://github.com/byshape/cross-chain-swap/blob/c49176f8473d9a06db920990a07a4d8464dd4dd4/contracts/interfaces/IEscrowFactory.sol) +[Git Source](https://github.com/1inch/cross-chain-swap/blob/f45e33f855d5dd79428a1ba540d9f8df14bbb794/contracts/interfaces/IEscrowFactory.sol) + + +## Functions +### createEscrow + +Creates a new escrow contract for taker on the destination chain. + +*The caller must send the safety deposit in the native token along with the function call +and approve the destination token to be transferred to the created escrow.* + + +```solidity +function createEscrow(DstEscrowImmutablesCreation calldata dstEscrowImmutables) external payable; +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`dstEscrowImmutables`|`DstEscrowImmutablesCreation`|The immutables of the escrow contract that are used in deployment.| + + +### addressOfEscrow + +Returns the deterministic address of the escrow based on the salt. + + +```solidity +function addressOfEscrow(bytes32 salt) external view returns (address); +``` +**Parameters** + +|Name|Type|Description| +|----|----|-----------| +|`salt`|`bytes32`|The salt used to deploy escrow.| + +**Returns** + +|Name|Type|Description| +|----|----|-----------| +|``|`address`|The computed address of the escrow.| ## Errors @@ -17,10 +57,12 @@ error InvalidCreationTime(); ## Structs ### DstEscrowImmutablesCreation +token, amount and safetyDeposit are related to the destination chain. + ```solidity struct DstEscrowImmutablesCreation { - uint256 hashlock; + bytes32 hashlock; address maker; address taker; address token;