跳轉到內容

EIP-712 訂單簽名

概述

在創建訂單之前,Maker需要使用EIP-712標準對訂單數據進行簽名。EIP-712是以太坊的結構化數據簽名標準,可以讓用戶在簽名時清楚地看到要簽名的數據內容。

合約地址

text
Chain ID:      97
RFQSettlement: 0xCB310C56A19078aA969A922f382613d932D89D83

測試代幣

測試環境中的MOCK穩定幣地址和獲取方式請參考測試指南

EIP-712 Domain

Domain定義了簽名的上下文環境,包括合約名稱、版本、鏈ID和驗證合約地址。

javascript
const domain = {
  name: "RFQSettlement",
  version: "1",
  chainId: "<Chain ID>",
  verifyingContract: "<RFQSettlement合約地址>"
}

訂單類型定義

訂單數據結構包含以下字段:

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" }
  ]
}

字段說明

訂單字段的詳細說明請參考創建訂單 - 請求參數

完整示例

javascript
import { ethers } from 'ethers'

// 1. 連接錢包
const provider = new ethers.BrowserProvider(window.ethereum)
const signer = await provider.getSigner()
const userAddress = await signer.getAddress()

// 2. 獲取鏈ID
const network = await provider.getNetwork()
const chainId = Number(network.chainId)

// 3. 從後端API獲取nonce和maker地址
const jwtToken = "your_jwt_token"
const nonceResponse = await fetch('/api/v1/orders/maker/next-nonce', {
  headers: { 'Authorization': `Bearer ${jwtToken}` }
})
const { maker, next_nonce } = (await nonceResponse.json()).data

// 4. 定義Domain
const domain = {
  name: "RFQSettlement",
  version: "1",
  chainId: "<Chain ID>",
  verifyingContract: "<RFQSettlement合約地址>"
}

// 5. 定義訂單類型
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" }
  ]
}

// 6. 構建訂單數據
const order = {
  maker: maker,
  principal: userAddress,
  isBuy: true,
  ticker: "AAPL",
  exchange: 0,
  asset: "<USDT合約地址>",
  price: ethers.parseUnits("150.5", 18),  // 18位精度
  quantity: "100",  // 整數
  incentive: ethers.parseUnits("1.0", 18),  // 18位精度
  deadline: Math.floor(Date.now() / 1000) + 86400 * 30,  // 30天後過期
  nonce: next_nonce
}

// 7. 簽名
const signature = await signer.signTypedData(domain, types, order)

// 8. 提交訂單
const response = await fetch('/api/v1/orders', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${jwtToken}`
  },
  body: 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 result = await response.json()
console.log('訂單創建成功:', result)

完整JSON示例

請求示例

json
{
  "order": {
    "maker": "0x1234567890123456789012345678901234567890",
    "principal": "0x1234567890123456789012345678901234567890",
    "is_buy": true,
    "ticker": "AAPL",
    "exchange": 0,
    "asset": "<USDT合約地址>",
    "price": "150500000000000000000",
    "quantity": "100",
    "incentive": "1000000000000000000",
    "deadline": 1735689600,
    "nonce": 1
  },
  "signature": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12"
}

響應示例

json
{
  "code": 0,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "maker": "0x1234567890123456789012345678901234567890",
    "principal": "0x1234567890123456789012345678901234567890",
    "is_buy": true,
    "ticker": "AAPL",
    "exchange": 0,
    "asset": "<USDT合約地址>",
    "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"
  }
}

重要注意事項

1. Nonce管理

  • 每個訂單必須使用唯一的nonce
  • 必須從後端API獲取,詳見查詢Nonce
  • nonce用於防止重放攻擊

2. 授權檢查

創建訂單前需要授權代幣:

javascript
// 買入訂單:授權USDT/USDC
await usdtContract.approve(rfqSettlementAddress, ethers.MaxUint256)

3. Deadline設置

  • deadline必須至少為當前時間 + 720小時(30天)
  • 建議限價單設置更長的有效期以確保有足夠時間成交
  • 使用Unix時間戳(秒)
javascript
const deadline = Math.floor(Date.now() / 1000) + 86400 * 30  // 30天後

4. 價格和手續費

  • 使用預估訂單手續費接口獲取準確的價格和手續費
  • 價格需要考慮匯率換算
  • incentive(手續費)必須 >= 預估手續費,否則訂單不會被執行

相關接口