Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x643aDac1a1Fc6cCE46120bc7FEe8f58a7E535328
Balance 0 ETH
Nonce 1
Code Size 6129 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

6129 bytes
0x60806040526004361015610011575f80fd5b5f3560e01c80633c930575146100e45780633f965e56146100df57806351160630146100da5780635131bf8e146100d55780635744daef146100d057806377a1736b146100cb5780638aebd348146100c6578063904d1da7146100c15780639b552cc2146100bc578063aced1661146100b7578063d6ad7a7e146100b2578063f698da25146100ad5763f7260d3e146100a8575f80fd5b6107b0565b610758565b6106ea565b61067c565b61060e565b6105c8565b610570565b6104c7565b6102df565b610287565b610219565b610187565b34610152575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015257602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2168152f35b5f80fd5b9181601f840112156101525782359167ffffffffffffffff8311610152576020808501948460051b01011161015257565b346101525760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101525767ffffffffffffffff600435818111610152576101d7903690600401610156565b919060243592828411610152573660238501121561015257836004013592831161015257366024606085028601011161015257602461021794019161081e565b005b34610152575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015257602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41168152f35b34610152575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101525760206040517f0000000000000000000000000000000000000000000000000429d069189e00008152f35b34610152576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610152576004359067ffffffffffffffff908183116101525736602384011215610152578260040135918211610152576024906006933660248560061b830101116101525773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000005c5494572e4ab2d48d3ab3aaf6bd4e7b1c9838216330361049d5761039684610ec6565b945f5b8581106103a957610217876114a8565b80600191831b84016104266103cb60446103c48a8501610f89565b9301610f89565b61045260409182519384917f095ea7b3000000000000000000000000000000000000000000000000000000008c8401528c830160205f9193929373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101845283610de6565b61047961045d610ea1565b73ffffffffffffffffffffffffffffffffffffffff9094168452565b5f8884015282015261048b828a61100a565b52610496818961100a565b5001610399565b60046040517fc60eb335000000000000000000000000000000000000000000000000000000008152fd5b346101525760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101525760043567ffffffffffffffff811161015257610516903690600401610156565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000005c5494572e4ab2d48d3ab3aaf6bd4e7b1c9838216330361049d5761056b6102179261056383610ec6565b92839161106e565b6114a8565b34610152575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101525760206040517fbcca8463f460f14bca0185afeeb75923ee4434612f41063d0171b1e743ffe84b8152f35b34610152575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015257602061060061104b565b63ffffffff60405191168152f35b34610152575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015257602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c92e8bdf79f0507f65a392b0ab4667716bfe0110168152f35b34610152575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015257602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000005c5494572e4ab2d48d3ab3aaf6bd4e7b1c98382168152f35b34610152575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015257602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000423cec87f19f0778f549846e0801ee267a917935168152f35b34610152575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101525760206040517fc078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e89438152f35b34610152575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015257602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a03be496e67ec29bc62f01a428683d7f9c204930168152f35b73ffffffffffffffffffffffffffffffffffffffff949391927f00000000000000000000000005c5494572e4ab2d48d3ab3aaf6bd4e7b1c983828616330361049d576040517f70a082310000000000000000000000000000000000000000000000000000000081527f0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41871673ffffffffffffffffffffffffffffffffffffffff1660048201527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28716966020826024818b5afa948515610d775786925f96610d46575b506109576109456109128386610e6e565b7f0000000000000000000000000000000000000000000000000429d069189e00008910610d3e5760ff60015b1690610e6e565b9561094f87610ec6565b98899161106e565b6109e561096261104b565b61098f61096d610e80565b5f815273ffffffffffffffffffffffffffffffffffffffff909c1660208d0152565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a03be496e67ec29bc62f01a428683d7f9c2049301660408c01525f60608c0181905260808c015263ffffffff1660a08b0152565b7fbcca8463f460f14bca0185afeeb75923ee4434612f41063d0171b1e743ffe84b60c08a01525f60e08a01527ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467756101008a015260016101208a01527f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9806101408b01526101608a01525f5b818110610ba5575050505050610ab29394507f0000000000000000000000000000000000000000000000000429d069189e0000821015610ab4575b50506114a8565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201527f000000000000000000000000a03be496e67ec29bc62f01a428683d7f9c20493073ffffffffffffffffffffffffffffffffffffffff166024820152604480820193909352918252610b9d9190610b8b90610b39606484610de6565b610b41610ea1565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2168152925f6020850152604084015261101e565b90610b96828561100a565b528261100a565b505f80610aab565b6040610bb2828488610f74565b610bf4610bda610bc183610f89565b73ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff168d52565b602081013560608d015201358060808c01527f0000000000000000000000000000000000000000000000000429d069189e000011610d1457600190610d0d610c76610ca2610c418e611188565b6040519283917fec6cb13f00000000000000000000000000000000000000000000000000000000602084015260248301610fed565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610de6565b610caa610ea1565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab418816168152905f60208301526040820152610cfb8784610e6e565b90610d06828d61100a565b528a61100a565b5001610a70565b60046040517f529196de000000000000000000000000000000000000000000000000000000008152fd5b60ff5f61093e565b610d6991965060203d602011610d70575b610d618183610de6565b810190610e27565b945f610901565b503d610d57565b610e36565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6060810190811067ffffffffffffffff821117610dc557604052565b610d7c565b6020810190811067ffffffffffffffff821117610dc557604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610dc557604052565b90816020910312610152575190565b6040513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b91908201809211610e7b57565b610e41565b60405190610180820182811067ffffffffffffffff821117610dc557604052565b60405190610ab282610da9565b67ffffffffffffffff8111610dc55760051b60200190565b90610ed082610eae565b604090610ee06040519182610de6565b8381527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610f0e8295610eae565b01915f5b838110610f1f5750505050565b6020908251610f2d81610da9565b5f8152825f81830152606085830152828601015201610f12565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9190811015610f84576060020190565b610f47565b3573ffffffffffffffffffffffffffffffffffffffff811681036101525790565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b91906020611005600192604086526040860190610faa565b930152565b8051821015610f845760209160051b010190565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211610e7b57565b610e1042064203428111610e7b57611c208101809111610e7b5763ffffffff1690565b7f000000000000000000000000c92e8bdf79f0507f65a392b0ab4667716bfe011073ffffffffffffffffffffffffffffffffffffffff16905f5b8381106110b6575050505050565b6110c48160051b8301610f89565b9060409182516020937f095ea7b3000000000000000000000000000000000000000000000000000000008583015286602483015260447fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8184015282526080820182811067ffffffffffffffff821117610dc5576001955f91835261116661114a610ea1565b73ffffffffffffffffffffffffffffffffffffffff9096168652565b840152820152611176828861100a565b52611181818761100a565b50016110a8565b7fffffffff0000000000000000000000000000000000000000000000000000000060a060427fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0840180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a082209152604051907f190100000000000000000000000000000000000000000000000000000000000082527fc078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e894360028301526022820152209201516040519260208401527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000007f0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab4160601b16604084015260e01b166054820152603881526112bc81610da9565b90565b908082519081815260208091019281808460051b8301019501935f915b8483106112ec5750505050505090565b90919293949584806113bc837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086600196030187528a51906101609082518152848301518582015261135b6040808501519083019073ffffffffffffffffffffffffffffffffffffffff169052565b606083810151908201526080808401519082015260a08084015163ffffffff169082015260c0808401519082015260e08084015190820152610100808401519082015261012080840151908201528161014080940151938201520190610faa565b98019301930191949392906112dc565b9080606080820193925f915b600383106113e857505050505090565b9091929394848103835285518051918281526020928382019084808260051b8501019401925f5b82811061142f5750505050509080600192970193019301919392906113d8565b9091929394868061149b837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe087600196030189528b8a519173ffffffffffffffffffffffffffffffffffffffff8351168152848301518582015281604080940151938201520190610faa565b970195019392910161140f565b9060409182516114b781610dca565b5f81528351936114c685610dca565b5f855280516114d481610dca565b5f81528151916114e383610da9565b80516114ee81610dca565b5f8152835260209485840152805161150581610dca565b5f81528184015251937f13d79a0b000000000000000000000000000000000000000000000000000000008186015260a485016080602487015284518091528160c487019501905f5b81811061161f575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc93848682030160448701528180895192838152019801915f5b82811061160b57505050508284926115bd88610c76946115cc97876116089b9c030160648801526112bf565b918483030160848501526113cc565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41166116e0565b50565b83518a529881019892810192600101611591565b825173ffffffffffffffffffffffffffffffffffffffff168752958301959183019160010161154d565b91906040838203126101525782518015158103610152579260208082015167ffffffffffffffff9283821161015257019183601f84011215610152578251908111610dc557604051936116c3837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160186610de6565b8185528282850101116101525780825f94018386015e8301015290565b611749915f809273ffffffffffffffffffffffffffffffffffffffff918291604051968795869485937f5229073f000000000000000000000000000000000000000000000000000000008552166004840152836024840152608060448401526084830190610faa565b82606483015203927f000000000000000000000000423cec87f19f0778f549846e0801ee267a917935165af1908115610d77575f905f92611796575b501561178e5790565b602081519101fd5b90506117b491503d805f833e6117ac8183610de6565b810190611649565b905f61178556fea26469706673582212202d143bc56eae9a2e3f5e0075b30fe943ac94cf39d25e0f1c4ef3a97da181b9e064736f6c63430008190033

