Skip to main content
POST
/
orders
/
approve
EIP-2612 Permit
import { Contract, JsonRpcProvider, MaxUint256, Wallet } from "ethers";

async function approveOrderFill() {
  const privateKey = process.env.SX_PRIVATE_KEY;
  const tokenAddress = process.env.TOKEN_ADDRESS;

  // get the following from https://api.sx.bet/metadata
  const tokenTransferProxyAddress = process.env.TOKEN_TRANSFER_PROXY_ADDRESS;
  const chainId = Number(process.env.CHAIN_ID); // Mainnet — use 79479957 for testnet

  const wallet = new Wallet(
    privateKey,
    new JsonRpcProvider(process.env.RPC_URL) // find this under the 'references' section
  );

  const tokenContract = new Contract(
    tokenAddress,
    [
      {
        inputs: [
          { internalType: "address", name: "usr", type: "address" },
          { internalType: "uint256", name: "wad", type: "uint256" },
        ],
        name: "approve",
        outputs: [{ internalType: "bool", name: "", type: "bool" }],
        stateMutability: "nonpayable",
        type: "function",
      },
      {
        inputs: [{ internalType: "address", name: "owner", type: "address" }],
        name: "nonces",
        outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
        stateMutability: "view",
        type: "function",
      },
      {
        inputs: [],
        name: "name",
        outputs: [{ internalType: "string", name: "", type: "string" }],
        stateMutability: "view",
        type: "function",
      },
    ],
    wallet
  );

  const nonce = await tokenContract.nonces(wallet.address);
  const tokenName = await tokenContract.name();

  const domain = {
    name: tokenName,
    version: "1",
    chainId,
    verifyingContract: tokenAddress,
  };

  const types = {
    Permit: [
      { name: "owner", type: "address" },
      { name: "spender", type: "address" },
      { name: "value", type: "uint256" },
      { name: "nonce", type: "uint256" },
      { name: "deadline", type: "uint256" },
    ],
  };

  const deadline = Math.floor(Date.now() / 1000) + 7200; // 2 hours

  const value = {
    owner: wallet.address,
    spender: tokenTransferProxyAddress,
    value: MaxUint256,
    nonce,
    deadline,
  };

  const approveProxySignature = await wallet.signTypedData(domain, types, value);

  const apiPayload = {
    owner: wallet.address,
    spender: tokenTransferProxyAddress,
    tokenAddress,
    value: MaxUint256.toString(),
    signature: approveProxySignature,
  };

  const response = await fetch("https://api.sx.bet/orders/approve", { // Mainnet — use https://api.toronto.sx.bet for testnet
    method: "POST",
    body: JSON.stringify(apiPayload),
    headers: { "Content-Type": "application/json" },
  });
}
{
  "status": "success",
  "data": {
    "hash": "0x840763ae29b7a6adfa0e315afa47be30cdebd5b793d179dc07dc8fc4f0034965"
  }
}
This endpoint approves the specified value to be spent by spender on behalf of owner for token transfers that occur as part of the Filling orders flow according to Ethereum’s EIP-2612 Permit Extension. Note that deadline field here is only used during signature verification and that the value set will be the spender’s allowance until changed or revoked.

Body

application/json
owner
string
required

Address of the taker granting approval to TokenTransferProxy for filling orders on their behalf

spender
string
required

The address of the account which will be able to spend token amounts on behalf of the owner. In this case, the spender should be TokenTransferProxy address

tokenAddress
string
required

The token address to grant approval for

value
string
required

The token amount to grant approval for, in Ethereum units

deadline
integer
required

The deadline as a UNIX timestamp format used in signature verification

signature
string
required

Your wallet signature over the payload. See the example of how to compute this.

Response

200 - application/json
status
string

success or failure if the request succeeded or not

data
object