mcpField
Q
qmax

qmax

远程服务
qmax.exchange金融数据02 周前更新

关于 qmax

qmax 是面向 Qubic 交易者和应用的 DEX 路由服务,可比较 QX 订单簿与 QSwap 池的报价,并计入成本、按需拆分订单。

主要功能

  1. 01比较 QX 与 QSwap 的最优报价
  2. 02支持路由及拆分订单
  3. 03计算费用、价格影响和深度
  4. 04提供资产目录与市场活跃度
  5. 05提供 HTTP API 和 SDK

适用场景

  1. 01下单前比较 Qubic 交易场所
  2. 02用批量报价选择订单规模
  3. 03在其他 DEX 网站展示市场报价

MCP 相关

项目包含供 Agent 使用的 MCP 服务,向 MCP 客户端提供 QMax 市场报价和交易规划能力。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://qmax.exchange/api/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

详细介绍

QMax

关于此仓库。 这是 QMax 的开源部分:路由器、HTTP API、网站、SDK、MCP 服务和 x402 辅助工具。QMax 自身部署的一些部分不包含在内:Max 规划器、Max 通行证逻辑、Discord 机器人(其 QU 价格源除外)、服务部署文件以及所有机密信息。此处的代码若依赖未公开的部分,会提供一个小型替代文件,以保留类型并说明这一点,确保其余部分可以构建和运行。保留所有权利;不授予任何许可。

QMax 会在 Qubic 上找到最划算的交易路线,让你的钱发挥最大价值。对于 buy 5000 ASSET,它会计算 QX 订单簿和 QSwap 池中的订单价格(包括费用、价格影响和转账成本),并将订单路由到更便宜的交易场所,或拆分到两者。

npm i
npm run qmax -- buy 100000 [--snapshot file.json] [--no-split]
npm test

哪些需要付费(哪些不需要)

几乎所有内容都是免费的,以促进采用,因为其他 Qubic 网站也都是免费的:网站(无需通行证,也不收取单笔交易费用)、HTTP API(无需密钥,也不计费)、SDK、MCP 服务和 Agent。唯一出售的是面向 Agent 的 Max 报价(GET /v1/max,API_MAX_PRICE_QU,在线服务上每份计划 100 QU):Agent 从预付密钥余额中付款,或持有 x402 会话;而网站自带的 Max 和 QMax 自己的密钥永远不会付费(见下文)。Discord 机器人的订阅功能虽保留在代码中,但目前已关闭。“免费”不代表“无限制”:不使用 QMax 自有密钥的调用者在市场端点上受 IP 限流(API_FREE_PER_MIN,默认为每分钟 60 次),以防其中任何一个调用者压垮 Qubic 节点;QMax 自有密钥(Discord 机器人)不受限流。因此,收入来自 Agent 购买的 Max 报价(以及任何支持小费),以及日后若重新启用 Discord 订阅功能所带来的收入;订阅者的利润分成也来自这些收入(见下文)。

  • API_ACCESS=free(默认):所有人都可以访问,无需密钥。billing:保留旧版的预付单次调用价格和 x402 会话,但默认关闭。private:只有 API_KEY 可以访问。
  • API_MAX_PRICE_QU(默认值为 0:Max 报价免费;在线服务上为 100)可在 API_ACCESS=free 时向 Agent 出售 Max 计划:此时计量器只服务于 GET /v1/max,密钥和充值也可正常使用(POST /v1/keys、GET /v1/topup、POST /v1/topup/claim、GET /v1/account),但其他任何内容都不收费。谁来付款:使用预付密钥(x-api-key)的 Agent 会在计划生成之后扣费,因此无法生成计划的请求不收费(若余额在此期间被扣完,则会返回 402,而不是计划);使用 x402 会话(GET /v1/x402,通过 API_SESSION_PRICE_QU 支付 API_SESSION_SECONDS 时长)的 Agent 无需为每份计划单独付费;其他调用者会收到 402,其中会说明价格和两种付款方式。**永不收费:**QMax 自有密钥(API_KEY、ADMIN_KEY)以及网站页面自身发出的请求(浏览器会标记 Sec-Fetch-Site: same-origin,页面脚本无法更改此标记,因此来自其他网站的页面会被收费)。这只是宽松检查,并非锁定机制:浏览器之外的程序可以发送相同的标头以省下费用,这也是价格设得较低的原因。我们有意不提供按计划单次付款:QPayhub 会从每笔付款中至少收取 100 QU,付款也需要约十秒,因此每次调用支付 100 QU 会让费用耗尽其价值。充值 10,000 QU 可购买 100 份计划,手续费约为 1%。
  • 网站的通行证功能已关闭。使用 VITE_REQUIRE_PASS=on 构建网站即可重新启用该功能(其价格由 src/config.ts 中的 PAYWALL 设置)。
  • 以下有关通行证、预付 API 密钥和 x402 会话的章节介绍了这些可选模式。

费用模型(来源:qubic/core 的 Qx.h 和 Qswap.h;请核实后再信任)

  • **QX:**交易费为 0.3%(tradeFee 为 3,000,000 / 1e9),每次撮合向上取整(floor(v*rate)+1)。在合约中,费用从卖方收到的 QU 中扣除,因此买方无需支付费用(文档称“持有 QUBIC 的一方”;请核实)。订单不收取固定费用(已于 2026-10-08 在链上核查:买单附带的金额恰好是价格 x 数量,成交时不会多收,例如,1,303 QMINE 的价格为 3,989,发送了 5,197,667 QU,成本恰好如此;卖单不附带任何金额)。只有在 QX 和 QSwap 之间转移管理权时才会收取 100 QU 的资产转移费,这是单独的一步。
  • **QSwap:**兑换费为 0.3%(swapFeeRate 为 30 / 10,000)。买入使用 QuoteExactAssetOutput(对输入的 QU 收费,向上取整);卖出使用 QuoteExactAssetInput(从输出的 QU 中扣费)。协议、股东和 QX 的分成均由这 0.3% 支付,不会额外收费。每次操作收取 100,000 QU 固定费用,另加资产转移费,这部分被视为 QSwap 的固定成本。
  • 费用、舍入规则和固定成本都位于 QxConfig / QswapConfig 中,因此无需改动路由器即可调整。

HTTP API

其他 DEX 网站可以通过 HTTP 调用 QMax(无需钱包或 SDK):npm run api(环境变量:PORT、SNAPSHOT,可选的 API_KEY)。

GET  /v1/quote?side=buy&asset=DEMO&qty=100000[&split=false]
POST /v1/quote   {"side":"sell","asset":"DEMO","qty":500}
GET  /v1/quotes?side=sell&asset=DEMO&qtys=1000,10000,50000      (several sizes at once; free access only)
GET  /v1/assets[?category=contract|token&q=CF]   GET /v1/assets/search?name=CFB
GET  /v1/openapi.json        GET /health

报价响应包含 route(交易场所、数量、有效价格、价格影响、费用、使用的 QX 深度)、totalQu、fillable、单一交易场所的 alternatives 和 warnings,以及通俗易懂的 summary(src/quotesummary.ts):总额、平均值、订单的去向和拆分的价值,供只读取而不计算的助手使用。GET /v1/quotes(src/quotesroute.ts)会基于同一份市场数据,为同一订单的最多 10 种数量报价,并说明每种数量相对于最小数量的劣势(averageVsSmallestPct),这样机器人一次调用就能选择拆分数量;此功能仅在 API_ACCESS=free 时提供,因为预付费部署会对每个拆分报价收费,而批量请求会绕过这一限制。每个受地址限流的调用都会包含 X-RateLimit-Limit、X-RateLimit-Remaining 和 X-RateLimit-Reset(秒),以便调用方在收到 429 和 Retry-After 拒绝前降低请求频率;每个错误除了对应的说明句子外,还会带有稳定的 code(bad_request、unauthorized、payment_required、not_found、rate_limited 等)。CORS 为开放状态,因此浏览器可以直接调用;设置 API_KEY 可要求请求包含 x-api-key 标头。

资产列表

GET /v1/assets 会返回所有可交易资产(QX 订单簿或 QSwap 池),按流动性从高到低排列,每项包含 id、symbol、issuer、category(contract = 智能合约股份,token = 其他所有资产)、venues、priceQu 和 liquidityQu。首次网络扫描完成前,ready 为 false;结果会缓存到 .cache/catalog.json,因此重启后可立即使用。

src/catalog.ts 会构建列表:所有合约股份(由零身份发行)、assets.json 中列出的代币,以及网络的发行列表(RPC 将其上限设为 150 项)。不在列表中的代币可通过 GET /v1/assets/search?name=ABC 添加;该接口会在网络上查询名称,检查该代币是否可交易,并将其保留。如果两个发行方使用相同名称,代币的 ID 会是 GARTH.PHOEN 这样的形式;合约股份则保留原始符号。扫描限速为每秒 3 个请求,并使用独立客户端,因此不会拖慢报价。

活跃状态筛选

GET /v1/assets 中的每项资产都有 activity(active、inactive 或 unknown)和 lastActiveAt。inactive 表示连续两个周期(14 天)内没有 QX 订单,也没有资金池变动。src/activity.ts 会从归档 Query API(/query/v1/getTransactionsForIdentity,订单类型 5 和 6)读取 QX 订单历史,按每个窗口 100,000 个 tick 扫描;如果某个窗口达到 10,000 条结果上限,就会拆分该窗口。首次扫描会在几分钟内覆盖 14 天的数据;之后只读取新的 tick,进度保存在 .cache/activity.json 中。首次扫描期间,响应还会包含 activity: { ready, progress }。

限制:此功能统计的是在 QX 上提交的订单(包括做市商的订单),而不是已完成的交易。QSwap 没有便捷的历史记录,因此当 QMax 开始监视某个资金池后,只要其储备发生变化,该资金池就会被视为活跃。只有监视满 24 小时后,资金池才会被判定为静默;在此之前,其状态为 unknown,不会被隐藏。

实时数据

