exchange.IO("signTypedData", ...)
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
| Type | Description |
object | Returns a signature object with the same fields as the return value of |
Arguments
| Name | Type | Required | Description |
k | string | Yes | Function of the |
typedData | object / string | No | Object containing |
domain | object | No | EIP-712 domain, for example |
types | object | No | Type definitions, for example |
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 |
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.