@rozoai/checkout 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ja.md DELETED
@@ -1,265 +0,0 @@
1
- # rozo-checkout
2
-
3
- [English](README.md) | [简体中文](README.zh.md) | **日本語** | [Español](README.es.md)
4
-
5
- **[クイックスタート →](QUICKSTART.ja.md)** — 本文を読まずに、5 分でリンクを支払う。
6
-
7
- ```bash
8
- npx @rozoai/checkout pay <coinbase-link> --with usdt-solana
9
- ```
10
-
11
- **OpenRouter の Coinbase 決済リンク (Payment Link)** を、そのリンクが直接受け取れない
12
- 通貨で支払うためのものです — Lightning 経由の BTC、あるいは Solana、BNB Chain、Ethereum、
13
- Polygon、Base、Stellar 上の USDT/USDC が使えます。
14
-
15
- Coinbase の決済リンクは Base 上の USDC しか受け付けません。このリポジトリはエージェント
16
- スキル (agent skill) であり、その裏で動く Node スクリプトも含みます。上記のいずれの通貨も
17
- ブリッジ (bridge) を通して中継します。実際に保有している通貨向けの使い捨て入金アドレス
18
- (deposit address) が発行され、入金が着金すると資金提供ウォレット (funder wallet) が
19
- あなたに代わって Coinbase のインボイスを決済します。
20
-
21
- インボイス自体には**割引はありません**。`callerPays` はインボイス金額と等しくなります。
22
- 一方、あなたが送金する**入金額**はそれとは別の数値であり、通常はより大きくなります。
23
- インボイス金額を Base USDC で届けるために必要なブリッジ手数料とソースチェーン手数料が
24
- 含まれるためです。バックエンドが返した `deposit.amount` を必ずそのまま送金してください。
25
- インボイス金額と等しいと決して思い込まないでください。
26
-
27
- - `SKILL.md` — エージェント向けの指示書(Claude Code のスキル形式)。
28
- - `llms.txt` — 1 ファイルだけ読むエージェント向けの簡潔な要約。
29
- - `scripts/` — Node による実装。`src/` がソースで、`dist/` には素の `node` で実行できる
30
- 自己完結型のバンドルが入っています。
31
- - `test/` — 資金処理と安全性ロジックのオフライン単体テスト。
32
- - `PLAN.md` — 実装が従っている設計ドキュメント。
33
-
34
- 利用にあたって、アカウント、API キー、運営者との何らかの関係は**一切必要ありません**。
35
- 呼び出す全エンドポイントは公開かつ鍵不要です。
36
-
37
- ## 仕組み
38
-
39
- ```mermaid
40
- flowchart TD
41
- A["Coinbase Payment Link<br/>payments.coinbase.com/payment-links/pl_*"] --> B
42
- B["quote-invoice<br/>(public POST)"] --> C["create-invoice<br/>(public POST)"]
43
- C --> D["Bridge order<br/>one-time deposit address<br/>+ exact amount + expiry"]
44
- D --> E["You send USDT/USDC/BTC<br/>on your chosen chain"]
45
- E --> F["Bridge converts the pay-in"]
46
- F --> G["Funder wallet settles<br/>the Coinbase invoice"]
47
- G --> H["Merchant is paid<br/>(e.g. OpenRouter credit)"]
48
- ```
49
-
50
- mermaid を表示できない端末向けに、同じ内容を ASCII で示します。
51
-
52
- ```
53
- Coinbase Payment Link (pl_* / paymentSession_*)
54
- |
55
- v
56
- [ quote-invoice ] -> merchant, amount, expiry, short-lived quote receipt
57
- |
58
- v
59
- [ create-invoice ] -> bridge order: rozoPaymentId + deposit address
60
- | + exact amount + order expiry
61
- v
62
- you send USDT / USDC / BTC on your chain ------> deposit address
63
- |
64
- v
65
- bridge converts the pay-in ------> funder wallet pays the Coinbase invoice
66
- |
67
- v
68
- merchant credited; poll until the state is `settled`
69
- ```
70
-
71
- 全体を通して 3 つの識別子が登場します。これらは決して互換ではありません。
72
-
73
- | 識別子 | 内容 |
74
- |---|---|
75
- | `linkId` | Coinbase 側の id: `pl_*`(決済リンク)または `paymentSession_*`(v3 セッション) |
76
- | `rozoPaymentId` | ブリッジ注文の UUID — 入金詳細とステータスの照会にはこれを使います |
77
- | `paymentLink` | ブリッジ注文用のホスト型決済ページ URL(人手によるフォールバック) |
78
-
79
- ## 対応するソース
80
-
81
- | チェーン | チェーン id | トークン | 備考 |
82
- |---|---|---|---|
83
- | Ethereum | `1` | USDC, USDT | 小数点以下 6 桁 |
84
- | BNB Chain | `56` | USDC, USDT | **小数点以下 18 桁** — 10^12 のずれによるバグの典型的な原因 |
85
- | Polygon | `137` | USDC, USDT | 小数点以下 6 桁 |
86
- | Base | `8453` | USDC | 小数点以下 6 桁 |
87
- | Solana | `900` | USDC, USDT | 小数点以下 6 桁。SPL で、メモ (memo) が必要な場合あり。ネイティブの SOL は**非対応** |
88
- | Stellar | `1500` | USDC | 小数点以下 7 桁。メモが必須 |
89
- | Bitcoin Lightning | `lightning` | BTC | 金額は整数の **satoshi**。BOLT11 インボイス (BOLT11) で支払います |
90
-
91
- ネイティブのガス通貨(SOL、BNB、ETH、MATIC)およびオンチェーンの BTC は受け付けません。
92
-
93
- ## クイックスタート
94
-
95
- ### 1. curl で公開エンドポイントを試す
96
-
97
- `pl_01YOURLINKID` を実際の Coinbase 決済リンクに置き換えてください。以下のどれにも認証
98
- ヘッダーは不要です。
99
-
100
- ```bash
101
- MPP="https://apiserver.mpprouter.dev/v1/services/rozo-agent-api"
102
- INTENTS="https://intentapiv4.rozo.ai/functions/v1/payment-api"
103
- LINK="https://payments.coinbase.com/payment-links/pl_01YOURLINKID"
104
-
105
- # 見積もりを取得: 加盟店、金額、有効期限、約 60 秒有効な quoteReceipt。
106
- curl -s -X POST "$MPP/quote-invoice" \
107
- -H 'content-type: application/json' \
108
- -d "{\"url\":\"$LINK\"}"
109
-
110
- # 例として Solana 上の USDT でブリッジ注文を作成します。
111
- # 注文を作るだけで資金は動きません。入金のない注文はそのまま期限切れになります。
112
- curl -s -X POST "$MPP/create-invoice" \
113
- -H 'content-type: application/json' \
114
- -d "{\"url\":\"$LINK\",\"source\":{\"chainId\":\"900\",\"tokenSymbol\":\"USDT\"}}"
115
-
116
- # 入金手順(これが正)。上で得た rozoPaymentId を使います。
117
- curl -s "$INTENTS/payments/<rozoPaymentId>"
118
-
119
- # 履行ステータス。Coinbase の linkId を使います。
120
- curl -s "$MPP/invoice-status?payment_id=pl_01YOURLINKID"
121
- ```
122
-
123
- `create-invoice` は IP 単位でレート制限されています(およそ 30 回/時)。読み取り系
124
- エンドポイントには制限はありません。
125
-
126
- ### 2. CLI を使う
127
-
128
- インストールは不要です。`npx` が取得して実行します:
129
-
130
- ```bash
131
- npx @rozoai/checkout quote <coinbase-link>
132
- npx @rozoai/checkout pay <coinbase-link> --with usdt-solana
133
- npx @rozoai/checkout status <rozoPaymentId>
134
- ```
135
-
136
- `pay` はフロー全体を進めます。見積もりを取り、注文を作成し、マスクされた確認内容を表示し、
137
- 承認を求め、そのうえで入金手順を出力して決済完了までポーリングします。自分のウォレット
138
- ではなくホットウォレットから支払う場合は `--send` を、機械可読な出力が必要な場合は
139
- `--json` を、それ以外については `--help` を追加してください。
140
-
141
- ### 3. あるいはスクリプトを直接実行する
142
-
143
- リポジトリをクローンすると、同じフローが個別のスクリプトとして手に入ります。エージェント
144
- スキルが使っているのはこちらで、CLI も内部ではこれを呼び出しています。
145
-
146
- 各スクリプトは標準出力にちょうど 1 個の JSON オブジェクトを出力します。終了コードは
147
- `0` が成功、`1` が拒否/失敗(`error.code` を参照)、`2` が使い方の誤り、`3` が送信済みだが
148
- 未確認です。
149
-
150
- ```bash
151
- # ステップ 1 — 読み取り専用の見積もり。費用はかかりません
152
- node scripts/dist/quote.js --url "$LINK"
153
-
154
- # ステップ 2 — 注文を作成します(資金は動きません。入金のない注文は期限切れになります)。
155
- # この段階では完全な入金アドレスは伏せられます。確認用のマスクされた
156
- # サマリーと `depositWithheld: true` が返ります。
157
- node scripts/dist/create-order.js --url "$LINK" --chain 900 --token USDT
158
-
159
- # ステップ 3 — 金額、チェーン、マスクされたアドレス、メモの要否、有効期限を確認します。
160
- # 支払うと決めたときにだけ、同じコマンドを --confirm 付きで実行し直して
161
- # ください。これで完全な deposit ブロックが開示され、送金スクリプトが要求する
162
- # 確認記録が残ります。
163
- node scripts/dist/create-order.js --url "$LINK" --chain 900 --token USDT --confirm
164
-
165
- # ステップ 4a — モード A: deposit ブロックの内容を自分のウォレットから支払い、
166
- # その後の決済完了を監視します
167
- node scripts/dist/status.js --rozo-payment-id <uuid> --watch --timeout 600
168
-
169
- # ステップ 4b — モード B: スクリプトにホットウォレットから支払わせます。--dry-run では
170
- # 署名は一切行いません。実際に送金するにはさらに --send が必要です。
171
- ROZO_CHECKOUT_SOL_KEY=<base58 secret key> \
172
- node scripts/dist/send-sol.js --rozo-payment-id <uuid> --dry-run
173
- ```
174
-
175
- `scripts/dist/*.js` は自己完結型のバンドルです。呼び出し側で `npm install` を実行する
176
- 必要はありません。上記の CLI は同じコードにより扱いやすい入り口を付けたもので、これらの
177
- フローを再実装するのではなくインポートしています。したがって、以下に挙げるチェックは
178
- どちらの入り口を使っても等しく適用されます。
179
-
180
- ## ビルドとテスト
181
-
182
- ```bash
183
- npm install # 再ビルドまたはテスト実行のときだけ必要です
184
- npm run build # esbuild -> scripts/dist/*.js (node18 ターゲット) + blacklist.json
185
- npm test # node:test、完全オフライン
186
- npm run check # ビルド + テスト
187
- ```
188
-
189
- テストは**ネットワーク通信を一切行いません**。バックエンドのレスポンスはすべて
190
- `test/fixtures/` 内のフィクスチャです。テスト対象は、最小単位への金額変換(小数点以下
191
- 6/18 桁と Lightning の satoshi)、有効期限マージンの計算、危殆化アドレスの正規化と
192
- フェイルクローズ動作、注文再利用の判定、作成後の検証比較器、入金手順の完全性ルールです。
193
-
194
- 2 つのグループは関数呼び出しではなく実際の子プロセスを起動します。単一プロセスの
195
- テストでは検証できないものを対象とするためです。並行性スイートは複数プロセスを競合させて
196
- 1 つの注文の獲得(勝てるのはちょうど 1 つだけ)とセッション上限の使い切りを検証し、
197
- エントリーポイントスイートはビルド済みの送金スクリプトを実行して、`--send` がない場合、
198
- 確認がない場合、既に他が獲得済みの場合に拒否することを証明します。
199
-
200
- ## 安全性の設計
201
-
202
- このリポジトリで興味深いのは、何をするかではなく、何を頑として拒否するかです。
203
-
204
- - **二段階確認の強制。** `create-order.js` は、`--confirm` 付きで再実行されるまで完全な
205
- 入金アドレス、メモ、BOLT11 を伏せます。再実行時には、その手順そのものの sha256 に
206
- 紐づいた確認記録が保存されます。送金スクリプトは、`--send` と、ダイジェストが現在の
207
- データと一致し続けている確認記録の両方がなければ実行を拒否します。したがって、誤った
208
- 実行でも、すり替えられた入金アドレスでも、資金は動きません。
209
- - **常にインボイス全額。** `callerPays` はインボイス金額と等しくなければならず、
210
- `discount` は `"0"` でなければなりません。それ以外は `NO_DISCOUNT_VIOLATION` で中断します。
211
- セキュリティ上重要なフィールド(`linkId`、`merchant`、`original`、`callerPays`、
212
- エコーバックされた source)は、値が一致しているだけでなく存在していることも必要です。
213
- 欠落しているフィールドは乖離 (drift) とみなします。
214
- - **再利用ガード。** すでに期限切れでない注文があるリンクに対して注文を作成すると、その
215
- 既存の注文が返されます。たとえその注文がすでに入金済みであってもです。そのため実行の
216
- たびに、現在の注文が未入金であること(`payment_unpaid`、tx ハッシュなし、受領金額なし、
217
- 確認なし)と、呼び出し側が選んだチェーンおよびトークンと一致することを必須としています。
218
- そうでない場合は `ORDER_ALREADY_FUNDED` または `REUSED_SOURCE_MISMATCH` になります。
219
- - **入金検知ルール、フェイルクローズ。** いったん何らかの入金が存在すると、このツールは
220
- 単純な失敗として報告することも、再度の支払いを勧めることも、新しい注文で再試行することも
221
- ありません。`amountReceived` が null ではないが読み取れない場合は、資金がないのではなく
222
- 資金があるものとして扱います。バックエンドが読み取れない場合は `awaiting_deposit` では
223
- なく `unknown` を報告します。
224
- - **完全な入金手順。** 金額がゼロ、負数、あるいは解析不能な場合は中断します。Lightning では
225
- BOLT11 が必須です(アドレスは空で、`source.lnInvoice` に入って届きます)。Stellar では
226
- メモが必須で、メモの欠落は「メモ不要」と表示されることは決してなく、必ず強制中断となります。
227
- - **有効期限マージン。** 注文の有効期限と Coinbase の有効期限のうち早いほうが、チェーン
228
- ごとのマージン(EVM と Stellar は 10 分、Solana は 5 分)を超えて先でない限り、支払いは
229
- 拒否されます。Lightning ではさらに BOLT11 の有効期間が最低 10 分残っている必要があります。
230
- 期限が欠落している、または解析できない場合は中断します。
231
- - **支払い可能性の再検証。** quote receipt があると注文作成時のライブ Coinbase チェックが
232
- スキップされ、またリンクはいつ他人に消費されてもおかしくありません。そのため、入金
233
- アドレスを表示する直前に支払い可能性を再確認し、さらに RPC の準備がすべて済んだ後、
234
- ブロードキャスト直前の最終ステップとしてもう一度確認します。Coinbase の状態が不完全な
235
- 場合は、支払い可能ではなく「支払い可能だと証明できない」として扱います。
236
- - **危殆化アドレスリスト、フェイルクローズ。** `scripts/src/lib/blacklist.json` には、
237
- 出所ヘッダーとアドレス全体の sha256 を伴うベンダリング済みのリストが入っています。この
238
- ダイジェストが証明するのは、このベンダリングされたコピーが同期日以降編集されていない
239
- ことだけであり、上流ソースによる署名ではありません。入金アドレスと送金元ウォレットの
240
- 両方がチェックされます。ファイルが存在しない、形式が不正、空、あるいはダイジェストが
241
- 一致しない場合は、未チェックのまま処理を続けるのではなく、すべての送金を拒否します。
242
- - **プロセスをまたいだ一度きりの送金。** 注文の状態は
243
- `$HOME/.rozo-checkout/state/<uuid>.json` に置かれ、アトミックに書き込まれます
244
- (一時ファイル、fsync、rename)。状態ファイルの read-modify-write は、獲得処理、支出上限、
245
- 注文レコード、確認記録のいずれも、単一の排他ロックファイルの内側で実行されます。
246
- そのため、同時に起動した 2 つの実行が両方とも自分が先だと判断することも、互いの送金
247
- 記録を上書きすることもありません。送金はブロードキャストの*前*に獲得されるため、
248
- 曖昧な RPC エラーが二重送金になることは決してありません。トランザクションは
249
- ブロードキャスト前に署名されるのでハッシュは事前に判明しており、結果が曖昧な場合、
250
- スクリプトは再ブロードキャストせずにそのトランザクションそのものを照会します。
251
- - **ホットウォレットの制御。** 鍵は環境変数からのみ取得され
252
- (`ROZO_CHECKOUT_EVM_KEY`、`ROZO_CHECKOUT_SOL_KEY`)、決して出力されず、コマンドライン
253
- から渡すこともできません。ライブラリと RPC のエラーは、認証情報を含むプロバイダー URL、
254
- bearer トークン、鍵のような形の文字列も含めて、表示前に伏字化されます。作業ディレクトリの
255
- `.env`/`.env.*` のいずれかが git で追跡されている場合、スクリプトは実行を拒否します。
256
- git が未追跡であることを証明できない場合も同様に拒否します。署名の前に、RPC の
257
- チェーン id(Solana ではジェネシスハッシュ)とトークンのオンチェーン小数桁数が検証されます。
258
- 上限はトランザクションごとに $100、セッション累計で $200 です。
259
- - **アドレスのマスキング。** 説明文では `first6...last4` の形で表示します。完全な入金
260
- アドレス、メモ、BOLT11 文字列は機械可読な `deposit` オブジェクトの中にのみ現れるので、
261
- コピー&ペーストできる形を保ったまま、ログのあちこちに散らばることがありません。
262
-
263
- ## ライセンス
264
-
265
- MIT.
package/README.zh.md DELETED
@@ -1,187 +0,0 @@
1
- # rozo-checkout
2
-
3
- [English](README.md) | **简体中文** | [日本語](README.ja.md) | [Español](README.es.md)
4
-
5
- **[快速开始 →](QUICKSTART.zh.md)** —— 五分钟付掉一个链接,无需读完本文。
6
-
7
- ```bash
8
- npx @rozoai/checkout pay <coinbase-link> --with usdt-solana
9
- ```
10
-
11
- 用一种 **OpenRouter Coinbase 收款链接 (Payment Link)** 本身无法直接接受的币种去付款 —— 走闪电网络的 BTC,或者 Solana、BNB Chain、Ethereum、Polygon、Base、Stellar 上的 USDT/USDC。
12
-
13
- Coinbase 收款链接只接受 Base 上的 USDC。本仓库是一个 agent skill(以及背后的 Node 脚本),它把上面这些币种通过一座桥 (bridge) 路由过去:你会拿到一个针对你实际持有的币种的一次性充值地址 (deposit address),等你的充值到账后,一个出资钱包会代你结清这张 Coinbase 账单。
14
-
15
- 在账单本身上**没有折扣**:`callerPays` 等于账单金额。你要发送的**充值金额**是另一个数字,而且通常更大 —— 它包含了把账单金额以 Base USDC 形式送达所需的跨桥费用和源链费用。永远严格按后端返回的 `deposit.amount` 发送;绝不要假定它等于账单金额。
16
-
17
- - `SKILL.md` —— 面向 agent 的指令(Claude Code skill 格式)。
18
- - `llms.txt` —— 给只读一个文件的 agent 准备的精简摘要。
19
- - `scripts/` —— Node 实现;`src/` 是源码,`dist/` 存放可以用纯 `node` 直接运行的自包含打包产物。
20
- - `test/` —— 针对资金处理与安全逻辑的离线单元测试。
21
- - `PLAN.md` —— 实现所遵循的设计文档。
22
-
23
- 使用它**不**需要账号、API key,也不需要与运营方有任何关系。它调用的每一个端点都是公开且无需密钥的。
24
-
25
- ## 工作原理
26
-
27
- ```mermaid
28
- flowchart TD
29
- A["Coinbase Payment Link<br/>payments.coinbase.com/payment-links/pl_*"] --> B
30
- B["quote-invoice<br/>(public POST)"] --> C["create-invoice<br/>(public POST)"]
31
- C --> D["Bridge order<br/>one-time deposit address<br/>+ exact amount + expiry"]
32
- D --> E["You send USDT/USDC/BTC<br/>on your chosen chain"]
33
- E --> F["Bridge converts the pay-in"]
34
- F --> G["Funder wallet settles<br/>the Coinbase invoice"]
35
- G --> H["Merchant is paid<br/>(e.g. OpenRouter credit)"]
36
- ```
37
-
38
- 同样的流程用 ASCII 表示,供不支持 mermaid 的终端查看:
39
-
40
- ```
41
- Coinbase Payment Link (pl_* / paymentSession_*)
42
- |
43
- v
44
- [ quote-invoice ] -> merchant, amount, expiry, short-lived quote receipt
45
- |
46
- v
47
- [ create-invoice ] -> bridge order: rozoPaymentId + deposit address
48
- | + exact amount + order expiry
49
- v
50
- you send USDT / USDC / BTC on your chain ------> deposit address
51
- |
52
- v
53
- bridge converts the pay-in ------> funder wallet pays the Coinbase invoice
54
- |
55
- v
56
- merchant credited; poll until the state is `settled`
57
- ```
58
-
59
- 全文出现三个标识符,它们彼此绝不可混用:
60
-
61
- | 标识符 | 它是什么 |
62
- |---|---|
63
- | `linkId` | Coinbase 的 id:`pl_*`(收款链接)或 `paymentSession_*`(v3 会话) |
64
- | `rozoPaymentId` | 桥订单的 UUID —— 查充值详情和状态用它 |
65
- | `paymentLink` | 该桥订单对应的托管支付页面 URL(供人工兜底使用) |
66
-
67
- ## 支持的来源
68
-
69
- | 链 | 链 id | 代币 | 备注 |
70
- |---|---|---|---|
71
- | Ethereum | `1` | USDC, USDT | 6 位小数 |
72
- | BNB Chain | `56` | USDC, USDT | **18 位小数** —— 差 10^12 这类 bug 的常见来源 |
73
- | Polygon | `137` | USDC, USDT | 6 位小数 |
74
- | Base | `8453` | USDC | 6 位小数 |
75
- | Solana | `900` | USDC, USDT | 6 位小数;SPL,可能需要 memo。原生 SOL **不**支持 |
76
- | Stellar | `1500` | USDC | 7 位小数;必须带 memo |
77
- | Bitcoin Lightning | `lightning` | BTC | 金额是整数**聪 (satoshis)**,通过闪电网络发票 (BOLT11) 支付 |
78
-
79
- 原生 gas 币(SOL、BNB、ETH、MATIC)以及链上 BTC 均不接受。
80
-
81
- ## 快速上手
82
-
83
- ### 1. 用 curl 试试公开端点
84
-
85
- 把 `pl_01YOURLINKID` 换成一个真实的 Coinbase 收款链接。下面所有请求都不需要任何 auth header。
86
-
87
- ```bash
88
- MPP="https://apiserver.mpprouter.dev/v1/services/rozo-agent-api"
89
- INTENTS="https://intentapiv4.rozo.ai/functions/v1/payment-api"
90
- LINK="https://payments.coinbase.com/payment-links/pl_01YOURLINKID"
91
-
92
- # 报价:返回商家、金额、过期时间,以及一个约 60 秒有效的 quoteReceipt。
93
- curl -s -X POST "$MPP/quote-invoice" \
94
- -H 'content-type: application/json' \
95
- -d "{\"url\":\"$LINK\"}"
96
-
97
- # 创建一个桥订单,比如用 Solana 上的 USDT。
98
- # 这一步只创建订单,不动任何资金;未付款的订单会自动过期。
99
- curl -s -X POST "$MPP/create-invoice" \
100
- -H 'content-type: application/json' \
101
- -d "{\"url\":\"$LINK\",\"source\":{\"chainId\":\"900\",\"tokenSymbol\":\"USDT\"}}"
102
-
103
- # 充值指令(以此为准),用上一步拿到的 rozoPaymentId。
104
- curl -s "$INTENTS/payments/<rozoPaymentId>"
105
-
106
- # 履约状态,用 Coinbase 的 linkId 查询。
107
- curl -s "$MPP/invoice-status?payment_id=pl_01YOURLINKID"
108
- ```
109
-
110
- `create-invoice` 按 IP 限流(约每小时 30 次);读取类端点不限流。
111
-
112
- ### 2. 使用 CLI
113
-
114
- 无需安装任何东西 —— `npx` 会自动拉取并运行它:
115
-
116
- ```bash
117
- npx @rozoai/checkout quote <coinbase-link>
118
- npx @rozoai/checkout pay <coinbase-link> --with usdt-solana
119
- npx @rozoai/checkout status <rozoPaymentId>
120
- ```
121
-
122
- `pay` 会把整个流程走完:报价、创建订单、展示打码后的核对信息、等你确认,然后打印充值指令并轮询直到结清。加 `--send` 就用热钱包付款而不是用你自己的钱包,加 `--json` 输出机器可读格式,其余选项看 `--help`。
123
-
124
- ### 3. 或者直接运行脚本
125
-
126
- 克隆本仓库后,你会拿到同样的流程,只不过是一个个独立脚本 —— agent skill 用的就是它们,CLI 底层调用的也是它们。
127
-
128
- 每个脚本在 stdout 上只打印一个 JSON 对象。退出码 `0` 表示成功,`1` 表示被拒绝/失败(读 `error.code`),`2` 表示用法错误,`3` 表示已提交但未确认。
129
-
130
- ```bash
131
- # 第 1 步 —— 只读报价,不产生任何费用
132
- node scripts/dist/quote.js --url "$LINK"
133
-
134
- # 第 2 步 —— 创建订单(不动资金;未付款的订单会过期)。
135
- # 此阶段完整充值地址会被扣留:你只拿到打码后的摘要用于核对,
136
- # 以及 `depositWithheld: true`。
137
- node scripts/dist/create-order.js --url "$LINK" --chain 900 --token USDT
138
-
139
- # 第 3 步 —— 核对金额、链、打码地址、是否需要 memo 以及过期时间。
140
- # 只有在你决定付款之后,才用 --confirm 重新执行同一条命令。
141
- # 这会释放完整的充值信息块,并记录下发送脚本所需的确认。
142
- node scripts/dist/create-order.js --url "$LINK" --chain 900 --token USDT --confirm
143
-
144
- # 第 4a 步 —— 模式 A:用你自己的钱包按充值信息块付款,
145
- # 然后观察它结清
146
- node scripts/dist/status.js --rozo-payment-id <uuid> --watch --timeout 600
147
-
148
- # 第 4b 步 —— 模式 B:让脚本从热钱包付款。--dry-run 不会签任何名;
149
- # 真正发送还额外需要 --send。
150
- ROZO_CHECKOUT_SOL_KEY=<base58 secret key> \
151
- node scripts/dist/send-sol.js --rozo-payment-id <uuid> --dry-run
152
- ```
153
-
154
- `scripts/dist/*.js` 是自包含的打包产物 —— 在调用现场无需 `npm install`。上面那个 CLI 就是同一份代码,只是外层更友好:它是导入这些流程,而不是重新实现一遍,所以下面列出的每一项检查,不管你从哪个入口进来都同样生效。
155
-
156
- ## 构建与测试
157
-
158
- ```bash
159
- npm install # 只有重新构建或跑测试时才需要
160
- npm run build # esbuild -> scripts/dist/*.js(node18 目标)+ blacklist.json
161
- npm test # node:test,完全离线
162
- npm run check # 构建 + 测试
163
- ```
164
-
165
- 测试**不发起任何网络调用**;每一个后端响应都是 `test/fixtures/` 里的 fixture。它们覆盖了原子金额换算(6/18 位小数与闪电网络的聪)、过期余量的算术、被盗地址归一化与 fail-closed 行为、订单复用决策、创建后的校验比对器,以及充值指令完整性规则。
166
-
167
- 有两组测试会真正 spawn 子进程而不是直接调用函数,因为它们测的是单进程测试测不了的东西:并发测试组会让多个进程去抢同一个订单(只允许恰好一个赢)并把会话额度耗尽;入口点测试组会运行构建好的发送脚本,证明它们在缺少 `--send` 时、缺少确认时、以及已被先前的 claim 占用之后都会拒绝执行。
168
-
169
- ## 安全设计
170
-
171
- 这个仓库真正有意思的地方,在于它拒绝去做哪些事。
172
-
173
- - **两阶段确认,强制执行。** `create-order.js` 会扣留完整的充值地址、memo 和 BOLT11,直到用 `--confirm` 重新执行;此时会记录一条确认,并绑定到这份确切指令的 sha256 上。发送脚本在同时满足 `--send` 和一条摘要仍与实时数据匹配的确认之前,一律拒绝执行 —— 所以无论是误触发调用,还是被掉包的充值地址,都无法动用资金。
174
- - **足额付款,永远如此。** `callerPays` 必须等于账单金额,`discount` 必须是 `"0"`;任何其他情况都以 `NO_DISCOUNT_VIOLATION` 中止。安全攸关的字段(`linkId`、`merchant`、`original`、`callerPays`,以及回显的 source)不仅要相等,还必须存在 —— 字段缺失即视为漂移。
175
- - **复用防护。** 为一个已经存在未过期订单的链接再次创建订单,会返回那个已有订单 —— 哪怕它已经被付过款。因此每次运行都要求实时订单处于未付款状态(`payment_unpaid`,没有 tx hash、没有收到金额、没有确认),并且与调用方选择的链和代币一致。否则报:`ORDER_ALREADY_FUNDED` 或 `REUSED_SOURCE_MISMATCH`。
176
- - **一旦检测到资金即 fail closed。** 只要存在任何入账,工具就绝不报告为一个普通失败,绝不建议再付一次,也绝不重试去开一个新订单。一个非 null 但无法解析的 `amountReceived` 算作"有钱",而不是"没钱"。后端不可读时报告 `unknown`,绝不报 `awaiting_deposit`。
177
- - **完整的充值指令。** 金额为零、为负或无法解析都会中止。闪电网络必须有 BOLT11(它随 `source.lnInvoice` 返回,同时地址为空)。Stellar 必须有它的 memo —— memo 缺失是硬性中止,绝不会被渲染成"无需 memo"。
178
- - **过期余量。** 取订单过期时间与 Coinbase 过期时间中较早的那个,除非它距现在超过按链设定的余量,否则拒绝付款(EVM 与 Stellar 为 10 分钟,Solana 为 5 分钟)。闪电网络还额外要求 BOLT11 至少还有 10 分钟有效期。截止时间缺失或无法解析都会中止。
179
- - **可支付性复检。** 有了 quote receipt,创建订单时会跳过实时的 Coinbase 检查,而该链接随时可能被别人消费掉 —— 所以在展示充值地址之前会立刻重新检查一次可支付性,并在完成全部 RPC 准备工作之后、广播之前的最后一刻再检查一次。Coinbase 状态不完整时按"无法证明可支付"处理,而不是按可支付处理。
180
- - **被盗地址清单,fail closed。** `scripts/src/lib/blacklist.json` 内置了一份 vendored 清单,带有来源出处头部以及对这些地址的 sha256。该摘要只能证明这份 vendored 副本自同步日期以来未被改动,它并不是上游来源的签名。充值地址和发送钱包都会被检查。如果该文件缺失、格式损坏、为空,或摘要对不上,那么所有发送都会被拒绝,而不是跳过检查继续执行。
181
- - **只发一次,跨进程有效。** 订单状态存放在 `$HOME/.rozo-checkout/state/<uuid>.json`,以原子方式写入(临时文件、fsync、rename)。对状态文件的每一次读-改-写 —— claim、花费额度、订单记录和确认 —— 都在同一把独占 lockfile 内进行,因此两个并发调用既不会都认为自己是第一个,也不会互相覆盖对方的发送记录。发送会在广播*之前*被 claim,所以一个语义不明的 RPC 错误永远不会变成第二次转账。交易在广播前就已签名,因此 hash 是提前已知的;遇到结果不明确时,脚本会去查这笔确切的交易,而不是重新广播。
182
- - **热钱包管控。** 私钥只从环境变量读取(`ROZO_CHECKOUT_EVM_KEY`、`ROZO_CHECKOUT_SOL_KEY`),永不打印,也绝不接受从命令行传入;库和 RPC 的错误在展示前会被脱敏,包括带凭据的 provider URL、bearer token 和形似密钥的字符串。当工作目录下任何 `.env`/`.env.*` 被 git 跟踪时,脚本拒绝运行;当 git 无法证明它未被跟踪时,同样坚决拒绝。签名前会校验 RPC 的链 id(Solana 则是 genesis hash)以及代币的链上小数位。额度上限:单笔 $100,单会话累计 $200。
183
- - **地址打码。** 正文中显示为 `first6...last4`。完整的充值地址、memo 和 BOLT11 字符串只出现在机器可读的 `deposit` 对象里,这样它们既保持可复制粘贴,又不会散落在各处日志中。
184
-
185
- ## 许可证
186
-
187
- MIT。