npm run api 会提供实时 Qubic 数据(设置 ASSETS=file 可使用其他种子文件;该文件是包含代币名称或 { symbol, issuer } 对象的 JSON 列表;设置 QUBIC_RPC_URL 可更改 RPC,默认值为 https://rpc.qubic.org)。如果未设置该文件,或设置了 SNAPSHOT=file,则会提供演示快照,并在启动时说明这一点。

src/live.ts 会针对每项资产通过 /live/v1/querySmartContract 读取:

  • QX(合约 1):Fees(交易手续费、转账手续费)以及 AssetAskOrders / AssetBidOrders,每次分页读取 256 条,使用 offset,每侧最多读取 2,048 个订单(达到上限时会显示 QX book has N+ orders 警告)。
  • QSwap(合约 13):Fees(兑换手续费、转账手续费)以及用于读取储备的 GetPoolBasicState。每次兑换固定收取的 100,000 QU 手续费是合约的 QSWAP_ADDITIONAL_FEE。
  • 每项资产的状态会缓存 5 秒;读取失败时会重试,且绝不会缓存失败结果。
  • 每项 QSwap 分配都会使用合约自身的 QuoteExactAssetOutput / QuoteExactAssetInput 重新检查,并以 onChainCheck 报告(differenceQu 应为 0)。

要始终包含某个代币,请将其名称添加到 assets.json。可以通过在 src/data.ts 中实现 MarketData,使用基于快照的数据源或自定义数据源。

Web 应用和钱包

web/ 是一个 Vite + React 应用(npm run dev)。web/wallet/ 中的钱包代码移植自 double-k-3033/QRaffle-frontend 的连接模块,保留了相同的四种登录选项:MetaMask Snap、WalletConnect(包括现有的 WalletConnect project ID)、私钥种子和 .qubic-vault 文件,此外还增加了第五种选项:Qubic Wallet 浏览器扩展(qubic/wallet-extension,测试版;它会在页面上添加 window.qubic,见 web/wallet/extension.ts)。QubicConnectContext.getSignedTx 会使用当前连接的方式签署交易。扩展会使用其中当前激活的账户进行签名,因此在广播任何内容之前,都会根据请求的内容(账户、目标地址、金额、tick、调用和数据)检查其返回的签名字节是否完全匹配(src/signedtx.ts);页面也会跟踪扩展中的账户切换或断开连接。WalletConnect 会话和扩展连接会在重新加载后恢复(种子或保险库始终只保存在内存中,因此需要从对话框重新开始)。手机在钱包应用打开时会让浏览器进入休眠状态,也可能直接关闭页面,因此页面离开期间收到的 WalletConnect 批准会在页面返回后处理(页面会记住自己已开始配对);标签页返回时,对话框会立即重新检查;在手机上,按钮会跳转到 QMax 自己的交接页面(/open,Discord 机器人使用的页面)。

与 Qraffle 模块相比的改动:连接模态框使用纯 React/CSS(不使用 Tailwind 或 UI 工具包);移除了 jotai 余额存储;通过保险库登录时会显示所选账户的种子,以便进行签名;保存在 localStorage 中的钱包不再包含私钥(原实现会以纯文本保存)。 应用通过 API 获取报价(开发环境中的 /api 会代理到 npm run api;否则请设置 VITE_API_URL),并列出 API 提供的资产。使用 npm run api 和 npm run dev 启动两者。在手机上试用(连接同一 Wi-Fi):运行 npm run start:lan 会启动 API 和网站,并打印可打开的地址,例如 http://10.0.0.4:5173。网络中只共享网站(它使用同一个开发服务器,该服务器无法读取 .env 或 .cache);API 仍监听在 127.0.0.1 上,网站服务器会将 /api 请求转发给它。页面使用纯 http,因此手机浏览器会将其视为不安全上下文:浏览、图表和交易对话框都能正常使用,但需要 HTTPS 的钱包连接可能无法使用。必须允许 macOS 防火墙弹出的 node 提示;隔离设备的访客网络则无法使用。 外观与风格。 此界面是交易终端,而非落地页:扁平的炭灰色面板配细线边框,小号系统字体,所有数字均使用等宽数字字体,只有一种蓝色强调色,当前标签页上有橙色标记,绿色和红色仅用于买入和卖出。Logo 使用提供的图稿(brand/qmax-logo-source.jpg):字母“QMa”加上替代“x”的双箭头 X。字母部分是用作 CSS 蒙版的图片,叠加在文字颜色上(因此会随主题变化);X 则是矢量图。在没有足够空间显示完整 Logo 时(手机标题栏、网站图标、主屏幕图标),也只显示 X;npm run brand(scripts/make-brand.mjs,macOS)会根据图稿重新生成 web/public/brand、favicon.svg、favicon-32.png 和 apple-touch-icon.png。整个设计系统位于 web/style.css(顶部定义颜色、圆角和字体变量;包含深色和浅色主题,可通过太阳/月亮按钮切换,并记住此浏览器中的选择;在选择之前跟随系统设置),工作区布局和密集样式覆盖则位于最后加载的 web/styles/zz-terminal.css。从 1000px 宽度起,页面采用工作区布局(在 1000 到 1260px 之间,整个工作区会按较小比例显示,详见 web/media.ts 中的 useWorkspaceScale,这样普通浏览器窗口会显示相同的三栏布局,而不是手机布局;图表会反向缩放,确保指针和十字光标位置精确):标题栏包含 Trade、Orders、History、Pools 和 Swap 页面;行情栏显示资产数量和最新成交;左侧是自选列表(Mine、Favorites、All、Contracts、Tokens;点击列标题可排序,在 Vol: 旁选择 24h、72h 或 7d,成交量和价格变动列都会按所选时间段显示);中间是图表及其工具,占据大部分宽度和高度,布局类似 thinkorswim 等交易平台:左侧是资产,中间是大图表,右侧上方是最新成交,下方是订单面板(交易方向、数量、报价、就绪状态以及 Buy 或 Sell 按钮)。图表是用户首先看到的内容:在选择资产之前,中间显示的是Qubic 自有价格图表(web/QubicDesk.tsx,使用与所有资产相同的图表和工具,数据来自 MEXC 和 Gate.io 的蜡烛图),旁边显示所有资产的最新成交,下面则是一个 Swap 面板(Swap 区域的表单,可在 QSwap 上用 QU 兑换代币,或用代币兑换 QU;也可开启 Max 用一种资产兑换另一种资产;使用 SwapPanel 的 compact 模式),代替资产的订单面板。顶部的交易对符号旁有箭头和搜索功能,可切换资产而无需关闭任何内容(按 [ 和 ] 可按成交量切换到上一个或下一个资产;按 / 可打开交易对话框中的搜索框)。“Hide order panel”栏可收起订单面板(选择会在此浏览器中记住;成交列表保持显示),“Wide chart”可隐藏整个右侧区域,让图表显示得更宽。自选列表、图表和右侧区域之间的分隔线可拖动调整大小(双击分隔线可恢复默认大小,也可聚焦分隔线后使用方向键;详见 web/Resizer.tsx 和 web/layout.ts:每个区域的宽度都会保存在此浏览器中,限制在指定范围内,且图表宽度不会小于设定的最小值)。图表自己的按钮(适应视图、最新数据、设置、图片、全屏)浮动在图表右上角。成交列表显示此资产的成交记录,并提供一个标签页显示所有资产的成交(列包括:时间、方向、数量、价格、QU、市场;一小时内的时间显示为 4 min,不带“ago”)。宽度小于 1000px 时(平板电脑、手机),相同的三栏会变成同一行内的三个屏幕,左右滑动切换,后面还有一个投资组合屏幕(web/Pager.tsx,一行使用滚动吸附布局;布局使用工作区的组件):左侧是 Assets(市场,包括 Favorites、All assets、Contracts 和 Tokens,并提供搜索、排序和筛选);中间是 Chart(默认打开此屏幕,在选择资产之前显示 Qubic 图表;无论右侧显示两个屏幕中的哪一个,交易对栏和价格数据都会固定在顶部);右侧是 Trades & order(最新成交及其下方的订单面板;Qubic 则显示 Swap 面板);最后是 Portfolio(My assets 及其价值和收益、Orders、History、Pools 和 Swap,与工作区的 Portfolio、Orders、History、Pools 和 Swap 页面使用相同的标签页)。底部栏标示当前屏幕,点击即可切换;在列表中选择资产会滑动到其图表,打开含有数量的链接则会跳转到订单面板。在图表上横向拖动会切换到下一个屏幕,而不是平移图表(可用鼠标平移图表、捏合缩放,也可使用上方按钮移动图表);上下拖动则会滚动屏幕。列表上方先显示标签栏(手机上分两行,上方是你的标签,下方是市场标签,因此无需横向滚动),搜索、排序和筛选接在其后,作为一个整体;排序和筛选使用同一组分段控件。在手机上,排序控件还包含 24h、72h 或 7d 菜单,用来设置成交量和价格变动的时间段(宽屏上则位于 Vol 列标题中)。筛选器每次只能选择一项(Both markets:在 QX 和 QSwap 上交易的资产;Active:最近 2 个 epoch 内有交易的资产;Arbitrage:Max 的一部分);再次选择当前启用的筛选项会重新显示完整列表。手机上每个资产都以紧凑行显示在列标题下方(Asset、Price、24h 涨跌幅、Vol:;点击标题可排序):星标、Logo、资产名称及其下方显示的交易市场(QX、QSwap 或两者)、价格、涨跌幅和成交量;评级、资产类型和“cheaper on”提示显示在图表标题中。整行都可点击以打开资产,因此没有 Buy 和 Sell 按钮,也不显示价差。标题栏下方的最新成交条会缓慢地从右向左滚动,新成交从右侧加入;鼠标悬停或点击暂停按钮即可停止滚动,如果系统设置了减少动态效果,则显示为普通行,可手动滚动。所有页面共用的组件位于 web/ui.tsx(图标、QMax 标记、按 Esc 关闭并将焦点保持在内部的无障碍 Modal、头像、步骤标记)和页面框架(标题栏、显示余额的钱包菜单、行情栏、状态栏)web/chrome.tsx 中。/ 可聚焦搜索框。页面不会加载 Web 字体,资产 Logo 是从 QMax 自有地址提供的副本(存放于 web/public/logos,由 npm run logos 从 qubictrade.com 保存;没有独立 Logo 的资产会显示带字母的徽章;加载后会识别白色或透明边角的纯色方形底圆形 Logo,并用 Logo 外沿的颜色填充徽章,同时将图片裁切为圆形,因此不会显示白色边角;详见 src/logofill.ts、web/logofill.ts),因此绘制页面时无需从第三方获取任何资源。 **限价单。**每个下单面板都有一个 Market / Limit 切换开关。限价单是以你选定的价格提交的 QX 买单或卖单:该价格或更优价格上的现有挂单会立即成交(按挂单价格成交,绝不会劣于你的限价),其余部分则会留在订单簿上,直到成交或你在 Orders 下取消。QSwap 是没有订单簿的池子,因此限价单仅适用于 QX。订单会在浏览器中根据你设置的价格、数量以及资产列表中的资产和发行方构建(src/limit.ts),并在签名前严格按这些内容进行检查(向 QX 提交一笔买单或卖单、资产正确、价格和单位正确、买单附带价格乘以单位的金额,不包含其他内容);之后会重新读取钱包和订单簿,并显示已成交和等待成交的部分。

我的资产:价值、成本和盈亏。“我的资产”标签页(以及工作区中的“投资组合”页面)会显示每项持仓现在卖出实际能得到的金额:POST /v1/liquidation 会将全部持仓通过实际卖出时使用的路由器执行,因此会计入 QX 订单簿深度、池子和所有费用(市场无法全部接收的持仓会被标记,且只计算可接收的部分)。旁边还会显示平均成本、相对于卖出价值的盈亏,以及首次买入的时间;这些数据来自钱包过去 365 天的交易账本(src/portfolio.ts)。更早买入或从其他钱包收到的单位有价值,但不计入盈亏。总额也会以美元显示。**服务器成本及其为何很低:**为资产估算卖出价格时,需要读取每项资产的实时订单簿和池子(25 项持仓约需 10 到 15 秒;公共节点限制请求时耗时更长)。同一资产的同一笔卖出只估价一次,并在两分钟内与所有请求者共享(LIQUIDATION_CACHE_SECONDS)(许多钱包持有相同的少数几种股票)。同时最多为三个投资组合估价,并限制每个地址的请求次数;页面会在浏览器中保留上次估价,每次重新打开“我的资产”时立即显示,只有当估价已过 15 分钟或按下 Refresh 时才重新估价(数字下方会显示估价的时效)。购买历史是耗费资源的部分(它会读取请求频率受限的公共归档),因此每个钱包的账本只构建一次,并由所有人共享五分钟(LEDGER_CACHE_SECONDS);同时最多构建两个账本(其余请求会收到几秒后重试的提示,并自动重试)。钱包历史会在浏览器中保留 15 分钟;当归档表示请求受限时,30 秒内不会开始构建新账本。

**不连接钱包查看钱包。**有些人不愿将钱包连接到刚发现的网站,而投资组合显示的所有信息都是 Qubic 网络上的公开信息。因此,每个投资组合页面(“我的资产”“订单”“历史记录”“池子”)都有一个可粘贴地址的输入框(web/ViewWallet.tsx、web/viewwallet.ts):系统会从粘贴的内容中提取地址(60 个字母,不区分大小写,或浏览器区块链浏览器页面的链接),并检查地址末四位和校验和;因此,输入错误时会显示提示句,而不是展示一个空钱包。随后,投资组合会显示该钱包的持仓(当前卖出价值、成本、盈亏)、未完成订单、交易历史和池子头寸,并注明钱包所有者以及只读状态,同时提供 Change 和 Stop viewing 选项。以这种方式查看的钱包无法签署任何内容:“买入”“卖出”和“兑换”按钮会变成 Open,订单无法取消,池子头寸没有 Add 或 Remove 选项,“兑换”会提示需要使用你自己的钱包。地址会保存在此浏览器中(qmax.view),直到用户停止查看;连接自己的钱包后,此模式也会结束。系统会直接从公共节点和 QMax 的账本 API 读取信息,与连接钱包时相同。 Max 和 QMax Pro。 普通的买入和卖出是常规订单,而且每笔订单都会采用最佳路由(路由器会分别计算每个市场以及拆分交易的价格,并选择成本最低的方案)。Max 会为交易寻找最佳的持仓方式(如何执行交易、交易规模、两个市场之间的套利,以及现有持仓的最佳退出方式)。它是在 Settings 中的一个开关,即 Max mode,由 GET /v1/max 提供服务。Max 规划器不属于此代码库:src/maxplan.ts 保留了它的类型(即 API 文档中所述的计划结构)和一个说明这一点的替代实现;其背后的通行逻辑(src/pro.ts、src/proapi.ts、src/procover.ts)也是让 Max 免费使用的替代实现。QMax 自己的服务运行的是实际实现。

欢迎窗口(web/WelcomeModal.tsx)会在网站加载时打开:用几句简单的话介绍 QMax 的功能(所有人都可免费使用,密钥由你保管)、一个 Support QMax 按钮(web/SupportModal.tsx:支持邮箱地址、包含 QMax X 的二维码、一个 Copy 按钮),以及一个“Don't show this again”复选框(保存在此浏览器中)。

实时价格。 页面处于可见状态时,列表每 20 秒重新读取一次(页面重新变为可见时也会立即读取),打开的资产标题也会同步更新。价格取自 QX。 每种资产都在 QX 上交易(QSwap 池是旁边的额外市场,绝不是唯一市场),因此始终有 QX 价格:如果某种资产最近有 QX 成交(在 7 天内),则采用该资产最近一笔 QX 成交的价格。QSwap 池只有储备比例,无人交易时比例会保持不变(QMINE 的价格曾连续几天维持在 4,157,而 QX 的成交价为 3,994);而流动性不足的 QX 订单簿的中间价可能远离所有成交价(QSILVER 的中间价为 365 万,而最近一笔成交价为 100,001)。较早的成交价可能已无法反映当前市场情况(QEARN 在 146 天前的成交价高于今天的最佳卖价),因此会被限制在当前 QX 买价和卖价之间;没有 QX 成交记录的资产则采用 QX 买价和卖价的中间价。GET /v1/assets 会将该价格放入 priceQu,并提供 lastPriceQu(原始成交价)、lastTradeAt、bookPriceQu(订单簿或资金池价格)和 probedAt(上次读取订单簿的时间;每 10 分钟读取一次,以减轻公共节点的负担);服务器每 15 秒读取一次成交列表,网站列表每 20 秒读取一次(src/api.ts 中的 priceFromQx、src/liveprice.ts)。成交列表和行情行情代码每隔几秒轮询一次,Qubic 美元价格每分钟更新一次。

All 和 Max。 填入你所持有的全部资产(你持有的某种代币的全部数量,或你可以投入资金池的全部 QU)的按钮标为 All。Max 专用于 QMax 搜索最佳持仓方式,以及将一种资产兑换成另一种资产。 Max 模式在搜索之外解锁的功能。 关闭 Max 时,普通交易界面保持不变。以下功能属于 Max(src/chartaccess.ts 列出了免费功能):近期交易列表中每笔交易所在的市场(关闭 Max 时,此处显示短横线);哪个市场价格更低的提示(显示在列表的每一行,以及交易面板中的 QX 与 QSwap 对比;关闭 Max 时,列表行只会提示存在更低价格);套利标记(行上的 ARB 标签、套利筛选器及其数量、市场栏中的套利数值,以及交易面板中的实时套利检查;关闭 Max 时,标签、筛选器和数值会以灰色提示 Max 功能并可开启 Max,筛选器会被忽略,也不会进行实时检查;Max 开启时,Settings 中的套利限制才会生效;API 的 /v1/arbitrage 保持原样);以及图表的大部分功能。图表免费提供蜡烛图和折线图、所有时间范围、所有蜡烛宽度(自动、1、5、15 和 30 分钟、1 和 4 小时、1 天)、成交量、20 根蜡烛均线、线性坐标轴、市场选择、趋势线和水平线、适应视图、全屏,以及按屏幕尺寸生成图片。其他图表样式、其他指标、纪元标记、填补缺口、对数和百分比坐标轴、图表设置面板、大于屏幕尺寸的图片及其他绘图工具都会以文字标注(工具提示中显示“属于 Max”,选项上显示“· Max”);关闭 Max 时选择这些功能会开启 Max。Max 功能不再带有小标记,因为 Max 已免费。开启 Max 时做出的选择会保留,并在 Max 再次开启时恢复。

交易卡片。 签署市价单、限价单或兑换时,交易对话框顶部会显示一张跟随交易进度的卡片(src/tradecard.ts、web/TradeCard.tsx):进度条会为每个步骤以及钱包检查各显示一段,并展示正在等待什么(你的钱包、区块链或检查)、已耗时多久以及当前进度。整个对话框会根据进展显示轮廓:进行中时为稳定的蓝色轮廓;钱包确认交易成功时显示绿色轮廓并弹跳;某个步骤失败(或订单在签署前被拒绝)时显示红色轮廓并左右摇晃;需要留意时则保持静止的琥珀色(部分步骤已完成,或尚未有任何进展)。对于系统要求减少动态效果的用户,不会有任何动画;颜色保持不变。

QU 的价格。 标题栏中央始终显示 QU 的美元价格及其 24 小时涨跌情况;点击后会打开与其他资产相同的图表(蜡烛图样式、从 1 分钟到 1 天的时间间隔、指标、绘图工具、纪元线、成交量、图表设置、保存图片),以 100 万 QU 的美元价格绘制,因为 1 QU 的价值还不到一美分的一小部分(GET /v1/qu、/v1/qu/candles)。价格是对五个来源进行核验后得到的中位数,与 Discord 订阅定价使用的价格相同(bot/price.ts);市场数据来自 CoinGecko,蜡烛图来自 MEXC 上的 QUBIC/USDT 市场(无法访问 MEXC 时使用 Gate.io;USDT 按美元计),每次响应最多 5,000 根蜡烛,并按每页 500 根读取。MEXC 从 2024 年 7 月 17 日起提供 QU 交易数据;对于 4 小时或日线蜡烛图的更长时间范围,此前的日期数据来自 Gate.io,QU 于 2024 年 5 月 9 日首次在该平台交易(Gate.io 不会提供那么久以前的小时级或更短间隔蜡烛图,而且没有免费的来源能提供更早的价格)。CoinGecko 免费计划最多只能查询一年前的数据,因此它会提供市场数据,以及 /v1/qu/candles 在未指定 interval 时的一年以内蜡烛图。所有数据都会按范围和宽度缓存一到几分钟,这样大量用户同时打开图表时,服务器只需向交易所请求少数几次,而非每人请求一次。/v1/qu/candles 在未指定 interval 时仍会返回 CoinGecko 自己的蜡烛图。 图表设置。 图表上的齿轮图标可打开设置,用于配置配色方案、纯色或渐变背景、蜡烛、影线和线条颜色、空心蜡烛、线条粗细、网格、成交量强度、字体和文字大小。设置会保存在当前浏览器中,读回时会再次校验(src/chartstyle.ts),保存的图片也会使用这些设置。任何蜡烛图上都可以标记 Epoch(UTC 时间周三 12:00,src/epochs.ts)。

交易

src/exec.ts 会将报价转换为钱包签署的有序交易。报价 API 会在 route[].execution 中返回每个环节的限额(通过 slippageBps 设置,默认值 100 = 1%),因此任何前端都可以构建相同的交易:

环节合约调用发送的 QU保护机制
在 QX 买入AddToBidOrder限价 x 数量(多余部分会退还)限价 = 达到的最差卖价 + 滑点
在 QX 卖出AddToAskOrder0限价 = 达到的最差买价 - 滑点
在 QSwap 买入SwapQuForExactAsset输入的最大 QU + 100,000 手续费(多余部分会退还)输入的最大 QU = 报价 + 滑点
在 QSwap 卖出SwapExactAssetForQu100,000 手续费输出的最小 QU = 报价 - 滑点
转移份额TransferShareManagementRights转移手续费(100)仅限卖出:份额必须由交易场所管理
QMax 通行证QPAYHUB.Pay1,000 QU,每 24 小时一次仅在通行证到期后(见下文)

ExecuteModal 会在签名前立即重新获取报价,在价格变动时发出警告,检查钱包余额(买入)和份额持有量(卖出),然后依次签署、广播并等待每笔交易(web/exec/),遇到首个失败时停止。API 仅在提供实时数据时返回执行提示。

交易后,ExecuteModal 会重新读取钱包(src/verify.ts):将 QU 余额和份额持有量与签名时记录的基准进行比较,并报告实际成交的份额与请求数量、实际支出或收到的 QU(含交易场所手续费)、实际价格及其与报价的偏差,以及仍挂在订单簿上的任何 QX 订单(及其中锁定的 QU)。未成交的 QX 订单通过 EntityBidOrders / EntityAskOrders 读取。

已使用真实资金。 网站上的交易已在主网上签署、广播并确认:QX 交易、QSwap 兑换和 QSwap 流动性变更。使用记录(GET /v1/stats,参见使用情况跟踪)会针对链上数据核验其统计的每笔交易,因此该数量是实际测量结果,而非单纯宣称。负载布局和交易大小也通过了与合约源代码和 Qubic 库对照的单元测试。Discord 机器人和 Agent SDK 使用相同代码构建相同的交易,但使用真实资金的次数少于网站:请从小额开始(对于 Agent,可先进行 dry run,使用 agentPlan)。使用任何新功能时,请先尝试一笔极小额交易。已知限制:未完全成交的 QX 买单会作为未完成订单留在订单簿上,而且余额可能需要几个 tick 才会更新,因此结果检查可能需要稍等片刻。

市场对比、套利、订单与交易准备就绪

  • 价格对比(src/arbitrage.ts、comparePrices):对于在 QX 和 QSwap 上都有的资产,展示扣除 0.3% 手续费后的单位买入价和卖出价。该信息会显示在卡片上(“在 QSwap 上买入便宜 5%”)和交易面板中(两者都属于 Max 模式)。
  • 套利标记(findArbitrage):查找在一个市场买入、在另一个市场卖出后,扣除所有费用(QX 的 0.3%、QSwap 的 0.3% 和固定的 100,000 QU;QMax 不额外收费)、资金池价格影响以及 QX 订单簿顶部深度后,最终获得更多 QU 的交易。找到套利机会的资产会标记 ARB 标签;此外还有套利筛选器,交易面板也会对此进行说明。这只是一个快照:两条腿是独立交易,QMax 不会替你执行套利。
  • 实时套利检查(GET /v1/arbitrage?asset=ID、findArbitrageVenues):卡片上的标记来自缓存的订单簿顶部数据(最多可能有 10 分钟的延迟),因此交易面板会在显示任何内容前,基于实时完整订单簿和资金池重新检查。截至撰写本文时,16 种在两个市场都有的资产中,没有一种存在套利机会。
  • 设置(标题栏中的齿轮图标、src/settings.ts、web/settings.tsx):默认滑点(上限为 10%)、隐藏交易不活跃的资产、默认排序方式、简短或完整价格,以及套利筛选器(见下文)。设置存储在浏览器的 localStorage 中;已存储的值无效时,将回退到默认值。
  • 未完成订单(src/verify.ts 中的 fetchAllRestingOrders、web/OrdersPanel.tsx):列出钱包在所有资产上的 QX 未成交买单和卖单,并通过 RemoveFromBidOrder / RemoveFromAskOrder(src/exec.ts 中的 buildCancelStep)取消这些订单。取消免费,取消买单后会返还锁定的 QU。
  • 交易准备就绪检查清单(src/readiness.ts):启用 Review 前,面板会检查钱包是否已连接、流动性是否充足、QU 是否足以支付手续费(卖出时也会检查)、份额是否位于正确的合约中(或是否需要执行额外的转移步骤),并对交易不活跃的市场和手续费较高的交易发出警告。检查失败会阻止交易,警告则不会。

订单簿和价格图表

  • 订单簿(GET /v1/book?asset=ID[&levels=15],src/book.ts):按价格分组的 QX 订单,包含累计数量和成本、最佳买价和卖价、中间价和价差(以及 QX 的订单是否超过单次查询返回的 256 笔),还有 QSwap 池:其价格、储备金、手续费,以及交易量占池子 0.1%、0.5%、1%、2% 和 5% 时价格会移动多少(包含手续费,另加 QSwap 固定收取的 100,000 QU)。读取的数据与路由器使用的实时数据相同。
  • 价格历史(GET /v1/history?asset=ID&range=1d|7d|30d|90d|all[&interval=1h|4h|1d],src/history.ts、src/trades.ts、src/events.ts):两个来源合并为一条曲线。历史交易:QX 会为每笔撮合的订单记录一条 TradeMessage,QSwap 会为每笔兑换记录一条 SwapMessage,归档 Query API 提供这些事件日志(/query/v1/getEventLogs,测试版)。QMax 会读取一次,最远回溯 TRADE_HISTORY_DAYS(默认值为 1,825 天,即 5 年;远超现有数据,因为 Qubic 归档中的交易日志只从 207 纪元(2026 年 4 月)左右开始,因此扫描不到更早的数据,并会在找到首个月份的交易时停止;如果归档日后加入更早的日志,也会将其纳入),按资产和交易场所汇总为分钟数据(成交量加权价格、开盘价/最高价/最低价/收盘价、成交量;小时数据以及任意整分钟长度、最长一天的 K 线都由此生成;第一个版本保留的是小时数据,其文件会另存为 .cache/trades.json.v1.bak,然后从头按时间倒序重新读取),存入 .cache/trades.json,之后只读取新增的交易记录,因此重启后会从停止的位置继续。每个有交易的小时都会成为一个历史数据点,并标记为 src: "trades";有 QSwap 池的资产使用其兑换数据绘制(因为其实时价格就是池子的价格),其他资产则使用其 QX 交易数据。首次读取约需 1.5 分钟,图表会随着读取逐步填充。**实时采样:**每次目录重新读取市场数据时(约每 10 分钟一次),QMax 也会将每种资产的价格、最佳买价和卖价、池子价格及流动性保存到 .cache/history.json。已记录的采样数据始终优先:只有某个小时(对于经过稀疏处理的旧数据则为某一天)没有记录数据时,才会添加重建的数据点;响应中的 recordedSince 表示实时记录的起始位置。交易清淡的时段没有数据点(曲线会在相邻数据点之间连线),兑换价格包含池子手续费和价格影响,因此重建的数据点与池子的边际价格略有差异(对比的资产约为 0.0–0.4%)。最近的采样数据会全部保留,早于 3 天的数据每小时保留一条,早于 90 天的数据每天保留一条。interval 也会返回开盘价/最高价/最低价/收盘价 K 线。TRADE_HISTORY=off 会关闭交易扫描;npm run trades-check -- 210 会显示扫描结果,但不会写入任何内容。已与归档自身的计数核对:QX 完全吻合(27 个纪元共 21,518 笔交易);在 QSwap 交易最繁忙的纪元中,137,339 条事件有 137,305 条成功解码(其余事件的数量为零)。
  • **更早的 QX 历史(Quhub),可选:**Qubic 归档没有 2026 年 4 月之前的交易记录,但 Quhub(一个由社区运营、开放副本形式运行 QX 服务的网站)提供从 2024 年 10 月开始的每日汇总;对于整个生命周期内交易不超过 1,000 笔的资产(大多数资产),还提供每笔交易及其时间。npm run import-quhub 会读取一次(约 150 次请求,每秒一次,使用其页面本身调用的公开 API;--dry-run 不会写入任何内容,--only CFB 只尝试读取一种资产),并保存到 .cache/quhub.json,服务器启动时会加载该文件;QMax 运行时不会调用 Quhub。更早的 K 线只会显示在 K 线图表上,且仅适用于 QX(不适用于“仅 QSwap”;如果数据存在,“最佳市场”指 QX 和 QSwap 的合并数据,因此更早的 QX K 线会延续到一段并非仅包含 QSwap 数据的序列中),仅限归档中首个日期之前的数据,并在 API 中标记为 src: "quhub";图表下方会显示一行说明。交易繁忙的资产会将每日汇总绘制为 K 线(开盘价为前一天的平均价格,收盘价为当天的平均价格),因此对于这些资产,2026 年 4 月之前没有比日线更细的数据。链上无法验证这些数据;在两个来源都有数据的地方,它们的结果相差约 1% 以内(少数资产和日期的差异更大),因此回测、健康度评级、池子及其他所有功能仍只读取归档确认的数据(src/quhub.ts)。
  • K 线和成交量(GET /v1/candles?asset=ID&range=1d|7d|30d|90d|all[&interval=1m|5m|15m|30m|1h|4h|1d][&venue=auto|QX|QSwap|all],src/chart.ts 中的 candleChartSvg):每根 K 线包含真实的开盘价、最高价、最低价、收盘价、QU 成交量、单位数量和交易笔数,数据来自相同的每小时交易汇总,因此 K 线至少覆盖一分钟,而没有交易的时间段不会生成 K 线(图表会保留空缺,不会压缩掉)。默认宽度会根据时间范围自动选择。venue=all 会将 QX 和 QSwap 视为同一个市场(最高价和最低价涵盖两个市场,成交量相加);auto 会跟随实时价格的来源市场。响应还包含两个交易场所最近 24 小时的成交量。网页图表默认显示带成交量面板的 K 线(轻点一下即可切换为折线图),Discord 的 /chart 也提供相同功能,并带有 Line 按钮。SDK 中的 QMaxClient.candles()。
  • 网站图表使用 TradingView Lightweight Charts(Apache-2.0;根据许可证要求,每张图表上都会保留其“TradingView”署名链接)。该库只负责绘制传入的数据,因此 QMax 会补上其余功能(web/ChartView.tsx、web/LwChart.tsx、web/chart/,纯代码已在 src/ 中测试):
    • 样式:K 线、Heikin-Ashi、OHLC 柱、面积图和价格历史折线。K 线宽度(自动,或 1、5、15、30 分钟,1 小时、4 小时、1 天:交易按分钟保留,因此这些数据都是真实数据;自动模式会为 1D 选择 5 分钟,为 7D 选择 15 分钟,为 30D 选择 1 小时,为 90D 选择 4 小时,为 All 选择 1 天,每种情况都有数百根 K 线;单次响应最多包含最近的 5,000 根)和市场(“QX 图表”和“QSwap 图表”按钮;第二个按钮仅适用于在 QSwap 交易的资产;默认打开 QX 图表,对于只在 QSwap 交易的资产则打开 QSwap 图表)均可选择,而非固定设置;范围从 1D 到 All。如果所选范围内的数据太少,难以阅读(少于 12 根 K 线),系统会自动扩大一个级别并说明原因,除非该范围是你手动选择的。数据每分钟刷新一次,缩放位置会保持不变。
    • 指标(src/indicators.ts,已与独立计算结果核对):价格图表上有 SMA 20 和 50、EMA 21、布林带(20、2)、VWAP(从显示的第一根 K 线开始,根据 QU 和交易单位计算出的实际平均成交价);下方各自的面板中有 RSI 14、MACD(12、26、9)、随机指标(14、3、3)、ATR 14 和 OBV。价格坐标轴支持线性、对数和百分比模式,并可切换成交量显示。图例会显示十字光标位置的所有启用指标值。指标按实际存在的 K 线数量计算,因此在交易清淡的市场中,20 根 K 线的平均值可能涵盖超过 20 根 K 线对应的时间(填补空缺会在空 K 线中延续最后价格,使序列不中断);所需 K 线数量超过当前范围时,系统会说明原因。
    • 绘图工具(src/drawings.ts、web/chart/drawings-primitive.ts):趋势线、射线、水平线和垂直线、矩形、斐波那契回撤线和测量工具(变化的 QU 数量、百分比、K 线数量和时间)。点击即可放置,点击绘图即可选中,拖动绘图或其控制点即可修改,按 Delete 键删除,按 Esc 键取消;提供六种颜色。绘图固定到特定时间和价格(因此更改 K 线宽度或坐标轴时仍会保持原位),仅保存在当前浏览器中,并按资产分别存储(localStorage,加载时会验证,绝不会发送到任何地方),且会包含在保存的图片中。
    • **布局:**交易对话框几乎占满整个窗口,图表是主体部分,旁边是精简的下单面板;图表会填满其控制栏下方的剩余高度,绘图工具纵向排列在左侧,如同交易终端;宽屏图表会隐藏下单面板(点击显示下单面板即可恢复)。在手机上,工具会折叠到一个“图表工具”按钮后,让图表优先显示。
    • **图片:**相机按钮可将图表(包括绘图)保存为 PNG,尺寸可选屏幕尺寸、Full HD、4K 或 8K(宽 7,680 px)。大尺寸图片会在屏幕外按目标尺寸重新构建同一张图表,并按比例缩放类型、线条和绘图(web/chart/build.ts),因此画面清晰,不会像拉伸的屏幕截图;如果浏览器无法处理这么大的画布,则会改用下一个较小尺寸。屏幕上的图表会按显示设备的原生分辨率绘制。
    • **其他功能:**跳转到最新 K 线、适应全部数据和全屏显示(使用浏览器的 Fullscreen API)。不包括:文字备注、绘制在图表上的提醒,以及 TradingView 自带的完整工具集(其独立的 Advanced Charts 库需要获得其许可)。
  • 图表(src/chart.ts):使用纯数字绘制为 SVG 文本的价格曲线和深度图,网站(内嵌显示)和 Discord 机器人共用;Discord 机器人使用 @resvg/resvg-js 将其转换为 PNG。文本绘制需要运行机器人的设备上有字体;任何 Mac 或 Windows PC 都具备字体,而精简的 Linux 服务则需要安装一种字体,例如 DejaVu;如果无法绘制图片,机器人会改为显示一行方块字符。
  • 网站:交易面板有订单簿和图表标签页(打开时订单簿每 20 秒刷新一次;图表提供 1D/7D/30D/90D/All 范围,并会明确说明历史数据是否仍然较少)。
  • Discord:/book ASSET(深度图和包含池子数据的文字阶梯)、/chart ASSET [range],以及 /menu 首页上的订单簿和图表按钮(从下拉菜单中选择资产或按名称搜索;图表页面有范围按钮和切换到订单簿的按钮)。全部免费。
  • **API 和 SDK:**两个端点均可免费使用,无需密钥,并按 IP 限流(不会收费);SDK 中提供 client.book() 和 client.history(),并导出 priceChartSvg/depthChartSvg。
  • **其他网站的数据:**QubicTrade 和 QubicSwap 均未发布 API 或开发者文档(两者的 /api、/docs 和 /developers 都返回 404)。QubicTrade 页面通过供其自身页面使用的私有 WebSocket 服务器获取交易历史和成交量;QMax 不会使用该服务。如果你想获取他们的历史数据,请联系他们申请访问权限。

套利设置(网页、Discord 和 API)

每个人都可以通过三个筛选条件决定哪些套利值得显示(src/arbfilters.ts;0 表示没有最低值或限制):最低 QU 利润、投入 QU 的最低利润百分比,以及预算,即最多投入多少 QU。筛选条件会在搜索过程中应用,因此预算会返回符合预算的最佳循环(较小的循环),而不是返回最大的循环并丢弃其余部分;如果没有任何结果达到最低值,则返回“无”。

  • **网页:**设置(齿轮)中的套利部分:最低 QU 利润(默认值为 10,000)、最低百分比和预算。这些设置会影响卡片上的 ARB 标记、套利筛选条件,以及交易面板中的实时检查。它们只保存在当前浏览器中,与其他设置一样。
  • Discord:/arbitrage-settings min_profit min_profit_pct budget 会为你的 Discord 账户保存这些设置(不带选项时会显示当前设置;reset 会清除设置),每次使用 /arbitrage 时都会应用这些设置,包括非订阅用户可见的预览。
  • API:GET /v1/arbitrage?asset=ID&minProfitQu=…&minProfitPct=…&maxCostQu=…。如果没有任何结果达到筛选条件,则返回“无”,且不收费,因此筛选条件永远不会增加费用。

份额管理(QX 和 QSwap)

一个交易平台只能交易由它管理的份额:在 QX 买入的份额由 QX 管理,在 QSwap 买入的份额由 QSwap 管理。QMax 通过两种方式处理此问题。

  • 先转移卖出所需的份额。buildExecutionPlan 会检查每个交易腿中哪个合约管理份额。通过 QSwap 卖出(单独卖出或作为拆分交易的一部分)时,会先调用 TransferShareManagementRights,将恰好足够的份额转由 QSwap 管理;QX 交易腿也会以相同方式反向处理。转移操作是独立的交易,必须先确认,之后才会发送兑换或卖出请求;该操作会显示在步骤中(“将 40 CFB 从 QX 转为由 QSwap 管理,以便 QSwap 出售”)以及交易准备清单中,费用由接收份额的合约收取。只会转移不足的份额,因此拆分卖出时,QX 交易腿会保留自己的份额。由其他对象管理的份额(例如质押在智能合约中的份额)无法在此处出售,错误信息会说明原因。
  • 将所有份额保留在一个合约下(可选,默认 QX)。构建买入交易时会询问此选项:审核对话框中有一项买入后,将我的 ASSET 保留在一个合约下,可选 QX(默认)或 QSwap,并会说明需要根据交易路径额外执行的操作(“将 400 CFB 从 QSwap 转到 QX,费用约为 100 QU”;仅通过 QX 买入且保留在 QX 下时无需转移)。勾选后,买入确认后会将转移作为最后一步签署,无需再次确认;同时还会转移该资产已由另一个合约管理的任何份额。已保存的设置(设置、份额管理)仅决定初始选项;卖出后,系统会提供转移剩余份额的选项和按钮。我的资产 > 全部保留在一个合约下会一次性转移钱包中的每项资产,每项资产各需签署一笔交易(src/consolidate.ts;其他合约管理的份额会列出,但不会处理)。在 Discord 中,买入报价会有两个按钮:立即买入和买入并保留在 QX 下(后者会将转移作为最后一步);/keep-shares under: 会将后者设为主按钮,并在卖出后提供转移选项;/consolidate 会转移全部资产。按下按钮之前不会签署任何操作,每次转移都会收取接收合约的转账费(从 QX 和 QSwap 实时读取)。

QMax 通行证(可选,默认关闭)

现在交易免费:本节介绍通过 VITE_REQUIRE_PASS=on 重新启用的通行证。 QMax 不从交易中收取任何费用。价格、报价和完整的市场视图都免费;执行交易则需要通行证:在 src/config.ts 中设置 PAYWALL.priceQu(1,000 QU),一次支付即可在 PAYWALL.hours(24)小时内不限次数交易。

  • **支付方式:**通过 QPayhub(合约 29,代币 QPAY)支付,因此收益会流向 QPAY。钱包会签署 Pay(seller = QMax address, resourceId = "QMAXPASS", nonce),并附上 1,000 QU(src/pass.ts)。QPayhub 会为其股东和 QPAY 持有者保留 0.75%(至少 100 QU),在同一笔交易中将其余款项转给 QMax 地址,并记录收据。
  • **验证而非假定:**QPayhub 拒绝付款时会退款(且交易仍会确认),因此付款后,应用会从合约读取收据(fetchReceipt:先执行 ComputeReceiptKey,再执行 GetReceipt,并重试几秒),之后才保存通行证。我已使用主网上的真实 QPayhub 付款验证收据查询。
  • **显示位置:**交易就绪清单中有一项“QMax 通行证”;没有通行证时,按钮会显示“解锁交易:1,000 QU,时长 24 小时”,并打开 PassModal。签署前,审核步骤会重新检查通行证(是否仍在 24 小时有效期内,以及 QPayhub 是否仍持有收据)。如果无法连接网络,则会信任已保存的通行证,因此临时故障不会导致用户重复付款。
  • **如实说明限制:**通行证绑定单个钱包,并保存在该浏览器中(换用新浏览器会再次要求付款;通行证已激活时仍可付款)。检查在用户自己的浏览器中运行,因此无法阻止用户自行构建交易或修改应用;24 小时从通行证保存到浏览器的时间开始计算,链上收据只能证明付款已经发生。要对每个调用者强制执行付费墙,需要由 QMax 智能合约自行调用 QX 和 QSwap。

工作原理

  • **QX 深度:**按订单逐一遍历订单簿。报价会报告使用的订单数和消耗的深度比例;如果订单规模超过订单簿容量,QX 会返回“无法成交”。当订单簿达到 256 个订单(查询上限)时会触发警告,因为可能还存在更多深度。
  • **QSwap 对交易规模的依赖:**价格取决于交易规模,因此路由器会按订单规模的 25%/50%/75%/100% 分别为每个交易场所报价,在这些报价之间插值,选出最佳拆分,然后围绕胜出规模增加报价并再次搜索。最终价格始终来自真实报价;只有拆分执行在扣除固定成本后优于单一交易场所执行时,才会选择拆分方案。quoteCalls 会显示为此执行了多少次报价。
  • src/venues.ts:交易场所模型。src/router.ts:阶梯报价与拆分搜索。src/cli.ts:基于 JSON 快照运行。

尚未完成

  • 实时数据:交易场所数据来自快照。适配器必须从 Qubic RPC 获取 QX 订单簿和 QSwap 储备(或通过 variableNetQu hook 调用链上 Quote* 函数)。
  • 执行:目前仅提供报价;不构建交易,也没有防止报价与成交之间状态变化的滑点保护。

Discord 机器人

Discord 机器人的源代码不属于此仓库(它运行在 QMax 自有服务器上);本节介绍托管的机器人。除 bot/price.ts 中的 QU 价格源外,API 和网站均不依赖它。

运行 npm run bot,即可通过 Discord 交易(必须先运行 QMax API;运行 npm start 即可启动)。机器人不会持有密钥:它只会通过 WalletConnect 请求用户自己的钱包进行签名。

  • /menu 是一个点击式仪表板,无需输入任何内容。它仅对你可见,并会随着你的操作自动更新:买入 / 卖出 / 报价(从下拉菜单中选择资产:卖出时选择你持有的资产,否则选择流动性最高的资产,或者选择 按名称搜索…;然后点击数量按钮,卖出时可选 全部,或者选择 自定义数量…;接着使用与命令相同的报价和确认按钮)、套利(扫描所有资产、检查单个资产或设置筛选条件)、钱包、连接 / 断开连接、订阅和设置(套利筛选条件、是否保留股份、将所有资产转移到 QX 或 QSwap)。每个界面都有菜单或返回按钮;斜杠命令仍然可用,并使用相同的代码,因此订阅和检查的行为也相同。Discord 的下拉菜单最多只能有 25 个选项,按钮也无法接受输入,因此 按名称搜索… 和 自定义数量… 会打开小型弹出表单(bot/menu-ui.ts)。
  • /connect 会显示一个二维码(以及供手机使用的链接),用于配对 Qubic 钱包。/wallet 会显示地址、余额和计划;/disconnect 会解除关联。
  • /quote、/buy、/sell 使用与网页应用相同的路由器,计算 QX 和 QSwap 上的交易价格。/buy 和 /sell 会添加一个确认按钮;之后每一步都会作为签名请求发送到钱包,机器人随后会报告钱包中实际发生的变动。
  • 所有人均可免费使用,也可选择支持项目。QMax 的所有者于 2026-10-07 决定将其交给社区:机器人的订阅功能已关闭(未设置 BOT_SUBSCRIPTIONS;设为 on 即可恢复下文所述的全部功能),因此 Discord 中的交易和套利详情与其他所有功能一样免费;/support(以及 /menu 中的 Support QMax)通过 Q+Pay 小费罐提供支持:将 SUPPORT_URL 设为 QPay 仪表板中小费罐的链接(https://useqpay.com/tipjar/<id>,仅限 https),Support 就会显示一个 使用 Q+Pay 打赏 按钮和该链接的二维码(其中包含 QMax X);支持者可在 Q+Pay 结账时选择金额。设置 SUPPORT_URL 之前(或其不是纯 https 链接时),系统会退回到用于发送 QU 的 QMax 地址(SUPPORT_ADDRESS,默认为支付给 QMax 的地址),并以文本和二维码的形式显示。网站标题栏中有一个Qubic 爱心(像素风爱心;位于 web/ui.tsx 中的 QubicHeart,原先 Max 开关所在的位置;设置了 SUPPORT_URL 时,它会直接链接到小费罐;未设置时,则打开显示地址和二维码的 Support 窗口);页脚、Settings 和欢迎窗口中也有 Support QMax 按钮;GET /v1/plans 会返回 support: { url, address } 和 agents: { maxPriceQu, sessionPriceQu, sessionSeconds }(Agent 支付的价格,从相同设置中读取;欢迎窗口中的 Agent 行会显示这些数字,因此不会显示过时的价格)。本条其余内容介绍的是启用订阅功能时的情况。
  • 提醒是机器人唯一的付费功能(在线服务器上,BOT_ALERTS_PRICE_QU 为 BOT_SUB_DAYS(30)天收取 100,000 QU;未设置则免费)。机器人每分钟左右会检查每条提醒对应的市场,这会消耗实际资源。设置该项后,/subscribe(以及 /menu 中的 Subscribe)会像下文的订阅一样,通过 QPayhub 购买提醒计划(收据归属 QMAXSUB,经检查后才计入;每笔付款只计一次;提前付款会增加天数);任何类型的提醒都需要订阅:没有订阅时,/alerts add-… 会说明费用;订阅到期后,提醒会暂停而非删除,不会消耗市场检查次数;订阅后会自动恢复。交易、报价、图表、套利详情和其他所有功能仍然免费(BOT_SUBSCRIPTIONS 仍保持关闭),上线免费期(BOT_FREE_UNTIL)不包含提醒。GET /v1/plans 会返回 discord.alertsPriceQu,网站的欢迎窗口会读取该值。收入属于订阅收入,因此会像订阅收入一样计入订阅者的利润分成。
  • 单一订阅,不收取单笔交易费用(与网页通行证分开)。费用为 30 天 100,000 QU:固定金额(BOT_SUBSCRIPTION_PRICE_QU;BOT_SUB_DAYS 设置时长)。不设置 BOT_SUBSCRIPTION_PRICE_QU 时,费用按实时 QU 价格折算为 BOT_SUBSCRIPTION_USD 美元(默认 $1,见下文)。GET /v1/plans 会向网站提供当前价格、时长和免费期。通过 /menu 中的 Subscribe(或 /subscribe)即可像购买网页通行证一样通过 QPayhub 付款,因此款项也会计入 QPAY,并留下链上收据。机器人会在确认付款前检查收据,每笔付款只计一次;重试付款会复用其随机数,因此 QPayhub 会退还重复付款,而不会向用户重复收费。在订阅到期前再次付款,会将天数加到剩余时长上。
    • **需要订阅:**所有来自 Discord 的交易:/buy 和 /sell,无论采用何种路由(单一市场或在两个市场间拆分),以及完整的 /arbitrage 详情(资产、方向和规模)。/arbitrage ASSET 会以完整深度实时检查单个资产;未指定资产时,则会扫描两个市场上的所有资产。没有订阅时,/buy 和 /sell 仍会显示完整报价并说明费用;/arbitrage 会说明机会数量和最佳机会的价值,但不会指出具体机会。
    • 免费:/quote(包括拆分在内的完整最佳路由)、/connect、/wallet、/disconnect、/consolidate、/keep-shares、设置命令以及 /menu 本身。
  • 上线免费期(BOT_FREE_UNTIL,日期示例:2026-11-06)。在此之前,无论是否订阅,所有人都可以通过 Discord 交易并查看套利详情;菜单和钱包界面会显示“所有人免费使用,直至 …”。这只是机器人给出的答复(不涉及付款、收据或链上记录),因此不会延长付费订阅;即使订阅期超过免费期,免费期结束后订阅仍然有效;Subscribe 界面会告知用户暂时无需付款。不设置此项时,只有订阅者可以交易。
  • 连接代码(网站的 WalletConnect 步骤和机器人的 /connect)是一个二维码,中间白色区域上带有 QMax X(src/qrlogo.ts:纠错级别为 Q,因此读取时可以修复被遮挡的中心区域;已验证可在 420、300、240 和 180 像素下解码);在网站上,二维码及其下方的按钮宽度相同。
  • QU 价格波动时保持 $1 的价值(仅在未设置固定 QU 价格时生效)(bot/price.ts)。机器人每五分钟从五个独立来源读取 QU 价格(CoinGecko、CoinPaprika、Gate.io、MEXC 和 Bitget;交易所交易对为 USDT,并按美元处理),并取相互一致的数据的中位数。与中位数相差超过 15% 的读数会被剔除;来源数据分成不同阵营时会被拒绝;只有至少两个来源支持时,才会接受相较上次已接受价格变动超过 25% 的价格。金额为 $1 除以该价格,再向上舍入到三位有效数字(例如 1,760,000 QU),因此永远不会低于 $1,且超出部分最多为 1%。用户点击 Subscribe 时,金额会保留 15 分钟,并显示在 Pay 按钮上:按钮会携带其显示的金额;如果保留的价格已过期或发生变化,用户会看到新的报价,而不会支付一个自己没看过的金额。同一笔付款中报出的任何金额都会被接受,因此即使两次报价之间价格发生变化,也不会导致用户已付款却无法到账。如果所有来源都不可用,机器人会在最长 6 小时内保留上次有效价格;之后会说明无法计算价格(其他所有命令仍可使用)。如需低成本测试,可将 BOT_SUBSCRIPTION_PRICE_QU 设为固定 QU 金额(此时不会使用实时价格)。网页通行证和 API 仍以 QU 计价。
  • 在与 Discord 相同的手机上打开钱包。Discord 按钮只能打开网页地址,因此设置 BOT_PUBLIC_URL(手机可访问 API 的地址,例如 https://api.example.com)后,Connect 界面会出现一个 在钱包中打开按钮,链接到 API 的 /open 页面(src/openpage.ts)。该页面会从地址中 # 后的部分读取配对链接;浏览器永远不会将这部分发送到任何服务器,因此其中的密钥不会被记录。页面会检查链接是否为有效且未过期的 WalletConnect 链接,使用 qubic-wallet://pairwc/… 打开钱包应用(与网站使用的地址相同),清除地址栏中的链接,并提供真正的复制链接按钮作为备用方式。页面不会从其他网站加载任何内容,也不会向外发送任何内容(严格的 Content-Security-Policy、no-store、不发送 referrer)。未设置 BOT_PUBLIC_URL 时,Connect 界面会显示二维码和复制链接按钮,该按钮会在私信中单独发送链接(长按并选择复制文本)。
  • 所有涉及钱包的回复都仅对用户本人可见(临时消息),包括配对二维码。 设置:在 discord.com/developers 创建应用和机器人,将其令牌放入 .env 的 DISCORD_TOKEN 中,从 cloud.walletconnect.com 获取免费的 WALLETCONNECT_PROJECT_ID;如果希望价格不是 $1,还需设置 BOT_SUBSCRIPTION_USD(参见 .env.example)。使用 applications.commands 范围邀请机器人。状态(钱包地址、会话 ID、方案结束日期)保存在 .cache/bot/ 中。

面向其他网站的 API 计费(可选,默认关闭:API_ACCESS=billing)

API 目前免费(参见“哪些内容需要付费”);这里介绍预付费模式,该模式由 API_ACCESS=billing 重新启用。 其他网站付费购买的是拆分路由:单独使用 QX 和 QSwap 路由是 qubictrade.com 和 qubicswap.com 等 DEX 已有的功能,因此 API 只会对最佳路由跨两个场所拆分的报价收费。网站预付余额,通过 QPayhub 充值,因此也会为 QPAY 提供支持。文档:GET /v1/openapi.json。

  • 计费内容: 使用 x-api-key 发送的 /v1/quote,如果最佳路由使用两个场所,则收费 API_SPLIT_PRICE_QU(默认 100 QU)。若 /v1/arbitrage 检查发现机会,则收费 API_ARBITRAGE_PRICE_QU(默认 50 QU);“目前没有机会”免费,路由到单一场所的报价、失败的调用、列表、搜索和文档也都免费。响应会包含 x-qmax-charged-qu 和 x-qmax-balance-qu。余额不足时,拆分报价会返回 402,不提供路由,并告知拆分本可节省多少(splitWouldSaveQu);套利结果则会返回 402,不提供详情,并显示利润(opportunityProfitQu),让网站了解可获得的收益。发送 split=false 始终会获得免费的单一场所报价。
  • 无密钥: 报价仍可使用,但每个 IP 的请求限制为 API_FREE_PER_MIN(默认 60),这足够 QMax Web 应用和试用使用,但不足以满足繁忙网站的需求。密钥的请求上限为该值的十倍,因为免费报价仍会占用节点资源。如果位于由你控制的代理之后,请设置 TRUST_PROXY=1,以便限制按真实客户端 IP 生效。
  • 开始使用:
    1. POST /v1/keys 返回 { key, keyId }(免费,余额为 0;仅显示一次;每个 IP 每小时可创建少量密钥)。系统只存储密钥的哈希值。
    2. GET /v1/topup?keyId=…&amountQu=… 返回一笔交易,可使用任意钱包签名:向 QPayhub 支付相应数量 QU 的 Pay(至少 API_MIN_TOPUP_QU,默认 10,000,因为 QPayhub 会从每笔付款中至少留存 100 QU),并附上注明密钥的收据。
    3. 确认后,执行 POST /v1/topup/claim { keyId, payer, nonce }。服务器会从 QPayhub 读取收据,并将已付款金额加到余额中。每笔付款只能计算一次,且只能为收据中注明的密钥充值,因此无人能认领他人的付款。
    4. GET /v1/account 可查看余额。预付 10,000 QU 可购买 100 次拆分报价。
  • 自有密钥: API_KEY 不收费,也不受限制;Discord 机器人会使用该密钥(其 .env 中的 API_KEY 必须一致)。ADMIN_KEY(不同的值,不放入机器人的环境变量中)是所有者的密钥,用于查看订阅者列表、利润分成、付款和使用统计:即使机器人泄露了自己的密钥,也只会泄露市场访问权限。关闭计量(API_METER=off)后,API 将开放访问,或像之前一样仅由 API_KEY 保护。
  • 限制说明: 余额存储在服务器的 .cache/meter.json 中(请备份:这是用户预付金额的记录),每次调用的费用会在半秒内写入,而充值必须在 QPayhub 仍保留收据时认领(约两个 epoch)。免费层按 IP 限制,因此会减缓高频用户的请求,但无法阻止愿意更换地址的用户;付费路径才是获得可靠调用量的方式。

市场情报(其他 Qubic 网站都不提供)

所有数据都来自同一份公开数据:归档事件日志(src/trades.ts)中六个月的每笔 QX 成交和 QSwap 兑换、实时订单簿和流动性池,以及合约源码中有关费用的说明。每个端点都在 /v1/openapi.json 中有描述,有对应的类型化 QMaxClient 方法,也是一个 MCP 工具(mcp/)。每项功能都会说明忽略了什么。

  • 资产健康度(GET /v1/health?asset=ID、GET /v1/health/all、src/health.ts):根据距价格 2% 以内的深度(有流动性池时以池价为基准,而不是宽幅 QX 订单簿的中间价)、价差(QX 价格以整 QU 计,因此相差 1 QU 不算“宽”)、交易频率和交易时间新旧,给出 0 到 100 的分数、A 到 E 的评级,以及通俗易懂的原因说明。洗售交易检测刻意采用严格标准:归档记录了交易内容,但没有交易者身份,因此只会标记不可能是普通交易的模式(连续一小时至少 300 笔小额兑换、平均每笔不超过 5,000 QU,且这种模式反复出现并保持固定节奏)。真实数据中,只有一个资产符合条件:CFB 在第 211 个 epoch 的十天内,一个钱包与自己进行 103 QU 的买卖兑换,共 137,096 笔,交易量约占池子交易量的 0.1%。报告会标注“看起来像”,而过去发生的集中交易只作为信息提示(wash-past,不扣分)。这种方法无法检测大额洗售交易,因此没有标记不代表资产健康无虞。
  • 市场选项卡(GET /v1/premium?asset=ID&range=...、src/premium.ts):按小时显示 QX 和 QSwap 的价格相差多少,以及有多少小时价差超过特定金额交易的交易成本(盈亏平衡点根据费用常量计算:流动性池费用为 0.3%,QX 卖方费用为 0.3%,QSwap 固定费用为 100,200 QU,因此交易额为 10M QU 时约为 1.3% 到 1.6%,交易额为 1M QU 时则超过 10%)。这只是上限,不是利润:小时均价未计入 QX 买卖价差(通常比成本还大)以及两笔交易之间的延迟。除非允许价格最多延续 3 小时(carry),否则只比较两个市场都发生过交易的小时。
  • 流动性池(GET /v1/pools、GET /v1/pools/detail、src/pools.ts):按实际费用收入排列所有 QSwap 流动性池。根据合约源码和实时 Fees 函数:每笔兑换会收取 QU 一侧金额的 0.3%,其中 64% 留在池中供流动性提供者获得,因此每笔兑换交易量的 0.192% 会归 LP 所有者(其余部分分给 QSwap 股东、QX、奖励和销毁)。每笔兑换、添加和移除流动性的固定 100,000 QU 费用都不会成为 LP 收入。费用 APR 为滚动计算,价格变化和无常损失根据兑换价格计算,存款计算器则会估算特定金额对应的费用和无常损失。交易量稀少或集中爆发的池子会被标记,并排在情况良好的池子之后;不会隐藏或截断任何数据。
  • 回测(POST /v1/backtest、src/backtest.ts):使用实际小时 K 线和市场的真实费用,重放 hold、dca 或 bands 策略(QX 卖方费用为 0.3%,QSwap 每笔兑换固定收取 100,100 QU;QSwap 的 0.3% 已计入记录价格,不会重复收费)。在某小时收盘时作出决策,并在下一小时开盘时成交;没有交易的小时绝不会虚构价格。结果始终附带警告:历史数据不包含订单簿深度(因此大额交易的估算偏乐观),并会统计价格与相邻价格相差超过 40% 的小时。每周将 500,000 QU 投入 QDOGE,持续 90 天的 DCA 策略,回报约为 +8%,手续费占初始 QU 的 13%:QSwap 的固定费用意味着小额定期买入应使用 QX。
  • 实时成交和订单流(GET /v1/tape、GET /v1/flow、src/tape.ts):统一推送两个市场每笔新成交和兑换,并标明方向。QSwap 兑换方向记录在事件中;QX 成交的买卖双方记录相同,因此方向根据触发该交易的交易记录判断(发送方是吃单方:调用 6 = 买入,5 = 卖出)。我们通过检查某一天内每笔 QX 交易中谁收到了份额,核实了这一点(109 笔中有 107 笔完全吻合,另外 2 笔是账户与自己交易)。数据从内存中提供,因此轮询成本低。交易索引每 15 秒读取一次新行情。
  • 钱包账本和盈亏(GET /v1/ledger?identity=ID&format=json|csv&days=1..365、src/ledger.ts、History 选项卡):根据归档事件日志重建钱包在 QX 和 QSwap 上的买卖记录(按交易分组 QU 和份额转账;由于这些是公开链上数据,任何身份都可以查询),并附上价格、费用、持仓变化、按平均成本计算的已实现利润,以及按当前价格计算的未实现利润。CSV 导出包含固定列(日期、交易哈希、类型、市场、资产、发行方、数量、价格、QU 净额、预估费用、持仓、已实现盈亏),后接持仓表。我们在 7 个真实钱包和 707 笔交易上进行了核验:抽样的 232 笔交易中,232 笔与合约记录完全吻合;59 笔 QX 卖出中,59 笔的费用吻合;所有发生份额变动的自有交易都有对应记录。这是估算,并会注明以下情况:归档中约 2026 年 6 月 10 日至 14 日完全没有事件(这段时间内的交易都会缺失,账本会发出警告);通过转账或窗口期开始前获得的份额没有已知成本(卖出这些份额会单独计入,不算作利润);QSwap 流动性变动会显示为转账;未实现利润使用中间价或池价,在流动性稀薄的市场中可能会造成误导。每次构建需要 3 到 29 次归档请求(约 1 到 13 秒),每个钱包缓存 60 秒,最多同时运行 2 个构建任务。非税务建议。
  • 兑换和 Max 兑换(Swap 选项卡对应的 web/SwapPanel.tsx):该选项卡分为两部分。关闭 Max 时,选项卡提供普通兑换:将 QU 换成代币,或将代币换回 QU,直接通过 QSwap 流动性池完成(仅使用 QSwap 报价的 GET /v1/venue-quote,签名方式与任何交易相同;仅列出有流动性池的代币;如果买入金额太小,导致池子会留下全部付款,则拒绝交易)。在 Settings 中打开 Max 模式后,该选项卡可以将一种资产兑换为另一种资产,这是 QMax Pro 的一部分(可免费试用一段时间,参见“Max 和 QMax Pro”);My assets 中每种持有资产上的 Swap 按钮(仅在 Max 模式开启时显示)也是同一功能。本段其余内容介绍 Max 兑换。代币间兑换(POST /v1/swap-quote、src/swap.ts;签名界面为 web/SwapModal.tsx):输入来源代币、目标代币和金额,即可获取实时计划以及最佳交易证明。设置 compare: true 后,服务器会额外规划四次相同兑换,分别强制卖出和买入只通过 QX 或 QSwap 完成,并将各种组合的价值与 QMax 自己的路径进行比较(bestDeal)。“价值”是买入的单位数加上剩余 QU(按该计划自己的买入价格计算),再减去预先支付的费用,因为只看单位数会造成误导:某个计划可能以更好的价格买入,但按最坏情况限价计算后买入的单位数会更少,同时留下更多 QU。如果某种组合不可用,会列出原因;如果单一市场已是最佳选择,则不会声称能获利。兑换会先将一种代币卖成 QU,再用这些 QU 买入另一种代币,两个交易合并在一次审核中规划和签名:这是两笔交易,绝不是一笔原子交易,因此设计专门考虑了这一点:第二步的金额按第一步在限价内最少可获得的 QU 计算(minOutQty 仅在价格未超出滑点限额时有保证);第一步所需的固定 QU 费用会预先显示;第一步结算后,会根据钱包的实际余额重新计算第二步金额,如果余额不足则拒绝第二步(由你保留 QU),绝不会附上钱包实际没有的 QU。独立审计根据 Qx.h 和 Qswap.h 重新推导资金计算逻辑,并使用两个合约的模拟器测试了 4,000 笔随机兑换,期间市场在两步交易之间发生变动;审计发现并修复了四个错误,其中最严重的是一个真实合约陷阱(见下文)。除非运营方设置了限制(服务器环境中的 SWAP_MAX_OUTLAY_QU 会拒绝任何可能使超过相应 QU 金额面临风险的计划),否则没有交易金额限制;其余限制由合约本身规定。尚未验证:任何真实交易,以及连续两次出现签名提示时的真实钱包操作流程。
  • QMax 现在会在每次买入时规避的合约陷阱。在 Qswap.h 的 SwapQuForExactAsset 中,如果买入所需 QU 少于 36 QU 的协议费用,合约只会退还这部分少量 QU,却会留下你附上的其他全部金额,包括 100,000 QU 固定费用。如果某个仅由流动性池支持、价格约为 1 QU 的代币只买入几个单位,就会损失 100,000 QU。现在 route() 绝不会提供输入金额少于 1,000 QU 的 QSwap 买入(QSWAP_MIN_BUY_QU;卖出在任何失败情况下都会退还固定费用,不存在此类陷阱);报价会说明原因。只有自行计算订单金额的进程内调用方(例如使用自身检查逻辑的兑换规划器)才能绕过这一限制,API 请求绝不行。
  • 在 QSwap 上添加和移除流动性(GET /v1/liquidity/positions?identity=ID、GET /v1/liquidity/pool?asset=ID、src/liquidity.ts、web/LiquidityModal.tsx、web/PoolPositions.tsx、Pools 选项卡):“你的流动性”会列出钱包持仓(单位数、占池子比例、全部移除可获得的金额、按池价计算的价值,以及合约自身的 earnedFees),数据实时读取自 GetLiquidityOf 和 GetPoolBasicState;池子上的“添加流动性”和持仓上的“移除”会打开一个计划,并在签名之前再次与池子状态核对。该功能只负责规划,由钱包签名。我们逐行阅读了 Qswap.h,并梳理了所有拒绝路径。规划器会规避以下三个陷阱,源码均已验证:
    • **添加流动性可能会悄悄把代币的零头送出去。**如果你附上的 QU 限制了存款金额,合约会收取全部 QU 以换取向下取整后的代币数量,而且不会检查 quAmountMin,因此价格下跌也无法阻止这种情况(一次真实的 QCAP 存款用 6,000,000 QU 换得 21 个代币;另一次损失了 150,186 QU)。QMax 会固定代币一侧,并附上足够的 QU,使合约执行精确数量路径,将舍入误差控制在几个 QU 以内。如果存款太小,无法为至少 1 个代币留出滑点空间(QCAP 每个代币约需 270,000 QU),则会拒绝,并提示可行的最小金额。
    • **移除时不设置最低金额,可能一无所获,**同时还会留下固定费用并销毁流动性。每次移除都会设置两侧最低金额,且至少为 1;这样合约就会拒绝并退款。如果移除操作会导致某一侧获得 0,则会事先拒绝。
    • **代币以整数形式支付,**零头会留在池中;部分移除时只销毁能支付相同代币数量的最少流动性,其余部分仍留在你的持仓中。 每次添加和移除还需支付固定的 100,000 QU(仅在流动性实际变动时收取;任何拒绝操作都会退款);代币必须处于 QSwap 管理之下(QMax 会先将代币从 QX 转移过来,这一步会附上 100 QU,并立即退还);不提供创建流动性池(首次存款会永久锁定 1,000 个单位)。提供只读 SDK 方法 liquidityPositions / liquidityPool 和 MCP 工具;仅 Web 应用支持构建和签名。npm run liquidity-check 会根据实时合约重放本 epoch 的所有 QSwap 事件(最近一次运行结果为 adds 7 matched / 0 not, removes 1 / 0, swaps 189 / 0)。独立审计重新阅读了 Qswap.h,并从 BITE 的首次存款开始重放其完整历史(14 次添加全部吻合、5 次移除全部吻合、123 次兑换全部吻合,最终状态与实时流动性池一致;这涵盖了代币侧路径),未发现计算错误。审计还发现并修复了相关问题:在份额转移和存款之间没有重新读取池子状态(这段时间内若价格上涨,最多可能损失约 1 个代币的价值;现在会在审核时、签名时和转移之后拦截);错误地将“没有任何变化”归咎于合约,而实际上只是钱包拒绝了操作;部分移除可能导致剩余部分价值低于费用(现在会发出警告);变更后的持仓列表过期(fresh=1);以及存款金额超过流动性稀薄池子的 20% 时未发出警告。低于 100,000 QU 费用价值的移除,以及价值低于 200,000 QU 的存款,都会被主动拒绝。尚未验证:任何真实的添加或移除交易,以及连接钱包后的签名流程(签名被拒绝、tick 过期、份额转移被拒绝)。正式依赖此功能前,请先在流动性充足的池子(GARTH 或 CFB)上进行一次小额真实存款和移除操作。
  • 提醒(Discord /alerts、src/alerts.ts、bot/alerts.ts):价格触及设定水平、符合你自定义筛选条件的套利机会(订阅内容的一部分),以及大额交易(来自成交数据流)都会通过私信送达,并附带一键买入和卖出按钮,打开现有报价和钱包签名流程。价格规则仅在价格穿越设定水平时触发,不会在价格持续超出水平期间每分钟重复触发,并设有冷却时间;如果你关闭了私信,提醒会停止,并说明原因,同时提供 Resume 按钮。
  • 托管式 MCP 服务位于 https://qmax.exchange/api/mcp(src/mcphost.ts):通过 MCP 的 Streamable HTTP 传输提供相同工具,助手无需下载或运行任何内容即可连接(claude mcp add --transport http qmax https://qmax.exchange/api/mcp)。无状态、免费、无需密钥,且无需付费 Max 计划(调用方的钱包通过 x402 自行支付)。这些工具会通过回环地址向 API 发起调用,并将调用方地址作为名称,因此 MCP 使用和直接调用一样受免费地址限额约束;MCP 调用本身每个地址每分钟最多 120 次。将 MCP_HOSTED=off 设为 off 即可停止提供服务。
  • 可自行运行的 MCP 服务(mcp/,参见 mcp/README.md):将上述功能作为 AI Agent 工具提供,全部为只读工具,qmax_build_plan 会返回供调用方自己的钱包使用的未签名交易。除非你自行设置种子,否则可选的 x402 付款功能默认关闭,并设有上限。

节省金额回执(路由带来的价值)

src/savings.ts 会将每个报价的路由与各市场逐一比较,使用报价中已有的单市场价格(alternatives),因此这个数字是根据报价计算得出的,并非对其他网站的猜测。交易面板会显示“在 QX 和 QSwap 之间拆分交易,相比最佳单一市场可节省 N QU(x%)”(或者,在某个市场胜出时,显示在另一个市场交易会多花多少),并列出各市场的总额。交易完成后,回执会显示按签名前报价计算的相同金额,并与实际结果并列,还会显示“复制回执”一行。本浏览器会按钱包保存累计总额(Discord 机器人则会在其存储中按用户保存),并在钱包菜单中显示。累计金额只计入保守值(拆分交易时,相比最佳单一市场节省的金额;部分成交时按比例缩减),绝不计入相比较差市场节省的金额;未产生任何变动的交易不会增加累计金额。

使用情况跟踪(谁通过 QMax 交易)

钱包会对订单签名,应用会将其发送到网络,因此必须将订单告知 QMax。有两种方式,配合使用。**订单经过 QMax:**页面(以及 Discord 机器人和使用 SDK 的 Agent)会将已签名订单发送到 POST /v1/broadcast,该接口会检查它是否为 QX 或 QSwap 的订单、兑换或流动性变更(不会转发其他内容:src/relayable.ts),检查签名是否来自指定钱包,将订单原样传递给 Qubic 节点,并记录其交易 ID 以便计数(src/relay.ts)。订单发送时就会计数,因此即使页面在订单确认前关闭,也会计数;也没人能冒报他人的订单,因为 QMax 只统计自己转发的订单。如果 QMax 无法接收订单(服务宕机、响应缓慢或拒绝请求),发送方短暂等待后会直接将订单发送到网络,因此 QMax 永远无法阻止交易。**订单也会被报告:**每个步骤确认后,应用也会报告其交易 ID(POST /v1/trade-report;web/exec/run.ts、web/usage.ts 中各有一个钩子),这涵盖了无法使用中继的情况,也是中继功能推出前的计数方式。无论哪种方式,src/usage.ts 都会在计数前对照存档检查每个 ID:交易必须由该钱包发送给 QX 或 QSwap,属于买入、卖出、兑换或流动性变更,并且必须在 30 分钟内报告(因此无法补报较早的历史记录);交易还必须已成交(合约自身的事件日志会提供资产、数量和 QU),或是仍挂在 QX 订单簿上的订单(单独作为挂单计数,按其价格计算价值:资产、规模和价格从订单自身的输入中读取;合约直接退回 QU 的买单会被排除,兑换被拒或钱包不属于报告者的情况也会被排除,并记录排除原因)。格式错误的 ID 会立即被拒绝;存档中查不到的 ID 会重试 15 分钟(真实交易通常会在一分钟左右被索引);事件延迟或存档不可用时,最多重试两小时。每个 IP 地址最多可有 100 个 ID 等待处理,且报告和中继请求都有速率限制(不限制 QMax 自己的密钥和机器人的密钥),因此任何单个调用方都无法塞满队列,也无法利用中继对节点发起大量请求。

  • 读取统计:使用所有者的密钥调用 GET /v1/stats?days=30(x-api-key: $ADMIN_KEY;如果未单独设置 ADMIN_KEY,则使用 $API_KEY;两者都未设置时,无人可以读取)。返回总计数据(orders:每笔下单或兑换,包括已成交的订单和仍挂在 QX 上的订单;trades:已成交的订单;resting 和 restingQu:尚未成交的订单及其按挂单价格计算的价值,不是交易量;钱包数量、成交的 QU 交易量、新钱包数量、流动性操作),以及按日、按 ref(合作伙伴链接标签,或 direct)、按渠道和交易场所统计的数据、热门资产、按交易量排名前 20 的钱包,以及验证计数。GET /v1/stats?wallet=ID 会列出单个钱包的交易和付款记录。数据保存在 .cache/usage.json 中;since 表示开始计数的时间。
  • **销售无需报告。**QPayhub 是一个合约,因此所有支付给 QMax 地址的款项都记录在链上。每隔几分钟,scanPayments 就会读取 Pay 调用,筛选出支付给 QMax 地址的记录,并标明每笔款项的用途(资源 ID:QMAXPASS 通行证、QMAXSUB Discord 订阅、QMAXAPI API 充值;其他用途,例如 x402 会话,标记为 other)。只有 QPayhub 已转发给 QMax 的付款才会计数(付款即使被拒绝,交易仍会确认,但款项会退回),因此事件日志中的转发记录就是证明;被拒绝的付款会单独计数。已在真实链上核验:截至目前,扫描发现了一笔真实的 Discord 订阅。
  • **它能证明什么,不能证明什么。**可以确定由 QMax 转发的订单经过了 QMax(QMax 看到了它)。较早的报告方式证明力较弱:它只能证明该钱包进行了这笔交易,不能证明交易经过了 QMax(任何人都可以报告任意钱包最近的一笔真实交易);而且链上没有标记(没有逐笔交易手续费可用于附加标记),因此订单数是 QMax 发送的订单数加上被报告给 QMax 的订单数。挂单在下单时计数一次;之后成交时不会再次计数(成交是合约产生的,并非钱包发送的交易)。挂出的卖单没有可退还的款项,因此若合约在卖单被纳入后拒绝了它(这种情况很少见,因为应用会先检查持仓),该卖单仍会按已下单计数。关闭隐私开关的人,或在 Discord 上使用 /privacy count:false 的人,不会被计数。请将其视为使用情况的测量结果,而非向任何人付款的证明。
  • **各类订单的计数方式。**网站计为 web(并记录链接中的合作伙伴 ref)。Discord 机器人计为 discord:它会使用自己的密钥通过 QMax 发送每笔订单,并报告已确认的订单;每位用户都可以使用 /privacy count:false 关闭此功能(按用户保存,并按钱包应用;订单预览会说明订单将被计数)。使用 SDK 中 agentTrade 的 Agent 计为 agent:默认通过 QMax 发送;设置 reportTo: false 则会直接发送到网络。Discord 订阅、通行证和 API 充值会单独从链上计数(见下文)。
  • **隐私。**报告中包含钱包地址和交易 ID,这两者都公开在网络上。确认对话框会用一行文字说明这一点,设置中还有一个开关(隐私:允许 QMax 统计我的订单),关闭后会停止所有报告,并将订单直接发送到网络。在服务器上设置 TRADE_USAGE=off 会停止计数;设置 ORDER_RELAY=off 会停止通过 QMax 转发订单(订单随后会直接发送到网络,仅根据报告计数)。
  • 自行验证:npm run usage-check 会对照存档核验近期真实交易,展示陌生人的钱包和迟到的报告被拒绝的情况,并使用真实的 QPayhub 历史记录运行付款扫描。

谁在出售某项资产(Sellers 标签页)

在每项资产的交易区下方都有一个 Sellers 标签页(web/SellersView.tsx、GET /v1/sellers?asset=ID、src/sellers.ts):过去 7 天内,谁在 QX 或 QSwap 上卖出了该资产、持有了多久、买入价格是多少,以及卖出价格高于还是低于买入价格。数据来自公开存档。存档中的份额变动事件可按资产筛选,因此一次查询即可获取某项资产一周的事件(几百条;QDOGE 有 689 条),包括谁把什么发送给了谁。系统会读取发送量最大的卖家的交易账本(默认 12 位;QDOGE 为 8 位时约占发送单位总量的 58%),也就是 Portfolio 使用的同一份账本,追溯一年;随后将每笔卖出按先进先出原则,匹配到对应的买入或转入记录。这样就能得出每笔卖出的持有时长(过去 7 天内买入、8 至 30 天、1 至 3 个月、3 至 12 个月或一年多以前)、成本(含手续费)、盈亏结果,以及哪些单位是通过转账收到的(分配、空投、从其他钱包转入:没有成本记录)。转给其他钱包但并未卖出的单位会标记为已转出,而非已卖出;如果某位卖家在同一周收到的单位数量与卖出量大致相当,就会标记为循环交易(可能是机器人、做市商,或只是转手);如果卖家卖出了所持单位的几乎全部,则会标记为已清仓。

页面会用通俗的句子说明数据所表达的内容(“数据说明了什么”),绝不会声称知道卖出动机:区块链记录显示谁卖出了什么、支付了多少,但不显示原因。读取过程需要一两分钟(每个钱包约 20 次存档请求,速率限制为每秒 2 次),因此对某项资产的首次请求会返回 status: "working",并附上进度和目前已知的数据;页面每 4 秒再次请求一次,读取完成后会缓存 6 小时。为了让存档也能供其他用途使用:同一时间只进行一次读取,每小时最多启动 12 次新读取;无法读取的钱包会跳过(只有一个都无法读取时才会报错);每 6 小时预先读取最繁忙的 5 项资产(设置 SELLERS_WARM=off 可停止预读,设置 SELLERS=off 可关闭此功能)。助手可通过 qmax_get_sellers 工具和 QMaxClient.sellers 使用此功能。

代币页面(每项资产一个页面)

GET /token/<id>(src/tokenpages.ts)是列表中每项资产对应的纯 HTML 页面,由一个模板和 API 已提供的实时数据生成:价格(及其美元价值)、24 小时和 7 天的涨跌与交易量、QX 最优买价和卖价以及 QSwap 池,以及按当前价格计算,卖出和买入三种数量(价值约为 1,000 万、1 亿和 10 亿 QU)可获得多少;路由器会基于一次读取的两个市场数据进行报价(buildQuotes)。GET /token/ 会按交易活跃度从高到低列出这些页面。页面不含脚本,并采用独立的严格策略,因此搜索引擎或 AI 助手读取到的就是页面内容。为这些数量计算价格需要读取市场数据,因此每项资产每十分钟只计算一次(且同一时间只计算一次),与访问次数无关;爬虫遍历所有页面也不会导致 API 为每个页面读取节点。

搜索引擎可以收录的内容。 只有过去 7 天内有过交易的资产才会标记为 index,并列入 GET /sitemap-tokens.xml(其中 lastmod 是最近交易日期);没有交易的资产仍会保留页面供用户查看,但会标记为 noindex,因此大量长期没有交易的代币不会让索引充斥着内容单薄的页面。资产会随着交易开始或停止自动加入或移出。智能合约份额也遵循同一规则。两个资产即使共用一个符号,也会有各自独立的页面,并以 ID 命名(TWIN 和 TWIN.BBBBB)。地址的其他写法(大小写不同、末尾带斜杠)会通过 301 重定向到唯一对应的地址;未知资产会返回 404;网络首次扫描仍在运行时,页面会返回带有 Retry-After 的 503,而不是 404,让爬虫稍后再来,而不会误以为页面不存在。TOKEN_PAGES=off 会停止提供这些页面。

nginx 会将 /token/、/token 和 /sitemap-tokens.xml 转发给 API(deploy/nginx-tokens.sh 会对线上配置文件进行一次性修改;全新安装的配置则见 deploy/nginx-qmax.conf 中的相同路由)。robots.txt 会列出第二个站点地图。

订阅者与利润分成

订阅者根据链上记录追踪,按钱包区分。 Discord 订阅是向 QMax 地址支付的 QPayhub 款项,由订阅者自己的钱包签名;收据的资源 ID 中包含 Discord 用户 ID(QMAXSUB)。因此,付款钱包记录在链上,同一个钱包也会在网站上被识别,无需关联账户或登录:GET /v1/membership?wallet=ID(公开,适用于任何钱包,具有独立的速率限制)会说明该钱包是否为有效会员(订阅从每次付款起持续 BOT_SUB_DAYS 天,可累积,与机器人一致;通行证有效期为 24 小时)、有效期至何时,以及该钱包的收入(它为哪些 Discord 账号付款仅对所有者可见:GET /v1/subscribers)。刚付款的会员会立即显示:查询会读取该钱包自己的付款记录,而不是等待五分钟扫描。现在所有人都可以免费交易,因此会员资格不会解锁网站上的任何功能;钱包菜单会显示已连接钱包的会员状态(以及利润分成)。必须使用付款的钱包:从另一个钱包支付的订阅归属于那个钱包。

  • 分成内容。 每个 UTC 自然月为一个周期。分成池为当月净收入的 PROFIT_SHARE_PCT(75)%:即 QPayhub 转给 QMax 地址的金额。其他内容均免费的情况下,这就是 Discord 订阅收入(如果启用了相应模式,PROFIT_SHARE_INCOME 还可纳入通行证、API 充值或 x402 会话;发送到该地址的其他款项不计入)。分成按每位订阅者当月的付款金额比例分配(扣除 QPayhub 费用后),使用精确整数运算向下取整,且任何钱包获得的金额都不超过其付款金额的 PROFIT_SHARE_CAP(1)倍。这条上限确保分配公平:分成取决于钱包自己的付款,因此将一笔订阅拆分到多个钱包不会增加收益,而且任何人获得的返还都不会超过其付款金额。上限和取整扣下的金额由 QMax 保留。QMax 自己的地址以及 PROFIT_SHARE_EXCLUDE 中的钱包(你的测试钱包)会被完全排除。该计划从 PROFIT_SHARE_START 开始计算(首次启用时所在月份);只有月份结束且付款扫描已读取到该月结束之后,才会产生应付金额。
  • 查看数据(使用所有者密钥 x-api-key: $ADMIN_KEY,如果没有单独设置,则使用 $API_KEY):GET /v1/subscribers(所有曾订阅的用户:Discord ID、有效期至、已付款、已赚取、已付出、应付金额)、GET /v1/profit-share?period=2026-10(按类型列出的收入、分成池、各钱包的权重、分成、上限和收入,以及警告)、GET /v1/profit-share/balances。根据目前的真实链上数据:一位 Discord 订阅者(1,810,000 QU,QPayhub 转给 QMax 1,796,425),因此 10 月的分成池为 1,347,318 QU,该钱包预计可获得全部分成池金额(低于其 1,810,000 的上限)。如果这是你自己的测试钱包,请将其加入 PROFIT_SHARE_EXCLUDE。
  • 付款:由你签名,QMax 绝不持有密钥。 npm run payout 会显示应付金额和拟付款交易,但不会签名。npm run payout -- --send 会要求输入 QMax 地址的种子(输入时会隐藏,因此不会出现在 shell 历史或进程列表中;切勿将其存入文件或聊天记录;也可使用 QMAX_PAYOUT_SEED,通过 read -s 设置),检查付款计划,拒绝与 QMax 地址不匹配的种子或余额不足的钱包,并要求你输入总额,然后签名并发送每个批次。每个批次是一笔 QUtil SendToManyV1 交易(合约 4,过程 1),最多向 25 个钱包付款;附带的 QU 必须恰好等于付款金额加 QUtil 手续费(10 QU,每次从合约读取,将被销毁),否则 QUtil 会退还全部款项。签名器会在签名前重新核对交易字节与列出的钱包和金额是否一致(checkBatchView),并根据批次本身重新计算并显示总额、所需资金,并要求确认,而不是依赖计划的汇总;它还会拒绝向同一钱包支付两次、向 QMax 自己的地址付款,或向钱包支付超过其应得金额的计划(checkPlan)。一旦批次被预留或其交易状态有报告,账本(.cache/profitshare.json,并将上一次保存内容保留为 .bak)就会立即写入磁盘;如果文件存在但无法读取,利润分成会自行停用并显示消息,而不会从空账本开始,否则就会再次计划支付所有人过去收到的款项。只有在签名后一小时,归档服务确实已处理到该时间点但仍未显示交易时,才会放弃已发送的批次(归档滞后或发生错误时,绝不会释放钱包);即使交易之后才出现,也仍会计入。低于 PROFIT_SHARE_MIN_PAYOUT_QU 的余额会留待下一次付款。
  • 以链上记录为准。 批次依次处于已准备状态(付款计划:再次请求会安全地替换它)、已发送状态(正在签名,或已找到交易:其中的钱包已被预留,因此不会再次纳入计划),并且只有在所有者自己向 QUtil 发起的交易(载荷和金额必须完全一致)上链,且 QUtil 的转账事件显示每个钱包都恰好收到对应金额时,才会标记为已验证。QMax 还会根据每个批次的交易字节,搜索所有者自己发起的批量转账交易,因此,即使签名时没有通知 QMax,或计划被丢弃后才签名,批次仍会被找到并计入;如果一个批次被签名两次,系统会标记并计算两笔付款,以确保账目与链上记录一致;退款交易(手续费错误)不会计入款项,并会释放相关钱包。下个月再次欠付的相同明细会形成新批次,并按时间与对应的交易匹配。
  • 如实说明限制。 尚未签署任何真实付款:所有内容都经过伪造链测试,并以只读方式对照真实链验证(已检查一笔真实的 QUtil 批量转账,以确认数据布局和转账事件;实时读取的手续费为 10 QU)。网站显示的会员状态源自链上记录,可能与机器人的记录相差几秒(机器人从确认付款时开始延长会员期限)。Discord ID 和钱包地址会公开记录在链上(付款的资源 ID 中包含 Discord ID),但公开的会员查询不会提供这些信息。与付费客户分享费用收入可能会根据你和他们所在的地区产生证券或税务方面的后果;在将其称为“利润分成”而非费用返还之前,请先确认相关规定。

添加端点

功能可以添加自己的端点,无需编辑服务端:src/routes.ts 定义了 Route(method、path、limited、doc、handler),createApi 接受 routes: Route[],并将这些端点与内置端点一同提供服务(像其他市场端点一样进行速率限制;除非设置 limited: false,否则也像它们一样通过 x402 会话收费)。每个 doc 都会合并到 /v1/openapi.json 中。处理程序返回 JSON,或返回用于下载的 new Raw(body, contentType, filename);对于被拒绝的请求,则抛出 RouteError(status, message)。Web 功能样式放在 web/styles/*.css 中(会自动加载)。

让 Agent(和搜索引擎)发现

MCP 服务和 SDK 托管在网站的 /agents/ 下(包括指南页面、qmax-mcp.mjs、qmax-sdk.tgz、qmax-sdk.js 和 SHA256SUMS)。npm run agents:build(scripts/build-agents.mjs)会将它们构建到 web/public/agents/ 中(MCP 文件以实时 API 为默认地址;打包 SDK,并将 planner 的类型声明精简为 plan 的结构;生成校验和),部署时会在构建网站前运行此命令。/llms.txt 和站点地图都链接到这些文件。

验证下载文件

SHA256SUMS(/agents/ 下每个文件的哈希值)使用维护者自己的 minisign 密钥签名;该密钥保存在维护者的电脑上,绝不会放在服务端。公钥:

RWRMUiy37f8/2tR95zGd1GrgIuOk9ichS/Ohe99rlJrq7Xtd3d+Dfu3c
curl -O https://qmax.exchange/agents/SHA256SUMS
curl -O https://qmax.exchange/agents/SHA256SUMS.minisig
minisign -V -P RWRMUiy37f8/2tR95zGd1GrgIuOk9ichS/Ohe99rlJrq7Xtd3d+Dfu3c -m SHA256SUMS   # the list came from the key's owner
shasum -a 256 -c SHA256SUMS                                                              # each file matches the list

本 README 是可信密钥的副本:要验证的是网站,因此不要只从网站获取密钥。scripts/sign-release.sh 用于生成签名(部署时会运行它)。

web/index.html 包含标题、描述、规范地址、Open Graph 和 Twitter 卡片(1200x630 的 web/public/brand/og.png)、JSON-LD(WebSite、WebApplication、WebAPI)、指向 /llms.txt 和 OpenAPI 文档的 <link>,以及供不运行 JavaScript 的爬虫使用的 <noscript> 摘要(应用本身由客户端渲染,因此没有它,爬虫看到的将是空白页面)。web/public/robots.txt 欢迎爬虫访问(并禁止它们访问 API 端点,但不禁止访问 OpenAPI 文档),sitemap.xml 列出唯一的页面。/llms.txt(src/llms.ts,由 nginx 直接转发)是 Agent 首先阅读的 Markdown 指南:介绍 QMax、API 地址和主要端点、哪些内容免费、Max 套餐的价格,以及如何使用 x402 付款;它根据与 API 相同的设置生成(PUBLIC_BASE_URL、API_MAX_PRICE_QU、会话设置),因此不会提供过时价格。OpenAPI 文档会在 servers 下列出 API 的公开地址,以便客户端构建可用的 URL(设置 PUBLIC_BASE_URL=https://qmax.exchange/api;它也是 x402 挑战中指定的 resource.url)。

面向 Agent:自主签署交易(以及可选的 x402 会话)

Agent 使用免费 API 的方式与其他人相同,但 Max 计划的费用为 100 QU(GET /v1/max、QMaxClient.max()、MCP 工具 qmax_best_position):费用从预付密钥的余额中扣除;或者在 x402 会话中免费使用。启用 API_MAX_PRICE_QU 后,计量器和 x402 门控会开始计费,但其他所有内容仍然免费。只有设置 API_ACCESS=billing,API 的其余部分才提供 x402 会话;关于 Agent 自主签署交易的部分仍然适用。 QMax 使用与 Q+Pay 相同的 x402 线路格式(qubic-x402:方案 exact、网络 qubic:mainnet、资产 QUBIC,通过 QPayhub 结算),因此,已经为 Q+Pay 资源付款的 Agent 也可以用同样的方式支付 QMax,无需账户或密钥。

  • 为什么采用会话,而不是每次调用都付款。 分拆报价费用为 100 QU,套利结果费用为 50 QU,低于 QPayhub 接受的金额(最低支付额为 100 QU,最低手续费也为 100 QU,因此金额低于约 13,334 QU 时手续费占主导),而付款确认大约需要十秒。因此,Agent 会一次性购买一个会话:API_SESSION_PRICE_QU(默认值 10,000 QU),有效期为 API_SESSION_SECONDS(默认值 3,600)。会话内不按调用收费,速率限制与密钥用户相同(是免费额度的十倍),按会话而非地址计数。API_X402=off 可关闭此功能;此外还必须启用计量器。
  • 流程。 超出免费额度(或调用 GET /v1/session)时,Agent 会收到包含价格、QPayhub 地址、卖方、资源和票据的 402(GET /v1/x402 可在不触发 402 的情况下说明报价)。Agent 使用 QPAYHUB.Pay 付款(nonce 来自票据,金额必须完全匹配),然后在请求中带上 X-PAYMENT 重试。服务器会在 QPayhub 的收据中查找付款,检查付款方、卖方、资源、nonce、金额和时间,并确保每笔付款只计数一次(.cache/x402-used.json),随后返回 X-ACCESS-GRANT,这是一个在会话剩余时间内有效的签名令牌。票据和授权令牌使用 .cache/x402-secrets.json 中的密钥进行 HMAC 签名(文件权限为 0600);也可以设置 X402_TICKET_SECRET 和 X402_GRANT_SECRET(一个密钥可同时用于两者;在实际部署中应使用两个不同的密钥,因为票据密钥泄露后,别人就能伪造票据)。如果交易尚未确认,原因会是 invalid_transaction_state:请稍等,然后再次发送相同的请求头。
  • Agent 自主签署交易。 QMax 不会持有 Agent 的密钥,也不会代其交易。@qmax/sdk/agent 会获取报价,依据 Agent 设定的限制检查报价,使用 Agent 自己的种子签名并逐步发送交易。必须提供 maxOutlayQu(钱包最多可转出的 QU 数量,含手续费);卖出时还必须提供 minAveragePriceQu,因为卖出的支出只有手续费;maxAveragePriceQu 和 allowedAssets 为可选项。报价中的提示均视为不可信:交易计划只能调用 QX 和 QSwap(以及在两者之间转移份额),x402 付款方也只能向 QPayhub 付款,无论 402 中写了什么。任何内容超出限制时,都不会进行签名,TradeRefused 会列出原因。交易步骤逐个发送,遇到首个失败便停止,之后会重新读取钱包,报告实际情况。agentPlan 是试运行:使用相同的报价、相同的限制检查和相同的步骤,但不会签名或发送任何内容(它会读取钱包的公开余额,因此也会说明钱包是否有足够资金完成交易)。将一个 TradeBudget(new TradeBudget(totalQu))传给每次 agentTrade 调用,即可限制 Agent 的所有交易合计最多支出的金额,不论同时运行多少笔交易:每笔交易通过检查时都会预留最坏情况下的支出,转交给钱包后则保留该预留。
  • 对用户没有影响。 Web 应用(钱包签名、QMax 通行证)、Discord 机器人(订阅)和预付密钥仍按原方式工作。x402 只新增了会话,并将超出免费额度时的响应从 429 改为 Agent 可处理的 402。
  • 试用。 npm run agent-demo 会显示报价,不会花费任何资金(设置 QMAX_API=https://qmax.exchange/api 可让它连接线上站点;默认连接本地服务器)。在自己的终端中设置 QMAX_AGENT_SEED 后,运行 --max QDOGE --yes 即可一次完成整个 Agent 流程:请求 Max 计划,收到 402,通过 QPayhub 一次性支付会话费用(10,000 QU),获取计划,然后在会话内再次请求,无需再次付款。--session --yes 只会购买会话(运行结束后会话即被遗忘),--buy CFB 10 --max-outlay 5000 --yes 则会执行一笔受限制保护的交易。支出记录从付款发送时开始计入,因此尚未确认的付款也会计入:请在区块浏览器中检查。请使用只存有你愿意拿来测试的金额的钱包,切勿将种子粘贴到聊天窗口或文件中。
  • 如实说明限制。 付款时效按 tick 判断(每个 tick 为 0.55 秒,这是 2026 年 10 月在主网上测得的;如果网络速度发生变化,请修改 src/x402.ts 中的 TICK_SECONDS)。QPayhub 会保留收据约两个 epoch;本地已用付款账本则会在此之后继续防止重放。QMax 不会调用 Consume,也不会使用链上 USD 价格预言机(会话价格以 QU 固定,与 Web 通行证相同)。尚未实现:MCP 服务包装器,以及将验证工作委托给 Q+Pay facilitator。

供其他网站使用:SDK 和链接

两种接入方式,详见 sdk/README.md:

  • SDK(sdk/,使用 npm run sdk:build 构建,可在 Node 或浏览器中运行):QMaxClient 封装了 API(报价、带筛选条件的套利、创建密钥、充值和领取),提供类型化的答复,以及会说明被拒绝的调用本可获得什么收益的 QMaxError;buildExecutionPlan 会将报价转换为由钱包签名的交易(卖出时先转移权利,然后每个交易场所调用一次),因此已有自己钱包流程的网站只需对这些交易签名。
  • 预填链接:?asset=CFB&side=buy&qty=5000&ref=partner 会打开 QMax 的交易界面并填入订单(src/deeplink.ts 中的 buildDeepLink / parseDeepLink)。链接中的无效部分会被丢弃;未知资产会显示提示。ref 通过 POST /v1/ref 统计(一次打开,以及一笔附有交易 ID 的已完成交易),并使用 QMax 自己的密钥通过 GET /v1/refs 读取(.cache/refs.json)。报告来自用户的浏览器,因此能显示哪些合作伙伴带来了流量,但无法证明任何事情:向任何人支付分成前,请先在链上核对交易 ID。

安全

整个项目(Web 应用、API、机器人、SDK/MCP、付款)于 2026 年 10 月完成了审查;审查发现的问题及采取的措施记录在 .cache/security-review/TRACKER.md 中。运行时需要注意:

  • 密钥和机密信息。.env 和 .cache 中的所有内容均仅限所有者访问(模式为 600/700;代码会以这种方式写入自身文件,并在下次保存时收紧旧文件的权限)。请使用较长的随机值:用 openssl rand -hex 24 生成 API_KEY 和 ADMIN_KEY。机器人只获取 API_KEY;ADMIN_KEY(订阅者、利润分成、付款、统计数据)仅保留在服务端和运行 npm run payout 时使用的 shell 中。运行 npm run payout -- --send 时,付款种子会以隐藏输入的方式键入;QMax 不会存储任何种子。
  • 默认情况下,API 是公开的,因此它会按地址限流(API_FREE_PER_MIN)、限制发往 Qubic 节点的队列长度(节点繁忙时返回 503 和 Retry-After,而不是堆积等待请求),并以错误响应处理恶意输入,不会崩溃。若部署在自己的代理后面,请设置 TRUST_PROXY=1(填写你运行的代理数量);未设置时会忽略转发地址标头。API 仅监听本机(127.0.0.1);HOST=0.0.0.0 会使其对网络开放,因此应将其部署在自己的代理后面。
  • **网站不会将资金安全托付给 API。**签名前,网站会检查报价中的交易是否符合你的要求(资产、发行方、买卖方向和数量一致;仅限 QX 和 QSwap;限额不宽于你的滑点容忍度;以及合约的实际费用),审核对话框会说明最多可能有多少资金离开你的钱包。已设置严格的内容安全策略和安全标头(vite.config.ts、web/public/_headers)。
  • Agent 和机器人运行相同的计划检查(prepareTrade),Agent 交易还可以共享 TradeBudget。机器人会限制单个 Discord 用户每分钟可执行的操作次数,不会 ping 任何人,并会从日志中移除配对链接。
  • 资产名称只有由链上获取的名称为纯字母和数字(最多七位)时才会列出,因此恶意发行方无法在网站、机器人或 API 中注入标记或易混淆字符。
  • **不在保护范围内:**签名所用的钱包由你负责保护;QMax 不会为你验证代币的链上价格(流动性稀薄的订单簿可能被操纵;健康等级和审核对话框会说明它们能提供的信息)。npm audit 会报告 MetaMask snap 库的一个依赖项存在中等严重程度的问题,但此应用不会触及该依赖项。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。