Skip to content
Stove Website

EIP-712 Order Signature ​

Overview ​

Before creating an order, Makers need to sign the order data using the EIP-712 standard. EIP-712 is Ethereum's structured data signing standard that allows users to clearly see the data being signed.

Contract Addresses ​

Multi-Chain Support

The platform supports multiple blockchain networks. Please refer to the Multi-Chain Support documentation for:

  • All supported chains and their chain_id
  • RFQSettlement and StockTokenManager contract addresses on each chain
  • How to obtain and use Chain ID

EIP-712 Domain ​

The Domain defines the signing context, including contract name, version, chain ID, and verifying contract address.

javascript
const domain = {
  name: "RFQSettlement",
  version: "1",
  chainId: "<Chain ID>",
  verifyingContract: "<RFQSettlement Contract Address>"
}

Order Type Definition ​

The order data structure contains the following fields:

javascript
const types = {
  Order: [
    { name: "maker", type: "address" },
    { name: "principal", type: "address" },
    { name: "isBuy", type: "bool" },
    { name: "ticker", type: "string" },
    { name: "exchange", type: "uint16" },
    { name: "asset", type: "address" },
    { name: "price", type: "uint256" },
    { name: "quantity", type: "uint256" },
    { name: "incentive", type: "uint256" },
    { name: "deadline", type: "uint256" },
    { name: "nonce", type: "uint256" }
  ]
}

Field Description ​

For detailed field descriptions, please refer to Create Order - Request Parameters

Complete Example ​

javascript
import { ethers } from 'ethers'

// 1. Connect wallet
const provider = new ethers.BrowserProvider(window.ethereum)
const signer = await provider.getSigner()
const userAddress = await signer.getAddress()

// 2. Get chain ID
const network = await provider.getNetwork()
const chainId = Number(network.chainId)

// 3. API Authentication setup
const crypto = require('crypto')
const apiKey = "YOUR_API_KEY"
const apiSecret = "YOUR_API_SECRET"
const makerAddr = "YOUR_MAKER_ADDRESS"

function signRequest(method, path, body = '') {
  const timestamp = Date.now()
  const signatureString = `${method}|${path}|${makerAddr}|${timestamp}|${body}`
  const signature = crypto.createHmac('sha256', apiSecret).update(signatureString).digest('base64')
  return {
    'X-API-Key': apiKey,
    'X-Maker-Addr': makerAddr,
    'X-API-Timestamp': timestamp.toString(),
    'X-API-Signature': signature,
    'Content-Type': 'application/json'
  }
}

// 4. Get nonce and maker address from backend API
const nonceResponse = await fetch('/api/v1/orders/maker/next-nonce', {
  headers: signRequest('GET', '/api/v1/orders/maker/next-nonce')
})
const { maker, next_nonce } = (await nonceResponse.json()).data

// 5. Define Domain
const domain = {
  name: "RFQSettlement",
  version: "1",
  chainId: "<Chain ID>",
  verifyingContract: "<RFQSettlement Contract Address>"
}

// 6. Define order types
const types = {
  Order: [
    { name: "maker", type: "address" },
    { name: "principal", type: "address" },
    { name: "isBuy", type: "bool" },
    { name: "ticker", type: "string" },
    { name: "exchange", type: "uint16" },
    { name: "asset", type: "address" },
    { name: "price", type: "uint256" },
    { name: "quantity", type: "uint256" },
    { name: "incentive", type: "uint256" },
    { name: "deadline", type: "uint256" },
    { name: "nonce", type: "uint256" }
  ]
}

// 7. Build order data
const order = {
  maker: maker,
  principal: userAddress,
  isBuy: true,
  ticker: "AAPLs",
  exchange: 0,
  asset: "<USDT Contract Address>",
  price: ethers.parseUnits("150.5", 18),  // 18 decimals
  quantity: "100",  // Integer
  incentive: ethers.parseUnits("1.0", 18),  // 18 decimals
  deadline: Math.floor(Date.now() / 1000) + 86400 * 30,  // Expires in 30 days
  nonce: next_nonce
}

// 8. Sign
const signature = await signer.signTypedData(domain, types, order)

// 9. Submit order
const orderBody = JSON.stringify({
  order: {
    maker: order.maker,
    principal: order.principal,
    is_buy: order.isBuy,
    ticker: order.ticker,
    exchange: order.exchange,
    asset: order.asset,
    price: order.price.toString(),
    quantity: order.quantity,
    incentive: order.incentive.toString(),
    deadline: order.deadline,
    nonce: order.nonce
  },
  signature: signature
})

const response = await fetch('/api/v1/orders', {
  method: 'POST',
  headers: signRequest('POST', '/api/v1/orders', orderBody),
  body: orderBody
})

const result = await response.json()
console.log('Order created successfully:', result)

Complete JSON Examples ​

Request Examples ​

json
{
  "order": {
    "maker": "0x1234567890123456789012345678901234567890",
    "principal": "0x1234567890123456789012345678901234567890",
    "is_buy": true,
    "ticker": "AAPLs",
    "exchange": 0,
    "asset": "<USDT Contract Address>",
    "price": "150500000000000000000",
    "quantity": "100",
    "incentive": "1000000000000000000",
    "deadline": 1735689600,
    "nonce": 1
  },
  "signature": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12"
}

Response Example ​

json
{
  "code": 0,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "maker": "0x1234567890123456789012345678901234567890",
    "principal": "0x1234567890123456789012345678901234567890",
    "is_buy": true,
    "ticker": "AAPLs",
    "exchange": 0,
    "asset": "<USDT Contract Address>",
    "price": "150500000000000000000",
    "quantity": "100",
    "incentive": "1000000000000000000",
    "deadline": 1735689600,
    "nonce": 1,
    "signature": "0x1234567890abcdef...",
    "order_hash": "0xabcdef1234567890...",
    "status": "pending",
    "filled_quantity": "0",
    "created_at": "2025-01-17T03:00:24Z",
    "updated_at": "2025-01-17T03:00:24Z"
  }
}

Important Notes ​

1. Nonce Management ​

  • Each order must use a unique nonce
  • Must be obtained from the backend API, see Query Nonce
  • Nonce is used to prevent replay attacks

2. Authorization Check ​

Token authorization is required before creating orders:

javascript
// Buy order: Authorize USDT/USDC
await usdtContract.approve(rfqSettlementAddress, ethers.MaxUint256)

3. Deadline Setting ​

  • Deadline must be at least current time + 720 hours (30 days)
  • Recommend setting longer validity for limit orders to ensure sufficient time for execution
  • Use Unix timestamp (seconds)
javascript
const deadline = Math.floor(Date.now() / 1000) + 86400 * 30  // 30 days later

4. Price and Fees ​

  • Use Estimate Order Fee endpoint to get accurate price and fees
  • Price needs to consider exchange rate conversion
  • incentive (fee) must be >= estimated fee, otherwise the order will not be executed
  • For sell orders, the fee is deducted from the stablecoin proceeds; no separate USDT/USDC approval is required for the fee