Skip to content

Commit

Permalink
Merge pull request #10 from 1inch/SC-1039-Optimize-cross-chain
Browse files Browse the repository at this point in the history
[SC-1039] Optimize cross-chain gas efficiency
  • Loading branch information
ZumZoom authored Feb 8, 2024
2 parents b54d0ab + 52b783b commit 813078f
Show file tree
Hide file tree
Showing 23 changed files with 1,291 additions and 328 deletions.
63 changes: 32 additions & 31 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
EscrowFactoryTest:testFuzz_DeployCloneForMaker(bytes32,uint56,uint56) (runs: 256, μ: 317761, ~: 321353)
EscrowFactoryTest:testFuzz_DeployCloneForTaker(bytes32,uint56) (runs: 256, μ: 243976, ~: 247826)
EscrowFactoryTest:test_NoDeploymentForNotResolver() (gas: 112084)
EscrowFactoryTest:test_NoInsufficientBalanceDeploymentForMaker() (gas: 281570)
EscrowFactoryTest:test_NoInsufficientBalanceDeploymentForTaker() (gas: 30637)
EscrowFactoryTest:test_NoInsufficientBalanceNativeDeploymentForMaker() (gas: 241684)
EscrowFactoryTest:test_NoUnsafeDeploymentForTaker() (gas: 38019)
EscrowTest:test_CancelDst() (gas: 230915)
EscrowTest:test_CancelPublicSrc() (gas: 319805)
EscrowTest:test_CancelResolverSrc() (gas: 322942)
EscrowTest:test_NoAnyoneCancelDuringResolverCancelSrc() (gas: 320091)
EscrowTest:test_NoCancelByAnyoneDst() (gas: 238401)
EscrowTest:test_NoCancelDuringPublicWithdrawalDst() (gas: 238345)
EscrowTest:test_NoCancelDuringResolverWithdrawalDst() (gas: 238071)
EscrowTest:test_NoCancelDuringWithdrawalSrc() (gas: 319437)
EscrowTest:test_NoFailedNativeTokenTransferCancelDst() (gas: 249340)
EscrowTest:test_NoFailedNativeTokenTransferCancelSrc() (gas: 335616)
EscrowTest:test_NoFailedNativeTokenTransferWithdrawalDst() (gas: 271094)
EscrowTest:test_NoFailedNativeTokenTransferWithdrawalSrc() (gas: 353692)
EscrowTest:test_NoWithdrawalByAnyone() (gas: 319084)
EscrowTest:test_NoWithdrawalByNonResolverDst() (gas: 238110)
EscrowTest:test_NoWithdrawalDuringFinalityLockDst() (gas: 237218)
EscrowTest:test_NoWithdrawalDuringFinalityLockSrc() (gas: 319954)
EscrowTest:test_NoWithdrawalWithWrongSecretDst() (gas: 239029)
EscrowTest:test_NoWithdrawalWithWrongSecretSrc() (gas: 320533)
EscrowTest:test_WithdrawByAnyoneDst() (gas: 255262)
EscrowTest:test_WithdrawByResolverDst() (gas: 255974)
EscrowTest:test_WithdrawByResolverPublicDst() (gas: 255625)
EscrowTest:test_WithdrawSrc() (gas: 340100)
IntegrationEscrowFactoryTest:testFuzz_DeployCloneForMakerInt(bytes32,uint56,uint56) (runs: 256, μ: 398108, ~: 401576)
IntegrationEscrowFactoryTest:test_NoInsufficientBalanceDeploymentForMakerInt() (gas: 382262)
EscrowFactoryTest:testFuzz_DeployCloneForMaker(bytes32,uint56,uint56) (runs: 256, μ: 234194, ~: 237909)
EscrowFactoryTest:testFuzz_DeployCloneForTaker(bytes32,uint56) (runs: 256, μ: 180412, ~: 183236)
EscrowFactoryTest:test_NoDeploymentForNotResolver() (gas: 103456)
EscrowFactoryTest:test_NoInsufficientBalanceDeploymentForMaker() (gas: 185356)
EscrowFactoryTest:test_NoInsufficientBalanceDeploymentForTaker() (gas: 27715)
EscrowFactoryTest:test_NoInsufficientBalanceNativeDeploymentForMaker() (gas: 151006)
EscrowFactoryTest:test_NoUnsafeDeploymentForTaker() (gas: 34980)
EscrowTest:test_CancelDst() (gas: 165076)
EscrowTest:test_CancelPublicSrc() (gas: 229537)
EscrowTest:test_CancelResolverSrc() (gas: 230646)
EscrowTest:test_NoAnyoneCancelDuringResolverCancelSrc() (gas: 227896)
EscrowTest:test_NoCancelByAnyoneDst() (gas: 172822)
EscrowTest:test_NoCancelDuringPublicWithdrawalDst() (gas: 170625)
EscrowTest:test_NoCancelDuringResolverWithdrawalDst() (gas: 168351)
EscrowTest:test_NoCancelDuringWithdrawalSrc() (gas: 225333)
EscrowTest:test_NoFailedNativeTokenTransferCancelDst() (gas: 183501)
EscrowTest:test_NoFailedNativeTokenTransferCancelSrc() (gas: 245348)
EscrowTest:test_NoFailedNativeTokenTransferWithdrawalDst() (gas: 203410)
EscrowTest:test_NoFailedNativeTokenTransferWithdrawalSrc() (gas: 259494)
EscrowTest:test_NoWithdrawalByAnyone() (gas: 223044)
EscrowTest:test_NoWithdrawalByNonResolverDst() (gas: 168503)
EscrowTest:test_NoWithdrawalDuringFinalityLockDst() (gas: 165563)
EscrowTest:test_NoWithdrawalDuringFinalityLockSrc() (gas: 223873)
EscrowTest:test_NoWithdrawalWithWrongSecretDst() (gas: 169323)
EscrowTest:test_NoWithdrawalWithWrongSecretSrc() (gas: 226329)
EscrowTest:test_WithdrawByAnyoneDst() (gas: 187575)
EscrowTest:test_WithdrawByResolverDst() (gas: 186265)
EscrowTest:test_WithdrawByResolverPublicDst() (gas: 187938)
EscrowTest:test_WithdrawSrc() (gas: 245902)
IntegrationEscrowFactoryTest:testFuzz_DeployCloneForMakerInt(bytes32,uint56,uint56) (runs: 256, μ: 296280, ~: 299872)
IntegrationEscrowFactoryTest:test_NoInsufficientBalanceDeploymentForMakerInt() (gas: 281514)
TimelocksLibTest:test_getStartTimestamps() (gas: 15326)
80 changes: 45 additions & 35 deletions contracts/Escrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,22 @@ import { Clone } from "clones-with-immutable-args/Clone.sol";