Verified Source Code Full Match

Compiler: v0.8.25+commit.b61c2a91 EVM: cancun Optimization: Yes (100000 runs)
COWFeeModule.sol 200 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.25;

import { ISafe } from "./interfaces/ISafe.sol";
import { IGPv2Settlement } from "./interfaces/IGPv2Settlement.sol";
import { IERC20 } from "./interfaces/IERC20.sol";
import { GPv2Order } from "./libraries/GPv2Order.sol";

contract COWFeeModule {
    error OnlyKeeper();
    error BuyAmountTooSmall();

    // not public to save deployment costs
    ISafe public immutable targetSafe;
    address public immutable toToken;
    address public immutable keeper;
    bytes32 public immutable domainSeparator;
    bytes32 public immutable appData;
    IGPv2Settlement public immutable settlement;
    address public immutable vaultRelayer;
    address public immutable receiver;
    uint256 public immutable minOut;

    struct Revocation {
        address token;
        address spender;
    }

    struct SwapToken {
        address token;
        uint256 sellAmount;
        uint256 buyAmount;
    }

    modifier onlyKeeper() {
        if (msg.sender != keeper) {
            revert OnlyKeeper();
        }
        _;
    }

    constructor(
        address _settlement,
        address _targetSafe,
        address _toToken,
        address _keeper,
        bytes32 _appData,
        address _receiver,
        uint256 _minOut
    ) {
        settlement = IGPv2Settlement(_settlement);
        vaultRelayer = settlement.vaultRelayer();
        targetSafe = ISafe(_targetSafe);
        toToken = _toToken;
        keeper = _keeper;
        domainSeparator = settlement.domainSeparator();
        appData = _appData;
        receiver = _receiver;
        minOut = _minOut;
    }

    /// @notice Approve given tokens of settlement contract to vault relayer
    function approve(address[] calldata _tokens) external onlyKeeper {
        IGPv2Settlement.InteractionData[] memory approveInteractions =
            new IGPv2Settlement.InteractionData[](_tokens.length);
        _approveInteractions(_tokens, approveInteractions);
        _execInteractions(approveInteractions);
    }

    /// @notice Revoke approvals for given tokens to given contracts
    function revoke(Revocation[] calldata _revocations) external onlyKeeper {
        IGPv2Settlement.InteractionData[] memory revokeInteractions =
            new IGPv2Settlement.InteractionData[](_revocations.length);
        for (uint256 i = 0; i < _revocations.length;) {
            Revocation calldata revocation = _revocations[i];
            revokeInteractions[i] = IGPv2Settlement.InteractionData({
                to: revocation.token,
                value: 0,
                callData: abi.encodeCall(IERC20.approve, (revocation.spender, 0))
            });

            unchecked {
                ++i;
            }
        }
        _execInteractions(revokeInteractions);
    }

    /// @notice Commit presignatures for sell orders of given tokens of given amounts.
    ///         Optionally, also approve the tokens to be spent to the vault relayer.
    function drip(address[] calldata _approveTokens, SwapToken[] calldata _swapTokens) external onlyKeeper {
        // we need a special interaction for toToken because cowswap wont quote a swap where buy
        // and sell tokens are identical.
        uint256 toTokenBalance = IERC20(toToken).balanceOf(address(settlement));

        // determine if we need a toToken transfer interaction
        bool hasToTokenTransfer = toTokenBalance >= minOut;
        uint256 len = _approveTokens.length + _swapTokens.length + (hasToTokenTransfer ? 1 : 0);

        IGPv2Settlement.InteractionData[] memory approveAndDripInteractions = new IGPv2Settlement.InteractionData[](len);
        _approveInteractions(_approveTokens, approveAndDripInteractions);

        GPv2Order.Data memory order = GPv2Order.Data({
            sellToken: IERC20(address(0)),
            buyToken: IERC20(toToken),
            receiver: receiver,
            sellAmount: 0,
            buyAmount: 0,
            validTo: nextValidTo(),
            appData: appData,
            feeAmount: 0,
            kind: GPv2Order.KIND_SELL,
            partiallyFillable: true,
            sellTokenBalance: GPv2Order.BALANCE_ERC20,
            buyTokenBalance: GPv2Order.BALANCE_ERC20
        });

        uint256 offset = _approveTokens.length;
        for (uint256 i = 0; i < _swapTokens.length;) {
            SwapToken calldata swapToken = _swapTokens[i];
            order.sellToken = IERC20(swapToken.token);
            order.sellAmount = swapToken.sellAmount;
            order.buyAmount = swapToken.buyAmount;
            if (swapToken.buyAmount < minOut) revert BuyAmountTooSmall();
            bytes memory preSignature = _computePreSignature(order);

            approveAndDripInteractions[i + offset] = IGPv2Settlement.InteractionData({
                to: address(settlement),
                value: 0,
                callData: abi.encodeCall(IGPv2Settlement.setPreSignature, (preSignature, true))
            });

            unchecked {
                ++i;
            }
        }

        // add toToken direct transfer interaction
        if (hasToTokenTransfer) {
            approveAndDripInteractions[len - 1] = IGPv2Settlement.InteractionData({
                to: toToken,
                value: 0,
                callData: abi.encodeCall(IERC20.transfer, (receiver, toTokenBalance))
            });
        }

        _execInteractions(approveAndDripInteractions);
    }

    /// @notice The `validTo` that the orders will be createad with
    /// @dev deterministic so the script can push the orders before dripping onchain
    function nextValidTo() public view returns (uint32) {
        uint256 remainder = block.timestamp % 1 hours;
        return uint32((block.timestamp - remainder) + 2 hours);
    }

    function _approveInteractions(address[] calldata _tokens, IGPv2Settlement.InteractionData[] memory _interactions)
        internal
        view
    {
        for (uint256 i = 0; i < _tokens.length;) {
            address token = _tokens[i];
            _interactions[i] = IGPv2Settlement.InteractionData({
                to: token,
                value: 0,
                callData: abi.encodeCall(IERC20.approve, (vaultRelayer, type(uint256).max))
            });

            unchecked {
                ++i;
            }
        }
    }

    function _execFromModule(address _to, bytes memory _cd) internal returns (bytes memory) {
        (bool success, bytes memory returnData) =
            targetSafe.execTransactionFromModuleReturnData(_to, 0, _cd, ISafe.Operation.Call);
        if (!success) {
            assembly ("memory-safe") {
                revert(add(returnData, 0x20), mload(returnData))
            }
        }
        return returnData;
    }

    function _execInteractions(IGPv2Settlement.InteractionData[] memory _interactions) internal {
        address[] memory tokens = new address[](0);
        uint256[] memory clearingPrices = new uint256[](0);
        IGPv2Settlement.TradeData[] memory trades = new IGPv2Settlement.TradeData[](0);
        IGPv2Settlement.InteractionData[][3] memory interactions =
            [new IGPv2Settlement.InteractionData[](0), _interactions, new IGPv2Settlement.InteractionData[](0)];
        bytes memory cd = abi.encodeCall(IGPv2Settlement.settle, (tokens, clearingPrices, trades, interactions));
        _execFromModule(address(settlement), cd);
    }

    function _computePreSignature(GPv2Order.Data memory order) internal view returns (bytes memory) {
        bytes32 orderDigest = GPv2Order.hash(order, domainSeparator);
        return abi.encodePacked(orderDigest, address(settlement), order.validTo);
    }
}
ISafe.sol 15 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.25;

