Address Contract Verified
Address
0x643aDac1a1Fc6cCE46120bc7FEe8f58a7E535328
Balance
0 ETH
Nonce
1
Code Size
6129 bytes
Creator
0xc3792470...5178 at tx 0x63b794f5...51d080
Indexed Transactions
0
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