ETH Price: $2,060.21 (-4.87%)

Contract Diff Checker

Contract Name:
DepositAddressManager

Contract Source Code:

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.12;

import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import "openzeppelin-contracts/contracts/access/Ownable.sol";
import "openzeppelin-contracts/contracts/utils/Create2.sol";

import "./DepositAddressFactory.sol";
import "./DepositAddress.sol";
import "./DaimoPayExecutor.sol";
import "./TokenUtils.sol";
import "./SwapMath.sol";
import "./interfaces/IDaimoPayBridger.sol";
import "./interfaces/IDaimoPayPricer.sol";

/// @author Daimo, Inc
/// @custom:security-contact security@daimo.com
/// @notice Central escrow contract that manages the lifecycle of Deposit
///         Addresses
contract DepositAddressManager is Ownable, ReentrancyGuard {
    using SafeERC20 for IERC20;

    // ---------------------------------------------------------------------
    // Constants & Immutables
    // ---------------------------------------------------------------------

    /// Sentinel value used to mark a transfer claimed.
    address public constant ADDR_MAX =
        0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;

    /// Factory responsible for deploying deterministic Deposit Addresses.
    DepositAddressFactory public depositAddressFactory;

    /// Dedicated contract that performs swap / contract calls on behalf of the
    /// manager.
    DaimoPayExecutor public executor;

    // ---------------------------------------------------------------------
    // Storage
    // ---------------------------------------------------------------------

    /// Authorized relayer addresses.
    mapping(address relayer => bool authorized) public relayerAuthorized;

    /// On the source chain, record receiver addresses that have been used.
    mapping(address receiver => bool used) public receiverUsed;

    /// On the destination chain, map receiver address to status:
    /// - address(0) = not finished.
    /// - Relayer address = fast-finished, awaiting claim to repay relayer.
    /// - ADDR_MAX = claimed. any additional funds received are refunded.
    mapping(address receiver => address recipient) public receiverToRecipient;

    // ---------------------------------------------------------------------
    // Events
    // ---------------------------------------------------------------------

    event RelayerAuthorized(address indexed relayer, bool authorized);

    event Start(
        address indexed depositAddress,
        address indexed receiverAddress,
        DepositAddressRoute route,
        DepositAddressIntent intent,
        address paymentToken,
        uint256 paymentAmount,
        uint256 paymentTokenPriceUsd,
        uint256 bridgeTokenInPriceUsd
    );
    event FastFinish(
        address indexed depositAddress,
        address indexed receiverAddress,
        address indexed newRecipient,
        DepositAddressRoute route,
        DepositAddressIntent intent,
        uint256 outputAmount,
        uint256 bridgeTokenOutPriceUsd,
        uint256 toTokenPriceUsd
    );
    event Claim(
        address indexed depositAddress,
        address indexed receiverAddress,
        address indexed finalRecipient,
        DepositAddressRoute route,
        DepositAddressIntent intent,
        uint256 outputAmount,
        uint256 bridgeTokenOutPriceUsd,
        uint256 toTokenPriceUsd
    );
    event SameChainFinish(
        address indexed depositAddress,
        DepositAddressRoute route,
        address paymentToken,
        uint256 paymentAmount,
        uint256 outputAmount,
        uint256 paymentTokenPriceUsd,
        uint256 toTokenPriceUsd
    );
    event Refund(
        address indexed depositAddress,
        DepositAddressRoute route,
        address refundAddress,
        IERC20[] tokens,
        uint256[] amounts
    );
    event RefundReceiver(
        address indexed depositAddress,
        address indexed receiverAddress,
        DepositAddressRoute route,
        DepositAddressIntent intent,
        address refundAddress,
        IERC20[] tokens,
        uint256[] amounts
    );
    event Hop(
        address indexed depositAddress,
        address indexed hopReceiverAddress,
        address indexed destReceiverAddress,
        DepositAddressRoute route,
        DepositAddressIntent leg1Intent,
        DepositAddressIntent leg2Intent,
        uint256 hopAmount,
        uint256 leg1BridgeTokenOutPriceUsd,
        uint256 leg2BridgeTokenInPriceUsd
    );
    event FinalCallExecuted(
        address indexed depositAddress,
        address indexed target,
        bool success
    );

    // ---------------------------------------------------------------------
    // Modifiers
    // ---------------------------------------------------------------------

    /// @dev Only allow designated relayers to call certain functions.
    modifier onlyRelayer() {
        require(relayerAuthorized[msg.sender], "DAM: not relayer");
        _;
    }

    // ---------------------------------------------------------------------
    // Constructor
    // ---------------------------------------------------------------------

    /// @notice Initialize the contract.
    constructor(
        address _owner,
        DepositAddressFactory _depositAddressFactory,
        DaimoPayExecutor _executor
    ) Ownable(_owner) {
        depositAddressFactory = _depositAddressFactory;
        executor = _executor;
    }

    // Accept native asset deposits (for swaps).
    receive() external payable {}

    // ---------------------------------------------------------------------
    // External user / relayer entrypoints
    // ---------------------------------------------------------------------

    /// @notice Initiates a cross-chain transfer by pulling funds from the
    ///         deposit address, executing swaps if needed, and initiating a
    ///         bridge transfer to the destination chain.
    /// @dev Must be called on the source chain. Creates a deterministic
    ///      receiver address on the destination chain and bridges the
    ///      specified token amount to it.
    /// @param route           The cross-chain route containing destination
    ///                        chain, recipient, and token details
    /// @param paymentToken    The token the user paid the intent.
    /// @param bridgeTokenOut  The token and amount to be bridged to the
    ///                        destination chain
    /// @param relaySalt       Unique salt provided by the relayer to generate
    ///                        a unique receiver address
    /// @param calls           Optional swap calls to convert payment token to
    ///                        required bridge input token
    /// @param bridgeExtraData Additional data required by the specific bridge
    ///                        implementation
    function startIntent(
        DepositAddressRoute calldata route,
        IERC20 paymentToken,
        TokenAmount calldata bridgeTokenOut,
        PriceData calldata paymentTokenPrice,
        PriceData calldata bridgeTokenInPrice,
        bytes32 relaySalt,
        Call[] calldata calls,
        bytes calldata bridgeExtraData
    ) external nonReentrant onlyRelayer {
        require(block.chainid != route.toChainId, "DAM: start on dest chain");
        require(route.escrow == address(this), "DAM: wrong escrow");
        require(!isRouteExpired(route), "DAM: expired");

        bool paymentTokenPriceValid = route.pricer.validatePrice(
            paymentTokenPrice
        );
        bool bridgeTokenInPriceValid = route.pricer.validatePrice(
            bridgeTokenInPrice
        );
        require(paymentTokenPriceValid, "DAM: payment price invalid");
        require(bridgeTokenInPriceValid, "DAM: bridge price invalid");
        require(
            paymentTokenPrice.token == address(paymentToken),
            "DAM: payment token mismatch"
        );

        // Deploy (or fetch) deposit address
        DepositAddress da = depositAddressFactory.createDepositAddress(route);

        DepositAddressIntent memory intent = DepositAddressIntent({
            depositAddress: address(da),
            relaySalt: relaySalt,
            bridgeTokenOut: bridgeTokenOut,
            sourceChainId: block.chainid
        });
        (address receiverAddress, ) = computeReceiverAddress(intent);

        // Generate a unique receiver address for each bridge transfer. Without
        // this check, a malicious relayer could reuse the same receiver address
        // to claim multiple bridge transfers, double-paying themselves.
        require(!receiverUsed[receiverAddress], "DAM: receiver used");
        receiverUsed[receiverAddress] = true;

        // Quote bridge input requirements.
        (address bridgeTokenIn, uint256 inAmount) = route
            .bridger
            .getBridgeTokenIn({
                toChainId: route.toChainId,
                bridgeTokenOut: bridgeTokenOut
            });
        require(
            bridgeTokenIn == address(bridgeTokenInPrice.token),
            "DAM: bridge token mismatch"
        );

        // Send payment token to executor
        uint256 paymentAmount = da.sendBalance({
            route: route,
            token: paymentToken,
            recipient: payable(address(executor))
        });

        // Validate the inAmount is above the minimum output required by the
        // swap.
        TokenAmount memory minSwapOutput = SwapMath.computeMinSwapOutput({
            sellTokenPrice: paymentTokenPrice,
            buyTokenPrice: bridgeTokenInPrice,
            sellAmount: paymentAmount,
            maxSlippage: route.maxStartSlippageBps
        });
        require(inAmount >= minSwapOutput.amount, "DAM: bridge input low");

        // Run arbitrary calls provided by the relayer. These will generally
        // approve the swap contract and swap if necessary.
        // The executor contract checks that the output is sufficient. Any
        // surplus tokens are given to the relayer.
        TokenAmount[] memory expectedOutput = new TokenAmount[](1);
        expectedOutput[0] = TokenAmount({
            token: IERC20(bridgeTokenIn),
            amount: inAmount
        });
        executor.execute({
            calls: calls,
            expectedOutput: expectedOutput,
            recipient: payable(address(this)),
            surplusRecipient: payable(msg.sender)
        });

        // Approve bridger and initiate bridging
        IERC20(bridgeTokenIn).forceApprove({
            spender: address(route.bridger),
            value: inAmount
        });
        route.bridger.sendToChain({
            toChainId: route.toChainId,
            toAddress: receiverAddress,
            bridgeTokenOut: bridgeTokenOut,
            refundAddress: route.refundAddress,
            extraData: bridgeExtraData
        });

        emit Start({
            depositAddress: address(da),
            receiverAddress: receiverAddress,
            route: route,
            intent: intent,
            paymentToken: address(paymentToken),
            paymentAmount: paymentAmount,
            paymentTokenPriceUsd: paymentTokenPrice.priceUsd,
            bridgeTokenInPriceUsd: bridgeTokenInPrice.priceUsd
        });
    }

    /// @notice Send funds that are already on the destination chain.
    ///
    /// @param route        The DepositAddressRoute for the intent
    /// @param paymentToken Token to be used to pay the intent
    /// @param calls        Arbitrary swap calls to be executed by the executor
    ///                     Can be empty when assets are already `toToken`
    function sameChainFinishIntent(
        DepositAddressRoute calldata route,
        IERC20 paymentToken,
        PriceData calldata paymentTokenPrice,
        PriceData calldata toTokenPrice,
        Call[] calldata calls
    ) external nonReentrant onlyRelayer {
        require(route.toChainId == block.chainid, "DAM: wrong chain");
        require(route.escrow == address(this), "DAM: wrong escrow");
        require(!isRouteExpired(route), "DAM: expired");

        bool paymentTokenPriceValid = route.pricer.validatePrice(
            paymentTokenPrice
        );
        bool toTokenPriceValid = route.pricer.validatePrice(toTokenPrice);
        require(paymentTokenPriceValid, "DAM: payment price invalid");
        require(toTokenPriceValid, "DAM: toToken price invalid");
        require(
            paymentTokenPrice.token == address(paymentToken),
            "DAM: payment token mismatch"
        );
        require(
            toTokenPrice.token == address(route.toToken),
            "DAM: toToken mismatch"
        );

        // Deploy (or fetch) the Deposit Address for this route.
        DepositAddress da = depositAddressFactory.createDepositAddress(route);

        // Pull specified token balances from the da into the executor.
        uint256 paymentAmount = da.sendBalance({
            route: route,
            token: paymentToken,
            recipient: payable(address(executor))
        });

        // Compute the minimum amount of toToken the user should receive.
        TokenAmount memory minSwapOutput = SwapMath.computeMinSwapOutput({
            sellTokenPrice: paymentTokenPrice,
            buyTokenPrice: toTokenPrice,
            sellAmount: paymentAmount,
            maxSlippage: route.maxSameChainFinishSlippageBps
        });

        // Finish the intent and return any leftover tokens to the caller
        uint256 outputAmount = _finishIntent({
            depositAddress: address(da),
            route: route,
            calls: calls,
            minOutputAmount: minSwapOutput.amount
        });

        emit SameChainFinish({
            depositAddress: address(da),
            route: route,
            paymentToken: address(paymentToken),
            paymentAmount: paymentAmount,
            outputAmount: outputAmount,
            paymentTokenPriceUsd: paymentTokenPrice.priceUsd,
            toTokenPriceUsd: toTokenPrice.priceUsd
        });
    }

    /// @notice Allows a relayer to deliver funds early on the destination chain
    ///         before the bridge transfer completes.
    /// @dev Must be called on the destination chain. The relayer sends their
    ///      own funds to complete the intent atomically before calling fastFinish,
    ///      and is recorded as the recipient for the eventual bridged tokens.
    /// @param route           The DepositAddressRoute for the intent
    /// @param calls           Arbitrary swap calls to be executed by the executor
    /// @param token           The token sent by the relayer
    /// @param bridgeTokenOut  The token and amount expected from the bridge
    /// @param relaySalt       Unique salt from the original bridge transfer
    /// @param sourceChainId   The chain ID where the bridge transfer originated
    function fastFinishIntent(
        DepositAddressRoute calldata route,
        Call[] calldata calls,
        IERC20 token,
        PriceData calldata bridgeTokenOutPrice,
        PriceData calldata toTokenPrice,
        TokenAmount calldata bridgeTokenOut,
        bytes32 relaySalt,
        uint256 sourceChainId
    ) external nonReentrant onlyRelayer {
        require(sourceChainId != block.chainid, "DAM: same chain finish");
        require(route.toChainId == block.chainid, "DAM: wrong chain");
        require(route.escrow == address(this), "DAM: wrong escrow");
        require(!isRouteExpired(route), "DAM: expired");

        bool bridgeTokenOutPriceValid = route.pricer.validatePrice(
            bridgeTokenOutPrice
        );
        bool toTokenPriceValid = route.pricer.validatePrice(toTokenPrice);
        require(bridgeTokenOutPriceValid, "DAM: bridgeTokenOut price invalid");
        require(toTokenPriceValid, "DAM: toToken price invalid");
        require(
            bridgeTokenOutPrice.token == address(bridgeTokenOut.token),
            "DAM: bridgeTokenOut mismatch"
        );
        require(
            toTokenPrice.token == address(route.toToken),
            "DAM: toToken mismatch"
        );

        // Calculate salt for this bridge transfer.
        address da = depositAddressFactory.getDepositAddress(route);
        DepositAddressIntent memory intent = DepositAddressIntent({
            depositAddress: da,
            relaySalt: relaySalt,
            bridgeTokenOut: bridgeTokenOut,
            sourceChainId: sourceChainId
        });
        (address receiverAddress, ) = computeReceiverAddress(intent);

        // Check that the salt hasn't already been fast finished or claimed.
        require(
            receiverToRecipient[receiverAddress] == address(0),
            "DAM: already finished"
        );
        // Record relayer as new recipient when the bridged tokens arrive
        receiverToRecipient[receiverAddress] = msg.sender;

        // Finish the intent and return any leftover tokens to the caller
        TokenUtils.transferBalance({
            token: token,
            recipient: payable(address(executor))
        });
        TokenAmount memory toTokenAmount = SwapMath.computeMinSwapOutput({
            sellTokenPrice: bridgeTokenOutPrice,
            buyTokenPrice: toTokenPrice,
            sellAmount: bridgeTokenOut.amount,
            maxSlippage: route.maxFastFinishSlippageBps
        });
        uint256 outputAmount = _finishIntent({
            depositAddress: da,
            route: route,
            calls: calls,
            minOutputAmount: toTokenAmount.amount
        });

        emit FastFinish({
            depositAddress: da,
            receiverAddress: receiverAddress,
            newRecipient: msg.sender,
            route: route,
            intent: intent,
            outputAmount: outputAmount,
            bridgeTokenOutPriceUsd: bridgeTokenOutPrice.priceUsd,
            toTokenPriceUsd: toTokenPrice.priceUsd
        });
    }

    /// @notice Completes an intent after bridged tokens arrive on the destination
    ///         chain, either repaying a relayer or fulfilling the intent directly.
    /// @param route           The DepositAddressRoute for the intent
    /// @param calls           Arbitrary swap from bridgeTokenOut to toToken
    /// @param bridgeTokenOut  The token and amount that was bridged
    /// @param relaySalt       Unique salt from the original bridge transfer
    /// @param sourceChainId   The chain ID where the bridge transfer originated
    function claimIntent(
        DepositAddressRoute calldata route,
        Call[] calldata calls,
        TokenAmount calldata bridgeTokenOut,
        PriceData calldata bridgeTokenOutPrice,
        PriceData calldata toTokenPrice,
        bytes32 relaySalt,
        uint256 sourceChainId
    ) external nonReentrant onlyRelayer {
        require(route.toChainId == block.chainid, "DAM: wrong chain");
        require(route.escrow == address(this), "DAM: wrong escrow");

        // Calculate salt for this bridge transfer.
        address da = depositAddressFactory.getDepositAddress(route);
        DepositAddressIntent memory intent = DepositAddressIntent({
            depositAddress: da,
            relaySalt: relaySalt,
            bridgeTokenOut: bridgeTokenOut,
            sourceChainId: sourceChainId
        });
        (address receiverAddress, ) = computeReceiverAddress(intent);

        // Check the recipient for this intent.
        address recipient = receiverToRecipient[receiverAddress];
        require(recipient != ADDR_MAX, "DAM: already claimed");
        // Mark intent as claimed
        receiverToRecipient[receiverAddress] = ADDR_MAX;

        // Deploy receiver and pull bridged tokens
        uint256 bridgedAmount;
        (receiverAddress, bridgedAmount) = _deployAndPullFromReceiver(
            intent,
            bridgeTokenOut.token
        );

        uint256 outputAmount = 0;
        if (recipient == address(0)) {
            // Validate prices
            bool bridgeTokenOutPriceValid = route.pricer.validatePrice(
                bridgeTokenOutPrice
            );
            bool toTokenPriceValid = route.pricer.validatePrice(toTokenPrice);
            require(
                bridgeTokenOutPriceValid,
                "DAM: bridgeTokenOut price invalid"
            );
            require(toTokenPriceValid, "DAM: toToken price invalid");
            require(
                bridgeTokenOutPrice.token == address(bridgeTokenOut.token),
                "DAM: bridgeTokenOut mismatch"
            );
            require(
                toTokenPrice.token == address(route.toToken),
                "DAM: toToken mismatch"
            );

            // No relayer showed up, so just complete the intent. Update the
            // recipient to the route's recipient.
            recipient = route.toAddress;

            // Send tokens to the executor contract to run relayer-provided
            // calls in _finishIntent.
            TokenUtils.transfer({
                token: bridgeTokenOut.token,
                recipient: payable(address(executor)),
                amount: bridgedAmount
            });

            // Compute the minimum amount of toToken that is required to
            // complete the intent. This uses the promised bridgeTokenOut, even
            // if the actual bridgedAmount is slightly less.
            TokenAmount memory toTokenAmount = SwapMath.computeMinSwapOutput({
                sellTokenPrice: bridgeTokenOutPrice,
                buyTokenPrice: toTokenPrice,
                sellAmount: bridgeTokenOut.amount,
                maxSlippage: route.maxFastFinishSlippageBps
            });

            // Finish the intent and return any leftover tokens to the caller
            outputAmount = _finishIntent({
                depositAddress: da,
                route: route,
                calls: calls,
                minOutputAmount: toTokenAmount.amount
            });
        } else {
            // Otherwise, the relayer fastFinished the intent. Repay them.
            TokenUtils.transfer({
                token: bridgeTokenOut.token,
                recipient: payable(recipient),
                amount: bridgedAmount
            });
            outputAmount = bridgedAmount;
        }

        emit Claim({
            depositAddress: da,
            receiverAddress: receiverAddress,
            finalRecipient: recipient,
            route: route,
            intent: intent,
            outputAmount: outputAmount,
            bridgeTokenOutPriceUsd: bridgeTokenOutPrice.priceUsd,
            toTokenPriceUsd: toTokenPrice.priceUsd
        });
    }

    /// @notice Continues a multi-hop transfer by pulling funds from a hop chain
    ///         receiver and bridging to the final destination chain.
    /// @dev Must be called on the hop chain. Pulls funds from the receiver
    ///      created by the source→hop leg, then initiates hop→dest bridge.
    /// @param route               The DepositAddressRoute for the intent
    /// @param leg1BridgeTokenOut  Token and amount that was bridged in leg 1
    ///                            (source → hop)
    /// @param leg1RelaySalt       Relay salt used in leg 1
    /// @param leg1SourceChainId   Source chain ID for leg 1
    /// @param leg2BridgeTokenOut  Token and amount to bridge in leg 2 (hop → dest)
    /// @param leg1BridgeTokenOutPrice  Price data for leg 1 bridge token out
    /// @param leg2BridgeTokenInPrice   Price data for leg 2 bridge token in
    /// @param leg2RelaySalt       Relay salt for leg 2
    /// @param calls               Swap calls to convert leg 1 token to leg 2
    ///                            bridge input token
    /// @param bridgeExtraData     Additional data for the hop → dest bridge
    function hopIntent(
        DepositAddressRoute calldata route,
        TokenAmount calldata leg1BridgeTokenOut,
        bytes32 leg1RelaySalt,
        uint256 leg1SourceChainId,
        PriceData calldata leg1BridgeTokenOutPrice,
        TokenAmount calldata leg2BridgeTokenOut,
        bytes32 leg2RelaySalt,
        PriceData calldata leg2BridgeTokenInPrice,
        Call[] calldata calls,
        bytes calldata bridgeExtraData
    ) external nonReentrant onlyRelayer {
        // Must be on hop chain (not source, not dest)
        require(block.chainid != leg1SourceChainId, "DAM: hop on source chain");
        require(block.chainid != route.toChainId, "DAM: hop on dest chain");
        require(route.escrow == address(this), "DAM: wrong escrow");

        // Validate prices
        bool leg1PriceValid = route.pricer.validatePrice(
            leg1BridgeTokenOutPrice
        );
        bool leg2PriceValid = route.pricer.validatePrice(
            leg2BridgeTokenInPrice
        );
        require(leg1PriceValid, "DAM: leg1 price invalid");
        require(leg2PriceValid, "DAM: leg2 price invalid");
        require(
            leg1BridgeTokenOutPrice.token == address(leg1BridgeTokenOut.token),
            "DAM: leg1 bridge token mismatch"
        );
        require(
            leg2BridgeTokenInPrice.token == address(leg2BridgeTokenOut.token),
            "DAM: leg2 bridge token mismatch"
        );

        // Compute and deploy/fetch the hop receiver from leg 1
        address depositAddress = depositAddressFactory.getDepositAddress(route);
        DepositAddressIntent memory leg1Intent = DepositAddressIntent({
            depositAddress: depositAddress,
            relaySalt: leg1RelaySalt,
            bridgeTokenOut: leg1BridgeTokenOut,
            sourceChainId: leg1SourceChainId
        });
        (address hopReceiverAddress, ) = computeReceiverAddress(leg1Intent);

        // Check that leg1 hasn't been claimed already
        address recipient = receiverToRecipient[hopReceiverAddress];
        require(recipient != ADDR_MAX, "DAM: already claimed");
        // Mark as claimed to prevent double-processing
        receiverToRecipient[hopReceiverAddress] = ADDR_MAX;

        // Deploy receiver and pull funds
        uint256 bridgedAmount;
        (hopReceiverAddress, bridgedAmount) = _deployAndPullFromReceiver(
            leg1Intent,
            leg1BridgeTokenOut.token
        );

        // Compute leg 2 receiver address
        DepositAddressIntent memory leg2Intent = DepositAddressIntent({
            depositAddress: depositAddress,
            relaySalt: leg2RelaySalt,
            bridgeTokenOut: leg2BridgeTokenOut,
            sourceChainId: block.chainid // hop chain is source for leg 2
        });
        (address destReceiverAddress, ) = computeReceiverAddress(leg2Intent);

        // Ensure leg 2 receiver hasn't been used
        require(!receiverUsed[destReceiverAddress], "DAM: receiver used");
        receiverUsed[destReceiverAddress] = true;

        // Get bridge input requirements for leg 2
        (address bridgeTokenIn, uint256 inAmount) = route
            .bridger
            .getBridgeTokenIn({
                toChainId: route.toChainId,
                bridgeTokenOut: leg2BridgeTokenOut
            });
        require(
            bridgeTokenIn == address(leg2BridgeTokenInPrice.token),
            "DAM: bridge token mismatch"
        );

        // Validate swap output meets minimum requirements
        TokenAmount memory minSwapOutput = SwapMath.computeMinSwapOutput({
            sellTokenPrice: leg1BridgeTokenOutPrice,
            buyTokenPrice: leg2BridgeTokenInPrice,
            sellAmount: leg1BridgeTokenOut.amount,
            maxSlippage: route.maxStartSlippageBps
        });
        require(inAmount >= minSwapOutput.amount, "DAM: bridge input low");

        // Send to executor, run swap calls, get bridge input
        TokenUtils.transfer({
            token: leg1BridgeTokenOut.token,
            recipient: payable(address(executor)),
            amount: bridgedAmount
        });

        TokenAmount[] memory expectedOutput = new TokenAmount[](1);
        expectedOutput[0] = TokenAmount({
            token: IERC20(bridgeTokenIn),
            amount: inAmount
        });
        executor.execute({
            calls: calls,
            expectedOutput: expectedOutput,
            recipient: payable(address(this)),
            surplusRecipient: payable(msg.sender)
        });

        // Approve bridger and initiate leg 2 bridge
        IERC20(bridgeTokenIn).forceApprove({
            spender: address(route.bridger),
            value: inAmount
        });
        route.bridger.sendToChain({
            toChainId: route.toChainId,
            toAddress: destReceiverAddress,
            bridgeTokenOut: leg2BridgeTokenOut,
            refundAddress: route.refundAddress,
            extraData: bridgeExtraData
        });

        emit Hop({
            depositAddress: depositAddress,
            hopReceiverAddress: hopReceiverAddress,
            destReceiverAddress: destReceiverAddress,
            route: route,
            leg1Intent: leg1Intent,
            leg2Intent: leg2Intent,
            hopAmount: bridgedAmount,
            leg1BridgeTokenOutPriceUsd: leg1BridgeTokenOutPrice.priceUsd,
            leg2BridgeTokenInPriceUsd: leg2BridgeTokenInPrice.priceUsd
        });
    }

    /// @notice Refunds tokens from a deposit address to its designated
    ///         refund address after the deposit address has expired.
    /// @param route The Deposit Address route containing the refund address
    /// @param tokens The tokens to refund from the deposit address
    /// @dev Refunds are only allowed after the deposit address expires
    function refundIntent(
        DepositAddressRoute calldata route,
        IERC20[] calldata tokens
    ) external nonReentrant {
        require(route.escrow == address(this), "DAM: wrong escrow");
        require(isRouteExpired(route), "DAM: not expired");

        // Deploy (or fetch) the Deposit Address for this route
        DepositAddress da = depositAddressFactory.createDepositAddress(route);

        // Send refund to the designated refund address
        uint256[] memory amounts = new uint256[](tokens.length);
        for (uint256 i = 0; i < tokens.length; ++i) {
            amounts[i] = da.sendBalance({
                route: route,
                token: tokens[i],
                recipient: payable(route.refundAddress)
            });
        }

        emit Refund({
            depositAddress: address(da),
            route: route,
            refundAddress: route.refundAddress,
            tokens: tokens,
            amounts: amounts
        });
    }

    /// @notice Refunds tokens from a receiver address to the designated refund
    ///         address after the route has expired.
    /// @param route The Deposit Address route containing the refund address
    /// @param bridgeTokenOut The token and amount that was bridged (used to
    ///        compute receiver address)
    /// @param relaySalt Unique salt from the original bridge transfer
    /// @param sourceChainId The chain ID where the bridge transfer originated
    /// @param tokens The tokens to refund from the receiver
    /// @dev Refunds are only allowed after the route expires. This allows
    ///      recovery of bridged funds that were never claimed or fast-finished.
    function refundReceiverIntent(
        DepositAddressRoute calldata route,
        TokenAmount calldata bridgeTokenOut,
        bytes32 relaySalt,
        uint256 sourceChainId,
        IERC20[] calldata tokens
    ) external nonReentrant onlyRelayer {
        require(route.escrow == address(this), "DAM: wrong escrow");
        require(isRouteExpired(route), "DAM: not expired");

        // Compute the receiver address for this intent
        address da = depositAddressFactory.getDepositAddress(route);
        DepositAddressIntent memory intent = DepositAddressIntent({
            depositAddress: da,
            relaySalt: relaySalt,
            bridgeTokenOut: bridgeTokenOut,
            sourceChainId: sourceChainId
        });

        // Pull and transfer each token to the refund address
        address receiverAddress;
        uint256[] memory amounts = new uint256[](tokens.length);
        for (uint256 i = 0; i < tokens.length; ++i) {
            (receiverAddress, amounts[i]) = _deployAndPullFromReceiver(
                intent,
                tokens[i]
            );
            TokenUtils.transfer({
                token: tokens[i],
                recipient: payable(route.refundAddress),
                amount: amounts[i]
            });
        }

        emit RefundReceiver({
            depositAddress: da,
            receiverAddress: receiverAddress,
            route: route,
            intent: intent,
            refundAddress: route.refundAddress,
            tokens: tokens,
            amounts: amounts
        });
    }

    /// @notice Computes a deterministic DepositAddressReceiver address.
    /// @param intent The bridge intent
    /// @return addr The computed address for the DepositAddressReceiver contract
    /// @return recvSalt The CREATE2 salt used to deploy the DepositAddressReceiver
    function computeReceiverAddress(
        DepositAddressIntent memory intent
    ) public view returns (address payable addr, bytes32 recvSalt) {
        recvSalt = keccak256(abi.encode(intent));
        bytes memory initCode = type(DepositAddressReceiver).creationCode;
        addr = payable(Create2.computeAddress(recvSalt, keccak256(initCode)));
    }

    /// @notice Checks if a Deposit Address route has expired.
    /// @param route The Deposit Address route to check
    /// @return true if the route has expired, false otherwise
    function isRouteExpired(
        DepositAddressRoute calldata route
    ) public view returns (bool) {
        return block.timestamp >= route.expiresAt;
    }

    // ---------------------------------------------------------------------
    // Internal helpers
    // ---------------------------------------------------------------------

    /// @dev Deploy a DepositAddressReceiver if necessary and pull funds.
    /// @param intent The bridge intent used to compute receiver address
    /// @param token The token to pull from the receiver
    /// @return receiverAddress The receiver contract address
    /// @return pulledAmount The amount pulled from the receiver
    function _deployAndPullFromReceiver(
        DepositAddressIntent memory intent,
        IERC20 token
    ) internal returns (address receiverAddress, uint256 pulledAmount) {
        bytes32 recvSalt;
        (receiverAddress, recvSalt) = computeReceiverAddress(intent);

        // Deploy receiver if necessary
        DepositAddressReceiver receiver;
        if (receiverAddress.code.length == 0) {
            receiver = new DepositAddressReceiver{salt: recvSalt}();
            require(receiverAddress == address(receiver), "DAM: receiver");
        } else {
            receiver = DepositAddressReceiver(payable(receiverAddress));
        }

        // Pull funds from the receiver
        pulledAmount = receiver.pull(token);
    }

    /// @dev Internal helper that completes an intent by executing swaps,
    ///      delivering toToken to the recipient, and handling any surplus.
    ///      If the route has a finalCall, executes the call after swapping.
    ///      Precondition: input tokens must already be in PayExecutor.
    /// @param depositAddress   The deposit address for this intent (for events)
    /// @param route            The DepositAddressRoute containing
    ///                         recipient details and optional finalCall
    /// @param calls            Arbitrary swap calls to be executed by the
    ///                         executor
    /// @param minOutputAmount  The minimum amount of target token to deliver to
    ///                         the recipient
    function _finishIntent(
        address depositAddress,
        DepositAddressRoute calldata route,
        Call[] calldata calls,
        uint256 minOutputAmount
    ) internal returns (uint256 outputAmount) {
        if (route.finalCallData.length > 0) {
            // Swap and keep tokens in executor for final call
            outputAmount = executor.executeAndSendBalance({
                calls: calls,
                minOutputAmount: TokenAmount({
                    token: route.toToken,
                    amount: minOutputAmount
                }),
                recipient: payable(address(executor))
            });

            // Execute final call - approves token to toAddress and calls it
            bool success = executor.executeFinalCall({
                finalCall: Call({
                    to: route.toAddress,
                    value: 0,
                    data: route.finalCallData
                }),
                finalCallToken: TokenAmount({
                    token: route.toToken,
                    amount: outputAmount
                }),
                refundAddr: payable(route.refundAddress)
            });

            emit FinalCallExecuted(depositAddress, route.toAddress, success);
        } else {
            // No final call - send directly to recipient
            outputAmount = executor.executeAndSendBalance({
                calls: calls,
                minOutputAmount: TokenAmount({
                    token: route.toToken,
                    amount: minOutputAmount
                }),
                recipient: payable(route.toAddress)
            });
        }
    }

    // ---------------------------------------------------------------------
    // Admin functions
    // ---------------------------------------------------------------------

    /// @notice Set the authorized relayer address.
    /// @param relayer The address of the new relayer
    /// @param authorized Whether the relayer is authorized
    function setRelayer(address relayer, bool authorized) external onlyOwner {
        relayerAuthorized[relayer] = authorized;
        emit RelayerAuthorized(relayer, authorized);
    }
}

