OKX DEX
通过OKX DEX聚合器接口在链上兑换代币,钱包由配置的助记词派生(EVM链、Tron、Solana、TON、Aptos、SUI、Starknet)。只支持同一条链上的市价兑换;行情、K线、成交、代币列表来自OKX DEX的行情接口。接口凭据默认使用平台内置的项目凭据,也可以用exchange.IO("config", ...)换成自己的OKX API凭据(在OKX开发者平台 https://web3.okx.com/onchainos/dev-portal 申请,各字段来源见该指令说明)。钱包每条链固定使用助记词的第一个账户(EVM链为m/44'/60'/0'/0/0),不支持选择账户序号或导入私钥。
名称与配置
exchange.GetName():OKX_DEX(现货);别名:OKX Web3、欧易DEX。
| 配置项 | 必填 | 说明 |
|---|---|---|
| 助记词 | 是 | 钱包助记词(BIP39,12或24个单词,不支持私钥),各链钱包地址由它派生,每条链只用第一个账户(派生路径见注意事项)。OKX API凭据不在这里填写,见exchange.IO("config", ...)。 |
交易对与合约代码
交易对示例:1:ETH_USD、501:SOL_USD、1:ETH_1:USDC
品种代码写作<链>:<代币>_USD(例如1:ETH_USD、501:SOL_USD),用于行情、K线、成交;下单(兑换)使用双边写法<链>:<代币>_<链>:<代币>,例如1:ETH_1:USDC,两边必须是同一条链。链可以写OKX的链号(chainIndex)或链名(ETH、SOL、TRX、APT、SUI、TON、STRK等,其它别名可用regChain注册)。
代币可以写代币名或合约地址(如1:0xa0b8..._USD)。代币名区分大小写(OKX把BAX与BAx当作两个代币)。同一条链上名字相同的多个合约(例如GALA的新旧合约)不出现在代币列表中,也不能按名字使用,需要写合约地址或用regToken把名字绑定到某个地址。
专属IO指令
| 指令 | 参数 | 说明 | 返回值 |
|---|---|---|---|
config | string(JSON) | 设置OKX API凭据,字段ApiKey、SecretKey、Passphrase、Project缺一不可。(详见表下) | 成功返回true。 |
key | string | 运行时更换钱包助记词(12或24个单词),解析失败时保留原钱包。 | 成功返回true。 |
address | [chainIndex] | 获取钱包在某条链上的地址(链可写链号或链名),不传时为以太坊(1)。 | — |
addresses | — | 导出钱包在全部链上的地址。 | 以链号为键、地址为值的对象。 |
slippage | [number] | 无参数时读取,带参数时设置兑换滑点(百分比,大于0且不超过50,默认0.5)。 | 读取时返回当前值(字符串,如"0.5"),设置成功返回true。 |
gasLevel | [string] | 无参数时读取,带参数时设置Gas档位:average(默认)、fast、slow。 | 读取时返回当前值,设置成功返回true。 |
gasMultiplier | [number] | 无参数时读取,带参数时设置EVM交易gas上限的倍数(≥1,默认1.5)。 | 读取时返回当前值,设置成功返回true。 |
allChainBalance | [bool] | 无参数时读取,带参数时设置exchange.GetAssets()是否查询全部链的余额(默认只查以太坊),开启后exchange.GetAccount()的Equity也按全部链计。(详见表下) | 读取时返回当前值,设置成功返回true。 |
rpc | [chain[, url]] | 查询或设置各链的自定义RPC地址,chain须写链号(如1、501),写链名不生效:无参数返回全部,只传链返回该链的地址(未设置时为空字符串),url为空字符串时删除。(详见表下) | 设置或删除成功返回true。 |
regChain | chainId, alias | 注册链别名,之后可以在品种代码中用别名代替链号。别名不区分大小写,不能含_、:,最长20个字符。 | 成功返回true。 |
regToken | chainId, alias, address | 把代币名绑定到某条链上的合约地址(chainId须写链号),绑定的名字优先于OKX代币表,按名字使用时不区分大小写;名字规则同regChain。 | 成功返回true。 |
quote | symbol, amount | 只读报价预览(双边品种代码,例如1:USDC_1:ETH,两边须同链),amount是第一个代币(花费)的数量,滑点用slippage的设置;不构造链上交易。 | {toAmount, fromAmount, priceImpact, estimateGasFee, routerList, info}:toAmount、fromAmount为按精度换算后的代币数量(数字);priceImpact(价格影响,百分比)与estimateGasFee是OKX给的字符串;routerList为路由数组(每项有dexProtocol.dexName、dexProtocol.percent等);info是OKX报价接口原始数据的JSON字符串。 |
allowance | symbol[, spender] | 查询钱包对spender的ERC-20授权额度(品种代码第一个代币,也可以只写<链>:<代币>如1:USDC),不传spender时使用OKX DEX的授权合约。(详见表下) | 额度(最小单位的十进制字符串)。 |
approve | symbol[, amount] | ERC-20授权(品种代码第一个代币,也可以只写<链>:<代币>;只支持EVM链),amount按代币数量计(自动按精度换算),不传时为最大额度;等待交易上链(最多60秒)。 | 交易哈希。 |
signTx | tx, chainIndex | 只签名不广播。(详见表下) | 签名后的交易(字符串)。 |
broadcast | signedTx, chainIndex | 广播已签名的交易。 | {txHash, orderId} |
marketSupportedChains | — | 只读查询行情接口支持的链。 | — |
balanceSupportedChains | — | 只读查询余额接口支持的链。 | — |
swapSupportedChains | — | 只读查询兑换接口支持的链。 | OKX接口的原始数组,每项有chainIndex、chainName、dexTokenApproveAddress(授权合约)。 |
broadcastSupportedChains | — | 只读查询广播接口支持的链。 | — |
tokenSearch | chains, search | 按名称或地址搜索代币(chains为逗号分隔的链号),返回OKX接口的原始数据。 | 数组,每项有chainIndex、tokenSymbol、tokenName、tokenContractAddress、decimal、price、liquidity等(都是字符串)。 |
allTokens | chainIndex | 列出某条链上可兑换的全部代币,返回OKX接口的原始数据。 | 数组,每项有tokenSymbol、tokenName、tokenContractAddress、decimals等。 |
表中长说明的其余部分:
config:不设置时使用平台内置的项目凭据(所有用户共用一份限频额度,查询频繁时容易遇到HTTP 429)。
凭据在OKX开发者平台申请:https://web3.okx.com/onchainos/dev-portal (旧地址/build/dev-portal已失效)。登录后先创建项目,再在项目下创建API Key:Project是项目的Project ID;ApiKey与SecretKey是创建API Key时生成的API Key和Secret Key(Secret Key只在创建时显示一次);Passphrase是创建API Key时自己设置的口令。这里的SecretKey是OKX API的密钥,与配置中填写的钱包助记词无关。
allChainBalance:全链查询按钱包地址分组(EVM链共用一个地址,每次最多50条链,其它链各查一次),相邻两次请求间隔1秒以免触发限频,因此一次查询要十几秒(exchange.GetAccount()另查估值,请求数翻倍);不要高频轮询。rpc:EVM链查询授权额度(allowance与下单前的自动检查)必须配置RPC,OKX的nonce接口失败时也用它兜底;Solana、Tron、SUI、TON签名时查询链上状态,未配置时使用各链的公共节点。Unichain(130)已预置官方RPC。allowance:只适用于EVM链,需要先用exchange.IO("rpc", 链号, url)配置该链的RPC;原生币没有授权,报错。signTx:tx为交易JSON(字符串或对象),chainIndex可写链号或链名。EVM链的交易要有to、data、gas(或gasLimit),可选value、gasPrice、maxPriorityFeePerGas(与OKX兑换接口返回的tx相同):nonce自动查询,gas上限乘以gasMultiplier,没有gasPrice时经该链的RPC查询。
通用指令api、base、currency见exchange.IO。
常用用法
兑换前预览报价(只读,不发交易)
javascript
function main() {
// 以太坊(链号1)上花100 USDC能换多少ETH
var q = exchange.IO("quote", "1:USDC_1:ETH", 100)
if (!q) {
Log("报价失败:", GetLastError())
return
}
Log("花费:", q.fromAmount, "USDC", "得到:", q.toAmount, "ETH")
Log("价格:", q.fromAmount / q.toAmount, "价格影响(%):", q.priceImpact,
"预估gas:", q.estimateGasFee)
for (var i = 0; i < q.routerList.length; i++) {
var p = q.routerList[i].dexProtocol
Log("路由:", p.dexName, p.percent + "%")
}
var info = JSON.parse(q.info) // OKX报价接口的原始数据
Log("交易费(美元):", info.tradeFee)
}
配置RPC、检查授权额度后市价兑换,再查询兑换结果
javascript
function main() {
// 查授权额度、下单前自动授权都要该链的RPC(第一个参数写链号)
exchange.IO("rpc", 1, "https://ethereum-rpc.publicnode.com")
exchange.IO("slippage", 1) // 滑点1%
exchange.IO("gasLevel", "fast")
var allowance = exchange.IO("allowance", "1:USDC") // 最小单位的十进制字符串
Log("USDC授权额度:", allowance)
if (Number(allowance) < 20e6) { // USDC精度6位
// 只授权100 USDC(不传数量为无限额度),等交易上链后返回交易哈希
Log("授权交易:", exchange.IO("approve", "1:USDC", 100))
}
// 买入时数量是花费的第二个代币:花20 USDC买ETH
var id = exchange.CreateOrder("1:ETH_1:USDC", "buy", -1, 20)
if (!id) {
Log("兑换失败:", GetLastError())
return
}
for (var i = 0; i < 20; i++) {
var o = exchange.GetOrder(id)
if (o && o.Status != ORDER_STATE_PENDING) {
Log("状态:", o.Status, "买到ETH:", o.DealAmount, "均价:", o.AvgPrice)
break
}
Sleep(3000)
}
}
搜索代币,把名字绑定到合约地址,并注册链别名
javascript
function main() {
// 在Base(链号8453)上搜索USDC,返回OKX接口的原始数据
var rows = exchange.IO("tokenSearch", "8453", "USDC")
if (!rows || rows.length == 0) {
Log("没有搜到:", GetLastError())
return
}
for (var i = 0; i < rows.length; i++) {
var r = rows[i]
Log(r.chainIndex, r.tokenSymbol, r.tokenName, r.tokenContractAddress)
}
var all = exchange.IO("allTokens", "8453") // Base上可兑换的全部代币
Log("可兑换代币数:", all.length, "第一个:", all[0].tokenSymbol)
// 链别名:之后可以写MYBASE:USDC_USD(别名不区分大小写)
exchange.IO("regChain", 8453, "mybase")
// 把名字USDC绑定到搜到的第一个合约,优先于OKX代币表
exchange.IO("regToken", 8453, "USDC", rows[0].tokenContractAddress)
var q = exchange.IO("quote", "MYBASE:USDC_MYBASE:ETH", 10)
Log("10 USDC可换ETH:", q ? q.toAmount : GetLastError())
}
查看钱包在各链的地址、各接口支持的链与全链余额
javascript
function main() {
Log("以太坊地址:", exchange.IO("address"), "Solana地址:", exchange.IO("address", "SOL"))
var addrs = exchange.IO("addresses") // {链号: 地址}
Log("Base地址:", addrs["8453"], "Tron地址:", addrs["195"])
var chains = exchange.IO("swapSupportedChains")
for (var i = 0; i < chains.length; i++) {
Log("可兑换:", chains[i].chainIndex, chains[i].chainName)
}
Log("行情接口支持", exchange.IO("marketSupportedChains").length, "条链,",
"余额接口", exchange.IO("balanceSupportedChains").length, "条,",
"广播接口", exchange.IO("broadcastSupportedChains").length, "条")
// GetAssets默认只查以太坊;改为查全部链(一次十几秒,不要高频轮询)
exchange.IO("allChainBalance", true)
var assets = exchange.GetAssets()
for (var j = 0; assets && j < assets.length; j++) {
Log(assets[j].Currency, assets[j].Amount)
}
}
用OKX兑换接口取交易数据,自己签名后广播
javascript
function main() {
var chain = "1"
var wallet = exchange.IO("address", chain)
// 花1 USDC换ETH的交易数据(数量写最小单位);花ERC-20前要先授权,见上面的示例
var r = exchange.IO("api", "GET", "/api/v6/dex/aggregator/swap", {
chainIndex: chain,
amount: "1000000",
fromTokenAddress: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
toTokenAddress: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
slippagePercent: "0.5",
userWalletAddress: wallet
})
if (!r || r.code != "0") {
Log("取交易失败:", r ? r.msg : GetLastError())
return
}
// tx有to、data、value、gas、gasPrice等;签名时自动取nonce,gas上限乘以gasMultiplier
var signed = exchange.IO("signTx", r.data[0].tx, chain)
if (!signed) {
Log("签名失败:", GetLastError())
return
}
var res = exchange.IO("broadcast", signed, chain)
Log("交易哈希:", res.txHash, "OKX订单号:", res.orderId)
}
函数支持差异
不支持(调用时报错并返回空值):exchange.GetDepth、exchange.GetOrders、exchange.GetHistoryOrders、exchange.CancelOrder、exchange.ModifyOrder、exchange.CreateConditionOrder、exchange.ModifyConditionOrder、exchange.CancelConditionOrder、exchange.GetConditionOrder、exchange.GetConditionOrders、exchange.GetHistoryConditionOrders。
以回退方式支持:
exchange.GetRecords:原生周期为1分钟、3分钟、5分钟、15分钟、30分钟、1小时、2小时、4小时、6小时、12小时、1天、3天、1周、1月、3月;其它周期由托管者合成。
注意事项
- 只支持市价单(
price为-1),限价单报错;不支持跨链兑换。卖出时amount是品种代码第一个代币的数量,买入时是第二个代币(花费)的数量。订单ID为<品种代码>,<交易哈希>,用exchange.GetOrder()查询兑换结果。 - 下单附加参数原样传给OKX DEX的兑换接口(例如
slippagePercent覆盖本单滑点);Solana上的兑换不带gasLevel,改为自动设置computeUnitPrice、computeUnitLimit,也可以在附加参数中指定。 - EVM链上花费ERC-20代币(非原生币)的兑换,下单前自动检查授权额度,不足时先发送无限额度的授权交易并等待上链;检查额度需要该链的RPC,没有用
exchange.IO("rpc", 链号, url)配置时下单报错。 exchange.GetOrder()按交易哈希查询OKX的兑换记录,数量按订单ID中品种代码的第一个代币(基础币)统一口径,买卖一致:换到基础币的是买单、花出基础币的是卖单(Type);Amount是花出的代币数量(买单是花费的计价币,同下单时的amount);DealAmount是成交的基础币数量(买单为买到的、卖单为卖出的);AvgPrice是计价币÷基础币。DealAmount与AvgPrice只在兑换成功后给出,失败或未完成时为0;交易尚未被索引时状态为未完成。- Solana上OKX的兑换记录不给到账代币的数量,
exchange.GetOrder()改从链上交易读取(钱包在这笔交易前后的余额差,节点为exchange.IO("rpc", "501", url)设置的,缺省公共主网节点);节点还没索引到这笔交易时按挂单中报,下次轮询再取。 - 请求OKX接口遇到限频(HTTP 429,错误码50011)时自动等待1、2、4秒重试,最多3次,仍失败才报错。
- 链上没有订单簿和挂单:
exchange.GetDepth()、exchange.GetOrders()、exchange.CancelOrder()等函数报错并返回空值。 exchange.GetTickers()返回以太坊(链号1)上24小时成交量排行榜中的代币,不是全部代币;exchange.GetMarkets()列出以太坊上可兑换的代币(同一条链上重名的代币不列出)。exchange.GetAssets()默认只查询以太坊上的余额,资产名写作链名:代币名(OKX没有给出代币名的资产用合约地址代替代币名);用exchange.IO("allChainBalance", true)查询全部链。exchange.GetAccount()查询当前交易对两边代币所在的链,按链号和合约地址取Stocks(左边代币)与Balance(右边代币,计价为USD时为0),交易对写链号、链名或合约地址都可以。- 钱包只能用助记词派生,每条链固定使用第一个账户,不支持选择账户序号或导入私钥。EVM链(以太坊、BSC、Base、Arbitrum等共用一个地址)为
m/44'/60'/0'/0/0,即MetaMask等钱包中该助记词的第1个账户,第2个及以后的账户无法使用。其它链:ETCm/44'/61'/0'/0/0;Tronm/44'/195'/0'/0/0;Bitcoinm/86'/0'/0'/0/0(Taproot地址bc1p…);Litecoinm/49'/2'/0'/0/0(P2SH-SegWit);Dogecoinm/44'/3'/0'/0/0、Dashm/44'/5'/0'/0/0、Bitcoin Cashm/44'/145'/0'/0/0;Osmosism/44'/118'/0'/0/0;Stacksm/44'/5757'/0'/0/0;Solanam/44'/501'/0'/0';Aptosm/44'/637'/0'/0'/0';SUIm/44'/784'/0'/0'/0';TONm/44'/607'/0'(W5R1钱包合约地址);Starknet以EVM私钥为种子再按m/44'/9004'/0'/0/0派生。可以用exchange.IO("address", 链)核对地址。