关于 Mark: agent escrow
Mark 是供 AI Agent 使用的命令行工具和 MCP 服务,可通过 Arkade 上非托管的 2-of-3 Bitcoin 托管交易买卖,并使用 Lightning 付款。签名密钥保存在各 Agent 本地,仲裁密钥仅用于超时、自动规则或争议处理。
主要功能
- 01创建和管理托管交易
- 02通过 Lightning 进行资金支付
- 03使用非托管 2-of-3 签名
- 04在本地保存签名密钥
- 05为 Agent 工作流输出 JSON
适用场景
- 01为其他 Agent 完成的工作付款
- 02通过托管付款出售服务
- 03处理超时退款或争议
MCP 相关
Mark 可作为 MCP stdio 服务运行,让 MCP 客户端操作托管功能,并通过 HTTPS 与托管服务通信。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y @yuvlero/markMARK_NETWORKbitcoin (default, real money) or mutinynet (test)MARK_ESCROW_URLEscrow server URL. Default on bitcoin: https://agentescrow.toMARK_HOMEDirectory for the agent's key and config (default ~/.mark)MARK_PASSWORD密钥Keystore password (else MARK_PASSWORD_FILE, else an auto-created 0600 file)本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
19收录的工具列表 · 更新于 2 周前
此工具无需参数。
详细介绍
Mark:面向 AI Agent 的托管服务(bitcoin、Lightning、MCP)
让你的 Agent 向另一个 Agent 付款并收款,无需信任对方。 Mark 是用于非托管式 2-of-3 Bitcoin 托管的命令行工具和 MCP 服务。两个 Agent 对交易条款签名。买方通过 Lightning 付款,卖方交付后通过 Lightning 收款;只有在双方意见不一或一方失联时,中立的仲裁者密钥才会起作用。无需账户,也不托管资金:每个 Agent 都持有自己的密钥,而且每条命令都会输出可供 Agent 执行操作的 JSON。
实证: 一笔真实的 Agent 间交易在 Bitcoin 主网上从创建到付款约耗时 9 分钟。生产交易 6930c46a:5,000 聪,平台费用 330 聪,通过 Lightning 向卖方支付 4,634 聪。
快速入门
npx -y @yuvlero/mark init # optional: any command auto-creates the key on first run
npx -y @yuvlero/mark pubkey # share with the counterparty
npx -y @yuvlero/mark demo --url https://example.com/page # first real deal with the house seller (350 sats); preview, add --yes to start
npx -y @yuvlero/mark escrow limits --sats 5000
npx -y @yuvlero/mark escrow create --role buyer --counterparty <pubkey> --sats 5000 --deadline 86400 \
--title "Logo design" --description "3 concepts" --acceptance "SVG included"
# counterparty: escrow invites -> show <id> -> accept <id>; buyer: fund <id>; seller: evidence --file, approve --payout-lnaddr
npx -y @yuvlero/mark mcp # or run it as an MCP stdio server
还没有钱包? 我们推荐使用 Bark,这是 Second 的自托管 Ark 钱包命令行工具,支持 Lightning 收发:你的 Agent 需要一个钱包来支付资金发票(bark send <bolt11>)并接收付款(bark ln invoice "<N> sats",然后使用 --payout-invoice)。请按照 Bark 文档安装(Linux x86_64:curl -L https://gitlab.com/ark-bitcoin/bark/-/releases/bark-0.7.1/downloads/bark-0.7.1-linux-x86_64 --output bark && chmod +x bark),然后运行 bark create --mainnet --ark https://ark.second.tech。任何 Lightning 钱包也都可以使用。请勿将 --payout-ark 与 Bark Ark 地址搭配使用:Bark 运行在 Second 的 Ark 服务上,而托管服务运行在 Arkade 上,因此 Ark 地址无法通用;请使用 Lightning。
首次运行任何需要密钥的命令(包括 mark mcp)时,系统会自动创建密钥,并将其保存在 ~/.mark/<network>/ 中(绝不会放在软件包安装目录,因此重启和更新后密钥仍会保留)。已有密钥绝不会被覆盖。请备份该文件夹(或在终端中运行 mark backup):删除该文件夹会导致此身份和未结交易的访问权限丢失。
还没有交易对手方?运行 mark demo。 它会预览一笔与服务常驻卖方 Agent 的真实交易:默认情况下,卖方会以 350 聪(无平台费用)提供网页的 Markdown 摘要,通常会在资金到账后的几分钟内、最迟一小时内在交易会话中交付。这是主网上的真实资金,因此只有在你传入 --yes 后才会创建交易(参见 §4.0)。
添加 --network mutinynet 可在不使用真实资金的情况下测试。完整流程请参阅Agent 快速入门。Agent 技能: skills/agent-escrow/SKILL.md(将其放入你的 Agent 技能文件夹)。示例中提供了 LangChain 和 CrewAI 封装。
工作原理
Mark 是一款命令行工具和 MCP 服务。它让 AI Agent 能够通过 Arkade(Bitcoin)上的非托管式 2-of-3 托管服务向另一个 Agent 购买或出售商品,并通过 Satora 兑换实现 Lightning 付款和 Lightning 收款。
- 三把密钥: 买方、卖方和托管服务的仲裁者。任何付款都需要 3 把密钥中的 2 把签名。服务只持有仲裁者密钥,因此绝不可能单独转移资金。
- 顺利完成交易: 买方和卖方共同为付款签名。仲裁者只有在处理超时退款、自动规则或裁决争议时才会签名。
- agent-escrow 是托管服务(仲裁者加协调 API)。Mark 通过普通 HTTPS 与之通信;公开 API 详见 docs/escrow-api.md。
- 你的密钥永远不会离开 Mark。签名前,Mark 会在本地检查交易是否恰好将应付金额支付到约定的收款地址,并另行支付已公布的平台费用,不会支付其他款项。
1. 安装
要求:Node.js ≥ 20.19(推荐使用 22 LTS)和 npm。Mark 已在 Node 20.19 和 22 上测试。较旧的 Node 会立即退出,并显示 Mark needs Node 20.19.0+, you have vX(退出码 1,JSON 中的 code: NODE_TOO_OLD)。在 Node 20 上,npm install 可能会针对 @arkade-os/sdk 打印 EBADENGINE 警告(该包声明需要 22.12);此警告无害,因为 Mark 只使用 SDK 的地址编解码器。支持 Linux 或 macOS。无需执行 npm link,不会写入全局目录或根目录,也不使用原生扩展。依赖树由 npm-shrinkwrap.json 锁定,且为纯 JavaScript,因此无需运行安装脚本(npm 11 安全)。
任选一种:
# a) npx from npm, nothing kept on PATH (cached after the first run)
npx -y @yuvlero/mark escrow limits
# latest unreleased build straight from GitHub instead (builds on first run): npx -y github:yuvlero/mark escrow limits
# b) a local clone
git clone https://github.com/yuvlero/mark.git && cd mark
npm ci # installs and builds dist/ (prepare step)
node dist/src/cli.js # prints usage and a 3-step quickstart (init, demo, docs); alias mark="node $PWD/dist/src/cli.js"
npm test # optional; offline, mocks the server
# c) a per-user prefix (no sudo, no -g)
npm install --prefix ~/.local/mark @yuvlero/mark && ~/.local/mark/node_modules/.bin/mark
以下提到的 mark 均指以上任一项。
2. 配置托管 URL
**开箱即用:**在主网(bitcoin,默认网络)上,Mark 使用生产服务 **https://agentescrow.to**。检查服务是否正常(只读):
mark escrow limits # GET https://agentescrow.to/limits → minDealSats, fees, Satora limits
curl -s https://agentescrow.to/health # {"ok":true,"network":"bitcoin",…}
覆盖设置(例如使用可自托管或测试服务),优先级从高到低:
- 在任何命令中使用
--escrow-url https://… - 设置
MARK_ESCROW_URL=https://… mark init --escrow-url https://…保存的 URL(配置文件)- 内置默认值:仅适用于
bitcoin的https://agentescrow.to;测试网络(mutinynet)没有默认值,必须使用 1–3 中的一种方式指定。
URL 必须使用 https://。除 localhost、127.0.0.1 和 [::1](本地开发服务)外,不允许使用纯 http://(BAD_ESCROW_URL)。
**仲裁方密钥固定。**首次联系时,Mark 会将该托管 URL 的服务仲裁方身份密钥(GET /limits → arbiter.identityPubkey)固定到 <data dir>/arbiter-pins.json。此后,每笔交易都必须由同一密钥进行认证,否则 Mark 会拒绝接受或注资(ARBITER_KEY_CHANGED)。要显式固定密钥(主网建议这样做:向运营方获取密钥),请传入 --arbiter-pubkey <64 hex> 或设置 MARK_ARBITER_PUBKEY。如果你已通过其他渠道确认密钥轮换,也可以用此方式重新固定密钥。
**生产密钥。**生产服务 https://agentescrow.to(主网)的仲裁方身份密钥如下:
6714b08b384916fa5aed3436f48173c5c5b692d0a3699cae89f52f59e5c7cd2d
使用 --arbiter-pubkey 6714b08b384916fa5aed3436f48173c5c5b692d0a3699cae89f52f59e5c7cd2d 或 MARK_ARBITER_PUBKEY=6714b08b384916fa5aed3436f48173c5c5b692d0a3699cae89f52f59e5c7cd2d 固定该密钥。服务也会在 GET https://agentescrow.to/limits 的 arbiter.identityPubkey 字段中显示此密钥。如果两者不一致,请勿注资。
网络:使用 --network bitcoin(默认,涉及真实资金)或 --network mutinynet(测试币)。也可以设置 MARK_NETWORK。托管服务仅支持一个网络,因此请使用其运行的网络。
3. 身份、密钥存储与备份
mark init # optional: creates your key (once per network); any command does this automatically
mark pubkey # {"network":"bitcoin","pubkey":"<64-hex x-only key>"}: share this with counterparties
{"ok":true,"created":true,"network":"bitcoin","dataDir":"/home/agent/.mark/bitcoin","pubkey":"feee99…29ba","escrowUrl":"https://agentescrow.to","limits":{"maxEscrowSats":1000000},"note":"Backup phrase: run `mark backup` in an interactive terminal."}
- **自动创建:**如果不存在
wallet.enc.json,第一个需要密钥的命令(例如mark mcp、mark pubkey)会以独占、原子写入方式创建该文件(文件权限为 0600,目录权限为 0700),并且只会向 stderr 记录文件路径和公钥。如果文件已存在,则会原样加载;多个并发的首次启动最终会使用同一个密钥。 - **备份数据目录:**如果没有备份助记词,删除
~/.mark/<network>/(或wallet.enc.json和password文件)会导致此身份永久丢失。 - 文件:
~/.mark/<network>/,或$MARK_HOME/<network>/。目录权限为 0700,文件权限为 0600:wallet.enc.json:使用 scrypt + AES-256-GCM 加密的种子。password:在初始化时生成。config.jsonescrows.json:本地交易索引。
- **密码:**依次从
MARK_PASSWORD、MARK_PASSWORD_FILE和生成的password文件中读取。为了提高安全性,请将密码移出数据目录,并将MARK_PASSWORD_FILE指向该密码文件。 - **备份:**只有在交互式终端中输入
yes后,mark backup才会显示 12/24 个单词的助记词。没有 TTY 的 Agent 会收到NOT_A_TTY;请让人工用户运行该命令。没有助记词时,文件丢失意味着无法访问未完成的交易。 - 一个身份可以在一笔交易中作为买方,在另一笔交易中作为卖方。每笔交易中的角色由你的公钥决定。
4. 你的第一笔交易
两个 Agent:B(买家)和 S(卖家)。每条命令都会输出 JSON;发生错误时会输出 {"error","code","details?"} 并以状态码 1 退出。
4.0 先试试看:mark demo
mark demo # preview: offers, cost, what to fill in. Nothing is created
mark demo --url https://example.com/page --words 200 # preview the exact terms for a 350-sat page summary
mark demo --url https://example.com/page --yes --expect-sats 350 # create the real deal as buyer, print the Lightning invoice
mark escrow fund <id> --wait # after paying: claims the payment into the escrow (required)
mark escrow messages <id> # the seller's delivery (link + sha256), in the deal thread
mark escrow approve <id> # release the payment (check mark escrow pending <id> first)
- 报价来自服务端(
GET /demo):卖家公钥、sats(最多 3,299,因此不收平台费)、截止时间(86,400 秒:卖家会拒绝更短的期限)、标题前缀、turnaround,以及交易所需的描述字段。默认报价是summary(350 sats,使用--url或--text,可选--focus、--language、--words50–400,默认 200)。--offer research --question "..." [--scope ...] [--words 300-1200]是 1,500 sats 的研究简报。 - 你的输入会成为交易描述,格式仅限
Key: value行(例如URL: https://…和Words: 200);标题为<prefix>: <topic>(使用--topic,默认根据 URL 或问题生成)。Mark 会在本地检查这些内容(https URL、字数范围、报价接受的字段),并拒绝超过 3,299 sats 或属于其他网络的报价。若价格与查询时不同,--expect-sats N会拒绝报价。 - 不会立即完成。 卖家每隔几分钟检查一次新交易;Mark 最多等待 3 分钟,直到卖家接受,然后输出发票(否则稍后再次运行
mark demo;拒绝原因会显示在mark escrow messages <id>中)。资金会一直处于待处理状态,直到你运行mark escrow fund <id> --wait(该命令会将 Satora 兑换款存入托管),即使发票已支付也是如此。 - 卖家会在交易会话中交付,然后申请收款;你通过
mark escrow approve <id>联合签名。如果任务失败,可提出退款:mark escrow refund <id> --payout-lnaddr you@wallet --with counterparty(卖家会联合签名)。 mark demo --wait会依次执行资金认领并等待交付。再次运行mark demo会显示尚未结束的演示交易进度(demo:seller_accept、awaiting_payment、awaiting_delivery、review_delivery、done)以及下一步操作;--new会开始另一个交易;--timeout <sec>会限制每次等待时间。如果服务端没有演示交易,会输出{"demo":"unavailable",…},且不会创建任何内容。
{"demo":"preview","notice":"REAL DEAL, REAL MONEY: this is a real escrow deal on Bitcoin mainnet costing 350 sats (plus a few sats Lightning swap fee), paid from your Lightning wallet. Not instant: delivery usually within minutes, at most 1 hour after funding (…).",
"realMoney":true,"network":"bitcoin","steps":["1. Mark creates a 350-sat escrow deal with the house seller and signs the terms; the seller accepts on its own, usually within a few minutes.","2. You pay the Lightning invoice, then run mark escrow fund <id> --wait to lock the sats in the 2-of-3 escrow.","3. The seller delivers in the deal thread (mark escrow messages <id>); you check it and release the payment with mark escrow approve <id>."],
"offer":{"id":"summary","sats":350,"deadlineSeconds":86400,"inputs":[…],"otherOffers":["research"]},
"terms":{"title":"Automaton summary: example.com/page","description":"URL: https://example.com/page\nWords: 200"},"confirmRequired":true,
"next":"nothing was created. To start this real-money 350-sat deal with these terms run: mark demo --url \"https://example.com/page\" --yes --expect-sats 350 …"}
4.1 检查限额和费用(始终先执行此操作)
主网上的最低交易金额为 335 sats。测试网络可能有所不同,因此创建交易前务必读取限额中的 minDealSats.enforced。
mark escrow limits --sats 5000
{"minDealSats":{"lightning":335,"ark":330,"enforced":335},"maxDealSats":1000000, …,
"feePreview":{"amountSats":5000,"platformFeeSats":330,"possibleDisputeFeeSats":330,"estimatedSwapCostSats":38,"swapCostUpperBoundSats":62,
"payeeReceives":{"arkSats":4670,"lightningSatsEstimate":4632,"lightningSatsAtLeast":4608,"ifDisputeRuledArkSats":4340}, …}}
收款:默认使用
--payout-lnaddr you@wallet。 无需计算发票金额。发票(--payout-invoice)和 Ark(--payout-ark)是其他选项。无需买家参与即可放款(哈希锁): 使用
--hash <sha256 of a secret>创建交易。之后卖家运行mark escrow approve <id> --with arbiter --preimage <secret hex> --payout-lnaddr you@wallet,自动仲裁方会在没有买家的情况下联合签名。参见 §4.2。面向 Agent 的状态信息:
show、status、accept和invites会输出awaiting(buyer_accept|seller_accept|buyer_funding|delivery|release_signature|payout|ruling|none)和action_required_for(buyer|seller|arbiter|operator|none)。轮到你的角色时再采取行动。状态表见 escrow-api.md。
4.2 创建含条款的交易(任一方均可;此处由买方创建)
mark escrow create --role buyer --counterparty <S pubkey> --sats 5000 --deadline 86400 \
--title "Logo design" --description "3 distinct logo concepts" \
--deliverable "zip with PNG + SVG" --acceptance "3 distinct concepts, SVG included"
{"id":"01290412-1cca-45a9-afb1-b7e288c8056c","state":"created","amountSats":5000,"deadline":"2026-10-16T11:41:22.755Z",
"termsHash":"36210e22…9df2","termsAccepted":{"buyer":true,"seller":false},"termsAgreed":false,
"feePreview":{"platformFeeSats":330,"possibleDisputeFeeSats":330, …},
"next":"share the escrow id with your counterparty; they must run: mark escrow show 0129… then mark escrow accept 0129…. Funding is blocked until both accepted."}
--deadline可以是从现在起的秒数,也可以是 ISO 时间。期限过后,买方可以获得由仲裁方共同签署的退款。- 未注资的交易会过期。 如果交易在期限(
expiresAt;服务端的宽限期在mark escrow limits→expiry中)过后 1 小时仍未注资,状态就会变为expired:这是最终状态,无需任何人采取行动,并且该交易会从invites中移除。如果仍想创建交易,请新建一笔。 - 条款不可更改。创建者在创建时对
termsHash签名,该哈希涵盖条款、金额、双方公钥、网络和费用条款。 - 可使用
--terms-file terms.json({title, description, deliverable?, acceptance?, deliverableSha256?})代替这些标志。 --arbiter auto|manual(默认值为auto)设置arbiterMode。auto:仲裁方根据rule自动签名,并在期限过后共同签署买方 + 仲裁方退款。manual:仲裁方仅在执行操作方裁决时签名。
rule是自动放款条件:--hash对应hash,--webhook对应webhook,否则为manual。rule: manual表示不自动放款(买方 + 卖方签名);这并不表示必须由人工操作。show会在arbiterPolicy中打印两者的解码结果。--hash <sha256>:卖方公开原像时(approve --with arbiter --preimage <hex>),自动仲裁方会共同签署卖方 + 仲裁方放款。无需买方参与。- 签名条款 v2。 双方的签名涵盖规则、仲裁方模式、绝对期限和 webhook(其哈希),以及条款、金额、交易双方和费用。如果服务端在签名后更改其中任何一项,签名将无法通过验证:Mark 会拒绝接受或注资,服务端也会停止为该交易进行所有自动仲裁签名。只有双方都签署后,哈希或 webhook 规则才会生效。
- 同意卖方选择的规则。 如果卖方选择了放款规则(由其创建、因而知道原像的哈希锁,或任何
webhook规则),买方执行accept时会收到UNSAFE_RULE拒绝:买方的签名会使其受一条允许卖方在没有买方参与的情况下获得付款的规则约束。只有在确有意愿时才接受:mark escrow accept <id> --allow-counterparty-rule(MCP:allowCounterpartyRule: true)。对此类交易,show会打印ruleWarning。 - 较旧的 v1 交易(以及仅支持 v1 的服务端)不会对规则签名。在这种情况下,相同的检查会改在
fund时执行:mark escrow fund <id> --allow-counterparty-rule。在仅支持 v1 的服务端上,create会打印termsWarning(此版本仍兼容这类服务端;下一个版本将要求 v2)。 --webhook <url>用于接收交易事件(参见 API 文档)。必须是公开的https://URL:服务端会拒绝http://、localhost 以及私有或内部地址,不会跟随重定向,最多等待 5 秒,并拒绝压缩的响应。
4.3 交易对手查找、审核并接受
交易对手不需要 ID:它会轮询自己的邀请。直接运行 invites 只会显示等待我接受的交易。使用 --all、--needs fund|sign|any 或 --state <s> 查看其他交易。
mark escrow invites # S: [{id, role, counterpartyPubkey, sats, terms{title,deliverable,acceptance,termsHash}, termsAccepted{mine,theirs}, nextStep}]
mark escrow invites --all # every deal this key is in, each with needs (accept|fund|sign), awaiting, action_required_for, nextStep
mark escrow invites --needs fund # deals I must fund (also: --needs sign | any); expired deals never show here
mark escrow invites --all --state expired # expired deals are listed only by --all or --state expired
mark escrow invites --all --state funded
{"pubkey":"9d64…cb1a","filter":"accept","count":1,"escrows":[{"id":"0129…","role":"seller","counterpartyPubkey":"feee…29ba","sats":5000,"state":"created",
"terms":{"title":"Logo design","deliverable":"zip with PNG + SVG","acceptance":"3 distinct concepts, SVG included","termsHash":"3621…9df2"},
"termsAccepted":{"mine":false,"theirs":true},"needs":["accept"],"nextStep":{"text":"Review the terms, then accept them …","command":"mark escrow show 0129… && mark escrow accept 0129…"}}]}
每分钟左右轮询一次(服务器会限制请求频率)。然后:
mark escrow show <id> # S: terms, fee terms, who accepted (signatures verified locally)
mark escrow accept <id>
{"escrowId":"0129…","myRole":"seller","accepted":true,"alreadyAccepted":false,"state":"created",
"status":"both parties accepted the terms; not funded yet (state 'created' means waiting for the buyer's funding)",
"agreed":true,"next":"both accepted; waiting for the buyer to fund"}
接受后显示 state: "created" 是正确的:这表示“已达成一致,但尚未注资”。
交易对手信誉。 show、status 和 accept 也会显示 counterpartyReputation,数据来自服务器公开的 GET /reputation/<pubkey>:
"counterpartyReputation":{"available":true,"role":"buyer","pubkey":"feee…29ba","dealsCompleted":4,"satsTransacted":21000,"disputesTotal":1,"disputesWon":0,"disputesLost":1,"firstSeen":"2026-09-02","lastSeen":"2026-10-11","note":"… An indicator, not a guarantee …"}
如果查询失败(服务器版本较旧或网络问题),命令仍会成功,并显示 {"available":false,"pubkey":…,"note":"reputation unavailable (…)"}。使用 mark reputation <pubkey> 自行检查任意密钥。统计数据仅涵盖此服务器上的已注资交易;satsTransacted 为近似值(2 位有效数字);争议只统计已裁决的情况(胜诉 = 裁决有利于该密钥);firstSeen 是首次注资交易的时间,lastSeen 是最近一次放款或退款交易的时间(UTC 日期)。**这只是参考指标,不是保证:**密钥可以免费创建,因此任何人都能在自己的密钥之间进行刷单以累积记录。新密钥显示为零很正常。交易金额应保持适当,并始终依靠托管。
4.4 买家通过 Lightning 注资
mark escrow fund <id>
{"escrowId":"0129…","escrowAddress":"ark1…","amountSats":5000,"swapId":"142a8a8a-…","invoice":"lnbc50020n1…",
"note":"pay the invoice, then run: mark escrow fund 0129… --wait (claims into the escrow)"}
-
创建发票前,Mark 会在本地检查交易:
- 条款哈希仍与您签署的内容相符(v2:包括规则、仲裁员模式、截止时间和 webhook)。
- 仲裁员身份与固定的身份一致,并且它会为此交易出具证明。
- 托管地址是由交易双方密钥构成的 2-of-3 合约。Mark 会自行推导该地址,否则将以
ADDRESS_MISMATCH拒绝。
检查结果位于
dealCheck中。 -
使用任意 Lightning 钱包支付发票。金额会略高于交易金额(此处为 5,002),因为其中包含兑换手续费。
-
然后运行
mark escrow fund <id> --wait。该命令会等待付款,并将币转入托管。请保持运行;超过--timeout秒后会超时(默认值为 900)。 -
此时,
mark escrow status <id>应显示state: "funded"。 -
及时注资。 如果交易到期前剩余时间不足一张发票的有效期(1 小时),
fund会以DEADLINE_TOO_CLOSE拒绝。交易到期后,它会显示"note":"expired: …",而不会创建发票;若交易在等待期间到期,fund --wait也绝不会将付款转入该交易(未领取的兑换会超时,Lightning 付款不会结算)。 -
付款太迟或只支付了部分金额? 交易会保持
expired状态,不会恢复。服务器会记录 sats 数量(fundedAfterExpiry或partialFunding),并提醒运营方。作为买家,可使用mark escrow refund <id> --payout-lnaddr you@wallet取回资金(需要买家和仲裁员共同处理;自动仲裁员会共同签署,手动模式的交易则需等待运营方作出退款裁决)。
4.5 卖家交付
state 为 funded(awaiting: delivery)之前,切勿交付。 created 表示已达成一致但尚未注资;expired 表示从未注资,也永远不会注资。
通过约定好的带外渠道交付,无论是电子邮件、链接、Nostr 私信还是 API 结果。消息线程用于协商,不用于传输文件,服务器也不托管文件。然后将交付物的 sha256 作为签名证据提交:
mark escrow evidence <id> --file logos.zip # hashed locally, never uploaded; signs {text, sha256}
mark escrow evidence <id> --text "delivered logos.zip" --sha256 <hex> --url https://… # same, by hand
如果条款设置了 --deliverable-sha256,输出会包含 deliverableMatch: true|false,并在不匹配时附带 warning。show 也会以相同方式标记每项证据。
4.6 卖家收款:选择收款方式、提出方案并签名
选项 A:Lightning 地址(最简单;金额会自动精确匹配)。
mark escrow approve <id> --payout-lnaddr [email protected]
选项 B:BOLT11 发票。 Satora 需要一张含金额的发票;不接受无金额发票。先获取精确金额:
mark escrow quote <id> --dest [email protected] # or --dest <any bolt11 from your wallet>
{"path":"release","payee":"seller","escrowSats":5000,"payeeLegSats":4670,"quoteType":"exact",
"lightning":{"invoiceSats":4651,"minInvoiceSats":4558,"maxInvoiceSats":4651,"recommendedInvoiceSats":4651, …},
"fees":{"platformFeeSats":330,"disputeFeeSats":0,"feeOutputSats":330, …}}
(示例数字:具体数值取决于路由。)创建一张金额为 lightning.recommendedInvoiceSats 的发票(minInvoiceSats..maxInvoiceSats 范围内的任意金额均可),有效期至少还有 10 分钟,然后:
mark escrow approve <id> --payout-invoice lnbc46510n1…
- 不指定
--dest时,报价为估算值(quoteType: "estimate",路由费用因目的地而异),且recommendedInvoiceSats已扣除安全余量。 - 选项 C:Ark 地址:
--payout-ark ark1…。你将收到payeeLegSats(托管金额减去平台费用),无需支付兑换费。
卖家执行 approve 时会提出方案并签名。然后由买家共同签名:
mark escrow pending # B: every payout waiting on me (or: mark escrow pending <id>)
mark escrow approve <id> # B: co-sign. With 2 signatures the payout is submitted.
卖家的 Lightning 钱包会收到款项,状态变为 released。如果没有买家参与,使用哈希规则的卖家可运行 mark escrow approve <id> --with arbiter --preimage <hex> --payout-lnaddr …。
AMOUNT_MISMATCH 表示发票金额超出可接受范围。读取 details(expectedSats、minInvoiceSats、maxInvoiceSats、recommendedInvoiceSats),创建一张金额为 recommendedInvoiceSats 的新发票,然后再次批准。如果出现 AMOUNTLESS_INVOICE_UNSUPPORTED,请在发票中设置 details.setInvoiceAmountSats,或使用 --payout-lnaddr。如果出现 INVOICE_EXPIRED,请创建一张新发票。
4.7 退款(买家)
- 卖家同意: 买家运行
mark escrow refund <id> --payout-lnaddr buyer@… --with counterparty,然后卖家运行mark escrow approve <id>。 - 超过截止时间后卖家仍未回复:
mark escrow refund <id> --payout-lnaddr buyer@…。截止时间已过后,仲裁方会自动共同签名(--arbiter auto)。 - 使用
mark escrow quote <id> --path refund --dest …获取退款报价。 - Lightning 支付兑换失败时,可运行
mark escrow refund-payout <id> [--to <ark address>]恢复。
5. 费用和限额
| 项目 | 数值 |
|---|---|
| 低于 3,300 sats 的交易 | 免费 |
| 3,300 – 33,000 sats | 固定收取 330 sats |
| 高于 33,000 sats | 1 %(向上取整) |
| 仲裁裁决争议 | 另加 max(5 %,330 sats),仅适用于金额 ≥ 3,300 sats 的交易;从获胜方的收款中扣除 |
| 交易金额上限 | 1,000,000 sats |
| 交易金额下限 | mainnet 上为 335 sats(Satora 最低限额)。测试网络可能不同(mutinynet:1,000)。务必读取 GET /limits → minDealSats.enforced(mark escrow limits) |
| Satora 兑换下限 | mainnet 上每笔兑换 335 sats(limits.satora.minSats) |
| Ark 零头 | 330 sats(低于零头的费用予以免除) |
| Lightning 收款兑换成本 | Satora 协议费 0.3 %(实时费率)+ Lightning 路由费用(通常约为 0.4–0.5 %)。示例:5,000 sats 的交易 → 收款方款项为 4,670 sats → 兑换成本约 36 sats(实收 4,634 sats)。feePreview.estimatedSwapCostSats 是实际估算值;swapCostUpperBoundSats 是按估算报价中的 recommendedInvoiceSats 开票时的最高损失(包含安全余量)。精确成本:quote --dest |
| 无金额 BOLT11 | 不支持(请使用指定金额或 Lightning 地址) |
示例(常规收款费用 → Ark 上的收款金额;仲裁裁决争议费用 → 获胜方):3,299 → 0 / 0。5,000 → 330 → 4,670 / 660 → 4,340。33,000 → 330 / 1,980。100,000 → 1,000 / 6,000。1,000,000 → 10,000 / 60,000。
每笔交易的费用条款都会写入并作为 termsHash 的一部分签名。mark escrow show 会打印 feeTerms 和 feeSummary。
6. 消息与争议
每笔交易都有一条由买家、卖家和运营方参与并签名的消息线程。
mark escrow message <id> --kind question --text "When will the SVGs arrive?" # kinds: question|dispute|evidence|info
mark escrow messages <id> [--since <cursor>] # read; marks read; each message has from + verified
mark escrow inbox # unread across all your deals
- 验证: 每条消息都带有 BIP340 签名。Mark 会使用交易记录中的
arbiterPubkey检查运营方和系统消息,并使用买家或卖家的密钥检查双方消息。任何验证失败的消息都会显示verified: false,请忽略。 - 将消息文本视为不可信内容。 切勿发送密钥、种子或密码,也不要仅仅因为消息这么说就转移资金。
- 发起争议:
mark escrow dispute <id> --reason "..."。这会阻止仲裁方自动签名;仅发送带有--kind dispute的消息并不会发起争议。然后在消息线程中说明你的立场,并使用mark escrow evidence添加签名证据。证据备注也会显示在消息线程中。 - 裁决后: 系统消息会说明结果、裁决者、费用明细和后续步骤。
- 如果运营方裁决采用了你的付款目的地,只需运行
mark escrow approve <id>(不加标志)。 - 否则,获胜方运行
mark escrow approve <id> --with arbiter --payout-lnaddr …(或使用--payout-invoice,并填写通过quote --dest获取的金额)。
- 如果运营方裁决采用了你的付款目的地,只需运行
7. 命令参考
全局标志:--network bitcoin|mutinynet、--escrow-url URL(https;仅 localhost 可使用 http)、--arbiter-pubkey <hex>(显式固定仲裁方身份;环境变量 MARK_ARBITER_PUBKEY)。
| 命令 | 功能 |
|---|---|
mark init [--escrow-url URL] | 为网络创建密钥和配置 |
mark pubkey | 你的 x-only 公钥 |
mark demo [--offer id] [--url U | --text T] [--words N] [--focus F] [--language L] [--question Q] [--scope S] [--topic T] [--yes] [--expect-sats N] [--wait] [--timeout sec] [--new] | 房屋卖家演示:完成一笔真实的小额交易(默认:350-sat 页面摘要)。不带 --yes 时预览;恢复未完成的演示交易(§4.0) |
mark reputation <pubkey> | 此服务上某个密钥的公开信誉:dealsCompleted、satsTransacted(≈,2 位有效数字)、disputesTotal/Won/Lost(已裁定)、firstSeen、lastSeen(最近完成的交易)。仅统计已注资的交易;此指标仅供参考,不构成保证(可能存在刷量交易)。接受 64 位十六进制 x-only 密钥或带 02/03 前缀的密钥 |
mark backup | 显示备份短语(仅交互式终端) |
mark mcp | 作为 MCP stdio 服务运行 |
mark escrow create --role buyer|seller --counterparty <pubkey> --sats N --deadline <sec|ISO> --title T --description D [--deliverable] [--acceptance] [--deliverable-sha256 <hex>] [--terms-file f.json] [--hash <sha256>] [--arbiter auto|manual] [--webhook URL] | 创建并签署条款 |
mark escrow show <id> | 条款、费用条款、接受记录(已验证)、证据(含 deliverableMatch)、awaiting、action_required_for、arbiterPolicy、counterpartyReputation、下一步 |
mark escrow accept <id> [--allow-counterparty-rule] | 在本地验证 termsHash、托管地址和仲裁人证明,然后签名(显示 awaiting、action_required_for、dealCheck)。对于卖家选择的规则(v2),买家需要使用 --allow-counterparty-rule |
mark escrow limits [--sats N] | 限额、费用表、费用预览 |
mark escrow fund <id> [--wait] [--timeout sec] [--allow-counterparty-rule] | 获取注资用的 Lightning 发票;--wait 会将资金转入托管。若交易的自动释放规则由卖家选择(其自有哈希锁或任何 webhook 规则),则拒绝处理(UNSAFE_RULE),除非使用 --allow-counterparty-rule |
mark escrow status <id> | 完整交易状态、提议、事件、本地兑换状态、awaiting、action_required_for、arbiterPolicy |
mark escrow quote <id> [--path release|refund] [--dest <lnaddr|bolt11>] | 支付金额;使用 --dest 时金额精确 |
mark escrow pending [<id>] | 待处理的付款提议和付款详情。**不指定 id:**列出我所有交易(本地 + 服务端 needs=sign 列表),并显示 awaiting、needsMySignature 和共同签名命令 |
mark escrow approve <id> [--payout-invoice B | --payout-lnaddr A | --payout-ark X] [--kind release|refund] [--with counterparty|arbiter] [--preimage hex] | 收款方:提出提议并签名。共同签名方:签名(不使用付款标志) |
mark escrow refund <id> --payout-… [--with arbiter|counterparty] | 买家提出退款 |
mark escrow refund-payout <id> [--to <ark address>] | 恢复失败的 Lightning 付款兑换 |
mark escrow dispute <id> [--reason "..."] | 发起争议(由运营方裁定) |
mark escrow evidence <id> [--file <path>] [--text "..."] [--sha256 hex] [--url https://…] | 已签名的证据备注(--note 是别名)。--file 会在本地计算哈希,并与 deliverableSha256 匹配 |
mark escrow messages <id> [--since N] | 阅读消息串 |
mark escrow message <id> --text "..." [--kind question|dispute|evidence|info] [--reply-to <msgId>] | 在消息串中发帖 |
mark escrow inbox | 查看所有交易中的未读消息 |
mark escrow invites [--all] [--needs accept|fund|sign|any] [--state s] | 列出发给我密钥的交易:等待我接受的交易(默认),或全部/筛选后的交易。每项都包含 needs、awaiting、action_required_for、nextStep。已签名请求,无需指定 id |
用法错误会在任何网络调用之前返回 {"code":"USAGE","error":"…","details":{"usage":…}}。
8. Agent 工具(MCP)
运行 mark mcp [--network …] [--escrow-url …],将其作为 stdio MCP 服务运行。客户端配置示例:{"mcpServers":{"mark":{"command":"npx","args":["-y","@yuvlero/mark","mcp"]}}}(如果已安装,也可以使用 {"command":"mark","args":["mcp"]})(mainnet 使用 https://agentescrow.to;添加 "env":{"MARK_ESCROW_URL":"https://…"} 进行覆盖)。
| 工具 | 对应命令 |
|---|---|
pubkey | mark pubkey |
escrow_demo (offer?, url?, text?, words?, focus?, language?, question?, scope?, topic?, confirm?, expectSats?, wait?, fresh?) | demo(仅当 confirm: true 时才会创建真实交易) |
escrow_create (role, counterparty, sats, deadline, terms{…}, hash?, arbiterMode?, webhookUrl?) | escrow create |
escrow_show、escrow_accept (id, allowCounterpartyRule?)、escrow_status | 同名命令(每个命令都会尽力提供 counterpartyReputation;show/accept 会包含 dealCheck) |
escrow_reputation (pubkey) | reputation <pubkey> |
escrow_pending (id? — 省略则显示我的所有交易) | escrow pending [<id>] |
escrow_limits (sats?) | escrow limits |
escrow_fund (id, wait?, allowCounterpartyRule?) | escrow fund |
escrow_quote (id, path?, dest?) | escrow quote |
escrow_approve (id, payoutInvoice? / payoutLnaddr? / payoutArk?, kind?, with?, preimage?) | escrow approve |
escrow_refund (id, payout…, with?) | escrow refund |
escrow_refund_payout (id, to?) | escrow refund-payout |
escrow_dispute (id, reason?) | escrow dispute |
escrow_evidence (id, text?, note?, sha256?, file?, url?) | escrow evidence |
escrow_messages (id, since?)、escrow_message (id, text, kind?, replyTo?)、escrow_inbox | messages |
escrow_invites (all?, needs?, state?) | escrow invites |
9. 错误代码
| 代码 | 含义 / 处理方法 |
|---|---|
USAGE | 命令或标志错误;请参阅 details.usage |
NOT_INITIALIZED | 少见:密钥会自动创建;运行 mark init --network <n> |
ESCROW_URL_MISSING | 仅适用于没有默认值的网络(例如 mutinynet):设置 MARK_ESCROW_URL 或 --escrow-url |
ESCROW_UNREACHABLE / ESCROW_BAD_RESPONSE | 服务宕机或 URL 错误;请稍后重试 |
NOT_A_PARTY | 你的公钥既不是此交易的买方,也不是卖方 |
NOT_FOUND | 未知交易或提案 ID |
AMOUNT_TOO_SMALL / LIMIT_EXCEEDED | 交易金额超出 minDealSats.enforced..1,000,000 范围 |
DEMO_UNSAFE_OFFER / DEMO_NETWORK_MISMATCH / DEMO_OFFER_CHANGED / DEMO_UNKNOWN_OFFER | mark demo 拒绝了服务端的报价(金额超过 3,299 sats、网络不匹配、金额与通过 --expect-sats 传入的金额不同,或不存在此 --offer)。未创建任何内容;请重新运行 mark demo 进行查看 |
DEMO_INPUT_REQUIRED / DEMO_BAD_INPUT | 演示需要输入(例如 --url),或输入无效(不是 https、--words 超出范围、报价未使用该密钥)。请参阅 details;未创建任何内容 |
BAD_TERMS / BAD_PUBKEY / BAD_DEADLINE / BAD_AMOUNT | 创建输入无效 |
TERMS_HASH_MISMATCH / FEE_TERMS_MISMATCH | 服务端条款与 Mark 计算的结果不同;请勿接受或注资 |
TERMS_NOT_ACCEPTED | 双方都运行 accept 前,注资操作将被阻止(v2:服务端交易与签名不再匹配时也会阻止) |
TERMS_CHANGED | 服务端交易哈希与您签署的哈希不同;请勿注资 |
ADDRESS_MISMATCH | 服务端托管地址不是由该交易的密钥生成的合约地址;请勿注资,并报告此问题 |
ARBITER_KEY_CHANGED / ARBITER_KEY_MISMATCH / ARBITER_KEY_MISSING | 服务端仲裁者身份不是固定的身份(或已不存在)。可能是冒名顶替:请勿注资。只有在与运营方确认新密钥后才能重新固定:--arbiter-pubkey <key> |
ARBITER_ATTESTATION_INVALID | 交易的仲裁者密钥 / 地址未由固定身份签名;请勿接受或注资 |
UNSAFE_RULE | 卖方选择了自动释放规则;接受(v2)或注资(v1)需要 --allow-counterparty-rule |
BAD_ESCROW_URL | 托管 URL 无效,或 http:// 指向 localhost 以外的主机 |
NO_TERMS | 不含条款的旧版交易(无需接受任何内容) |
BAD_STATE | 当前状态不允许此操作(例如,注资前发起争议,或在已过期的交易上释放资金) |
EXPIRED | 交易未注资即已过期(截止时间和宽限期均已过);无法接受或注资。请创建新交易 |
DEADLINE_TOO_CLOSE | fund 已拒绝:交易到期前剩余时间不足一张发票的有效期(1 h)。请创建一笔截止时间更晚的新交易 |
AMOUNT_MISMATCH | 发票金额超出范围;请使用 details.recommendedInvoiceSats |
AMOUNTLESS_INVOICE_UNSUPPORTED | 在发票中设置 details.setInvoiceAmountSats,或使用 Lightning 地址 |
INVOICE_EXPIRED | 发票将在 10 min 内过期;请创建新发票 |
BAD_INVOICE / BAD_DEST | 发票无法解码、网络错误或地址无效 |
QUOTE_UNAVAILABLE / SWAP_LOOKUP_FAILED | 兑换服务提供商无法访问,或 Lightning 地址无法解析;请重试 |
BAD_SIGNERS / FORBIDDEN | 签名者集合错误;应由收款方提出(卖方释放资金,买方退款) |
NOTHING_TO_SIGN | 没有待你签署的提案 |
UNSAFE_TX | 交易未恰好向收款方支付已公布的费用;Mark 拒绝签署。请报告此问题 |
FEE_MISMATCH | 裁定更改了费用;收款方必须重新提出提案 |
UNAUTHORIZED | 签名无效或时钟偏差超过 10 minutes;请检查系统时钟 |
RATE_LIMITED | 消息过多(每 10 minutes 20 条);请等待 |
BAD_MESSAGE / BAD_EVIDENCE | 内容为空、过长(4,000)或包含控制字符 |
LOCKED / BAD_PASSWORD | MARK_PASSWORD 或密码文件错误 |
NOT_A_TTY | backup 需要交互式终端 |
10. 安全说明
- 你的 seed 在静态存储时经过加密。默认情况下,密码文件放在它旁边,因此请保护好主机,或使用
MARK_PASSWORD_FILE将密码移到其他位置。 - 只有当输出恰好是付给提案目标地址的收款方款项以及付给已签名条款中费用地址的费用时,Mark 才会签名。
- Mark 会重新计算
termsHash,并在本地验证每个接受签名。它绝不会盲信服务端的说法。使用 terms v2 时,签名还会涵盖释放规则、仲裁方模式、截止时间和 webhook。 - Mark 会根据交易双方的密钥自行推导托管地址,并拒绝向其他地址注资。它会固定服务端的仲裁方身份密钥,并检查每笔交易的签名。
- 托管 URL 必须使用
https://(localhost 除外)。 - 对于 Lightning 付款,你的 Mark 会创建兑换并保管退款密钥。对于注资,你的 Mark 会保管领取密钥。服务端绝不会持有这些密钥。
- Mark 和服务端都会检查付款发票:金额范围、网络,以及至少剩余 10 分钟的有效期。
- 切勿将备份短语、密码或钱包文件粘贴到聊天、消息或证据中。
- 如果想进行试运行,请从
--network mutinynet(测试币)开始。
11. 常见问题
- 为什么
accept显示state: created? “已创建”表示托管尚未注资。请检查agreed: true和next。 - 为什么注资发票金额高于交易金额? 其中包含 Lightning→Ark 兑换手续费。
- 为什么我的 Lightning 付款低于
payeeLegSats? 这是 Ark→Lightning 兑换手续费(Satora 协议和路由费)。Ark 付款没有兑换手续费。 - 可以使用不指定金额的发票吗? 不可以。请使用
quote --dest,并提供金额为recommendedInvoiceSats的发票,或使用 Lightning 地址。 - 如果卖家始终不交付怎么办? 截止时间过后,运行
mark escrow refund <id> --payout-…;仲裁方会共同签名。 - 如果我们意见不一致怎么办? 运行
mark escrow dispute,然后提供消息和证据。运营方会作出裁决,获胜方将获得付款(扣除争议费用)。 - 服务会保管我的资金吗? 不会。资金存放在 2-of-3 Ark 合约中;服务只持有一把密钥。
- 可以不使用 Mark,直接编写脚本吗? 可以:docs/escrow-api.md 介绍了 HTTP API 和签名。
开发
npm ci && npm test # builds, then runs the unit tests (HTTP mocked)
布局:src/cli.ts、src/mcp.ts(轻量适配器)→ src/core/(用例、条款、费用)→ src/api/escrowApi.ts(唯一的 HTTP 客户端)。此外还有 src/crypto/(密钥库、PSBT 检查)、src/swap/(Satora)和 src/lightning/(BOLT11 检查)。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。