feat: CLOB V1 → V2 完整迁移

- 更新 EIP-712 签名结构: domain version "1"→"2", 移除 taker/expiration/nonce/feeRateBps, 新增 timestamp/metadata/builder
- 更新合约地址为 V2 (CTF_EXCHANGE, NEG_RISK_EXCHANGE)
- CLOB URL 切换到 clob-v2.polymarket.com
- 抵押品代币 USDC.e → pUSD (0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB)
- 新增 USDC.e → pUSD wrap 功能 (CollateralOnramp 合约)
- SignedOrderObject 补充 API payload 必需的 taker/expiration 字段
- NewOrderRequest 补充 deferExec/postOnly 字段
- 前端账户管理新增 pUSD 迁移按钮
- 移除所有 feeRateBps 相关逻辑

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
WrBug
2026-04-20 22:24:50 +08:00
co-authored by Claude Opus 4.7
parent 04b7505094
commit 22a6544373
18 changed files with 1454 additions and 231 deletions
+59 -1
View File
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'
import { Card, Table, Button, Space, Tag, Popconfirm, message, Typography, Spin, Modal, Descriptions, Divider, Form, Input, Alert, Tooltip, List, Empty } from 'antd'
import { PlusOutlined, ReloadOutlined, EditOutlined, CopyOutlined, EyeOutlined, DeleteOutlined, WalletOutlined } from '@ant-design/icons'
import { PlusOutlined, ReloadOutlined, EditOutlined, CopyOutlined, EyeOutlined, DeleteOutlined, WalletOutlined, SwapOutlined } from '@ant-design/icons'
import { useTranslation } from 'react-i18next'
import { useAccountStore } from '../store/accountStore'
import type { Account } from '../types'
@@ -8,6 +8,7 @@ import { useMediaQuery } from 'react-responsive'
import { formatUSDC } from '../utils'
import AccountImportForm from '../components/AccountImportForm'
import AccountSetupStatusBlock from '../components/AccountSetupStatusBlock'
import apiService from '../services/api'
const { Title } = Typography
@@ -27,6 +28,43 @@ const AccountList: React.FC = () => {
const [editLoading, setEditLoading] = useState(false)
const [accountImportModalVisible, setAccountImportModalVisible] = useState(false)
const [accountImportForm] = Form.useForm()
const [wrapLoading, setWrapLoading] = useState<Record<number, boolean>>({})
const handleWrapToPusd = async (account: Account) => {
try {
setWrapLoading(prev => ({ ...prev, [account.id]: true }))
const res = await apiService.accounts.getUsdceBalance(account.id)
if (res.data.code !== 0 || !res.data.data) {
message.error(res.data.msg || '查询 USDC.e 余额失败')
return
}
const balance = parseFloat(res.data.data.balance)
if (balance <= 0) {
message.info('USDC.e 余额为 0,无需迁移')
return
}
Modal.confirm({
title: 'USDC.e → pUSD 迁移',
content: `检测到 ${balance.toFixed(2)} USDC.e,将全部 wrap 为 pUSD。确认继续?`,
okText: '确认迁移',
cancelText: '取消',
onOk: async () => {
const wrapRes = await apiService.accounts.wrapToPusd(account.id)
if (wrapRes.data.code === 0) {
const txHash = wrapRes.data.data?.transactionHash
message.success(txHash ? `迁移成功,交易: ${txHash.slice(0, 10)}...` : '迁移成功(无需操作)')
fetchAccountBalance(account.id)
} else {
message.error(wrapRes.data.msg || '迁移失败')
}
}
})
} catch (e: any) {
message.error(e.message || '迁移失败')
} finally {
setWrapLoading(prev => ({ ...prev, [account.id]: false }))
}
}
useEffect(() => {
fetchAccounts()
@@ -374,6 +412,26 @@ const AccountList: React.FC = () => {
</div>
</Tooltip>
<Tooltip title="USDC.e → pUSD">
<div
onClick={() => handleWrapToPusd(record)}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '32px',
height: '32px',
cursor: wrapLoading[record.id] ? 'wait' : 'pointer',
borderRadius: '6px',
transition: 'background-color 0.2s'
}}
onMouseEnter={(e) => e.currentTarget.style.backgroundColor = '#fff7e6'}
onMouseLeave={(e) => e.currentTarget.style.backgroundColor = 'transparent'}
>
<SwapOutlined style={{ fontSize: '16px', color: '#fa8c16' }} spin={wrapLoading[record.id]} />
</div>
</Tooltip>
<Popconfirm
title={t('accountList.deleteConfirm')}
description={
+14 -2
View File
@@ -284,9 +284,21 @@ export const apiService = {
/**
* 赎回仓位
*/
redeemPositions: (data: any) =>
redeemPositions: (data: any) =>
apiClient.post<ApiResponse<any>>('/accounts/positions/redeem', data),
/**
* 将 USDC.e wrap 为 pUSDV2 迁移)
*/
wrapToPusd: (accountId: number) =>
apiClient.post<ApiResponse<{ transactionHash: string | null }>>('/accounts/wrap-to-pusd', { accountId }),
/**
* 查询 USDC.e 余额(V2 迁移用)
*/
getUsdceBalance: (accountId: number) =>
apiClient.post<ApiResponse<{ balance: string }>>('/accounts/usdce-balance', { accountId }),
},
/**