@4mica/sdk 0.5.1 → 0.5.2
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 +251 -395
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,444 +1,300 @@
|
|
|
1
|
-
|
|
1
|
+
[](https://www.npmjs.com/package/@4mica/sdk)
|
|
2
|
+
[](LICENSE)
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
<a href="https://github.com/4mica-network/x402-4mica/actions/workflows/ci.yml">
|
|
5
|
-
<img src="https://github.com/4mica-network/x402-4mica/actions/workflows/ci.yml/badge.svg" alt="CI">
|
|
6
|
-
</a>
|
|
7
|
-
<a href="LICENSE">
|
|
8
|
-
<img src="https://img.shields.io/badge/License-MIT-green.svg" alt="License: MIT">
|
|
9
|
-
</a>
|
|
10
|
-
</p>
|
|
4
|
+
# 4Mica TypeScript SDK
|
|
11
5
|
|
|
12
|
-
|
|
13
|
-
open tabs, validate `X-PAYMENT` headers against their `paymentRequirements`, and settle by returning
|
|
14
|
-
the BLS certificate to the recipient.
|
|
6
|
+
The official TypeScript SDK for interacting with the 4Mica payment network.
|
|
15
7
|
|
|
8
|
+
## Overview
|
|
16
9
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- [Integrate from x402](#integrate-from-x402)
|
|
20
|
-
- [Run your own facilitator](#run-your-own-facilitator)
|
|
10
|
+
4Mica is a payment network that enables cryptographically-enforced lines of credit for autonomous
|
|
11
|
+
payments. This SDK provides:
|
|
21
12
|
|
|
22
|
-
|
|
13
|
+
- **User Client**: deposit collateral, sign payments, and manage withdrawals in ETH or ERC20 tokens
|
|
14
|
+
- **Recipient Client**: create payment tabs, verify payment guarantees, and claim from user collateral
|
|
15
|
+
- **X402 Flow Helper**: generate X-PAYMENT headers for 402-protected HTTP resources via an X402-compatible service
|
|
16
|
+
- **Admin RPCs**: manage user suspension and admin API keys (when authorized)
|
|
23
17
|
|
|
24
|
-
|
|
18
|
+
## Installation
|
|
25
19
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
```bash
|
|
21
|
+
npm install @4mica/sdk
|
|
22
|
+
# or
|
|
23
|
+
yarn add @4mica/sdk
|
|
24
|
+
```
|
|
30
25
|
|
|
31
|
-
|
|
26
|
+
Node.js 18+ is required.
|
|
32
27
|
|
|
33
|
-
|
|
28
|
+
## Initialization and Configuration
|
|
34
29
|
|
|
35
|
-
|
|
36
|
-
pip install sdk-4mica
|
|
37
|
-
```
|
|
30
|
+
The SDK requires a signing key and can use sensible defaults for the rest:
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
- `walletPrivateKey` (**required** unless `signer` is provided): private key used for signing
|
|
33
|
+
- `rpcUrl` (optional): URL of the 4Mica core RPC server. Defaults to `http://127.0.0.1:3000`.
|
|
34
|
+
- `ethereumHttpRpcUrl` (optional): Ethereum JSON-RPC endpoint; fetched from core if omitted
|
|
35
|
+
- `contractAddress` (optional): Core4Mica contract address; fetched from core if omitted
|
|
36
|
+
- `adminApiKey` (optional): API key for admin RPCs
|
|
37
|
+
- `bearerToken` (optional): static bearer token for auth
|
|
38
|
+
- `authUrl` and `authRefreshMarginSecs` (optional): SIWE auth config
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
> Note: `ethereumHttpRpcUrl` and `contractAddress` are fetched from the core service and validated
|
|
41
|
+
> against the connected Ethereum provider automatically. Only override these if you need to use
|
|
42
|
+
> different values than the server defaults.
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
cfg = ConfigBuilder().wallet_private_key(payer_key).rpc_url("https://api.4mica.xyz/").build()
|
|
48
|
-
client = await Client.new(cfg)
|
|
49
|
-
flow = X402Flow.from_client(client)
|
|
44
|
+
### 1) Using ConfigBuilder
|
|
50
45
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
requirements = PaymentRequirements.from_raw(req_raw)
|
|
46
|
+
```ts
|
|
47
|
+
import { Client, ConfigBuilder } from "@4mica/sdk";
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
async function main() {
|
|
50
|
+
const cfg = new ConfigBuilder()
|
|
51
|
+
.rpcUrl("https://api.4mica.xyz/")
|
|
52
|
+
.walletPrivateKey("0x...")
|
|
53
|
+
.build();
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
const client = await Client.new(cfg);
|
|
56
|
+
try {
|
|
57
|
+
// use client.user, client.recipient, client.rpc
|
|
58
|
+
} finally {
|
|
59
|
+
await client.aclose();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
### 2) Using Environment Variables
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
npm install sdk-4mica
|
|
66
|
-
```
|
|
66
|
+
Set environment variables:
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
```bash
|
|
69
|
+
export 4MICA_WALLET_PRIVATE_KEY="0x..."
|
|
70
|
+
export 4MICA_RPC_URL="https://api.4mica.xyz/"
|
|
71
|
+
export 4MICA_ETHEREUM_HTTP_RPC_URL="http://localhost:8545"
|
|
72
|
+
export 4MICA_CONTRACT_ADDRESS="0x..."
|
|
73
|
+
export 4MICA_ADMIN_API_KEY="ak_..."
|
|
74
|
+
export 4MICA_BEARER_TOKEN="Bearer <access_token>"
|
|
75
|
+
export 4MICA_AUTH_URL="https://api.4mica.xyz/"
|
|
76
|
+
export 4MICA_AUTH_REFRESH_MARGIN_SECS="60"
|
|
77
|
+
```
|
|
70
78
|
|
|
71
|
-
|
|
72
|
-
const cfg = new ConfigBuilder().walletPrivateKey("0x...").build();
|
|
73
|
-
const client = await Client.new(cfg);
|
|
74
|
-
const flow = X402Flow.fromClient(client);
|
|
79
|
+
Then in code:
|
|
75
80
|
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
```ts
|
|
82
|
+
import { Client, ConfigBuilder } from "@4mica/sdk";
|
|
78
83
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
84
|
+
const cfg = new ConfigBuilder().fromEnv().build();
|
|
85
|
+
const client = await Client.new(cfg);
|
|
86
|
+
```
|
|
83
87
|
|
|
84
|
-
|
|
85
|
-
```
|
|
88
|
+
### 3) Using a Custom Signer
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
If you want to integrate with a custom signer (hardware wallet, remote signer, etc.), provide an
|
|
91
|
+
`EvmSigner` implementation. It must expose `address`, `signTypedData`, and `signMessage`.
|
|
88
92
|
|
|
89
|
-
|
|
90
|
-
|
|
93
|
+
```ts
|
|
94
|
+
import { Client, ConfigBuilder, createLocalSigner } from "@4mica/sdk";
|
|
91
95
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
.build();
|
|
96
|
+
const signer = createLocalSigner(process.env.PAYER_KEY!);
|
|
97
|
+
const cfg = new ConfigBuilder().signer(signer).build();
|
|
98
|
+
const client = await Client.new(cfg);
|
|
99
|
+
```
|
|
97
100
|
|
|
98
|
-
|
|
99
|
-
await client.login(); // optional: first RPC call also triggers auth
|
|
100
|
-
```
|
|
101
|
+
### SIWE Auth (Optional)
|
|
101
102
|
|
|
102
|
-
|
|
103
|
+
Enable automatic SIWE auth refresh, or pass a static bearer token:
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
```ts
|
|
106
|
+
import { Client, ConfigBuilder } from "@4mica/sdk";
|
|
107
|
+
|
|
108
|
+
const cfg = new ConfigBuilder()
|
|
109
|
+
.walletPrivateKey("0x...")
|
|
110
|
+
.rpcUrl("https://api.4mica.xyz/")
|
|
111
|
+
.enableAuth()
|
|
112
|
+
.build();
|
|
113
|
+
|
|
114
|
+
const client = await Client.new(cfg);
|
|
115
|
+
await client.login(); // optional: first RPC call also triggers auth
|
|
116
|
+
```
|
|
110
117
|
|
|
111
|
-
|
|
118
|
+
Or use a static token:
|
|
112
119
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
120
|
+
```ts
|
|
121
|
+
const cfg = new ConfigBuilder()
|
|
122
|
+
.walletPrivateKey("0x...")
|
|
123
|
+
.bearerToken("Bearer <access_token>")
|
|
124
|
+
.build();
|
|
125
|
+
```
|
|
116
126
|
|
|
117
|
-
|
|
127
|
+
Env vars: `4MICA_BEARER_TOKEN`, `4MICA_AUTH_URL`, `4MICA_AUTH_REFRESH_MARGIN_SECS`.
|
|
118
128
|
|
|
119
|
-
|
|
120
|
-
paywalled endpoint. Start it with `python examples/server/mock_paid_api.py` (set `PORT` to override
|
|
121
|
-
the default `9000`). The mock resource will call the facilitator’s `/verify` endpoint (defaulting to
|
|
122
|
-
`https://x402.4mica.xyz/`; override with `FACILITATOR_URL`) whenever it receives an `X-PAYMENT`
|
|
123
|
-
header.
|
|
129
|
+
## Usage
|
|
124
130
|
|
|
125
|
-
The
|
|
126
|
-
header with `rust-sdk-4mica`:
|
|
131
|
+
The SDK exposes three main entry points:
|
|
127
132
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
```
|
|
133
|
+
- `client.user`: payer-side operations (collateral, signing, withdrawals)
|
|
134
|
+
- `client.recipient`: recipient-side operations (tabs, guarantees, remuneration)
|
|
135
|
+
- `X402Flow`: helper for 402-protected HTTP resources
|
|
132
136
|
|
|
133
|
-
|
|
134
|
-
Python counterpart lives in `examples/python_client/client.py` (install deps with `pip install -r
|
|
135
|
-
examples/python_client/requirements.txt`). A TypeScript version lives in `examples/ts_client`
|
|
136
|
-
(`npm install && npm start`).
|
|
137
|
-
|
|
138
|
-
### X-PAYMENT header schema
|
|
139
|
-
|
|
140
|
-
`X-PAYMENT` must be a base64-encoded JSON envelope:
|
|
141
|
-
|
|
142
|
-
```json
|
|
143
|
-
{
|
|
144
|
-
"x402Version": 1,
|
|
145
|
-
"scheme": "4mica-credit",
|
|
146
|
-
"network": "polygon-amoy",
|
|
147
|
-
"payload": {
|
|
148
|
-
"claims": {
|
|
149
|
-
"user_address": "<0x-prefixed checksum string>",
|
|
150
|
-
"recipient_address": "<0x-prefixed checksum string>",
|
|
151
|
-
"tab_id": "<decimal or 0x value>",
|
|
152
|
-
"req_id": "<decimal or 0x value>",
|
|
153
|
-
"amount": "<decimal or 0x value>",
|
|
154
|
-
"asset_address": "<0x-prefixed checksum string>",
|
|
155
|
-
"timestamp": 1716500000,
|
|
156
|
-
"version": "v1"
|
|
157
|
-
},
|
|
158
|
-
"signature": "<0x-prefixed wallet signature>",
|
|
159
|
-
"scheme": "eip712"
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
```
|
|
137
|
+
### X402 flow (HTTP 402)
|
|
163
138
|
|
|
164
|
-
The
|
|
165
|
-
|
|
166
|
-
- `scheme` / `network` match both `/supported` and the resource server’s requirements.
|
|
167
|
-
- `payTo` equals the `recipient_address` present inside the claim.
|
|
168
|
-
- `asset` and `maxAmountRequired` must match the signed `amount` exactly (no partial spends).
|
|
169
|
-
- If `X402_GUARANTEE_DOMAIN` is set (legacy `FOUR_MICA_GUARANTEE_DOMAIN` / `4MICA_GUARANTEE_DOMAIN`
|
|
170
|
-
are also honored), the certificate domain returned by core matches it exactly.
|
|
171
|
-
|
|
172
|
-
### HTTP API
|
|
173
|
-
|
|
174
|
-
- `GET /supported` – returns all `(scheme, network)` tuples the facilitator can service (4mica and,
|
|
175
|
-
if configured, any additional `exact` flows).
|
|
176
|
-
- `GET /health` – liveness probe that returns `{ "status": "ok" }`.
|
|
177
|
-
- `POST /tabs`
|
|
178
|
-
- Request: `{ "userAddress", "recipientAddress", "erc20Token"?, "ttlSeconds"? }`.
|
|
179
|
-
Use `erc20Token = null` (or omit it) for ETH tabs; otherwise pass the token contract address.
|
|
180
|
-
- Response: `{ "tabId", "userAddress", "recipientAddress", "assetAddress", "startTimestamp", "ttlSeconds", "nextReqId"? }`.
|
|
181
|
-
`tabId` is always emitted as a canonical hex string. Recipients call this after a user shares
|
|
182
|
-
their wallet; the facilitator reuses the existing tab for that pair whenever possible.
|
|
183
|
-
- `POST /verify`
|
|
184
|
-
- Request: `{ "x402Version": 1, "paymentHeader": "<base64 X-PAYMENT>", "paymentRequirements": { ... } }`.
|
|
185
|
-
- Response: `{ "isValid": true|false, "invalidReason"?, "certificate": null }`.
|
|
186
|
-
- `POST /settle`
|
|
187
|
-
- Request: same shape as `/verify`.
|
|
188
|
-
- Response: for 4mica, `{ "success": true, "networkId": "<network>", "certificate": { "claims", "signature" } }`.
|
|
189
|
-
When delegating to the `exact` facilitator the structure mirrors upstream x402 responses and may
|
|
190
|
-
include `txHash`.
|
|
191
|
-
If `X402_DEBIT_URL` is set, debit requests are proxied to the configured x402-rs
|
|
192
|
-
facilitator, allowing clients to follow the x402 debit flow unchanged.
|
|
193
|
-
|
|
194
|
-
### End-to-end credit flow
|
|
195
|
-
|
|
196
|
-
The sequence below highlights each HTTP request, who sends it, and how data travels through
|
|
197
|
-
x402-4mica and the 4mica core service.
|
|
198
|
-
|
|
199
|
-
1. **Client discovers the paywall**
|
|
200
|
-
- Client → Recipient resource: request protected content.
|
|
201
|
-
- Recipient → Client: `402 Payment Required` that advertises the supported `(scheme, network)`
|
|
202
|
-
and instructs the client where to request a payment tab (for example, `POST /tab` with their
|
|
203
|
-
wallet address). No per-user data is known yet.
|
|
204
|
-
2. **Client requests a tab**
|
|
205
|
-
- Client → Recipient resource: `POST /tab` (or an equivalent endpoint) with their
|
|
206
|
-
`{ userAddress, erc20Token?, ttlSeconds? }`.
|
|
207
|
-
- Recipient → Facilitator: `POST /tabs` using the supplied body. The facilitator will reuse the
|
|
208
|
-
existing tab for that `(user, recipient, asset)` combination or create a fresh one.
|
|
209
|
-
- Facilitator → 4mica core: `POST core/tabs` whenever a new tab is required.
|
|
210
|
-
- Facilitator → Recipient: `{ tabId, userAddress, recipientAddress, assetAddress, startTimestamp, ttlSeconds }`.
|
|
211
|
-
Recipients cache this tab and reuse it until expiry, then hand `tabId`/`userAddress` back to
|
|
212
|
-
the client inside `paymentRequirements`.
|
|
213
|
-
3. **Client signs a guarantee**
|
|
214
|
-
- Client builds the JSON payload that matches the resource requirements, signs it with their
|
|
215
|
-
private key (EIP‑712 by default; EIP‑191 is also accepted), and wraps the result in a base64
|
|
216
|
-
`X-PAYMENT` header.
|
|
217
|
-
4. **Client retries the protected call**
|
|
218
|
-
- Client → Recipient resource: same HTTP request plus `X-PAYMENT: <base64 envelope>`.
|
|
219
|
-
5. **Recipient verifies the header**
|
|
220
|
-
- Recipient → Facilitator: `POST /verify` with
|
|
221
|
-
`{ x402Version, paymentHeader, paymentRequirements }`.
|
|
222
|
-
- Facilitator: decodes `paymentHeader`, ensures `scheme`/`network` match `/supported`, confirms
|
|
223
|
-
the claims reference the advertised tab, user, asset, `payTo`, and that `amount` exactly equals
|
|
224
|
-
`maxAmountRequired`.
|
|
225
|
-
- Facilitator → Recipient: `{ isValid, invalidReason?, certificate: null }`. No request touches
|
|
226
|
-
4mica core here; this is purely structural validation so recipients can pre-flight calls.
|
|
227
|
-
6. **Recipient settles the tab**
|
|
228
|
-
- Recipient → Facilitator: `POST /settle` with the same payload.
|
|
229
|
-
- Facilitator: revalidates the header, then
|
|
230
|
-
- sends `POST core/guarantees` with `{ claims, signature, scheme }` where `claims` contains the
|
|
231
|
-
tab id, user, recipient, asset, amount, and timestamp (plus a version field injected by the
|
|
232
|
-
facilitator),
|
|
233
|
-
- receives a BLS signature over those claims,
|
|
234
|
-
- verifies the certificate by reusing the public parameters fetched at startup, rejecting the
|
|
235
|
-
settlement if the signature or expected domain fail to match.
|
|
236
|
-
- Facilitator → Recipient: `{ success, networkId, certificate, error: null, txHash: null }`.
|
|
237
|
-
`certificate.claims` and `certificate.signature` are byte strings that recipients can persist or
|
|
238
|
-
pass to downstream infrastructure as proof of credit issuance. If the request belonged to a
|
|
239
|
-
delegated `exact` scheme the facilitator instead forwards the settlement to x402-rs and returns
|
|
240
|
-
that response (which may contain a `txHash` instead of a certificate).
|
|
241
|
-
|
|
242
|
-
## Integrate from x402
|
|
243
|
-
|
|
244
|
-
The facilitator can transparently replace the EIP-3009/x402 debit flow. The key is to swap the old
|
|
245
|
-
`exact` scheme for the 4mica credit primitives described below.
|
|
246
|
-
|
|
247
|
-
### Changes resource servers must make
|
|
248
|
-
|
|
249
|
-
1. **Point at the credit facilitator** – set `X402_FACILITATOR_URL=https://x402.4mica.xyz`
|
|
250
|
-
(or the TypeScript `CC_FACILITATOR_URL`). This host validates guarantee envelopes and returns BLS
|
|
251
|
-
certificates instead of ERC-3009 receipts.
|
|
252
|
-
2. **Provision tabs before issuing requirements** – whenever a user shares their wallet, call
|
|
253
|
-
`POST https://x402.4mica.xyz/tabs` with `{ userAddress, recipientAddress, erc20Token?, ttlSeconds? }`.
|
|
254
|
-
Cache `{ tabId, assetAddress, startTimestamp, ttlSeconds }` and reuse that tab per
|
|
255
|
-
`(user, recipient, asset)` combination.
|
|
256
|
-
3. **Emit credit-flavoured `paymentRequirements`** – embed the latest tab metadata and switch the
|
|
257
|
-
identifying strings:
|
|
258
|
-
|
|
259
|
-
```jsonc
|
|
260
|
-
{
|
|
261
|
-
"scheme": "4mica-credit",
|
|
262
|
-
"network": "polygon-amoy",
|
|
263
|
-
"maxAmountRequired": "<decimal or 0x amount>",
|
|
264
|
-
"resource": "/your/resource",
|
|
265
|
-
"description": "Describe the protected work",
|
|
266
|
-
"mimeType": "application/json",
|
|
267
|
-
"payTo": "<recipientAddress>",
|
|
268
|
-
"maxTimeoutSeconds": 300,
|
|
269
|
-
"asset": "<assetAddress>",
|
|
270
|
-
"extra": {
|
|
271
|
-
"tabEndpoint": "<tabEndpoint>",
|
|
272
|
-
"...other metadata you already add..."
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
The facilitator enforces that `scheme`, `network`, `payTo` and `asset`
|
|
278
|
-
match the tab exactly, so keep them synchronized.
|
|
279
|
-
|
|
280
|
-
4. **Expect credit certificates during settlement** – `/verify` still performs structural checks and
|
|
281
|
-
`/settle` now returns `{ success, networkId: "polygon-amoy", certificate: { claims, signature } }`.
|
|
282
|
-
Persist the certificate if you need to downstream claim remuneration via 4mica core.
|
|
283
|
-
|
|
284
|
-
### Changes clients (payers) must make
|
|
285
|
-
|
|
286
|
-
Payers sign guarantees instead of EIP-3009 transfers. Use the official SDK `rust-sdk-4mica` to manage collateral and produce signatures.
|
|
287
|
-
|
|
288
|
-
1. **Install the SDK** – inside your agent crate run
|
|
289
|
-
|
|
290
|
-
```bash
|
|
291
|
-
cargo add rust-sdk-4mica
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
or add the same entry manually to `Cargo.toml`.
|
|
295
|
-
|
|
296
|
-
2. **Configure the client** – create a `Client` with the payer’s signing key. The SDK pulls the
|
|
297
|
-
remaining parameters (domain separator, operator key, etc.) from `X402_CORE_API_URL`.
|
|
298
|
-
|
|
299
|
-
```rust
|
|
300
|
-
use rust_sdk_4mica::{Client, ConfigBuilder};
|
|
301
|
-
|
|
302
|
-
let config = ConfigBuilder::default()
|
|
303
|
-
.rpc_url("https://api.4mica.xyz/".into())
|
|
304
|
-
.wallet_private_key(std::env::var("PAYER_KEY")?)
|
|
305
|
-
.build()?;
|
|
306
|
-
let client = Client::new(config).await?;
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
3. **Fund the tab** – before requesting credit, ensure the payer has collateral using
|
|
310
|
-
`client.user.deposit(...)` (or `approve_erc20` + `deposit` for tokens). Refer to the SDK README
|
|
311
|
-
for concrete examples.
|
|
312
|
-
4. **Sign guarantee claims** – derive `PaymentGuaranteeClaims` from the recipient’s
|
|
313
|
-
`paymentRequirements` (copy `tabId`, `userAddress`, `payTo`, `asset`, and the desired `amount`),
|
|
314
|
-
choose a signing scheme (usually `SigningScheme::Eip712`), and call `client.user.sign_payment`.
|
|
315
|
-
|
|
316
|
-
```rust
|
|
317
|
-
use rust_sdk_4mica::{PaymentGuaranteeClaims, SigningScheme, U256};
|
|
318
|
-
|
|
319
|
-
let claims = PaymentGuaranteeClaims {
|
|
320
|
-
user_address: payer_wallet.clone(),
|
|
321
|
-
recipient_address: pay_to.clone(),
|
|
322
|
-
tab_id: tab_id_u256,
|
|
323
|
-
amount: U256::from(amount_wei),
|
|
324
|
-
asset_address: asset.clone(),
|
|
325
|
-
timestamp: chrono::Utc::now().timestamp() as u64,
|
|
326
|
-
req_id: U256::from(rand::random::<u64>()),
|
|
327
|
-
};
|
|
328
|
-
let signature = client
|
|
329
|
-
.user
|
|
330
|
-
.sign_payment(claims.clone(), SigningScheme::Eip712)
|
|
331
|
-
.await?;
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
5. **Build the `X-PAYMENT` header** – wrap `{ x402Version: 1, scheme: "4mica-credit", network:
|
|
335
|
-
"polygon-amoy", payload: { claims, signature, scheme: "eip712" } }` into base64 (see
|
|
336
|
-
`examples/rust_client/main.rs` or `examples/python_client/client.py`) and send it alongside the retrying
|
|
337
|
-
HTTP request.
|
|
338
|
-
6. **Settle your tabs** – every tab response includes `ttlSeconds`, which is the settlement window in
|
|
339
|
-
seconds from `startTimestamp`. Recipients should call `/settle` (and issue the guarantee) before
|
|
340
|
-
that TTL lapses; once a certificate comes back they must relay the `tabId`, `reqId`, `amount`, and
|
|
341
|
-
`asset` to the payer. Payers are expected to clear the balance within the same TTL window to avoid
|
|
342
|
-
the recipient redeeming their collateral. Use the SDK’s `UserClient::pay_tab` helper to repay the
|
|
343
|
-
outstanding credit with the exact asset used when the tab was opened:
|
|
344
|
-
|
|
345
|
-
```rust
|
|
346
|
-
use rust_sdk_4mica::U256;
|
|
347
|
-
|
|
348
|
-
let receipt = client
|
|
349
|
-
.user
|
|
350
|
-
.pay_tab(tab_id, req_id, U256::from(amount_wei), recipient_address.clone(), erc20_token)
|
|
351
|
-
.await?;
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
After broadcasting the repayment transaction, poll `client.user.get_tab_payment_status(tab_id)`
|
|
355
|
-
(or `client.user.get_user()`) to verify that `paid` equals the guaranteed amount. If the TTL
|
|
356
|
-
expires without repayment the recipient is free to run `recipient.remunerate(cert)` from the SDK,
|
|
357
|
-
which slashes your posted collateral on-chain.
|
|
358
|
-
|
|
359
|
-
## Run your own facilitator
|
|
360
|
-
|
|
361
|
-
### Configuration
|
|
362
|
-
|
|
363
|
-
Environment variables (defaults shown):
|
|
139
|
+
The X402 helper turns `paymentRequirements` from a `402 Payment Required` response into an
|
|
140
|
+
X-PAYMENT header (and optional `/settle` call) that the facilitator will accept.
|
|
364
141
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
142
|
+
#### What the SDK expects from `paymentRequirements`
|
|
143
|
+
|
|
144
|
+
At minimum you need:
|
|
145
|
+
- `scheme` and `network` (scheme must include `4mica`, e.g. `4mica-credit`)
|
|
146
|
+
- `extra.tabEndpoint` for tab resolution
|
|
147
|
+
|
|
148
|
+
`X402Flow` will refresh the tab by calling `extra.tabEndpoint` before signing.
|
|
149
|
+
|
|
150
|
+
#### X402 Version 1
|
|
151
|
+
|
|
152
|
+
Version 1 returns payment requirements in the JSON response body:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { Client, ConfigBuilder, X402Flow } from "@4mica/sdk";
|
|
156
|
+
import type { PaymentRequirementsV1 } from "@4mica/sdk";
|
|
157
|
+
|
|
158
|
+
type ResourceResponse = {
|
|
159
|
+
x402Version: number;
|
|
160
|
+
accepts: PaymentRequirementsV1[];
|
|
161
|
+
error?: string;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const cfg = new ConfigBuilder().walletPrivateKey("0x...").build();
|
|
165
|
+
const client = await Client.new(cfg);
|
|
166
|
+
const flow = X402Flow.fromClient(client);
|
|
167
|
+
|
|
168
|
+
// 1) GET the protected endpoint and parse JSON body
|
|
169
|
+
const res = await fetch("https://resource-url/resource");
|
|
170
|
+
const body = (await res.json()) as ResourceResponse;
|
|
171
|
+
|
|
172
|
+
// 2) Select a payment option
|
|
173
|
+
const requirements = body.accepts[0];
|
|
174
|
+
|
|
175
|
+
// 3) Build the X-PAYMENT header with the SDK
|
|
176
|
+
const payment = await flow.signPayment(requirements, "0xUser");
|
|
177
|
+
|
|
178
|
+
// 4) Call the protected resource with the header
|
|
179
|
+
await fetch("https://resource-url/resource", {
|
|
180
|
+
headers: { "X-PAYMENT": payment.header },
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
await client.aclose();
|
|
391
184
|
```
|
|
392
185
|
|
|
393
|
-
|
|
394
|
-
environment variables and enables multi-network support. Each configured network gets its own 4mica
|
|
395
|
-
Core API base URL so the facilitator can fetch operator parameters and issue guarantees for that
|
|
396
|
-
network independently.
|
|
186
|
+
#### X402 Version 2
|
|
397
187
|
|
|
398
|
-
|
|
399
|
-
variables are present, initialises the upstream `exact` ERC-3009 facilitator as well. Any schemes
|
|
400
|
-
that fail to initialise are omitted from `/supported`.
|
|
401
|
-
When `X402_DEBIT_URL` is provided, `/supported` also includes the debit schemes advertised by
|
|
402
|
-
the referenced x402-rs facilitator, and `/verify` / `/settle` proxy those requests to it.
|
|
188
|
+
Version 2 uses the `payment-required` header (base64-encoded) instead of a JSON response body:
|
|
403
189
|
|
|
404
|
-
|
|
190
|
+
```ts
|
|
191
|
+
import { Client, ConfigBuilder, X402Flow } from "@4mica/sdk";
|
|
192
|
+
import type { X402PaymentRequired, PaymentRequirementsV2 } from "@4mica/sdk";
|
|
405
193
|
|
|
406
|
-
|
|
407
|
-
|
|
194
|
+
const cfg = new ConfigBuilder().walletPrivateKey("0x...").build();
|
|
195
|
+
const client = await Client.new(cfg);
|
|
196
|
+
const flow = X402Flow.fromClient(client);
|
|
197
|
+
|
|
198
|
+
// 1) GET the protected endpoint and extract payment-required header
|
|
199
|
+
const res = await fetch("https://resource-url/resource");
|
|
200
|
+
const header = res.headers.get("payment-required");
|
|
201
|
+
if (!header) throw new Error("Missing payment-required header");
|
|
202
|
+
|
|
203
|
+
// 2) Decode the header
|
|
204
|
+
const decoded = Buffer.from(header, "base64").toString("utf8");
|
|
205
|
+
const paymentRequired = JSON.parse(decoded) as X402PaymentRequired;
|
|
206
|
+
|
|
207
|
+
// 3) Select a payment option
|
|
208
|
+
const accepted = paymentRequired.accepts[0] as PaymentRequirementsV2;
|
|
209
|
+
|
|
210
|
+
// 4) Build the PAYMENT-SIGNATURE header with the SDK
|
|
211
|
+
const signed = await flow.signPaymentV2(paymentRequired, accepted, "0xUser");
|
|
212
|
+
|
|
213
|
+
// 5) Call the protected resource with the header
|
|
214
|
+
await fetch("https://resource-url/resource", {
|
|
215
|
+
headers: { "PAYMENT-SIGNATURE": signed.header },
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
await client.aclose();
|
|
408
219
|
```
|
|
409
220
|
|
|
410
|
-
|
|
411
|
-
that resource servers should use inside their `402 Payment Required` responses.
|
|
221
|
+
#### Resource server / facilitator side
|
|
412
222
|
|
|
413
|
-
|
|
223
|
+
If your resource server proxies to the facilitator, you can reuse the SDK to settle after
|
|
224
|
+
verifying:
|
|
414
225
|
|
|
415
|
-
```
|
|
416
|
-
|
|
226
|
+
```ts
|
|
227
|
+
import { Client, ConfigBuilder, X402Flow } from "@4mica/sdk";
|
|
228
|
+
import type { PaymentRequirementsV1, X402SignedPayment } from "@4mica/sdk";
|
|
229
|
+
|
|
230
|
+
async function settle(
|
|
231
|
+
facilitatorUrl: string,
|
|
232
|
+
paymentRequirements: PaymentRequirementsV1,
|
|
233
|
+
payment: X402SignedPayment
|
|
234
|
+
) {
|
|
235
|
+
const core = await Client.new(
|
|
236
|
+
new ConfigBuilder().walletPrivateKey(process.env.RESOURCE_SIGNER_KEY!).build()
|
|
237
|
+
);
|
|
238
|
+
const flow = X402Flow.fromClient(core);
|
|
239
|
+
|
|
240
|
+
const settled = await flow.settlePayment(payment, paymentRequirements, facilitatorUrl);
|
|
241
|
+
console.log("settlement result:", settled.settlement);
|
|
242
|
+
|
|
243
|
+
await core.aclose();
|
|
244
|
+
}
|
|
417
245
|
```
|
|
418
246
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
247
|
+
Notes:
|
|
248
|
+
- `signPayment` and `signPaymentV2` always use EIP-712 signing and will error if the scheme is not 4mica.
|
|
249
|
+
- `settlePayment` only hits `/settle`; resource servers should still call `/verify` first when enforcing access.
|
|
250
|
+
|
|
251
|
+
### API Methods Summary
|
|
252
|
+
|
|
253
|
+
#### UserClient Methods
|
|
254
|
+
|
|
255
|
+
- `approveErc20(token, amount)`
|
|
256
|
+
- `deposit(amount, erc20Token?)`
|
|
257
|
+
- `getUser()`
|
|
258
|
+
- `getTabPaymentStatus(tabId)`
|
|
259
|
+
- `signPayment(claims, scheme?)`
|
|
260
|
+
- `payTab(tabId, reqId, amount, recipientAddress, erc20Token?)`
|
|
261
|
+
- `requestWithdrawal(amount, erc20Token?)`
|
|
262
|
+
- `cancelWithdrawal(erc20Token?)`
|
|
263
|
+
- `finalizeWithdrawal(erc20Token?)`
|
|
264
|
+
|
|
265
|
+
#### RecipientClient Methods
|
|
266
|
+
|
|
267
|
+
- `createTab(userAddress, recipientAddress, erc20Token?, ttl?)`
|
|
268
|
+
- `getTabPaymentStatus(tabId)`
|
|
269
|
+
- `issuePaymentGuarantee(claims, signature, scheme)`
|
|
270
|
+
- `verifyPaymentGuarantee(cert)`
|
|
271
|
+
- `remunerate(cert)`
|
|
272
|
+
- `listSettledTabs()`
|
|
273
|
+
- `listPendingRemunerations()`
|
|
274
|
+
- `getTab(tabId)`
|
|
275
|
+
- `listRecipientTabs(settlementStatuses?)`
|
|
276
|
+
- `getTabGuarantees(tabId)`
|
|
277
|
+
- `getLatestGuarantee(tabId)`
|
|
278
|
+
- `getGuarantee(tabId, reqId)`
|
|
279
|
+
- `listRecipientPayments()`
|
|
280
|
+
- `getCollateralEventsForTab(tabId)`
|
|
281
|
+
- `getUserAssetBalance(userAddress, assetAddress)`
|
|
282
|
+
|
|
283
|
+
#### Admin / RPC Methods
|
|
284
|
+
|
|
285
|
+
Available under `client.rpc` (requires an admin API key):
|
|
286
|
+
|
|
287
|
+
- `updateUserSuspension(userAddress, suspended)`
|
|
288
|
+
- `createAdminApiKey({ name, scopes })`
|
|
289
|
+
- `listAdminApiKeys()`
|
|
290
|
+
- `revokeAdminApiKey(keyId)`
|
|
291
|
+
|
|
292
|
+
## Error Handling
|
|
293
|
+
|
|
294
|
+
All SDK errors extend `FourMicaError`. Common error types include `ConfigError`, `RpcError`,
|
|
295
|
+
`ClientInitializationError`, `ContractError`, `SigningError`, `VerificationError`, `X402Error`, and
|
|
296
|
+
`AuthError`.
|
|
297
|
+
|
|
298
|
+
## License
|
|
299
|
+
|
|
300
|
+
MIT
|