EVM Permits
Learn how to use EIP-2612 and Permit2 signatures in Omniston EVM order payloads instead of relying only on pre-approved ERC-20 allowances.
Last updated
import { encodeAbiParameters, hexToBytes } from "viem";
const ownerAddress = "0x..."; // trader wallet address on the source EVM chain
const tokenAddress = quote.inputAsset.chain.value.kind.value;
const spenderAddress = quote.settlementData.value.srcProtocolContractAddress.chain.value;
const permitTypedData = {
domain: {
name: "Polymarket USD",
version: "1",
chainId: 137,
verifyingContract: "0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB",
},
types: {
Permit: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
],
},
primaryType: "Permit" as const,
message: {
owner: ownerAddress,
spender: spenderAddress,
value: BigInt(quote.inputUnits),
nonce: await getContractNonce(ownerAddress, tokenAddress),
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
},
};
const permitTypedDataSignature = await signTypedData({
...permitTypedData,
account: ownerAddress,
});
const encodedPermitData = hexToBytes(
encodeAbiParameters(
[
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
],
[
permitTypedData.message.owner,
permitTypedData.message.spender,
permitTypedData.message.value,
permitTypedData.message.nonce,
permitTypedData.message.deadline,
],
),
);
const evmOrderPayload = await omniston.evmBuildOrderPayload({
quoteId: quote.quoteId,
ownerSrcAddress: inputWalletAddress,
traderDstAddress: outputWalletAddress,
traderDstDiscloseAddress: outputWalletAddress,
encodedPermitData,
permitSignature: hexToBytes(permitTypedDataSignature),
usePermit2: false,
});import { erc20Abi, maxUint256 } from "viem";
const PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
const currentAllowance = await readContract(wagmiConfig, {
address: tokenAddress,
abi: erc20Abi,
functionName: "allowance",
args: [ownerAddress, PERMIT2_ADDRESS],
});
if (currentAllowance < BigInt(quote.inputUnits)) {
const approveTxHash = await writeContract(walletClient, {
address: tokenAddress,
abi: erc20Abi,
functionName: "approve",
args: [PERMIT2_ADDRESS, maxUint256],
account: ownerAddress,
});
await waitForTransactionReceipt(wagmiConfig, {
hash: approveTxHash,
});
}import { encodeAbiParameters, hexToBytes } from "viem";
const ownerAddress = "0x..."; // trader wallet address on the source EVM chain
const tokenAddress = quote.inputAsset.chain.value.kind.value;
const spenderAddress = quote.settlementData.value.srcProtocolContractAddress.chain.value;
const permitTypedData = {
domain: {
name: "Permit2",
chainId: 8453,
verifyingContract: PERMIT2_ADDRESS,
},
types: {
PermitDetails: [
{ name: "token", type: "address" },
{ name: "amount", type: "uint160" },
{ name: "expiration", type: "uint48" },
{ name: "nonce", type: "uint48" },
],
PermitSingle: [
{ name: "details", type: "PermitDetails" },
{ name: "spender", type: "address" },
{ name: "sigDeadline", type: "uint256" },
],
},
primaryType: "PermitSingle" as const,
message: {
details: {
token: tokenAddress,
amount: BigInt(quote.inputUnits),
expiration: Math.floor(Date.now() / 1000) + 3600,
nonce: await getPermit2Nonce(ownerAddress, tokenAddress, spenderAddress),
},
spender: spenderAddress,
sigDeadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
},
};
const permitTypedDataSignature = await signTypedData({
...permitTypedData,
account: ownerAddress,
});
const encodedPermitData = hexToBytes(
encodeAbiParameters(
[
{
name: "permitSingle",
type: "tuple",
components: [
{
name: "details",
type: "tuple",
components: [
{ name: "token", type: "address" },
{ name: "amount", type: "uint160" },
{ name: "expiration", type: "uint48" },
{ name: "nonce", type: "uint48" },
],
},
{ name: "spender", type: "address" },
{ name: "sigDeadline", type: "uint256" },
],
},
],
[permitTypedData.message],
),
);
const evmOrderPayload = await omniston.evmBuildOrderPayload({
// other order payload fields are omitted here to keep the example focused on permit parameters
encodedPermitData,
permitSignature: hexToBytes(permitTypedDataSignature),
usePermit2: true,
});