@subly_fi/pay 0.6.2 → 0.7.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.md CHANGED
@@ -1,168 +1,110 @@
1
1
  # @subly_fi/pay
2
2
 
3
- Subly client for [x402](https://x402.org)-style HTTP payments funded by
4
- **Kamino vault yield** — your agent pays for paywalled APIs from the yield on
5
- deposited USDC, and the principal is never spent. Non-custodial: it signs
6
- locally with your own Solana key; Subly never holds it.
7
-
8
- Current payments target standard x402 sellers that offer a Solana USDC `exact`
9
- rail with facilitator `extra.feePayer` support (meaning the seller side
10
- sponsors the payment transaction's network fee — true of common facilitators
11
- such as PayAI and Coinbase CDP).
12
-
13
- > [!WARNING]
14
- > `@subly_fi/pay` is beta software and has not undergone an external security audit. It signs and submits transactions involving real Solana mainnet funds through a separate relayer and Kamino vault. The client package currently passes its production dependency audit, but this is not a guarantee of relayer, protocol, or vault safety. Use only amounts you can afford to lose and review the relayer operator and configuration before use.
15
-
16
- Ships one `pay` dispatcher bin with subcommands, all runnable with `npx` (no clone):
17
-
18
- - `pay mcp` — an MCP server (Claude Code, Cursor, any MCP client) exposing
19
- the full lifecycle as tools: `create_subly_setup_link` /
20
- `check_subly_setup` (owner onboarding: the human approves the spending
21
- mandate + first deposit with one Face ID), `deposit_to_subly_vault`,
22
- `get_subly_yield_budget`, `fetch_with_subly_payment`,
23
- `withdraw_from_subly_vault`. Payments above the owner's approval
24
- threshold, deposits, and (when the mandate opts in) withdrawals return an
25
- `approveUrl` to paste into chat; retry with the `approvalId` once the
26
- human approved.
27
- - `pay fetch <url> [maxAmountRawUsdc] [apr_<approvalId>]` — one-shot: pay for
28
- a URL, print the receipt (used by the OpenClaw skill); retry with the
29
- `apr_...` id after an `approval_required` refusal
30
- - `pay deposit <amountRawUsdc> [apr_...]` / `pay withdraw <amountRawUsdc>
31
- [apr_...]` — vault deposit / withdraw with the same owner-approval flow
32
- - `pay setup-link [--initial-deposit <raw>] [--approval-threshold <raw>] ...`
33
- / `pay setup-status <st_sessionId | setupUrl>` — owner onboarding for
34
- CLI/skill harnesses (same flow as the MCP setup tools)
35
-
36
- ## Wallet
37
-
38
- Subly does not create wallets — bring your own Solana keypair (`solana-keygen`
39
- ships with the [Solana CLI](https://docs.anza.xyz/cli/install)):
3
+ CLI and stdio MCP client for paying compatible x402 APIs with Kamino USDC vault yield on Solana. MIT licensed. Works with your own [Subly relayer](https://github.com/SublyFi/subly-payment-protocol/tree/main/deploy); no Subly account is required.
40
4
 
41
- ```bash
42
- solana-keygen new --no-bip39-passphrase -o ~/.subly/agent.json
43
- export SUBLY_DEMO_AGENT_KEYPAIR_PATH=~/.subly/agent.json
44
- ```
5
+ Version 0.7 is beta software and has not had an external security audit. Vault operations use real mainnet funds. Yield accounting and owner policies depend on your relayer operator. Read the [security model](https://github.com/SublyFi/subly-payment-protocol/blob/main/docs/security-model.md).
6
+
7
+ ## Quick start
45
8
 
46
- Or bring a custody-held agent wallet the key then never touches this
47
- machine; every signature is requested from the provider's API and verified
48
- locally before use:
9
+ You need **Node.js 24+**, a Solana agent wallet with mainnet USDC, a trusted relayer URL, and a mainnet RPC endpoint that supports transaction simulation with inner instructions. Your wallet can be a local keypair or a supported custody signer. The owner who approves spending controls can use a passkey or a separate Solana wallet.
49
10
 
50
11
  ```bash
51
- # Circle developer-controlled wallet (a Solana wallet in your wallet set):
52
- export SUBLY_SIGNER_PROVIDER=circle
53
- export CIRCLE_API_KEY=... CIRCLE_ENTITY_SECRET=... CIRCLE_WALLET_ID=...
54
-
55
- # Privy server wallet (Solana), incl. agentic wallets owned by an
56
- # authorization key — pass that key so requests carry the required
57
- # privy-authorization-signature:
58
- export SUBLY_SIGNER_PROVIDER=privy
59
- export PRIVY_APP_ID=... PRIVY_APP_SECRET=... PRIVY_WALLET_ID=...
60
- export PRIVY_AUTHORIZATION_KEY=wallet-auth:... # only for owner-key wallets
12
+ npx -y @subly_fi/pay@0.7.1 --help
13
+ export SUBLY_RELAYER_URL=https://your-relayer.example.com
14
+ export SOLANA_RPC_URL=https://your-mainnet-rpc.example.com
15
+ export SUBLY_DEMO_AGENT_KEYPAIR_PATH=/absolute/path/to/agent.json
16
+ npx -y @subly_fi/pay@0.7.1 doctor
17
+ npx -y @subly_fi/pay@0.7.1 vaults
61
18
  ```
62
19
 
63
- Each Circle/Privy credential var also accepts a `SUBLY_`-prefixed form (e.g.
64
- `SUBLY_CIRCLE_API_KEY`) that wins over the plain one, so Subly can use a
65
- different credential than other tooling on the same machine. Note the
66
- `circle` CLI "agent wallet" (email + OTP) is a different Circle product that
67
- exposes no signing API and cannot be used here.
20
+ Use an existing dedicated agent wallet, or create one with `solana-keygen new -o agent.json`. Keep its recovery material private and restrict the file to its owner (`chmod 600 agent.json`). Fund its public address with **USDC on Solana mainnet**. Subly does not create or fund wallets. Vault fees require a funded relayer sponsor; the final API payment requires the seller's facilitator fee payer.
68
21
 
69
- Send USDC (Solana mainnet) to the printed address no SOL needed, fees are
70
- sponsored then deposit (vault minimum is just over 1 USDC: share rounding
71
- refuses exactly 1.000000; deposit self-registers the wallet):
22
+ 1. Review the selected vault, its curator, fees and liquidity. For a catalogue supplied by your operator, install the reviewed file locally and set `SUBLY_VAULTS_FILE=/absolute/path/vaults.json`. `SUBLY_VAULT_ADDRESS` selects one listed vault for CLI commands. Never install transaction trust anchors merely because a remote response says to.
23
+ 2. Create an owner setup link. This example pre-approves a **1.01 USDC** deposit; the selected vault's minimum can differ:
72
24
 
73
- ```bash
74
- npx -y @subly_fi/pay deposit 1010000 # 1.01 USDC
75
- ```
25
+ ```bash
26
+ npx -y @subly_fi/pay@0.7.1 setup-link --initial-deposit 1010000
27
+ ```
76
28
 
77
- ## Use it
29
+ Open the returned `setupUrl`, review the wallet, vault and limits, then approve with your passkey or wallet. Links expire in 10 minutes. Treat setup and approval links as private capabilities. The first person completing an initial setup becomes the owner for that wallet/vault.
30
+ 3. Check completion and deposit promptly; initial deposit approval lasts about 15 minutes:
78
31
 
79
- ```bash
80
- # Claude Code (no clone):
81
- claude mcp add subly -- npx -y @subly_fi/pay mcp
32
+ ```bash
33
+ npx -y @subly_fi/pay@0.7.1 setup-status <sessionId>
34
+ npx -y @subly_fi/pay@0.7.1 deposit 1010000
35
+ npx -y @subly_fi/pay@0.7.1 budget
36
+ ```
82
37
 
83
- # One-shot pay (also what the OpenClaw skill calls):
84
- npx -y @subly_fi/pay fetch https://seller.example.com/api/premium
85
- ```
38
+ 4. Wait until **spendable yield** covers the price and vault fees. A new deposit does not immediately provide a payment budget. Then request a compatible API:
39
+
40
+ ```bash
41
+ npx -y @subly_fi/pay@0.7.1 fetch https://seller.example.com/paid-resource
42
+ ```
43
+
44
+ 5. Withdraw funds back to the same agent wallet when needed:
86
45
 
87
- ### Claude Desktop
88
-
89
- Prerequisites: [Node.js](https://nodejs.org) 20+ installed, and an agent
90
- keypair (see [Wallet](#wallet) above).
91
-
92
- 1. Open the config file (create it if it does not exist):
93
- - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
94
- - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
95
-
96
- Or in the app: **Settings → Developer → Edit Config**.
97
-
98
- 2. Add the `subly` server. Claude Desktop is a GUI app and does **not**
99
- inherit your shell environment (`.zshrc`, `.env` files), so every
100
- variable must go in the `env` block:
101
-
102
- ```json
103
- {
104
- "mcpServers": {
105
- "subly": {
106
- "command": "npx",
107
- "args": ["-y", "@subly_fi/pay", "mcp"],
108
- "env": {
109
- "SUBLY_DEMO_AGENT_KEYPAIR_PATH": "/Users/you/.subly/agent.json"
110
- }
111
- }
112
- }
113
- }
46
+ ```bash
47
+ npx -y @subly_fi/pay@0.7.1 withdraw 1000000
114
48
  ```
115
49
 
116
- Use an absolute path for the keypair (`~` is not expanded). For a
117
- custody wallet, replace the keypair var with the `circle` / `privy`
118
- variables from [Environment](#environment). Optional vars
119
- (`SUBLY_MCP_MAX_AMOUNT_RAW_USDC`, `SOLANA_RPC_URL`, …) go in the same
120
- `env` block.
121
-
122
- 3. Restart Claude Desktop (quit fully, then reopen). The tools icon under
123
- the chat input should now list **subly-payments** with the tools above.
124
-
125
- If the server fails to start, the usual cause is that Claude Desktop
126
- cannot find `npx` (e.g. Node installed via nvm). Point `command` at the
127
- absolute path instead — run `which npx` in a terminal and use that
128
- value, e.g. `"command": "/opt/homebrew/bin/npx"`.
129
-
130
- 4. Use it by chatting. First time: "set up Subly" walks you through the
131
- owner setup link (spending mandate + first deposit). After that,
132
- asking for anything behind an x402 paywall ("fetch
133
- https://seller.example.com/api/premium") pays from vault yield
134
- automatically and returns the response plus a payment receipt.
135
- Payments above the owner's approval threshold return an `approveUrl` —
136
- open it in a browser, approve, then tell Claude to retry.
137
-
138
- Claude Desktop asks for permission on each first tool use. The permission
139
- prompt is effectively your payment confirmation: "Allow always" on
140
- `fetch_with_subly_payment` removes that human check and relies entirely on
141
- the spending-mandate caps — keep per-use approval for payments, and reserve
142
- "Allow always" for read-only tools like `get_subly_yield_budget`.
143
-
144
- ## Environment
145
-
146
- | Var | Required | Default |
147
- |---|---|---|
148
- | `SUBLY_SIGNER_PROVIDER` | no | `local` (`circle` / `privy` for custody wallets) |
149
- | `SUBLY_DEMO_AGENT_KEYPAIR_PATH` | with `local` (or `SUBLY_DEMO_AGENT_KEYPAIR` base58) | |
150
- | `CIRCLE_API_KEY` / `CIRCLE_ENTITY_SECRET` / `CIRCLE_WALLET_ID` | with `circle` | |
151
- | `PRIVY_APP_ID` / `PRIVY_APP_SECRET` / `PRIVY_WALLET_ID` | with `privy` | |
152
- | `PRIVY_AUTHORIZATION_KEY` | only for owner-key (agentic) Privy wallets | |
153
- | `SUBLY_RELAYER_URL` | no | `https://api.demo.sublyfi.com` |
154
- | `SOLANA_RPC_URL` | no | public mainnet RPC |
155
- | `SUBLY_MCP_MAX_AMOUNT_RAW_USDC` | no | `10000` (0.01 USDC) per-payment cap |
156
- | `SUBLY_MCP_STATE_PATH` | no | `~/.subly/standard-x402-pending.json` (pending-payment store, double-payment protection) |
157
- | `SUBLY_PAY_METHOD` / `SUBLY_PAY_BODY` | no (`pay fetch` only) | `GET` / (JSON body for POST-body sellers) |
158
- | `SUBLY_PAY_FORCE_NEW_PAYMENT` | no (`pay fetch` only) | unset (`1` forces a fresh payment — may double-pay) |
159
- | `CIRCLE_BASE_URL` / `PRIVY_BASE_URL` | no | provider API defaults |
160
- | `SUBLY_VAULT_ADDRESS` / `SUBLY_VAULT_SHARE_MINT` / `SUBLY_VAULT_USDC_MINT` / `SUBLY_VAULT_FARM` | only with a custom-vault relayer | Subly's public vault and Farm. These are your signer's trust anchor (intents are validated against this local config, never the relayer's claims) — set them only to addresses you independently verified or control |
161
-
162
- Requests authenticate with a signature from your wallet key — there is no API
163
- token. `SUBLY_FACILITATOR_URL` is still accepted as a legacy fallback for
164
- `SUBLY_RELAYER_URL`. Spending is bounded twice: the client cap, and the
165
- relayer's server-side guard that refuses to realize anything beyond the
166
- spendable yield the deposited principal is never touched by a payment.
167
- (A plain `pay withdraw` is the exit path and may of course move principal
168
- back to your wallet.)
50
+ All amounts are raw USDC integers: `1000000` = 1 USDC. `fetch` defaults to a **0.01 USDC cap**, configurable with `SUBLY_MCP_MAX_AMOUNT_RAW_USDC` or `fetch <URL> <capRawUSDC>`. The owner mandate may set stricter limits. `setup-link --help` lists policy options. A withdrawal can include principal and is subject to liquidity, fees and the owner's policy. A revoked mandate also blocks relayer withdrawals.
51
+
52
+ A subsequent deposit/payment/withdrawal may return `approvalRequired` with an `approveUrl`. After the owner approves, retry the same operation with the returned `apr_...` as a trailing argument. Never automatically retry a transaction reported as submitted or an API payment with an unknown outcome.
53
+
54
+ ## MCP configuration
55
+
56
+ Add this to the MCP configuration of your editor or agent host. Replace all example values with your own absolute paths and endpoints. Pinning the version keeps upgrades explicit.
57
+
58
+ ```json
59
+ {
60
+ "mcpServers": {
61
+ "subly": {
62
+ "command": "npx",
63
+ "args": ["-y", "@subly_fi/pay@0.7.1", "mcp"],
64
+ "env": {
65
+ "SUBLY_RELAYER_URL": "https://your-relayer.example.com",
66
+ "SOLANA_RPC_URL": "https://your-mainnet-rpc.example.com",
67
+ "SUBLY_DEMO_AGENT_KEYPAIR_PATH": "/absolute/path/to/agent.json",
68
+ "SUBLY_MCP_STATE_PATH": "/absolute/path/to/subly-pending.json",
69
+ "SUBLY_MCP_MAX_AMOUNT_RAW_USDC": "10000"
70
+ }
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ Tools: `list_subly_vaults`, `select_subly_vault`, `create_subly_setup_link`, `check_subly_setup`, `deposit_to_subly_vault`, `get_subly_yield_budget`, `withdraw_from_subly_vault`, `fetch_with_subly_payment`. Ask the agent to list vaults and follow owner setup before depositing. Each selected vault has its own mandate and accounting; changing selection never moves funds. Stdio stdout is reserved for MCP messages.
77
+
78
+ ## Configuration
79
+
80
+ | Variable | Meaning |
81
+ | --- | --- |
82
+ | `SUBLY_RELAYER_URL` | Chosen operator's HTTPS URL. Set explicitly; the historical demo fallback has no availability promise. |
83
+ | `SOLANA_RPC_URL` | Your trusted mainnet RPC; fallback is the rate-limited public mainnet RPC. Used to verify lookup tables and simulate withdrawals before signing. |
84
+ | `SUBLY_DEMO_AGENT_KEYPAIR_PATH` | Local Solana 64-byte JSON keypair; the historical `DEMO` name also applies in production. |
85
+ | `SUBLY_DEMO_AGENT_KEYPAIR` | Alternative base58 64-byte secret; if set, takes precedence over the file. Avoid putting secrets in shell history. |
86
+ | `SUBLY_SIGNER_PROVIDER` | `local` (default), `circle` or `privy`. |
87
+ | `SUBLY_VAULTS_FILE` | Reviewed local vault catalogue. Without it, the built-in vault is used. |
88
+ | `SUBLY_VAULT_ADDRESS` | Selected catalogue entry (or custom single-vault address with matching share mint/farm settings). |
89
+ | `SUBLY_MCP_MAX_AMOUNT_RAW_USDC` | Client payment cap; default `10000`. |
90
+ | `SUBLY_MCP_STATE_PATH` | Persistent pending-payment file. Default `~/.subly/standard-x402-pending.json`. Use one shared file for all clients paying from the same wallet. |
91
+ | `SUBLY_PAY_METHOD` / `SUBLY_PAY_BODY` | Optional HTTP method and body for CLI `fetch`; MCP accepts these as tool arguments. |
92
+
93
+ For Circle configure `CIRCLE_API_KEY`, `CIRCLE_ENTITY_SECRET`, `CIRCLE_WALLET_ID`. For Privy use `PRIVY_APP_ID`, `PRIVY_APP_SECRET`, `PRIVY_WALLET_ID`, and `PRIVY_AUTHORIZATION_KEY` when required by wallet ownership. Each accepts a `SUBLY_` prefix which takes precedence. See [provider details](https://github.com/SublyFi/subly-payment-protocol/blob/main/docs/agent-wallet-providers.md).
94
+
95
+ Only sellers offering **Solana mainnet USDC `exact`** with `extra.feePayer` are supported. EVM, unsupported tokens and unsponsored rails are refused. A supported seller does not need a Subly integration. Yield realization and x402 payment are separate transactions: if the payment fails after realization, USDC may remain in the agent wallet.
96
+
97
+ ## Recovery and troubleshooting
98
+
99
+ - `doctor` performs read-only configuration, relayer/vault and RPC checks. It never signs or transacts; it does not prove vault safety or available yield.
100
+ - A withdrawal preview failure is a refusal to sign. Check your RPC's simulation support and liquidity; do not disable transaction validation.
101
+ - Preserve the pending-state JSON across restarts and upgrades. An `external_outcome_unknown` record blocks a second payment until you investigate the seller/facilitator outcome.
102
+ - Concurrent clients using the same state file serialize payments with a `.lock` file. After a crash, stop **all** clients using that file before removing only the stale `.lock`. Preserve the JSON. A new file or another machine cannot coordinate with the old one.
103
+ - `submitted` means the transaction may still confirm. Poll the original intent ID / transaction instead of preparing another deposit or withdrawal.
104
+ - Setup passkeys bind to the operator's domain. Use the original domain and device credential; follow the documented recovery delay if access is lost.
105
+
106
+ [Full troubleshooting](https://github.com/SublyFi/subly-payment-protocol/blob/main/docs/troubleshooting.md) · [Support](https://github.com/SublyFi/subly-payment-protocol/blob/main/SUPPORT.md) · [Private security reports](https://github.com/SublyFi/subly-payment-protocol/security/advisories/new)
107
+
108
+ ## Build from source
109
+
110
+ In the repository root: `npm ci`, then `npm ci --prefix packages/pay` and `npm run check --prefix packages/pay`. `npm run test:package` verifies a packed installation from outside the checkout, including the MCP handshake. The published package contains the client only; it does not include the relayer or Kamino server SDK.