Type/to search
Built-in Functions
Structures
Built-in Variables and Constants
Conventions
Exchanges
Capability Matrix
Centralized Exchanges
Decentralized Exchanges (DEX)
Prediction Markets
Securities and Futures
On-chain & Custom

Signs structured data according to the EIP-712 standard. A single call completes the calculation of the type hash, domain separator, struct hash, and digest, and then signs it. It is suitable for scenarios such as ERC-20 Permit, Permit2, UniswapX, CoW, and 1inch limit orders.

exchange.IO(k, typedData)
exchange.IO(k, typedData, key)
exchange.IO(k, domain, types, message)
exchange.IO(k, domain, types, message, key)

Examples

Sign a Permit for USDC on the Ethereum mainnet, and have the USDC contract verify the signature via exchange.IO("call", ...).

javascript
function main() { var USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" // Ethereum mainnet USDC // Spender (authorized party), fill in as needed var spender = "0x1111111254EEB25477B68fb85Ed929f73A960582" var owner = exchange.IO("address") var deadline = Math.floor(Date.now() / 1000) + 3600 // nonce must equal nonces(owner) in the contract: it is no longer 0 once the wallet has used a // permit exchange.IO("abi", USDC, JSON.stringify([{ type: "function", name: "nonces", stateMutability: "view", inputs: [{ type: "address" }], outputs: [{ type: "uint256" }] }])) var nonce = exchange.IO("api", USDC, "nonces", owner) // ethers style: domain, types (without EIP712Domain), message; the primary type is inferred // automatically var domain = { name: "USD Coin", version: "2", chainId: 1, verifyingContract: USDC } var types = { Permit: [ { name: "owner", type: "address" }, { name: "spender", type: "address" }, { name: "value", type: "uint256" }, { name: "nonce", type: "uint256" }, { name: "deadline", type: "uint256" } ] } var message = { owner: owner, spender: spender, value: "1000000", nonce: nonce, deadline: deadline } var sig = exchange.IO("signTypedData", domain, types, message) Log("digest:", sig.digest, "v:", sig.v, "r:", sig.r, "s:", sig.s) // Single-object style (MetaMask eth_signTypedData_v4 format) produces the same result var sig2 = exchange.IO("signTypedData", { domain: domain, types: types, primaryType: "Permit", message: message }) Log("Both styles match:", sig.signature === sig2.signature) // Simulate USDC's permit with eth_call so the contract verifies the signature (no transaction // is sent) var calldata = "0x" + String(exchange.IO("hash", "keccak256", "raw", "hex", "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)")).replace(/^0x/, "").slice(0, 8) + exchange.IO("encode", "address,address,uint256,uint256,uint8,bytes32,bytes32", owner, spender, "1000000", deadline, sig.v, sig.r, sig.s) Log("permit simulation:", exchange.IO("call", USDC, calldata) !== null ? "Signature valid" : GetLastError()) }

Returns

TypeDescription

object

Returns a signature object with the same fields as the return value of exchange.IO("sign", ...): r, s, v (27 or 28), signature (65 bytes), and vs (EIP-2098 compact signature). In addition, it contains the digest field, which is the EIP-712 digest. Returns a null value when the call fails.

Arguments

NameTypeRequiredDescription

k

string

Yes

Function of the exchange.IO() function. Setting it to signTypedData means using the function for EIP-712 signing.

typedData

object / string

No

Object containing domain, types, primaryType, and message (i.e., the MetaMask eth_signTypedData_v4 format; types may include EIP712Domain). The JSON string of this object can also be passed in.

domain

object

No

EIP-712 domain, for example {name, version, chainId, verifyingContract}. The calling method using the three parameters domain, types, and message is the same as ethers' signTypedData: types does not need to include EIP712Domain (it is automatically derived from the fields present in domain), and the primary type is the type that is not referenced by any other type.

types

object

No

Type definitions, for example {Permit: [{name: "owner", type: "address"}, ...]}. Nested structs and arrays are supported.

message

object

No

Data to be signed. Large integers can be passed in as strings.

key

string

No

Private key used for signing. When this parameter is not passed, the private key configured for the exchange object is used.

See Also

Remarks

An error is reported when message is missing a field from the type definitions; missing fields are not zero-filled and then signed.

The private key is used only inside the exchange object; strategy code cannot access the private key.