Forkast Developer Docs
Forkast SDK Integration Guide
Create Order Signature
8 min
orders on forkast use eip 712 typed data signing the signature proves the order was authorized by the wallet owner without exposing the private key step 1 construct the eip 712 domain { "name" "ctf exchange", "version" "1", "chainid" 42161, "verifyingcontract" "0x2d7aa09fe8a9af205ad6e0fef1441834c4250cdc" } step 2 define the order type structure { "order" \[ { "name" "salt", "type" "uint256" }, { "name" "maker", "type" "address" }, { "name" "signer", "type" "address" }, { "name" "taker", "type" "address" }, { "name" "tokenid", "type" "uint256" }, { "name" "makeramount", "type" "uint256" }, { "name" "takeramount", "type" "uint256" }, { "name" "expiration", "type" "uint256" }, { "name" "nonce", "type" "uint256" }, { "name" "feeratebps", "type" "uint256" }, { "name" "side", "type" "uint8" }, { "name" "signaturetype", "type" "uint8" } ] } step 3 build the order message field type description salt uint256 a unique value per order generate by hashing order fields + random entropy + timestamp using sha 256, then convert to a uint256integer maker address the proxy wallet (gnosis safe) address â not the eoa signer address the user's eoa wallet address (the key that signs) taker address 0x0000000000000000000000000000000000000000 (public order, anyone can fill) tokenid uint256 the ctf erc 1155 token id of the outcome being traded makeramount uint256 see calculation below scaled to 6 decimals (usdc precision) takeramount uint256 see calculation below scaled to 6 decimals expiration uint256 "0" (no expiration) nonce uint256 "0" feeratebps uint256 "0" side uint8 0 = buy, 1= sell signaturetype uint8 3 (eip 712 with gnosis safe proxy â signer is eoa, maker is proxy) calculating makeramount and takeramount amounts are scaled by 1e6(usdc has 6 decimals) buy order (side = 0) makeramount = floor(amount à price à 1,000,000) // tc you pay takeramount = floor(amount à 1,000,000) // outcome tokens you receive sell order (side = 1) makeramount = floor(amount à 1,000,000) // outcome tokens you sell takeramount = floor(amount à price à 1,000,000) // tc you receive example makeramount = floor(50 à 0 80 à 1,000,000) = 40,000,000 takeramount = floor(50 à 1,000,000) = 50,000,000 step 4 generate a unique salt import crypto from "crypto"; const raw = \[ signeraddress tolowercase(), makeraddress tolowercase(), tokenid, side, type, price, amount, (bigint(date now()) bigint(1 000 000)) tostring(), crypto randombytes(16) tostring("hex"), ] join("|"); const digest = crypto createhash("sha256") update(raw) digest("hex"); const salt = bigint("0x" + digest) tostring(); step 5 sign with eip 712 import { ethers } from "ethers"; const domain = { name "ctf exchange", version "1", chainid 42161, // or 421614 for testnet verifyingcontract "0x2d7aa09fe8a9af205ad6e0fef1441834c4250cdc", }; const types = { order \[ { name "salt", type "uint256" }, { name "maker", type "address" }, { name "signer", type "address" }, { name "taker", type "address" }, { name "tokenid", type "uint256" }, { name "makeramount", type "uint256" }, { name "takeramount", type "uint256" }, { name "expiration", type "uint256" }, { name "nonce", type "uint256" }, { name "feeratebps", type "uint256" }, { name "side", type "uint8" }, { name "signaturetype", type "uint8" }, ], }; const message = { salt salt, maker proxywalletaddress, signer walletaddress, taker ethers zeroaddress, tokenid tokenid, makeramount "40000000", takeramount "50000000", expiration "0", nonce "0", feeratebps "0", side 0, signaturetype 3, }; const wallet = new ethers wallet(privatekey); const signature = await wallet signtypeddata(domain, types, message); validation rules field constraint side must be 0 (buy) or 1 (sell) amount must be > 0, max 2 decimal places price must be > 0 and < 1, max 2 decimal places signer must match the private key used to sign signaturetype must be 3 (eoa signer + gnosis safe maker)