Exact Output 兑换¶
Exact Output 从接收者必须收到的金额出发计算报价。当前流程使用钱包资金和固定输入扣款,要求 gas_mode="pay_more"、funding_policy="wallet_fixed_exact_output",不使用已有 Vault 余额支付这笔兑换。整数取整后,成功到账金额可能高于目标;实际结果以确认金额为准。
可用性取决于目标部署。临时 503 不能证明执行失败,请保留请求身份并遵循下方重试规则。
请求报价¶
身份验证: 无。
请求体¶
{
"quote_uuid": "client-quote-001",
"from_token": "0x1111111111111111111111111111111111111111",
"to_token": "0x2222222222222222222222222222222222222222",
"to_amount": "1000000",
"max_from_amount": "1200000",
"owner_address": "0x3333333333333333333333333333333333333333",
"recipient": "0x3333333333333333333333333333333333333333",
"expiration": 1800000000,
"gas_mode": "pay_more",
"funding_policy": "wallet_fixed_exact_output"
}
GET /api/v1/system/time 设置未来截止时间,并预留报价、签名和执行时间。 | 字段 | 必填 | 说明 |
|---|---|---|
quote_uuid | 否 | 1–64 个不含空格的可见 ASCII 字符;省略时生成 UUID。建议自行提供并保存,以便识别报价重试 |
from_token、to_token | 是 | 不同、非零、严格小写的 0x EVM 地址 |
owner_address、recipient | 是 | 非零小写签名/付款钱包与接收钱包 |
to_amount | 是 | 目标输出金额,正 uint256 十进制 raw 字符串 |
max_from_amount | 否 | 包含报价 gas 费用的最大钱包输入扣款,正 raw 字符串 |
expiration | 是 | Unix 秒数整数,0 < expiration < 2**48;报价后必须留有执行时间 |
gas_mode | 是 | pay_more |
funding_policy | 是 | wallet_fixed_exact_output |
额外字段、浮点金额和非规范 raw 字符串会被拒绝。报价有效期最长 30 秒,且至少早于路由截止时间 30 秒结束;请始终使用返回的 expires_at。
响应¶
| 字段 | 说明 |
|---|---|
quote_uuid | 执行和状态查询使用的标识符 |
execution_flow | exact_output_fok_v1 |
status | quoted |
expires_at | 报价过期的 Unix 秒数 |
funding_policy、gas_mode | 已接受的资金与 gas 选项 |
route_params | 必须原样签名的 EIP-712 Intent 字段;其中 uuid 是签名 uint256,不是 quote_uuid |
signing_domain | 本次报价应使用的 EIP-712 域 |
permit | 资金授权元数据,沿用 Swap 的 permit/approve 分支 |
fee_breakdown.quoted_gas_fee_input_raw | 以输入代币 raw 单位计价的 gas 费 |
fee_breakdown.wallet_debit_raw | 固定的钱包总扣款 |
fee_breakdown.expected_recipient_output_raw | 预期输出,不低于 to_amount |
fee_breakdown.confirmed_recipient_output_raw | 报价时为 null |
fee_breakdown.gas_fee_usd | gas 的美元成本,十进制字符串 |
route_params.maxInputAmount 和 initialDepositAmount 均等于固定钱包扣款。minOutputAmount 是请求的目标金额。使用 Intent 类型和本次报价的 signing_domain,原样签署所有返回字段。
执行¶
身份验证: EIP-712 Intent 签名。如携带 API Key,必须属于报价所有者。
请求体¶
{
"quote_uuid": "client-quote-001",
"signature": "0x...",
"permit_signature": "0x...",
"permit_deadline": 1800000000
}
quote_uuid 和 signature 必填。只有已存报价要求且支持 EIP-2612 permit 时,才提交 permit_signature / permit_deadline。否则完成 approve 流程并省略这两个字段;多余的 permit 字段会被拒绝。 待确认执行返回 HTTP 202;其他正常 HTTP 响应使用 200。HTTP 200 本身不表示交易成功,必须检查 status。
查询状态¶
GET /api/v1/swap/exact-output/{quote_uuid}
GET /api/v1/swap/exact-output?quote_uuid=client-quote-001
身份验证: 需要 API Key,结果仅对报价所有者可见。自定义或不透明 ID 优先使用查询参数形式,并由 HTTP 客户端编码参数。路径形式仅适用于单路径段 ID:合法的 a/b 即使编码为 a%2Fb 也可能因路由解码返回 404,不能据此认定报价不存在。
| 状态 | 含义 |
|---|---|
quoted | 报价存在且仍有效,尚无确认的执行结果 |
expired | 未执行报价已失效 |
pending | 执行结果尚未确定 |
succeeded | 成功结算已确认 |
failed | 执行已进入终态失败 |
报价/过期响应包含 quote_uuid、execution_flow、status。执行记录持久化后,还包含 order_id、route_uuid、intent_hash、transaction_hash、error_code、confirmed_recipient_output_raw、confirmed_actual_input_cost_raw;待确认时相关确认字段可能为 null。最终记账应使用确认字段,不能使用报价估计值。
重试与错误¶
- 报价重试使用同一
quote_uuid和完全相同的报价字段。相同 ID 绑定不同请求会返回 409;过期身份不能作为新报价复用。 - 发送前保存完整执行请求体。超时、503 或 pending 后查询原 ID,必要时重试完全相同的签名请求。改变签名字节或 permit 内容会与已认领执行冲突;编码说明见下文。
- 执行结果未知时,不要创建新报价 ID 替代原执行。关闭新报价/执行准入时,状态读取仍保留。
pending 可能包含服务在确认尚未广播交易后,对临时提交失败进行的自动重试,也可能表示提交或链上恢复结果尚不确定。这两种情况都不要求客户端创建新报价或重新签署替代 Intent;应持续查询原 quote_uuid,直到得到终态结果。
| HTTP | 含义 / 处理 |
|---|---|
| 400 | Intent/permit 签名无效、多余 permit 或资金预检失败 |
| 401 | 状态查询缺少或使用无效 API Key |
| 404 | 报价不存在 |
| 409 | 报价/执行身份冲突;部分准入前 permit nonce 冲突需重新报价 |
| 410 | 计划或报价过期 |
| 422 | 请求无效、超出输入上限或类型化报价拒绝 |
| 429 | 限流;存在 Retry-After 时遵循该值 |
| 503 | 临时不可用或关闭新准入;保留 ID 并查询状态 |
类型化 4xx 使用 detail.code,例如 EXACT_OUTPUT_QUOTE_CONFLICT、EXACT_OUTPUT_EXECUTION_CONFLICT、EXACT_OUTPUT_PLAN_EXPIRED、EXACT_OUTPUT_INPUT_CAP_EXCEEDED。共用的 Swap 预检错误也可能使用 detail.error_code 或字符串。5xx 通常返回通用 503 响应,不能依赖内部 EXACT_OUTPUT_* 码一定出现在该响应中。
Intent 与 permit 长度限制见签名编码。为保持兼容,应保存并原样重试签名请求:新执行认领将等价的十六进制编码规范化为签名字节,但改变签名字节或签名内容会改变执行身份;历史认领仍可能使用原字符串指纹。同时遵守整体请求体上限。