Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x60e06040 | 18627864 | 546 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
CowswapOrderSigner
Compiler Version
v0.8.12+commit.f00d7308
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT // implementation based on https://gist.github.com/Arachnid/6950b3367258b5d5033f6e1c411086e8 // cowswap contracts taken from https://github.com/cowprotocol/contracts/releases/tag/v1.3.2 pragma solidity ^0.8.12; import "./cowProtocol/libraries/GPv2Order.sol"; import "./cowProtocol/mixins/GPv2Signing.sol"; import "./cowProtocol/interfaces/IERC20.sol"; contract CowswapOrderSigner { using GPv2Order for GPv2Order.Data; using GPv2Order for bytes; GPv2Signing public immutable signing; bytes32 public immutable domainSeparator; address public immutable deployedAt; constructor(GPv2Signing _signing) { require(address(_signing) != address(0), "Invalid signing address"); signing = _signing; domainSeparator = _signing.domainSeparator(); deployedAt = address(this); } function _setPreSignature( GPv2Order.Data calldata order, bool signed ) internal { require(address(this) != deployedAt, "DELEGATECALL only"); // compute order UID bytes32 orderDigest = order.hash(domainSeparator); bytes memory orderUid = new bytes(GPv2Order.UID_LENGTH); orderUid.packOrderUidParams(orderDigest, address(this), order.validTo); signing.setPreSignature(orderUid, signed); } function signOrder( GPv2Order.Data calldata order, uint32 validDuration, // seconds uint256 feeAmountBP // basis points ) external { require( block.timestamp + validDuration > order.validTo, "Dishonest valid duration" ); require( order.feeAmount <= (order.sellAmount * feeAmountBP) / 100_00 + 1, "Fee too high" ); _setPreSignature(order, true); } function unsignOrder(GPv2Order.Data calldata order) external { _setPreSignature(order, false); } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.8.12; library GPv2EIP1271 { /// @dev Value returned by a call to `isValidSignature` if the signature /// was verified successfully. The value is defined in EIP-1271 as: /// bytes4(keccak256("isValidSignature(bytes32,bytes)")) bytes4 internal constant MAGICVALUE = 0x1626ba7e; } /// @title EIP1271 Interface /// @dev Standardized interface for an implementation of smart contract /// signatures as described in EIP-1271. The code that follows is identical to /// the code in the standard with the exception of formatting and syntax /// changes to adapt the code to our Solidity version. interface EIP1271Verifier { /// @dev Should return whether the signature provided is valid for the /// provided data /// @param _hash Hash of the data to be signed /// @param _signature Signature byte array associated with _data /// /// MUST return the bytes4 magic value 0x1626ba7e when function passes. /// MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for /// solc > 0.5) /// MUST allow external calls /// function isValidSignature(bytes32 _hash, bytes memory _signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT // Vendored from OpenZeppelin contracts with minor modifications: // - Modified Solidity version // - Formatted code // - Added `name`, `symbol` and `decimals` function declarations // <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/token/ERC20/IERC20.sol> pragma solidity ^0.8.12; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface 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 number of decimals the token uses. */ function decimals() external view returns (uint8); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) 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 `amount` 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 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @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 ); }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.8.12; 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))) } } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.8.12; import "../interfaces/IERC20.sol"; import "../mixins/GPv2Signing.sol"; import "./GPv2Order.sol"; /// @title Gnosis Protocol v2 Trade Library. /// @author Gnosis Developers library GPv2Trade { using GPv2Order for GPv2Order.Data; using GPv2Order for bytes; /// @dev A struct representing a trade to be executed as part a batch /// settlement. struct Data { uint256 sellTokenIndex; uint256 buyTokenIndex; address receiver; uint256 sellAmount; uint256 buyAmount; uint32 validTo; bytes32 appData; uint256 feeAmount; uint256 flags; uint256 executedAmount; bytes signature; } /// @dev Extracts the order data and signing scheme for the specified trade. /// /// @param trade The trade. /// @param tokens The list of tokens included in the settlement. The token /// indices in the trade parameters map to tokens in this array. /// @param order The memory location to extract the order data to. function extractOrder( Data calldata trade, IERC20[] calldata tokens, GPv2Order.Data memory order ) internal pure returns (GPv2Signing.Scheme signingScheme) { order.sellToken = tokens[trade.sellTokenIndex]; order.buyToken = tokens[trade.buyTokenIndex]; order.receiver = trade.receiver; order.sellAmount = trade.sellAmount; order.buyAmount = trade.buyAmount; order.validTo = trade.validTo; order.appData = trade.appData; order.feeAmount = trade.feeAmount; ( order.kind, order.partiallyFillable, order.sellTokenBalance, order.buyTokenBalance, signingScheme ) = extractFlags(trade.flags); } /// @dev Decodes trade flags. /// /// Trade flags are used to tightly encode information on how to decode /// an order. Examples that directly affect the structure of an order are /// the kind of order (either a sell or a buy order) as well as whether the /// order is partially fillable or if it is a "fill-or-kill" order. It also /// encodes the signature scheme used to validate the order. As the most /// likely values are fill-or-kill sell orders by an externally owned /// account, the flags are chosen such that `0x00` represents this kind of /// order. The flags byte uses the following format: /// /// ``` /// bit | 31 ... | 6 | 5 | 4 | 3 | 2 | 1 | 0 | /// ----+----------+-------+---+-------+---+---+ /// | reserved | * * | * | * * | * | * | /// | | | | | | | /// | | | | | | +---- order kind bit, 0 for a sell order /// | | | | | | and 1 for a buy order /// | | | | | | /// | | | | | +-------- order fill bit, 0 for fill-or-kill /// | | | | | and 1 for a partially fillable order /// | | | | | /// | | | +---+------------ use internal sell token balance bit: /// | | | 0x: ERC20 token balance /// | | | 10: external Balancer Vault balance /// | | | 11: internal Balancer Vault balance /// | | | /// | | +-------------------- use buy token balance bit /// | | 0: ERC20 token balance /// | | 1: internal Balancer Vault balance /// | | /// +---+------------------------ signature scheme bits: /// 00: EIP-712 /// 01: eth_sign /// 10: EIP-1271 /// 11: pre_sign /// ``` function extractFlags(uint256 flags) internal pure returns ( bytes32 kind, bool partiallyFillable, bytes32 sellTokenBalance, bytes32 buyTokenBalance, GPv2Signing.Scheme signingScheme ) { if (flags & 0x01 == 0) { kind = GPv2Order.KIND_SELL; } else { kind = GPv2Order.KIND_BUY; } partiallyFillable = flags & 0x02 != 0; if (flags & 0x08 == 0) { sellTokenBalance = GPv2Order.BALANCE_ERC20; } else if (flags & 0x04 == 0) { sellTokenBalance = GPv2Order.BALANCE_EXTERNAL; } else { sellTokenBalance = GPv2Order.BALANCE_INTERNAL; } if (flags & 0x10 == 0) { buyTokenBalance = GPv2Order.BALANCE_ERC20; } else { buyTokenBalance = GPv2Order.BALANCE_INTERNAL; } // NOTE: Take advantage of the fact that Solidity will revert if the // following expression does not produce a valid enum value. This means // we check here that the leading reserved bits must be 0. signingScheme = GPv2Signing.Scheme(flags >> 5); } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.8.12; import "../interfaces/GPv2EIP1271.sol"; import "../libraries/GPv2Order.sol"; import "../libraries/GPv2Trade.sol"; /// @title Gnosis Protocol v2 Signing Library. /// @author Gnosis Developers abstract contract GPv2Signing { using GPv2Order for GPv2Order.Data; using GPv2Order for bytes; /// @dev Recovered trade data containing the extracted order and the /// recovered owner address. struct RecoveredOrder { GPv2Order.Data data; bytes uid; address owner; address receiver; } /// @dev Signing scheme used for recovery. enum Scheme { Eip712, EthSign, Eip1271, PreSign } /// @dev The EIP-712 domain type hash used for computing the domain /// separator. bytes32 private constant DOMAIN_TYPE_HASH = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); /// @dev The EIP-712 domain name used for computing the domain separator. bytes32 private constant DOMAIN_NAME = keccak256("Gnosis Protocol"); /// @dev The EIP-712 domain version used for computing the domain separator. bytes32 private constant DOMAIN_VERSION = keccak256("v2"); /// @dev Marker value indicating an order is pre-signed. uint256 private constant PRE_SIGNED = uint256(keccak256("GPv2Signing.Scheme.PreSign")); /// @dev The domain separator used for signing orders that gets mixed in /// making signatures for different domains incompatible. This domain /// separator is computed following the EIP-712 standard and has replay /// protection mixed in so that signed orders are only valid for specific /// GPv2 contracts. bytes32 public immutable domainSeparator; /// @dev Storage indicating whether or not an order has been signed by a /// particular address. mapping(bytes => uint256) public preSignature; /// @dev Event that is emitted when an account either pre-signs an order or /// revokes an existing pre-signature. event PreSignature(address indexed owner, bytes orderUid, bool signed); constructor() { // NOTE: Currently, the only way to get the chain ID in solidity is // using assembly. uint256 chainId; // solhint-disable-next-line no-inline-assembly assembly { chainId := chainid() } domainSeparator = keccak256( abi.encode( DOMAIN_TYPE_HASH, DOMAIN_NAME, DOMAIN_VERSION, chainId, address(this) ) ); } /// @dev Sets a presignature for the specified order UID. /// /// @param orderUid The unique identifier of the order to pre-sign. /// @param signed True to set the order as tradable with pre-sign, false to /// false to unset it. function setPreSignature(bytes calldata orderUid, bool signed) external { (, address owner, ) = orderUid.extractOrderUidParams(); require(owner == msg.sender, "GPv2: cannot presign order"); if (signed) { preSignature[orderUid] = PRE_SIGNED; } else { preSignature[orderUid] = 0; } emit PreSignature(owner, orderUid, signed); } /// @dev Returns an empty recovered order with a pre-allocated buffer for /// packing the unique identifier. /// /// @return recoveredOrder The empty recovered order data. function allocateRecoveredOrder() internal pure returns (RecoveredOrder memory recoveredOrder) { recoveredOrder.uid = new bytes(GPv2Order.UID_LENGTH); } /// @dev Extracts order data and recovers the signer from the specified /// trade. /// /// @param recoveredOrder Memory location used for writing the recovered order data. /// @param tokens The list of tokens included in the settlement. The token /// indices in the trade parameters map to tokens in this array. /// @param trade The trade data to recover the order data from. function recoverOrderFromTrade( RecoveredOrder memory recoveredOrder, IERC20[] calldata tokens, GPv2Trade.Data calldata trade ) internal view { GPv2Order.Data memory order = recoveredOrder.data; Scheme signingScheme = GPv2Trade.extractOrder(trade, tokens, order); (bytes32 orderDigest, address owner) = recoverOrderSigner( order, signingScheme, trade.signature ); recoveredOrder.uid.packOrderUidParams( orderDigest, owner, order.validTo ); recoveredOrder.owner = owner; recoveredOrder.receiver = order.actualReceiver(owner); } /// @dev The length of any signature from an externally owned account. uint256 private constant ECDSA_SIGNATURE_LENGTH = 65; /// @dev Recovers an order's signer from the specified order and signature. /// /// @param order The order to recover a signature for. /// @param signingScheme The signing scheme. /// @param signature The signature bytes. /// @return orderDigest The computed order hash. /// @return owner The recovered address from the specified signature. function recoverOrderSigner( GPv2Order.Data memory order, Scheme signingScheme, bytes calldata signature ) internal view returns (bytes32 orderDigest, address owner) { orderDigest = order.hash(domainSeparator); if (signingScheme == Scheme.Eip712) { owner = recoverEip712Signer(orderDigest, signature); } else if (signingScheme == Scheme.EthSign) { owner = recoverEthsignSigner(orderDigest, signature); } else if (signingScheme == Scheme.Eip1271) { owner = recoverEip1271Signer(orderDigest, signature); } else { // signingScheme == Scheme.PreSign owner = recoverPreSigner(orderDigest, signature, order.validTo); } } /// @dev Perform an ECDSA recover for the specified message and calldata /// signature. /// /// The signature is encoded by tighyly packing the following struct: /// ``` /// struct EncodedSignature { /// bytes32 r; /// bytes32 s; /// uint8 v; /// } /// ``` /// /// @param message The signed message. /// @param encodedSignature The encoded signature. function ecdsaRecover(bytes32 message, bytes calldata encodedSignature) internal pure returns (address signer) { require( encodedSignature.length == ECDSA_SIGNATURE_LENGTH, "GPv2: malformed ecdsa signature" ); bytes32 r; bytes32 s; uint8 v; // NOTE: Use assembly to efficiently decode signature data. // solhint-disable-next-line no-inline-assembly assembly { // r = uint256(encodedSignature[0:32]) r := calldataload(encodedSignature.offset) // s = uint256(encodedSignature[32:64]) s := calldataload(add(encodedSignature.offset, 32)) // v = uint8(encodedSignature[64]) v := shr(248, calldataload(add(encodedSignature.offset, 64))) } signer = ecrecover(message, v, r, s); require(signer != address(0), "GPv2: invalid ecdsa signature"); } /// @dev Decodes signature bytes originating from an EIP-712-encoded /// signature. /// /// EIP-712 signs typed data. The specifications are described in the /// related EIP (<https://eips.ethereum.org/EIPS/eip-712>). /// /// EIP-712 signatures are encoded as standard ECDSA signatures as described /// in the corresponding decoding function [`ecdsaRecover`]. /// /// @param orderDigest The EIP-712 signing digest derived from the order /// parameters. /// @param encodedSignature Calldata pointing to tightly packed signature /// bytes. /// @return owner The address of the signer. function recoverEip712Signer( bytes32 orderDigest, bytes calldata encodedSignature ) internal pure returns (address owner) { owner = ecdsaRecover(orderDigest, encodedSignature); } /// @dev Decodes signature bytes originating from the output of the eth_sign /// RPC call. /// /// The specifications are described in the Ethereum documentation /// (<https://eth.wiki/json-rpc/API#eth_sign>). /// /// eth_sign signatures are encoded as standard ECDSA signatures as /// described in the corresponding decoding function /// [`ecdsaRecover`]. /// /// @param orderDigest The EIP-712 signing digest derived from the order /// parameters. /// @param encodedSignature Calldata pointing to tightly packed signature /// bytes. /// @return owner The address of the signer. function recoverEthsignSigner( bytes32 orderDigest, bytes calldata encodedSignature ) internal pure returns (address owner) { // The signed message is encoded as: // `"\x19Ethereum Signed Message:\n" || length || data`, where // the length is a constant (32 bytes) and the data is defined as: // `orderDigest`. bytes32 ethsignDigest = keccak256( abi.encodePacked("\x19Ethereum Signed Message:\n32", orderDigest) ); owner = ecdsaRecover(ethsignDigest, encodedSignature); } /// @dev Verifies the input calldata as an EIP-1271 contract signature and /// returns the address of the signer. /// /// The encoded signature tightly packs the following struct: /// /// ``` /// struct EncodedEip1271Signature { /// address owner; /// bytes signature; /// } /// ``` /// /// This function enforces that the encoded data stores enough bytes to /// cover the full length of the decoded signature. /// /// @param encodedSignature The encoded EIP-1271 signature. /// @param orderDigest The EIP-712 signing digest derived from the order /// parameters. /// @return owner The address of the signer. function recoverEip1271Signer( bytes32 orderDigest, bytes calldata encodedSignature ) internal view returns (address owner) { // NOTE: Use assembly to read the verifier address from the encoded // signature bytes. // solhint-disable-next-line no-inline-assembly assembly { // owner = address(encodedSignature[0:20]) owner := shr(96, calldataload(encodedSignature.offset)) } // NOTE: Configure prettier to ignore the following line as it causes // a panic in the Solidity plugin. // prettier-ignore bytes calldata signature = encodedSignature[20:]; require( EIP1271Verifier(owner).isValidSignature(orderDigest, signature) == GPv2EIP1271.MAGICVALUE, "GPv2: invalid eip1271 signature" ); } /// @dev Verifies the order has been pre-signed. The signature is the /// address of the signer of the order. /// /// @param orderDigest The EIP-712 signing digest derived from the order /// parameters. /// @param encodedSignature The pre-sign signature reprenting the order UID. /// @param validTo The order expiry timestamp. /// @return owner The address of the signer. function recoverPreSigner( bytes32 orderDigest, bytes calldata encodedSignature, uint32 validTo ) internal view returns (address owner) { require(encodedSignature.length == 20, "GPv2: malformed presignature"); // NOTE: Use assembly to read the owner address from the encoded // signature bytes. // solhint-disable-next-line no-inline-assembly assembly { // owner = address(encodedSignature[0:20]) owner := shr(96, calldataload(encodedSignature.offset)) } bytes memory orderUid = new bytes(GPv2Order.UID_LENGTH); orderUid.packOrderUidParams(orderDigest, owner, validTo); require( preSignature[orderUid] == PRE_SIGNED, "GPv2: order not presigned" ); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract GPv2Signing","name":"_signing","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"deployedAt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"sellToken","type":"address"},{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes32","name":"kind","type":"bytes32"},{"internalType":"bool","name":"partiallyFillable","type":"bool"},{"internalType":"bytes32","name":"sellTokenBalance","type":"bytes32"},{"internalType":"bytes32","name":"buyTokenBalance","type":"bytes32"}],"internalType":"struct GPv2Order.Data","name":"order","type":"tuple"},{"internalType":"uint32","name":"validDuration","type":"uint32"},{"internalType":"uint256","name":"feeAmountBP","type":"uint256"}],"name":"signOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signing","outputs":[{"internalType":"contract GPv2Signing","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"sellToken","type":"address"},{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes32","name":"kind","type":"bytes32"},{"internalType":"bool","name":"partiallyFillable","type":"bool"},{"internalType":"bytes32","name":"sellTokenBalance","type":"bytes32"},{"internalType":"bytes32","name":"buyTokenBalance","type":"bytes32"}],"internalType":"struct GPv2Order.Data","name":"order","type":"tuple"}],"name":"unsignOrder","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60e060405234801561001057600080fd5b506040516108a03803806108a083398101604081905261002f91610104565b6001600160a01b0381166100895760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964207369676e696e672061646472657373000000000000000000604482015260640160405180910390fd5b6001600160a01b03811660808190526040805163f698da2560e01b8152905163f698da25916004808201926020929091908290030181865afa1580156100d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f79190610134565b60a052503060c05261014d565b60006020828403121561011657600080fd5b81516001600160a01b038116811461012d57600080fd5b9392505050565b60006020828403121561014657600080fd5b5051919050565b60805160a05160c05161071261018e6000396000818160cd015261022f01526000818160f401526102980152600081816089015261037001526107126000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063569d34891461005c5780635a66c223146100715780638302757a14610084578063eae4c19f146100c8578063f698da25146100ef575b600080fd5b61006f61006a366004610474565b610124565b005b61006f61007f3660046104b4565b610216565b6100ab7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6100ab7f000000000000000000000000000000000000000000000000000000000000000081565b6101167f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016100bf565b61013460c0840160a085016104d8565b63ffffffff168263ffffffff164261014c9190610509565b1161019e5760405162461bcd60e51b815260206004820152601860248201527f446973686f6e6573742076616c6964206475726174696f6e000000000000000060448201526064015b60405180910390fd5b6127106101af826060860135610521565b6101b99190610540565b6101c4906001610509565b8360e0013511156102065760405162461bcd60e51b815260206004820152600c60248201526b08ccaca40e8dede40d0d2ced60a31b6044820152606401610195565b610211836001610224565b505050565b610221816000610224565b50565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614156102915760405162461bcd60e51b815260206004820152601160248201527044454c454741544543414c4c206f6e6c7960781b6044820152606401610195565b60006103157f00000000000000000000000000000000000000000000000000000000000000006102c6368690038601866105c1565b601f190180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a08220915260405161190160f01b8152600281019290925260228201526042902090565b6040805160388082526060820190925291925060009190602082018180368337019050509050610359823061035060c0880160a089016104d8565b849291906103df565b60405163ec6cb13f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ec6cb13f906103a7908490879060040161067f565b600060405180830381600087803b1580156103c157600080fd5b505af11580156103d5573d6000803e3d6000fd5b5050505050505050565b60388451146104305760405162461bcd60e51b815260206004820152601960248201527f475076323a2075696420627566666572206f766572666c6f77000000000000006044820152606401610195565b60388401526034830152602090910152565b6000610180828403121561045557600080fd5b50919050565b803563ffffffff8116811461046f57600080fd5b919050565b60008060006101c0848603121561048a57600080fd5b6104948585610442565b92506104a3610180850161045b565b91506101a084013590509250925092565b600061018082840312156104c757600080fd5b6104d18383610442565b9392505050565b6000602082840312156104ea57600080fd5b6104d18261045b565b634e487b7160e01b600052601160045260246000fd5b6000821982111561051c5761051c6104f3565b500190565b600081600019048311821515161561053b5761053b6104f3565b500290565b60008261055d57634e487b7160e01b600052601260045260246000fd5b500490565b604051610180810167ffffffffffffffff8111828210171561059457634e487b7160e01b600052604160045260246000fd5b60405290565b80356001600160a01b038116811461046f57600080fd5b8035801515811461046f57600080fd5b600061018082840312156105d457600080fd5b6105dc610562565b6105e58361059a565b81526105f36020840161059a565b60208201526106046040840161059a565b6040820152606083013560608201526080830135608082015261062960a0840161045b565b60a082015260c083013560c082015260e083013560e082015261010080840135818301525061012061065c8185016105b1565b908201526101408381013590820152610160928301359281019290925250919050565b604081526000835180604084015260005b818110156106ad5760208187018101516060868401015201610690565b818111156106bf576000606083860101525b50921515602083015250601f91909101601f19160160600191905056fea26469706673582212209492c82cd1530f2d2d13fb87c4631f1db3a91a6c67f6f86df5d017ec7bb9967f64736f6c634300080c00330000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100575760003560e01c8063569d34891461005c5780635a66c223146100715780638302757a14610084578063eae4c19f146100c8578063f698da25146100ef575b600080fd5b61006f61006a366004610474565b610124565b005b61006f61007f3660046104b4565b610216565b6100ab7f0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab4181565b6040516001600160a01b0390911681526020015b60405180910390f35b6100ab7f00000000000000000000000023da9ade38e4477b23770ded512fd37b12381fab81565b6101167fc078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e894381565b6040519081526020016100bf565b61013460c0840160a085016104d8565b63ffffffff168263ffffffff164261014c9190610509565b1161019e5760405162461bcd60e51b815260206004820152601860248201527f446973686f6e6573742076616c6964206475726174696f6e000000000000000060448201526064015b60405180910390fd5b6127106101af826060860135610521565b6101b99190610540565b6101c4906001610509565b8360e0013511156102065760405162461bcd60e51b815260206004820152600c60248201526b08ccaca40e8dede40d0d2ced60a31b6044820152606401610195565b610211836001610224565b505050565b610221816000610224565b50565b306001600160a01b037f00000000000000000000000023da9ade38e4477b23770ded512fd37b12381fab1614156102915760405162461bcd60e51b815260206004820152601160248201527044454c454741544543414c4c206f6e6c7960781b6044820152606401610195565b60006103157fc078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e89436102c6368690038601866105c1565b601f190180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a08220915260405161190160f01b8152600281019290925260228201526042902090565b6040805160388082526060820190925291925060009190602082018180368337019050509050610359823061035060c0880160a089016104d8565b849291906103df565b60405163ec6cb13f60e01b81526001600160a01b037f0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41169063ec6cb13f906103a7908490879060040161067f565b600060405180830381600087803b1580156103c157600080fd5b505af11580156103d5573d6000803e3d6000fd5b5050505050505050565b60388451146104305760405162461bcd60e51b815260206004820152601960248201527f475076323a2075696420627566666572206f766572666c6f77000000000000006044820152606401610195565b60388401526034830152602090910152565b6000610180828403121561045557600080fd5b50919050565b803563ffffffff8116811461046f57600080fd5b919050565b60008060006101c0848603121561048a57600080fd5b6104948585610442565b92506104a3610180850161045b565b91506101a084013590509250925092565b600061018082840312156104c757600080fd5b6104d18383610442565b9392505050565b6000602082840312156104ea57600080fd5b6104d18261045b565b634e487b7160e01b600052601160045260246000fd5b6000821982111561051c5761051c6104f3565b500190565b600081600019048311821515161561053b5761053b6104f3565b500290565b60008261055d57634e487b7160e01b600052601260045260246000fd5b500490565b604051610180810167ffffffffffffffff8111828210171561059457634e487b7160e01b600052604160045260246000fd5b60405290565b80356001600160a01b038116811461046f57600080fd5b8035801515811461046f57600080fd5b600061018082840312156105d457600080fd5b6105dc610562565b6105e58361059a565b81526105f36020840161059a565b60208201526106046040840161059a565b6040820152606083013560608201526080830135608082015261062960a0840161045b565b60a082015260c083013560c082015260e083013560e082015261010080840135818301525061012061065c8185016105b1565b908201526101408381013590820152610160928301359281019290925250919050565b604081526000835180604084015260005b818110156106ad5760208187018101516060868401015201610690565b818111156106bf576000606083860101525b50921515602083015250601f91909101601f19160160600191905056fea26469706673582212209492c82cd1530f2d2d13fb87c4631f1db3a91a6c67f6f86df5d017ec7bb9967f64736f6c634300080c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41
-----Decoded View---------------
Arg [0] : _signing (address): 0x9008D19f58AAbD9eD0D60971565AA8510560ab41
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.