// ---------------------------------------------------------------------
// Minimal deterministic receiver
// ---------------------------------------------------------------------

/// @notice Minimal deterministic contract that receives bridged tokens and
///         allows the Deposit Address Manager to sweep them.
/// @dev Deployed via CREATE2 using a salt that encodes bridge transfer
///      parameters into the deployment address, creating predictable addresses
///      that are unique to each bridge transfer. Only the deploying manager
///      can pull funds from this contract.
contract DepositAddressReceiver {
    using SafeERC20 for IERC20;

    /// @notice Address allowed to pull funds from this contract
    address payable public immutable depositAddressManager;

    constructor() {
        depositAddressManager = payable(msg.sender);

        // Emit event for any ETH that arrived before deployment
        if (address(this).balance > 0) {
            emit NativeTransfer(
                address(0),
                address(this),
                address(this).balance
            );
        }
    }

    // Accept native asset deposits.
    receive() external payable {
        emit NativeTransfer(msg.sender, address(this), msg.value);
    }

    /// @notice Sweep entire balance of `token` (ERC20 or native when
    ///         token == IERC20(address(0))) to the deployer address.
    /// @return amount The amount of tokens pulled
    function pull(IERC20 token) external returns (uint256) {
        require(msg.sender == depositAddressManager, "BR: not authorized");
        return
            TokenUtils.transferBalance({
                token: token,
                recipient: depositAddressManager
            });
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC-20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Create2.sol)

pragma solidity ^0.8.20;

import {Errors} from "./Errors.sol";

/**
 * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
 * `CREATE2` can be used to compute in advance the address where a smart
 * contract will be deployed, which allows for interesting new mechanisms known
 * as 'counterfactual interactions'.
 *
 * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
 * information.
 */
library Create2 {
    /**
     * @dev There's no code to deploy.
     */
    error Create2EmptyBytecode();

    /**
     * @dev Deploys a contract using `CREATE2`. The address where the contract
     * will be deployed can be known in advance via {computeAddress}.
     *
     * The bytecode for a contract can be obtained from Solidity with
     * `type(contractName).creationCode`.
     *
     * Requirements:
     *
     * - `bytecode` must not be empty.
     * - `salt` must have not been used for `bytecode` already.
     * - the factory must have a balance of at least `amount`.
     * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
     */
    function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }
        if (bytecode.length == 0) {
            revert Create2EmptyBytecode();
        }
        assembly ("memory-safe") {
            addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
            // if no address was created, and returndata is not empty, bubble revert
            if and(iszero(addr), not(iszero(returndatasize()))) {
                let p := mload(0x40)
                returndatacopy(p, 0, returndatasize())
                revert(p, returndatasize())
            }
        }
        if (addr == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
     * `bytecodeHash` or `salt` will result in a new destination address.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
        return computeAddress(salt, bytecodeHash, address(this));
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
     * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
        assembly ("memory-safe") {
            let ptr := mload(0x40) // Get free memory pointer

            // |                   | ↓ ptr ...  ↓ ptr + 0x0B (start) ...  ↓ ptr + 0x20 ...  ↓ ptr + 0x40 ...   |
            // |-------------------|---------------------------------------------------------------------------|
            // | bytecodeHash      |                                                        CCCCCCCCCCCCC...CC |
            // | salt              |                                      BBBBBBBBBBBBB...BB                   |
            // | deployer          | 000000...0000AAAAAAAAAAAAAAAAAAA...AA                                     |
            // | 0xFF              |            FF                                                             |
            // |-------------------|---------------------------------------------------------------------------|
            // | memory            | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
            // | keccak(start, 85) |            ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |

            mstore(add(ptr, 0x40), bytecodeHash)
            mstore(add(ptr, 0x20), salt)
            mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
            let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
            mstore8(start, 0xff)
            addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff)
        }
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.12;

import "openzeppelin-contracts/contracts/utils/Create2.sol";
import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol";

import "./DepositAddress.sol";

/// @author Daimo, Inc
/// @custom:security-contact security@daimo.com
/// @notice Factory contract that creates deterministic Deposit Address vault
///         contracts using CREATE2 deployment for predictable addresses.
/// @dev Deploys Deposit Address contracts at addresses determined by the
///      route parameters, enabling desterministic vault addresses across
///      chains.
contract DepositAddressFactory {
    /// Singleton implementation that all minimal proxies delegate to.
    DepositAddress public immutable depositAddressImpl;

    event DepositAddressDeployed(
        address indexed depositAddress,
        DepositAddressRoute route
    );

    constructor() {
        depositAddressImpl = new DepositAddress();
    }

    /// @dev Deploy the Deposit Address for the given DepositAddressRoute
    ///      (or return existing one).
    function createDepositAddress(
        DepositAddressRoute calldata route
    ) public returns (DepositAddress ret) {
        address depositAddress = getDepositAddress(route);
        if (depositAddress.code.length > 0) {
            // Already deployed, another CREATE2 would revert,
            // so not deploying and just returning the existing one.
            return DepositAddress(payable(depositAddress));
        }
        ret = DepositAddress(
            payable(
                address(
                    new ERC1967Proxy{salt: bytes32(0)}(
                        address(depositAddressImpl),
                        abi.encodeCall(
                            DepositAddress.initialize,
                            calcRouteHash(route)
                        )
                    )
                )
            )
        );
        emit DepositAddressDeployed(depositAddress, route);
    }

    /// @notice Pure view helper: compute CREATE2 address for a
    ///         DepositAddressRoute.
    function getDepositAddress(
        DepositAddressRoute calldata route
    ) public view returns (address) {
        return
            Create2.computeAddress(
                0,
                keccak256(
                    abi.encodePacked(
                        type(ERC1967Proxy).creationCode,
                        abi.encode(
                            address(depositAddressImpl),
                            abi.encodeCall(
                                DepositAddress.initialize,
                                calcRouteHash(route)
                            )
                        )
                    )
                )
            );
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.12;

import "openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import "openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";

import "./TokenUtils.sol";
import "./interfaces/IDepositAddressBridger.sol";
import "./interfaces/IDaimoPayPricer.sol";

/// @notice Parameters that uniquely identify a Deposit Address.
struct DepositAddressRoute {
    /// Destination chain
    uint256 toChainId;
    /// Final token received on destination chain
    IERC20 toToken;
    /// Destination address. If finalCallData is empty, tokens are transferred
    /// here. Otherwise, tokens are transferred here and a call is made with
    /// finalCallData (e.g., toAddress is an adapter contract).
    address toAddress;
    /// Recipient for refunds
    address refundAddress;
    /// Optional calldata to execute on toAddress after swapping to toToken.
    /// If empty, tokens are simply transferred to toAddress.
    bytes finalCallData;
    /// DepositAddressManager escrow contract
    address escrow;
    /// DepositAddressBridger contract
    IDepositAddressBridger bridger;
    /// DaimoPayPricer contract
    IDaimoPayPricer pricer;
    /// Maximum slippage allowed on starts. Expected slippage from token sent
    /// by the user to the bridge token.
    uint256 maxStartSlippageBps;
    /// Maximum slippage allowed on fast finishes. Expected slippage from bridge
    /// token to final token.
    uint256 maxFastFinishSlippageBps;
    /// Maximum slippage allowed on same chain finishes. Expected slippage from
    /// payment token to final token.
    uint256 maxSameChainFinishSlippageBps;
    /// Timestamp after which the deposit address expires and can be refunded
    uint256 expiresAt;
}

/// @notice Parameters that uniquely identify a single intent (cross-chain
///         transfer) for a Deposit Address.
struct DepositAddressIntent {
    /// The Deposit Address contract for this intent
    address depositAddress;
    /// Unique salt/nonce provided by the relayer
    bytes32 relaySalt;
    /// Address and amount of token bridged to destination chain
    TokenAmount bridgeTokenOut;
    /// Chain ID where the bridge transfer originated
    uint256 sourceChainId;
}

/// @notice Calculate the deterministic hash committed to by the Deposit Address
function calcRouteHash(
    DepositAddressRoute calldata route
) pure returns (bytes32) {
    return keccak256(abi.encode(route));
}

/// @author Daimo, Inc
/// @notice Minimal vault contract that holds funds for a cross-chain deposit
///         route, enabling deterministic address across chains.
/// @dev Stateless design with only a fixed route hash allows cheap deployment
///      via proxy clones and reuse across multiple chains. Funds are held
///      securely until the Universal Address Manager orchestrates their release
///      for swaps, bridging, or refunds. Each vault is uniquely tied to a
///      specific route and can only be controlled by its designated escrow.
contract DepositAddress is Initializable, ReentrancyGuard {
    using SafeERC20 for IERC20;

    // ---------------------------------------------------------------------
    // Storage
    // ---------------------------------------------------------------------

    /// @dev Cheap single-slot storage – keccak256(DepositAddressRoute).
    bytes32 public routeHash;

    // ---------------------------------------------------------------------
    // Constructor / Initializer
    // ---------------------------------------------------------------------

    constructor() {
        _disableInitializers();
    }

    /// Accept native chain asset (e.g. ETH) deposits
    receive() external payable {
        emit NativeTransfer(msg.sender, address(this), msg.value);
    }

    /// @param _routeHash keccak256(DepositAddressRoute) committed by the factory.
    function initialize(bytes32 _routeHash) public initializer {
        routeHash = _routeHash;

        // Emit event for any ETH that arrived before deployment
        if (address(this).balance > 0) {
            emit NativeTransfer(
                address(0),
                address(this),
                address(this).balance
            );
        }
    }

    // ---------------------------------------------------------------------
    // Escrow helpers – only callable by the escrow/manager
    // ---------------------------------------------------------------------

    /// @notice Transfers the balance of a token from the vault to a
    ///         designated recipient. Callable only by the authorized escrow.
    /// @param route       The DepositAddressRoute that this vault was created for
    /// @param token       The token to transfer from the vault
    /// @param recipient   The address to receive the transferred tokens
    function sendBalance(
        DepositAddressRoute calldata route,
        IERC20 token,
        address payable recipient
    ) public nonReentrant returns (uint256) {
        require(calcRouteHash(route) == routeHash, "DA: route mismatch");
        require(msg.sender == route.escrow, "DA: only escrow");

        return TokenUtils.transferBalance({token: token, recipient: recipient});
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.12;

import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import "openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";

import "./TokenUtils.sol";

/// Represents a contract call.
struct Call {
    /// Address of the contract to call.
    address to;
    /// Native token amount for call, or 0
    uint256 value;
    /// Calldata for call
    bytes data;
}

/// @author Daimo, Inc
/// @custom:security-contact security@daimo.com
/// @notice This contract is used to execute arbitrary contract calls on behalf
/// of the DaimoPay escrow contract.
/// WARNING: Never approve tokens directly to this contract. Never transfer
/// tokens to this contract. Such tokens can be stolen by anyone. All
/// interactions with this contract should be done via the DaimoPay contract.
contract DaimoPayExecutor is ReentrancyGuard {
    using SafeERC20 for IERC20;

    /// The only address that is allowed to call the `execute` function.
    address public immutable escrow;

    constructor(address _escrow) {
        escrow = _escrow;
    }

    /// Execute arbitrary calls. Revert if any fail.
    /// Check that at least one of the expectedOutput tokens is present. Assumes
    /// that exactly one token is present and transfers it to the recipient.
    /// Returns any surplus tokens to the surplus recipient.
    function execute(
        Call[] calldata calls,
        TokenAmount[] calldata expectedOutput,
        address payable recipient,
        address payable surplusRecipient
    ) external nonReentrant {
        require(msg.sender == escrow, "DPCE: only escrow");

        // Execute provided calls.
        uint256 callsLength = calls.length;
        for (uint256 i = 0; i < callsLength; ++i) {
            Call calldata call = calls[i];
            (bool success, ) = call.to.call{value: call.value}(call.data);
            require(success, "DPCE: call failed");
        }

        /// Check that at least one of the expectedOutput tokens is present
        /// with enough balance.
        uint256 outputIndex = TokenUtils.checkBalance({
            tokenAmounts: expectedOutput
        });
        require(
            outputIndex < expectedOutput.length,
            "DPCE: insufficient output"
        );

        // Transfer the expected amount of the token to the recipient.
        TokenUtils.transfer({
            token: expectedOutput[outputIndex].token,
            recipient: recipient,
            amount: expectedOutput[outputIndex].amount
        });

        // Transfer any surplus tokens to the surplus recipient.
        TokenUtils.transferBalance({
            token: expectedOutput[outputIndex].token,
            recipient: surplusRecipient
        });
    }

    /// Execute arbitrary calls. Revert if any fail.
    /// Verify output token balance meets the expected minimum amount.
    /// Transfer the full balance to the recipient and return the amount.
    function executeAndSendBalance(
        Call[] calldata calls,
        TokenAmount calldata minOutputAmount,
        address payable recipient
    ) external nonReentrant returns (uint256 outputAmount) {
        require(msg.sender == escrow, "DPCE: only escrow");

        // Execute provided calls.
        uint256 callsLength = calls.length;
        for (uint256 i = 0; i < callsLength; ++i) {
            Call calldata call = calls[i];
            (bool success, ) = call.to.call{value: call.value}(call.data);
            require(success, "DPCE: call failed");
        }

        outputAmount = TokenUtils.getBalanceOf({
            token: minOutputAmount.token,
            addr: address(this)
        });
        require(
            outputAmount >= minOutputAmount.amount,
            "DPCE: output below min"
        );

        // Transfer the full balance of the token to the recipient.
        TokenUtils.transfer({
            token: minOutputAmount.token,
            recipient: recipient,
            amount: outputAmount
        });
    }

    /// Execute a final call. Approve the final token and make the call.
    /// Return whether the call succeeded.
    function executeFinalCall(
        Call calldata finalCall,
        TokenAmount calldata finalCallToken,
        address payable refundAddr
    ) external nonReentrant returns (bool success) {
        require(msg.sender == escrow, "DPCE: only escrow");

        // Approve the final call token to the final call contract.
        TokenUtils.approve({
            token: finalCallToken.token,
            spender: address(finalCall.to),
            amount: finalCallToken.amount
        });

        // Then, execute the final call.
        (success, ) = finalCall.to.call{value: finalCall.value}(finalCall.data);

        // Send any excess funds to the refund address.
        TokenUtils.transferBalance({
            token: finalCallToken.token,
            recipient: refundAddr
        });
    }

    /// Accept native-token (eg ETH) inputs
    receive() external payable {}
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.12;

import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";

/// Asset amount, e.g. $100 USDC or 0.1 ETH
struct TokenAmount {
    /// Zero address = native asset, e.g. ETH
    IERC20 token;
    uint256 amount;
}

/// Event emitted when native tokens (ETH, etc.) are transferred
event NativeTransfer(address indexed from, address indexed to, uint256 value);

/// Utility functions that work for both ERC20 and native tokens.
library TokenUtils {
    using SafeERC20 for IERC20;

    /// Returns ERC20 or ETH balance.
    function getBalanceOf(
        IERC20 token,
        address addr
    ) internal view returns (uint256) {
        if (address(token) == address(0)) {
            return addr.balance;
        } else {
            return token.balanceOf(addr);
        }
    }

    /// Approves a token transfer.
    function approve(IERC20 token, address spender, uint256 amount) internal {
        if (address(token) != address(0)) {
            token.forceApprove({spender: spender, value: amount});
        } // Do nothing for native token.
    }

    /// Sends an ERC20 or ETH transfer. For ETH, verify call success.
    function transfer(
        IERC20 token,
        address payable recipient,
        uint256 amount
    ) internal {
        if (recipient == address(this)) return; // No-op: tokens already here
        if (address(token) != address(0)) {
            token.safeTransfer({to: recipient, value: amount});
        } else {
            // Native token transfer
            (bool success, ) = recipient.call{value: amount}("");
            require(success, "TokenUtils: ETH transfer failed");
        }
    }

    /// Sends an ERC20 or ETH transfer. Returns true if successful.
    function tryTransfer(
        IERC20 token,
        address payable recipient,
        uint256 amount
    ) internal returns (bool) {
        if (recipient == address(this)) return true; // No-op: tokens already here
        if (address(token) != address(0)) {
            return token.trySafeTransfer({to: recipient, value: amount});
        } else {
            (bool success, ) = recipient.call{value: amount}("");
            return success;
        }
    }

    /// Sends an ERC20 transfer.
    function transferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        require(
            address(token) != address(0),
            "TokenUtils: ETH transferFrom must be caller"
        );
        token.safeTransferFrom({from: from, to: to, value: amount});
    }

    /// Sends any token balance in the contract to the recipient.
    function transferBalance(
        IERC20 token,
        address payable recipient
    ) internal returns (uint256) {
        uint256 balance = getBalanceOf({token: token, addr: address(this)});
        if (balance > 0) {
            transfer({token: token, recipient: recipient, amount: balance});
        }
        return balance;
    }

    /// Check that the address has enough of at least one of the tokenAmounts.
    /// Returns the index of the first token that has sufficient balance, or
    /// the length of the tokenAmounts array if no token has sufficient balance.
    function checkBalance(
        TokenAmount[] calldata tokenAmounts
    ) internal view returns (uint256) {
        uint256 n = tokenAmounts.length;
        for (uint256 i = 0; i < n; ++i) {
            TokenAmount calldata tokenAmount = tokenAmounts[i];
            uint256 balance = getBalanceOf({
                token: tokenAmount.token,
                addr: address(this)
            });
            if (balance >= tokenAmount.amount) {
                return i;
            }
        }
        return n;
    }

    /// @notice Converts a token amount between different decimal representations.
    /// @param amount The token amount in the source decimal format.
    /// @param fromDecimals Decimals of the source token (e.g., 6 for USDC).
    /// @param toDecimals Decimals of the destination token (e.g., 18 for DAI).
    /// @param roundUp If true, rounds up when scaling down (losing precision).
    ///        Use true when calculating required input amounts (user pays more).
    ///        Use false when calculating output amounts (user receives less).
    /// @return The converted amount in the destination decimal format.
    function convertTokenAmountDecimals(
        uint256 amount,
        uint256 fromDecimals,
        uint256 toDecimals,
        bool roundUp
    ) internal pure returns (uint256) {
        if (toDecimals == fromDecimals) {
            return amount;
        } else if (toDecimals > fromDecimals) {
            return amount * 10 ** (toDecimals - fromDecimals);
        } else {
            uint256 decimalDiff = fromDecimals - toDecimals;
            uint256 divisor = 10 ** decimalDiff;
            if (roundUp) {
                return (amount + divisor - 1) / divisor;
            } else {
                return amount / divisor;
            }
        }
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.12;

import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";

import "./TokenUtils.sol";
import "./interfaces/IDaimoPayPricer.sol";

/// @title SwapMath
/// @author Daimo, Inc
/// @custom:security-contact security@daimo.com
/// @notice Pure mathematical functions for computing swap outputs based on
///         USD price feeds. All functions are stateless and overflow-safe.
library SwapMath {
    /// @notice Compute the amount of buy token that can be purchased with a
    ///         given amount of sell token, based on USD prices and slippage.
    /// @dev Formula:
    ///      buyAmount = (sellAmount / 10^sellDecimals * sellPriceUsd)
    ///                  / buyPriceUsd * 10^buyDecimals
    ///                  * (10_000 - maxSlippage) / 10_000
    ///
    ///      Simplified to minimize rounding errors:
    ///      buyAmount = (sellAmount * sellPriceUsd * (10_000 - maxSlippage) * 10^buyDecimals)
    ///                  / (buyPriceUsd * 10_000 * 10^sellDecimals)
    ///
    /// @param sellTokenPrice Price data for the token being sold
    /// @param buyTokenPrice Price data for the token being bought
    /// @param sellAmount Amount of sell token (in token's native decimals)
    /// @param maxSlippage Maximum slippage in basis points (e.g., 50 = 0.5%)
    /// @return TokenAmount struct containing the buy token and computed amount
    function computeMinSwapOutput(
        PriceData memory sellTokenPrice,
        PriceData memory buyTokenPrice,
        uint256 sellAmount,
        uint256 maxSlippage
    ) public view returns (TokenAmount memory) {
        require(maxSlippage <= 10_000, "SwapMath: slippage > 100%");
        require(sellTokenPrice.priceUsd > 0, "SwapMath: sell price zero");
        require(buyTokenPrice.priceUsd > 0, "SwapMath: buy price zero");

        uint256 sellDecimals = IERC20Metadata(sellTokenPrice.token).decimals();
        uint256 buyDecimals = IERC20Metadata(buyTokenPrice.token).decimals();

        // Calculate: numerator = sellAmount * sellPriceUsd * (10_000 - maxSlippage) * 10^buyDecimals
        // Calculate: denominator = buyPriceUsd * 10_000 * 10^sellDecimals
        // Result: buyAmount = numerator / denominator

        uint256 slippageFactor = 10_000 - maxSlippage;

        // To avoid overflow, we do multiplication in stages and use mulDiv where possible
        // For now, implement straightforward version with overflow protection
        uint256 buyAmount;

        // Calculate intermediate value: sellAmount * sellPriceUsd
        uint256 sellValueUsd = sellAmount * sellTokenPrice.priceUsd;

        // Apply slippage: sellValueUsd * (10_000 - maxSlippage)
        uint256 sellValueWithSlippage = sellValueUsd * slippageFactor;

        // Adjust for decimals and divide by buy price
        // buyAmount = (sellValueWithSlippage * 10^buyDecimals) / (buyPriceUsd * 10_000 * 10^sellDecimals)
        if (buyDecimals >= sellDecimals) {
            uint256 decimalDiff = buyDecimals - sellDecimals;
            uint256 numerator = sellValueWithSlippage * (10 ** decimalDiff);
            uint256 denominator = buyTokenPrice.priceUsd * 10_000;
            buyAmount = numerator / denominator;
        } else {
            uint256 decimalDiff = sellDecimals - buyDecimals;
            uint256 denominator = buyTokenPrice.priceUsd *
                10_000 *
                (10 ** decimalDiff);
            buyAmount = sellValueWithSlippage / denominator;
        }

        return
            TokenAmount({
                token: IERC20(buyTokenPrice.token),
                amount: buyAmount
            });
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.12;

import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

import "../TokenUtils.sol";

/// @author Daimo, Inc
/// @custom:security-contact security@daimo.com
/// @notice Bridges assets. Specifically, it lets any relayer initiate a bridge
/// transaction to another chain.
interface IDaimoPayBridger {
    /// Emitted when a bridge transaction is initiated
    event BridgeInitiated(
        address fromAddress,
        address fromToken,
        uint256 fromAmount,
        uint256 toChainId,
        address toAddress,
        address toToken,
        uint256 toAmount,
        address refundAddress
    );

    /// Determine the input token and amount required to achieve one of the
    /// given output options on a given chain.
    function getBridgeTokenIn(
        uint256 toChainId,
        TokenAmount[] memory bridgeTokenOutOptions
    ) external view returns (address bridgeTokenIn, uint256 inAmount);

    /// Initiate a bridge. Guarantee that one of the bridge token options
    /// (bridgeTokenOut, outAmount) shows up at toAddress on toChainId.
    /// Otherwise, revert.
    function sendToChain(
        uint256 toChainId,
        address toAddress,
        TokenAmount[] calldata bridgeTokenOutOptions,
        address refundAddress,
        bytes calldata extraData
    ) external;
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.12;

import "../TokenUtils.sol";

struct PriceData {
    address token;
    uint256 priceUsd; // price of token in USD with 18 decimals
    uint256 timestamp;
    bytes signature;
}

/// @author Daimo, Inc
/// @custom:security-contact security@daimo.com
/// @notice Validates price data signature is from a trusted source.
interface IDaimoPayPricer {
    /// Validate the signature of the price data comes from a trusted source.
    function validatePrice(
        PriceData calldata priceData
    ) external view returns (bool);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 *
 * _Available since v5.1._
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedCall();

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Proxy.sol)

pragma solidity ^0.8.22;

import {Proxy} from "../Proxy.sol";
import {ERC1967Utils} from "./ERC1967Utils.sol";

/**
 * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
 * implementation address that can be changed. This address is stored in storage in the location specified by
 * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967], so that it doesn't conflict with the storage layout of the
 * implementation behind the proxy.
 */
contract ERC1967Proxy is Proxy {
    /**
     * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
     *
     * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
     * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
     *
     * Requirements:
     *
     * - If `data` is empty, `msg.value` must be zero.
     */
    constructor(address implementation, bytes memory _data) payable {
        ERC1967Utils.upgradeToAndCall(implementation, _data);
    }

    /**
     * @dev Returns the current implementation address.
     *
     * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using
     * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
     * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
     */
    function _implementation() internal view virtual override returns (address) {
        return ERC1967Utils.getImplementation();
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reinitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
     *
     * NOTE: Consider following the ERC-7201 formula to derive storage locations.
     */
    function _initializableStorageSlot() internal pure virtual returns (bytes32) {
        return INITIALIZABLE_STORAGE;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        bytes32 slot = _initializableStorageSlot();
        assembly {
            $.slot := slot
        }
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.12;

import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

import "../TokenUtils.sol";

/// @notice Simplified bridging interface for the Deposit Address system
///         that multiplexes between multiple bridge-specific adapters (e.g.
///         CCTP, Across, Axelar).
interface IDepositAddressBridger {
    /// @notice Returns the bridge output token for the given destination chain ID.
    /// @param toChainId The destination chain ID
    /// @return stableOut The bridge output token
    function chainIdToStableOut(
        uint256 toChainId
    ) external view returns (address stableOut);

    /// @notice Fetches a quote: what do I have to send in so that $x shows up
    ///         on the destination?
    /// @param toChainId       Destination chain
    /// @param bridgeTokenOut  The stablecoin token and amount to receive on
    ///                        the destination chain
    /// @return bridgeTokenIn  The asset that must be provided on the source
    ///                        chain
    /// @return inAmount       The exact quantity of bridgeTokenIn that must be
    ///                        provided
    function getBridgeTokenIn(
        uint256 toChainId,
        TokenAmount calldata bridgeTokenOut
    ) external view returns (address bridgeTokenIn, uint256 inAmount);

    /// @notice Execute the bridge. Reverts if the adapter can't deliver the
    ///         specified destination amount.
    /// @param toChainId       Destination chain id
    /// @param toAddress       Recipient address on the destination chain
    /// @param bridgeTokenOut  The stablecoin token and amount to receive on
    ///                        the destination chain
    /// @param refundAddress   Address to send funds to if the bridge fails
    /// @param extraData       Adapter-specific calldata
    function sendToChain(
        uint256 toChainId,
        address toAddress,
        TokenAmount calldata bridgeTokenOut,
        address refundAddress,
        bytes calldata extraData
    ) external;
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../utils/introspection/IERC165.sol";

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)

pragma solidity ^0.8.20;

/**
 * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
 * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
 * be specified by overriding the virtual {_implementation} function.
 *
 * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
 * different contract through the {_delegate} function.
 *
 * The success and return data of the delegated call will be returned back to the caller of the proxy.
 */
abstract contract Proxy {
    /**
     * @dev Delegates the current call to `implementation`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _delegate(address implementation) internal virtual {
        assembly {
            // Copy msg.data. We take full control of memory in this inline assembly
            // block because it will not return to Solidity code. We overwrite the
            // Solidity scratch pad at memory position 0.
            calldatacopy(0, 0, calldatasize())

            // Call the implementation.
            // out and outsize are 0 because we don't know the size yet.
            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

            // Copy the returned data.
            returndatacopy(0, 0, returndatasize())

            switch result
            // delegatecall returns 0 on error.
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }

    /**
     * @dev This is a virtual function that should be overridden so it returns the address to which the fallback
     * function and {_fallback} should delegate.
     */
    function _implementation() internal view virtual returns (address);

    /**
     * @dev Delegates the current call to the address returned by `_implementation()`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _fallback() internal virtual {
        _delegate(_implementation());
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
     * function in the contract matches the call data.
     */
    fallback() external payable virtual {
        _fallback();
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Utils.sol)

pragma solidity ^0.8.22;

import {IBeacon} from "../beacon/IBeacon.sol";
import {IERC1967} from "../../interfaces/IERC1967.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";

/**
 * @dev This library provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots.
 */
library ERC1967Utils {
    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev The `implementation` of the proxy is invalid.
     */
    error ERC1967InvalidImplementation(address implementation);

    /**
     * @dev The `admin` of the proxy is invalid.
     */
    error ERC1967InvalidAdmin(address admin);

    /**
     * @dev The `beacon` of the proxy is invalid.
     */
    error ERC1967InvalidBeacon(address beacon);

    /**
     * @dev An upgrade function sees `msg.value > 0` that may be lost.
     */
    error ERC1967NonPayable();

    /**
     * @dev Returns the current implementation address.
     */
    function getImplementation() internal view returns (address) {
        return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the ERC-1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        if (newImplementation.code.length == 0) {
            revert ERC1967InvalidImplementation(newImplementation);
        }
        StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Performs implementation upgrade with additional setup call if data is nonempty.
     * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
     * to avoid stuck value in the contract.
     *
     * Emits an {IERC1967-Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) internal {
        _setImplementation(newImplementation);
        emit IERC1967.Upgraded(newImplementation);

        if (data.length > 0) {
            Address.functionDelegateCall(newImplementation, data);
        } else {
            _checkNonPayable();
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Returns the current admin.
     *
     * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using
     * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
     * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
     */
    function getAdmin() internal view returns (address) {
        return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the ERC-1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        if (newAdmin == address(0)) {
            revert ERC1967InvalidAdmin(address(0));
        }
        StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {IERC1967-AdminChanged} event.
     */
    function changeAdmin(address newAdmin) internal {
        emit IERC1967.AdminChanged(getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Returns the current beacon.
     */
    function getBeacon() internal view returns (address) {
        return StorageSlot.getAddressSlot(BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the ERC-1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        if (newBeacon.code.length == 0) {
            revert ERC1967InvalidBeacon(newBeacon);
        }

        StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;

        address beaconImplementation = IBeacon(newBeacon).implementation();
        if (beaconImplementation.code.length == 0) {
            revert ERC1967InvalidImplementation(beaconImplementation);
        }
    }

    /**
     * @dev Change the beacon and trigger a setup call if data is nonempty.
     * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
     * to avoid stuck value in the contract.
     *
     * Emits an {IERC1967-BeaconUpgraded} event.
     *
     * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
     * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
     * efficiency.
     */
    function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
        _setBeacon(newBeacon);
        emit IERC1967.BeaconUpgraded(newBeacon);

        if (data.length > 0) {
            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
        } else {
            _checkNonPayable();
        }
    }

    /**
     * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
     * if an upgrade doesn't perform an initialization call.
     */
    function _checkNonPayable() private {
        if (msg.value > 0) {
            revert ERC1967NonPayable();
        }
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeacon {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {UpgradeableBeacon} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)

pragma solidity ^0.8.20;

/**
 * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
 */
interface IERC1967 {
    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Emitted when the beacon is changed.
     */
    event BeaconUpgraded(address indexed beacon);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol)

pragma solidity ^0.8.20;

import {Errors} from "./Errors.sol";

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }

        (bool success, bytes memory returndata) = recipient.call{value: amount}("");
        if (!success) {
            _revert(returndata);
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {Errors.FailedCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
     * of an unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {Errors.FailedCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            assembly ("memory-safe") {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert Errors.FailedCall();
        }
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC-1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct Int256Slot {
        int256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Int256Slot` with member `value` located at `slot`.
     */
    function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns a `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):