import { SafeERC20 } from "solidity-utils/libraries/SafeERC20.sol";

import { PackedAddresses, PackedAddressesLib } from "./libraries/PackedAddressesLib.sol";
import { Timelocks, TimelocksLib } from "./libraries/TimelocksLib.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.
* chain taker calls the `createEscrowDst` function.
* Withdrawal and cancellation functions for the source and destination chains are implemented separately.
*/
contract Escrow is Clone, IEscrow {
using SafeERC20 for IERC20;
using PackedAddressesLib for PackedAddresses;
using TimelocksLib for Timelocks;

/**
* @notice See {IEscrow-withdrawSrc}.
Expand All @@ -27,25 +31,28 @@ contract Escrow is Clone, IEscrow {
*/
function withdrawSrc(bytes32 secret) external {
SrcEscrowImmutables calldata escrowImmutables = srcEscrowImmutables();
if (msg.sender != escrowImmutables.interactionParams.taker) revert InvalidCaller();
address taker = escrowImmutables.packedAddresses.taker();
if (msg.sender != taker) revert InvalidCaller();

uint256 finalisedTimestamp = escrowImmutables.deployedAt + escrowImmutables.extraDataParams.srcTimelocks.finality;
// Check that it's public withdrawal period.
Timelocks timelocks = escrowImmutables.timelocks;
uint256 deployedAt = escrowImmutables.timelocks.deployedAt();

// Check that it's a withdrawal period.
if (
block.timestamp < finalisedTimestamp ||
block.timestamp >= finalisedTimestamp + escrowImmutables.extraDataParams.srcTimelocks.withdrawal
block.timestamp < timelocks.srcWithdrawalStart(deployedAt) ||
block.timestamp >= timelocks.srcCancellationStart(deployedAt)
) revert InvalidWithdrawalTime();

_checkSecretAndTransfer(
secret,
escrowImmutables.extraDataParams.hashlock,
escrowImmutables.interactionParams.taker,
escrowImmutables.interactionParams.srcToken,
escrowImmutables.interactionParams.srcAmount
escrowImmutables.hashlock,
taker,
escrowImmutables.packedAddresses.token(),
escrowImmutables.srcAmount
);

// Send the safety deposit to the caller.
(bool success, ) = msg.sender.call{value: escrowImmutables.extraDataParams.srcSafetyDeposit}("");
(bool success, ) = msg.sender.call{value: escrowImmutables.deposits >> 128}("");
if (!success) revert NativeTokenSendingFailure();
}

Expand All @@ -56,28 +63,29 @@ contract Escrow is Clone, IEscrow {
*/
function cancelSrc() external {
SrcEscrowImmutables calldata escrowImmutables = srcEscrowImmutables();
uint256 finalisedTimestamp = escrowImmutables.deployedAt + escrowImmutables.extraDataParams.srcTimelocks.finality;
uint256 cancellationTimestamp = finalisedTimestamp + escrowImmutables.extraDataParams.srcTimelocks.withdrawal;
// Check that it's cancellation period.
if (block.timestamp < cancellationTimestamp) {
Timelocks timelocks = escrowImmutables.timelocks;
uint256 deployedAt = escrowImmutables.timelocks.deployedAt();

// Check that it's a cancellation period.
if (block.timestamp < timelocks.srcCancellationStart(deployedAt)) {
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
block.timestamp < timelocks.srcPubCancellationStart(deployedAt) &&
msg.sender != escrowImmutables.packedAddresses.taker()
) {
revert InvalidCaller();
}

IERC20(escrowImmutables.interactionParams.srcToken).safeTransfer(
escrowImmutables.interactionParams.maker,
escrowImmutables.interactionParams.srcAmount
IERC20(escrowImmutables.packedAddresses.token()).safeTransfer(
escrowImmutables.packedAddresses.maker(),
escrowImmutables.srcAmount
);

// Send the safety deposit to the caller.
(bool success, ) = msg.sender.call{value: escrowImmutables.extraDataParams.srcSafetyDeposit}("");
(bool success, ) = msg.sender.call{value: escrowImmutables.deposits >> 128}("");
if (!success) revert NativeTokenSendingFailure();
}

Expand All @@ -88,22 +96,25 @@ contract Escrow is Clone, IEscrow {
*/
function withdrawDst(bytes32 secret) external {
DstEscrowImmutables calldata escrowImmutables = dstEscrowImmutables();
uint256 finalisedTimestamp = escrowImmutables.deployedAt + escrowImmutables.timelocks.finality;
uint256 publicWithdrawalTimestamp = finalisedTimestamp + escrowImmutables.timelocks.withdrawal;
// Check that it's an withdrawal period.

uint256 deployedAt = escrowImmutables.timelocks.deployedAt();
// Check that it's a withdrawal period.
if (
block.timestamp < finalisedTimestamp ||
block.timestamp >= publicWithdrawalTimestamp + escrowImmutables.timelocks.publicWithdrawal
block.timestamp < escrowImmutables.timelocks.dstWithdrawalStart(deployedAt) ||
block.timestamp >= escrowImmutables.timelocks.dstCancellationStart(deployedAt)
) revert InvalidWithdrawalTime();

// Check that the caller is a taker if it's the private withdrawal period.
if (block.timestamp < publicWithdrawalTimestamp && msg.sender != escrowImmutables.taker) revert InvalidCaller();
if (
block.timestamp < escrowImmutables.timelocks.dstPubWithdrawalStart(deployedAt) &&
msg.sender != escrowImmutables.packedAddresses.taker()
) revert InvalidCaller();

_checkSecretAndTransfer(
secret,
escrowImmutables.hashlock,
escrowImmutables.maker,
escrowImmutables.token,
escrowImmutables.packedAddresses.maker(),
escrowImmutables.packedAddresses.token(),
escrowImmutables.amount
);

Expand All @@ -119,19 +130,18 @@ contract Escrow is Clone, IEscrow {
*/
function cancelDst() external {
DstEscrowImmutables calldata escrowImmutables = dstEscrowImmutables();
if (msg.sender != escrowImmutables.taker) revert InvalidCaller();
address taker = escrowImmutables.packedAddresses.taker();
if (msg.sender != taker) revert InvalidCaller();

uint256 finalisedTimestamp = escrowImmutables.deployedAt + escrowImmutables.timelocks.finality;
// Check that it's a cancellation period.
if (
block.timestamp <
finalisedTimestamp + escrowImmutables.timelocks.withdrawal + escrowImmutables.timelocks.publicWithdrawal
block.timestamp < escrowImmutables.timelocks.dstCancellationStart(escrowImmutables.timelocks.deployedAt())
) {
revert InvalidCancellationTime();
}

IERC20(escrowImmutables.token).safeTransfer(
escrowImmutables.taker,
IERC20(escrowImmutables.packedAddresses.token()).safeTransfer(
taker,
escrowImmutables.amount
);

Expand Down
Loading

0 comments on commit 813078f

Please sign in to comment.