interface ISafe {
    enum Operation {
        Call,
        DelegateCall
    }

    function execTransactionFromModuleReturnData(address to, uint256 value, bytes memory data, Operation operation)
        external
        returns (bool success, bytes memory returnData);

    function enableModule(address module) external;
}
IERC20.sol 8 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.25;

interface IERC20 {
    function approve(address, uint256) external;
    function balanceOf(address) external view returns (uint256);
    function transfer(address, uint256) external;
}
GPv2Order.sol 227 lines
// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity 0.8.25;

import "../interfaces/IERC20.sol";

/// @title Gnosis Protocol v2 Order Library
/// @author Gnosis Developers
library GPv2Order {
    /// @dev The complete data for a Gnosis Protocol order. This struct contains
    /// all order parameters that are signed for submitting to GP.
    struct Data {
        IERC20 sellToken;
        IERC20 buyToken;
        address receiver;
        uint256 sellAmount;
        uint256 buyAmount;
        uint32 validTo;
        bytes32 appData;
        uint256 feeAmount;
        bytes32 kind;
        bool partiallyFillable;
        bytes32 sellTokenBalance;
        bytes32 buyTokenBalance;
    }

    /// @dev The order EIP-712 type hash for the [`GPv2Order.Data`] struct.
    ///
    /// This value is pre-computed from the following expression:
    /// ```
    /// keccak256(
    ///     "Order(" +
    ///         "address sellToken," +
    ///         "address buyToken," +
    ///         "address receiver," +
    ///         "uint256 sellAmount," +
    ///         "uint256 buyAmount," +
    ///         "uint32 validTo," +
    ///         "bytes32 appData," +
    ///         "uint256 feeAmount," +
    ///         "string kind," +
    ///         "bool partiallyFillable," +
    ///         "string sellTokenBalance," +
    ///         "string buyTokenBalance" +
    ///     ")"
    /// )
    /// ```
    bytes32 internal constant TYPE_HASH = hex"d5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e489";

    /// @dev The marker value for a sell order for computing the order struct
    /// hash. This allows the EIP-712 compatible wallets to display a
    /// descriptive string for the order kind (instead of 0 or 1).
    ///
    /// This value is pre-computed from the following expression:
    /// ```
    /// keccak256("sell")
    /// ```
    bytes32 internal constant KIND_SELL = hex"f3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775";

    /// @dev The OrderKind marker value for a buy order for computing the order
    /// struct hash.
    ///
    /// This value is pre-computed from the following expression:
    /// ```
    /// keccak256("buy")
    /// ```
    bytes32 internal constant KIND_BUY = hex"6ed88e868af0a1983e3886d5f3e95a2fafbd6c3450bc229e27342283dc429ccc";

    /// @dev The TokenBalance marker value for using direct ERC20 balances for
    /// computing the order struct hash.
    ///
    /// This value is pre-computed from the following expression:
    /// ```
    /// keccak256("erc20")
    /// ```
    bytes32 internal constant BALANCE_ERC20 = hex"5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9";

    /// @dev The TokenBalance marker value for using Balancer Vault external
    /// balances (in order to re-use Vault ERC20 approvals) for computing the
    /// order struct hash.
    ///
    /// This value is pre-computed from the following expression:
    /// ```
    /// keccak256("external")
    /// ```
    bytes32 internal constant BALANCE_EXTERNAL = hex"abee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea0632";

    /// @dev The TokenBalance marker value for using Balancer Vault internal
    /// balances for computing the order struct hash.
    ///
    /// This value is pre-computed from the following expression:
    /// ```
    /// keccak256("internal")
    /// ```
    bytes32 internal constant BALANCE_INTERNAL = hex"4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce";

    /// @dev Marker address used to indicate that the receiver of the trade
    /// proceeds should the owner of the order.
    ///
    /// This is chosen to be `address(0)` for gas efficiency as it is expected
    /// to be the most common case.
    address internal constant RECEIVER_SAME_AS_OWNER = address(0);

    /// @dev The byte length of an order unique identifier.
    uint256 internal constant UID_LENGTH = 56;

    /// @dev Returns the actual receiver for an order. This function checks
    /// whether or not the [`receiver`] field uses the marker value to indicate
    /// it is the same as the order owner.
    ///
    /// @return receiver The actual receiver of trade proceeds.
    function actualReceiver(Data memory order, address owner) internal pure returns (address receiver) {
        if (order.receiver == RECEIVER_SAME_AS_OWNER) {
            receiver = owner;
        } else {
            receiver = order.receiver;
        }
    }

    /// @dev Return the EIP-712 signing hash for the specified order.
    ///
    /// @param order The order to compute the EIP-712 signing hash for.
    /// @param domainSeparator The EIP-712 domain separator to use.
    /// @return orderDigest The 32 byte EIP-712 struct hash.
    function hash(Data memory order, bytes32 domainSeparator) internal pure returns (bytes32 orderDigest) {
        bytes32 structHash;

        // NOTE: Compute the EIP-712 order struct hash in place. As suggested
        // in the EIP proposal, noting that the order struct has 12 fields, and
        // prefixing the type hash `(1 + 12) * 32 = 416` bytes to hash.
        // <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-encodedata>
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let dataStart := sub(order, 32)
            let temp := mload(dataStart)
            mstore(dataStart, TYPE_HASH)
            structHash := keccak256(dataStart, 416)
            mstore(dataStart, temp)
        }

        // NOTE: Now that we have the struct hash, compute the EIP-712 signing
        // hash using scratch memory past the free memory pointer. The signing
        // hash is computed from `"\x19\x01" || domainSeparator || structHash`.
        // <https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html#layout-in-memory>
        // <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#specification>
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let freeMemoryPointer := mload(0x40)
            mstore(freeMemoryPointer, "\x19\x01")
            mstore(add(freeMemoryPointer, 2), domainSeparator)
            mstore(add(freeMemoryPointer, 34), structHash)
            orderDigest := keccak256(freeMemoryPointer, 66)
        }
    }

    /// @dev Packs order UID parameters into the specified memory location. The
    /// result is equivalent to `abi.encodePacked(...)` with the difference that
    /// it allows re-using the memory for packing the order UID.
    ///
    /// This function reverts if the order UID buffer is not the correct size.
    ///
    /// @param orderUid The buffer pack the order UID parameters into.
    /// @param orderDigest The EIP-712 struct digest derived from the order
    /// parameters.
    /// @param owner The address of the user who owns this order.
    /// @param validTo The epoch time at which the order will stop being valid.
    function packOrderUidParams(bytes memory orderUid, bytes32 orderDigest, address owner, uint32 validTo)
        internal
        pure
    {
        require(orderUid.length == UID_LENGTH, "GPv2: uid buffer overflow");

        // NOTE: Write the order UID to the allocated memory buffer. The order
        // parameters are written to memory in **reverse order** as memory
        // operations write 32-bytes at a time and we want to use a packed
        // encoding. This means, for example, that after writing the value of
        // `owner` to bytes `20:52`, writing the `orderDigest` to bytes `0:32`
        // will **overwrite** bytes `20:32`. This is desirable as addresses are
        // only 20 bytes and `20:32` should be `0`s:
        //
        //        |           1111111111222222222233333333334444444444555555
        //   byte | 01234567890123456789012345678901234567890123456789012345
        // -------+---------------------------------------------------------
        //  field | [.........orderDigest..........][......owner.......][vT]
        // -------+---------------------------------------------------------
        // mstore |                         [000000000000000000000000000.vT]
        //        |                     [00000000000.......owner.......]
        //        | [.........orderDigest..........]
        //
        // Additionally, since Solidity `bytes memory` are length prefixed,
        // 32 needs to be added to all the offsets.
        //
        // solhint-disable-next-line no-inline-assembly
        assembly {
            mstore(add(orderUid, 56), validTo)
            mstore(add(orderUid, 52), owner)
            mstore(add(orderUid, 32), orderDigest)
        }
    }

    /// @dev Extracts specific order information from the standardized unique
    /// order id of the protocol.
    ///
    /// @param orderUid The unique identifier used to represent an order in
    /// the protocol. This uid is the packed concatenation of the order digest,
    /// the validTo order parameter and the address of the user who created the
    /// order. It is used by the user to interface with the contract directly,
    /// and not by calls that are triggered by the solvers.
    /// @return orderDigest The EIP-712 signing digest derived from the order
    /// parameters.
    /// @return owner The address of the user who owns this order.
    /// @return validTo The epoch time at which the order will stop being valid.
    function extractOrderUidParams(bytes calldata orderUid)
        internal
        pure
        returns (bytes32 orderDigest, address owner, uint32 validTo)
    {
        require(orderUid.length == UID_LENGTH, "GPv2: invalid uid");

        // Use assembly to efficiently decode packed calldata.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            orderDigest := calldataload(orderUid.offset)
            owner := shr(96, calldataload(add(orderUid.offset, 32)))
            validTo := shr(224, calldataload(add(orderUid.offset, 52)))
        }
    }
}
IGPv2Settlement.sol 52 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.25;

interface IGPv2Settlement {
    struct OrderData {
        address sellToken;
        address buyToken;
        address receiver;
        uint256 sellAmount;
        uint256 buyAmount;
        uint32 validTo;
        bytes32 appData;
        uint256 feeAmount;
        bytes32 kind;
        bool partiallyFillable;
        bytes32 sellTokenBalance;
        bytes32 buyTokenBalance;
    }

    struct TradeData {
        uint256 sellTokenIndex;
        uint256 buyTokenIndex;
        address receiver;
        uint256 sellAmount;
        uint256 buyAmount;
        uint32 validTo;
        bytes32 appData;
        uint256 feeAmount;
        uint256 flags;
        uint256 executedAmount;
        bytes signature;
    }

    struct InteractionData {
        address to;
        uint256 value;
        bytes callData;
    }

    function settle(
        address[] memory tokens,
        uint256[] memory clearingPrices,
        TradeData[] memory trades,
        InteractionData[][3] memory interactions
    ) external;

    function setPreSignature(bytes calldata orderUid, bool signed) external;

    function domainSeparator() external view returns (bytes32);

    function vaultRelayer() external view returns (address);
}

Read Contract

appData 0x8aebd348 → bytes32
domainSeparator 0xf698da25 → bytes32
keeper 0xaced1661 → address
minOut 0x5131bf8e → uint256
nextValidTo 0x904d1da7 → uint32
receiver 0xf7260d3e → address
settlement 0x51160630 → address
targetSafe 0xd6ad7a7e → address
toToken 0x3c930575 → address
vaultRelayer 0x9b552cc2 → address

Write Contract 3 functions

These functions modify contract state and require a wallet transaction to execute.

approve 0x77a1736b
address[] _tokens
drip 0xf2da73a2
address[] _approveTokens
tuple[] _swapTokens
revoke 0x5a0402f3
tuple[] _revocations

Recent Transactions

No transactions found for this address