envoy-pay 0.1.0 → 0.2.0
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/CHANGELOG.md +11 -4
- package/README.md +46 -6
- package/dist/cjs/server/index.js +3 -1
- package/dist/cjs/server/index.js.map +1 -1
- package/dist/cjs/server/verify-onchain.js +190 -0
- package/dist/cjs/server/verify-onchain.js.map +1 -0
- package/dist/cjs/server/x402-gate.js +10 -0
- package/dist/cjs/server/x402-gate.js.map +1 -1
- package/dist/esm/server/index.js +1 -0
- package/dist/esm/server/index.js.map +1 -1
- package/dist/esm/server/verify-onchain.js +187 -0
- package/dist/esm/server/verify-onchain.js.map +1 -0
- package/dist/esm/server/x402-gate.js +10 -0
- package/dist/esm/server/x402-gate.js.map +1 -1
- package/dist/types/server/index.d.ts +1 -0
- package/dist/types/server/index.d.ts.map +1 -1
- package/dist/types/server/verify-onchain.d.ts +96 -0
- package/dist/types/server/verify-onchain.d.ts.map +1 -0
- package/dist/types/server/x402-gate.d.ts +7 -1
- package/dist/types/server/x402-gate.d.ts.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,11 +4,13 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
For the dated decision journal behind these changes, see [`docs/BUILD_LOG.md`](docs/BUILD_LOG.md).
|
|
6
6
|
|
|
7
|
-
## [0.
|
|
7
|
+
## [0.2.0] — 2026-06-07
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The Celo-first re-imagining of the SDK with a real on-chain layer. Headlining this release: server-side on-chain settlement verification (`createOnchainVerifier`) and a formal security policy (`SECURITY.md`). Targets Celo Sepolia (testnet) and Celo mainnet.
|
|
10
10
|
|
|
11
11
|
### Added
|
|
12
|
+
- **`createOnchainVerifier(...)`** (`envoy-pay/server`) — a ready-made `verifyPayment` for `createX402Gate` that confirms an x402 proof maps to a real on-chain `EnvoyFacilitator` `Settled` event: checks the tx succeeded, paid the right merchant in the right token for at least the asking amount, replay-guards each `challengeId`, and optionally requires an ERC-8004 capability. Promotes the autonomous-loop example's verification into the SDK so production gates don't re-implement it. Pluggable `ReplayStore` for multi-instance deployments. (12-test suite, `verify-onchain.test.ts`.)
|
|
13
|
+
- **`SECURITY.md`** — security policy: pre-1.0 / unaudited status, on-chain trust model, deployed-contract list, the `verifyPayment` requirement, a production hardening checklist, and private vulnerability reporting.
|
|
12
14
|
- Scaffold forked from `ASGCompute-ows-agent-pay`, restructured around Celo as the first-class chain
|
|
13
15
|
- **`EnvoyFacilitator.sol`** — single on-chain payment contract that consumes an EIP-712 `PaymentAuth` from the agent's wallet, validates the signer against canonical ERC-8004 `getAgentWallet(agentId)`, enforces per-(agent, token) rolling-window spending limits atomically, splits the amount into net (→ merchant) and fee (→ treasury), and emits a `Settled(challengeId, agentId, merchant, …)` event. Strict CEI, custom errors, `ReentrancyGuardTransient`, ERC-1271 fallback for smart-wallet agents, zero internal balance (contract never holds funds).
|
|
14
16
|
- `MockIdentityRegistry.sol` + `MockSmartWallet.sol` test fixtures
|
|
@@ -22,6 +24,7 @@ This release is the Celo-first re-imagining of the SDK with a real on-chain laye
|
|
|
22
24
|
- `docs/BUILD_LOG.md` capturing the dated decision trail (architecture, demo, ERC-8004 interface notes, Facilitator design rationale, SDK design rationale)
|
|
23
25
|
|
|
24
26
|
### Changed
|
|
27
|
+
- **`createX402Gate` now warns when no settlement verification is configured.** Its built-in checks only confirm a proof is well-formed, not that it settled on-chain — so without `verifyPayment` (or `facilitatorUrl`) it logs a one-time security warning at gate creation. Pass `allowUnverified: true` to acknowledge and silence it (demo/testnet/trusted-upstream only). Non-breaking.
|
|
25
28
|
- **Testnet target switched from Celo Alfajores → Celo Sepolia** (chainId `11142220`). The canonical Celo ERC-8004 contracts are deployed on Sepolia; Alfajores is no longer a build target. `hardhat.config.ts` updated accordingly.
|
|
26
29
|
- Top-level + `contracts/` READMEs updated to reflect the lean architecture (one on-chain payment layer + canonical ERC-8004 delegation)
|
|
27
30
|
- **`src/contracts/addresses.ts`** rewritten: `EnvoyContractAddresses` shape is now `{ facilitator, identityRegistry, reputationRegistry }` (was four snowflake fields). Canonical 8004 addresses are baked in for both Celo mainnet (42220) and Celo Sepolia (11142220). New `CELO_MAINNET` / `CELO_SEPOLIA` chain-id constants exported.
|
|
@@ -33,11 +36,15 @@ This release is the Celo-first re-imagining of the SDK with a real on-chain laye
|
|
|
33
36
|
- SDK exports `AgentRegistryClient`, `createAgentRegistry`, `ReputationClient`, `createReputation`, `EscrowClient`, `createEscrow`, `PolicyGuardClient`, `createPolicyGuard`, the four `ENVOY_*_ABI` exports, and their types — viem wrappers moved to `src/contracts/_legacy/` pending replacement with a single `EnvoyFacilitator` client + canonical ERC-8004 helpers.
|
|
34
37
|
- `examples/celo-agent-identity.ts` and `examples/celo-escrow.ts` archived to `examples/_legacy/` (both referenced removed contracts).
|
|
35
38
|
|
|
36
|
-
###
|
|
37
|
-
-
|
|
39
|
+
### Deployed
|
|
40
|
+
- **`EnvoyFacilitator` is live on Celo mainnet** (chainId `42220`) at [`0xE268B6fE16319b49D22562C93c0d2395F65FCAcC`](https://celoscan.io/address/0xE268B6fE16319b49D22562C93c0d2395F65FCAcC), wired into `src/contracts/addresses.ts` alongside the canonical ERC-8004 Identity/Reputation registries.
|
|
38
41
|
|
|
39
42
|
---
|
|
40
43
|
|
|
44
|
+
## Pre-fork history
|
|
45
|
+
|
|
46
|
+
_The versions below are from the upstream project (`ASGCompute-ows-agent-pay`) that envoy was forked from, retained for provenance. envoy's npm lineage is the entries above (`0.1.0` → `0.2.0`)._
|
|
47
|
+
|
|
41
48
|
## [0.2.0] — 2026-04-04
|
|
42
49
|
|
|
43
50
|
### 🚀 Pay In Infrastructure (NEW)
|
package/README.md
CHANGED
|
@@ -65,7 +65,7 @@ AI agents are the new workforce, but payments are built for humans. An agent can
|
|
|
65
65
|
npm install envoy-pay viem
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
Node
|
|
68
|
+
Node 20+. Tree-shakable ESM + CJS dual build. Every non-Celo rail (Stripe, Solana, Stellar) is an **optional peer dependency**, pulled in only when you import its subpath.
|
|
69
69
|
|
|
70
70
|
### Make an agent pay for an API — Celo + cUSD
|
|
71
71
|
|
|
@@ -216,7 +216,7 @@ The core `EnvoyClient` handles protocol detection and the retry loop; pluggable
|
|
|
216
216
|
| [`SolanaPaymentAdapter`](src/adapters/solana.ts) · [`StellarPaymentAdapter`](src/adapters/stellar.ts) | `envoy-pay/solana` · `/stellar` | Non-EVM settlement + watchers + request URIs. |
|
|
217
217
|
| [`UnifiedWallet`](src/wallet/unified-wallet.ts) | `envoy-pay/wallet` | Cross-chain wallet with intent resolution + chain routing. |
|
|
218
218
|
| [`FacilitatorService`](src/facilitator/facilitator-service.ts) | `envoy-pay/facilitator` | Hosted facilitator with fee calculation + receipts. |
|
|
219
|
-
| [402 gates](src/server/) | `envoy-pay/server` | Server-side x402 / MPP gating, webhook + receipt verification. |
|
|
219
|
+
| [402 gates](src/server/) | `envoy-pay/server` | Server-side x402 / MPP gating + `createOnchainVerifier` (on-chain `Settled` verification), webhook + receipt verification. |
|
|
220
220
|
| [Watchers](src/monitor/) | `envoy-pay/monitor` | EVM, Solana, Stellar payment monitoring (the EVM watcher ships in core). |
|
|
221
221
|
|
|
222
222
|
> **Extensible:** add any rail by implementing the [`PaymentAdapter`](src/adapters/types.ts) interface.
|
|
@@ -224,19 +224,30 @@ The core `EnvoyClient` handles protocol detection and the retry loop; pluggable
|
|
|
224
224
|
### Charge agents for *your* API (Pay In)
|
|
225
225
|
|
|
226
226
|
```ts
|
|
227
|
-
import { createX402Gate } from 'envoy-pay/server';
|
|
227
|
+
import { createX402Gate, createOnchainVerifier } from 'envoy-pay/server';
|
|
228
|
+
import { CELO_MAINNET } from 'envoy-pay';
|
|
229
|
+
|
|
230
|
+
// Confirm the payment actually settled on-chain — don't just trust the proof.
|
|
231
|
+
const verifyPayment = createOnchainVerifier({
|
|
232
|
+
chainId: CELO_MAINNET,
|
|
233
|
+
payTo: '0xYOUR_TREASURY',
|
|
234
|
+
token: '0x765DE816845861e75A25fCA122bb6898B8B1282a', // cUSD
|
|
235
|
+
minAmount: 500000000000000000n, // 0.5 cUSD (18 decimals)
|
|
236
|
+
rpcUrl: process.env.CELO_RPC_URL, // or pass a viem publicClient
|
|
237
|
+
});
|
|
228
238
|
|
|
229
239
|
app.post('/api/premium', createX402Gate({
|
|
230
240
|
payTo: '0xYOUR_TREASURY',
|
|
231
|
-
amount: '
|
|
241
|
+
amount: '500000000000000000',
|
|
232
242
|
asset: 'cUSD',
|
|
233
243
|
network: 'eip155:42220', // Celo
|
|
244
|
+
verifyPayment, // ← verifies the on-chain Settled event
|
|
234
245
|
}), (req, res) => {
|
|
235
246
|
res.json({ data: 'premium content' });
|
|
236
247
|
});
|
|
237
248
|
```
|
|
238
249
|
|
|
239
|
-
Server returns `402` + challenge → agent pays on-chain → retries with proof → the
|
|
250
|
+
Server returns `402` + challenge → agent pays on-chain → retries with proof → `createOnchainVerifier` confirms the `EnvoyFacilitator` `Settled` event (right merchant, token, amount; replay-guarded) → `200 OK`. **Without `verifyPayment` the gate accepts any well-formed proof and logs a warning** — never ship that for real value (see [SECURITY.md](SECURITY.md)). MPP gating (`createMppGate`) works the same way.
|
|
240
251
|
|
|
241
252
|
### Generate payment-request URIs
|
|
242
253
|
|
|
@@ -477,7 +488,20 @@ npm run contracts:test # hardhat test (23 specs)
|
|
|
477
488
|
| `solana` · `stellar` · `chain-router` · `agent-card` · `did-resolver` … | 15–18 each | Non-EVM rails, routing, ERC-8004 identity |
|
|
478
489
|
| _… 35 suites total_ | **499 passing** (+9 integration tests skipped without creds) | + server gates, watchers, webhooks, contracts client |
|
|
479
490
|
|
|
480
|
-
CI runs the SDK and the Hardhat contracts on every push (Node
|
|
491
|
+
CI runs the SDK and the Hardhat contracts on every push (Node 20/22) — see [`.github/workflows/ci.yml`](.github/workflows/ci.yml).
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
## Security
|
|
496
|
+
|
|
497
|
+
envoy-pay moves money, so it's gated **twice** — the client `PolicyEngine` *and*
|
|
498
|
+
on-chain `EnvoyFacilitator` caps — and ships [`createOnchainVerifier`](src/server/verify-onchain.ts)
|
|
499
|
+
so your server confirms a payment actually settled (right merchant, token, amount;
|
|
500
|
+
replay-guarded) before serving. It is **pre-1.0 and the `EnvoyFacilitator` contract
|
|
501
|
+
is not yet independently audited.**
|
|
502
|
+
|
|
503
|
+
See **[SECURITY.md](SECURITY.md)** for the on-chain trust model, a production
|
|
504
|
+
hardening checklist, and how to report a vulnerability.
|
|
481
505
|
|
|
482
506
|
---
|
|
483
507
|
|
|
@@ -496,6 +520,22 @@ CI runs the SDK and the Hardhat contracts on every push (Node 18/20/22) — see
|
|
|
496
520
|
|
|
497
521
|
---
|
|
498
522
|
|
|
523
|
+
## Dependencies & security
|
|
524
|
+
|
|
525
|
+
The core is deliberately lean. A default `npm i envoy-pay` pulls just **three runtime dependencies** — [`viem`](https://viem.sh), [`axios`](https://axios-http.com), and `@open-wallet-standard/core` — and audits clean:
|
|
526
|
+
|
|
527
|
+
```bash
|
|
528
|
+
$ npm i envoy-pay
|
|
529
|
+
added 43 packages, audited 44 packages
|
|
530
|
+
found 0 vulnerabilities
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
- **Optional rails are opt-in.** Solana, Stellar, and Stripe are *optional peer dependencies* — installed only if you import their subpath (`envoy-pay/solana`, `envoy-pay/stellar`, `envoy-pay/stripe`). They carry their own, much larger dependency trees; any advisories there originate from those upstream packages (e.g. `@solana/web3.js`), not from envoy — and you inherit them only if you opt into that rail.
|
|
534
|
+
- **The Celo-first core stays vulnerability-free** regardless of which rails you add.
|
|
535
|
+
- **Verify anytime:** run `npm i envoy-pay && npm audit` in a clean project — you'll see `found 0 vulnerabilities`.
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
|
|
499
539
|
## Project layout
|
|
500
540
|
|
|
501
541
|
```
|
package/dist/cjs/server/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.buildReceipt = exports.createWebhookHandler = exports.createPaymentGate = exports.createMppGate = exports.createX402Gate = void 0;
|
|
3
|
+
exports.buildReceipt = exports.createWebhookHandler = exports.createPaymentGate = exports.createMppGate = exports.createOnchainVerifier = exports.createX402Gate = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* envoy — Server-Side Payment Gating
|
|
6
6
|
*
|
|
@@ -24,6 +24,8 @@ exports.buildReceipt = exports.createWebhookHandler = exports.createPaymentGate
|
|
|
24
24
|
*/
|
|
25
25
|
var x402_gate_1 = require("./x402-gate");
|
|
26
26
|
Object.defineProperty(exports, "createX402Gate", { enumerable: true, get: function () { return x402_gate_1.createX402Gate; } });
|
|
27
|
+
var verify_onchain_1 = require("./verify-onchain");
|
|
28
|
+
Object.defineProperty(exports, "createOnchainVerifier", { enumerable: true, get: function () { return verify_onchain_1.createOnchainVerifier; } });
|
|
27
29
|
var mpp_gate_1 = require("./mpp-gate");
|
|
28
30
|
Object.defineProperty(exports, "createMppGate", { enumerable: true, get: function () { return mpp_gate_1.createMppGate; } });
|
|
29
31
|
var payment_gate_1 = require("./payment-gate");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,yCAAkF;AAAzE,2GAAA,cAAc,OAAA;AACvB,uCAA+D;AAAtD,yGAAA,aAAa,OAAA;AACtB,+CAA2E;AAAlE,iHAAA,iBAAiB,OAAA;AAC1B,qCAAqE;AAA5D,+GAAA,oBAAoB,OAAA;AAC7B,qCAAmF;AAA1E,uGAAA,YAAY,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,yCAAkF;AAAzE,2GAAA,cAAc,OAAA;AACvB,mDAI0B;AAHxB,uHAAA,qBAAqB,OAAA;AAIvB,uCAA+D;AAAtD,yGAAA,aAAa,OAAA;AACtB,+CAA2E;AAAlE,iHAAA,iBAAiB,OAAA;AAC1B,qCAAqE;AAA5D,+GAAA,oBAAoB,OAAA;AAC7B,qCAAmF;AAA1E,uGAAA,YAAY,OAAA"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* On-chain settlement verification for x402 gates.
|
|
4
|
+
*
|
|
5
|
+
* `createX402Gate`'s default does NOT confirm a payment settled on-chain — it
|
|
6
|
+
* only checks that the `X-PAYMENT` header is well-formed and self-consistent.
|
|
7
|
+
* That's fine for a demo, but unsafe for real value: a client could present a
|
|
8
|
+
* fabricated proof and be served for free. This helper closes that gap.
|
|
9
|
+
*
|
|
10
|
+
* It returns a `verifyPayment` function you pass straight into `createX402Gate`,
|
|
11
|
+
* which, given the proof a paying agent presents:
|
|
12
|
+
*
|
|
13
|
+
* 1. pulls the transaction the proof references (tolerating brief RPC lag),
|
|
14
|
+
* 2. confirms it succeeded and emitted the deployed `EnvoyFacilitator`'s
|
|
15
|
+
* `Settled` event,
|
|
16
|
+
* 3. checks it paid THIS merchant, in the expected token, for at least the
|
|
17
|
+
* asking amount,
|
|
18
|
+
* 4. replay-guards it — a `challengeId` is redeemable exactly once,
|
|
19
|
+
* 5. (optionally) reads the paying agent's ERC-8004 card and requires it to
|
|
20
|
+
* declare a given capability.
|
|
21
|
+
*
|
|
22
|
+
* This is the same verification the autonomous-loop example performs, lifted
|
|
23
|
+
* into the SDK so production gates don't have to re-implement it.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* import { createX402Gate, createOnchainVerifier } from 'envoy-pay/server';
|
|
28
|
+
* import { CELO_MAINNET } from 'envoy-pay';
|
|
29
|
+
*
|
|
30
|
+
* const verifyPayment = createOnchainVerifier({
|
|
31
|
+
* chainId: CELO_MAINNET,
|
|
32
|
+
* payTo: '0xYourTreasury',
|
|
33
|
+
* token: '0x765DE816845861e75A25fCA122bb6898B8B1282a', // cUSD on Celo
|
|
34
|
+
* minAmount: 500000000000000000n, // 0.5 cUSD (18 decimals)
|
|
35
|
+
* rpcUrl: process.env.CELO_RPC_URL, // or pass a viem publicClient
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* app.post('/api/premium', createX402Gate({
|
|
39
|
+
* payTo: '0xYourTreasury',
|
|
40
|
+
* amount: '500000000000000000',
|
|
41
|
+
* asset: 'cUSD',
|
|
42
|
+
* network: 'eip155:42220',
|
|
43
|
+
* verifyPayment,
|
|
44
|
+
* }), handler);
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.createOnchainVerifier = createOnchainVerifier;
|
|
49
|
+
const viem_1 = require("viem");
|
|
50
|
+
const contracts_1 = require("../contracts");
|
|
51
|
+
const identity_1 = require("../identity");
|
|
52
|
+
const logger_1 = require("../logger");
|
|
53
|
+
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
54
|
+
function memoryStore() {
|
|
55
|
+
const set = new Set();
|
|
56
|
+
return { has: (id) => set.has(id), add: (id) => void set.add(id) };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Build a `verifyPayment` function that confirms an x402 proof corresponds to a
|
|
60
|
+
* real `EnvoyFacilitator` settlement on-chain. Pass the result to
|
|
61
|
+
* `createX402Gate({ verifyPayment })`.
|
|
62
|
+
*/
|
|
63
|
+
function createOnchainVerifier(config) {
|
|
64
|
+
const log = config.logger ?? logger_1.noopLogger;
|
|
65
|
+
const deployed = (0, contracts_1.getEnvoyAddresses)(config.chainId);
|
|
66
|
+
const facilitator = (0, viem_1.getAddress)(config.facilitator ?? deployed.facilitator);
|
|
67
|
+
const identityRegistry = (0, viem_1.getAddress)(config.identityRegistry ?? deployed.identityRegistry);
|
|
68
|
+
const token = (0, viem_1.getAddress)(config.token);
|
|
69
|
+
const payTo = (0, viem_1.getAddress)(config.payTo);
|
|
70
|
+
const tries = config.receiptRetries ?? 5;
|
|
71
|
+
const delayMs = config.receiptRetryDelayMs ?? 2000;
|
|
72
|
+
const seen = config.seen ?? memoryStore();
|
|
73
|
+
if (facilitator === (0, viem_1.getAddress)(ZERO_ADDRESS)) {
|
|
74
|
+
throw new Error(`createOnchainVerifier: no EnvoyFacilitator is deployed for chainId ${config.chainId} ` +
|
|
75
|
+
`(the facilitator is currently Celo Mainnet only). Pass an explicit \`facilitator\` if you have one.`);
|
|
76
|
+
}
|
|
77
|
+
const client = resolveClient(config);
|
|
78
|
+
return async function verifyPayment(proof) {
|
|
79
|
+
const reject = (why) => {
|
|
80
|
+
log(`[verify-onchain] ✗ payment rejected — ${why}`);
|
|
81
|
+
return false;
|
|
82
|
+
};
|
|
83
|
+
const txHash = proof?.payload?.transaction;
|
|
84
|
+
if (!txHash)
|
|
85
|
+
return reject('proof has no payload.transaction (tx hash)');
|
|
86
|
+
const receipt = await receiptWithRetry(client, txHash, tries, delayMs);
|
|
87
|
+
if (!receipt)
|
|
88
|
+
return reject(`tx ${txHash} not found on chain ${config.chainId}`);
|
|
89
|
+
if (receipt.status !== 'success')
|
|
90
|
+
return reject(`tx ${txHash} reverted`);
|
|
91
|
+
const settled = decodeSettled(receipt.logs, facilitator);
|
|
92
|
+
if (!settled)
|
|
93
|
+
return reject(`no EnvoyFacilitator Settled event in ${txHash}`);
|
|
94
|
+
if ((0, viem_1.getAddress)(settled.merchant) !== payTo) {
|
|
95
|
+
return reject(`paid the wrong merchant (${settled.merchant}, expected ${payTo})`);
|
|
96
|
+
}
|
|
97
|
+
if ((0, viem_1.getAddress)(settled.token) !== token) {
|
|
98
|
+
return reject(`paid in the wrong token (${settled.token}, expected ${token})`);
|
|
99
|
+
}
|
|
100
|
+
if (settled.amount < config.minAmount) {
|
|
101
|
+
return reject(`underpaid (${settled.amount} < ${config.minAmount})`);
|
|
102
|
+
}
|
|
103
|
+
if (await seen.has(settled.challengeId)) {
|
|
104
|
+
return reject(`receipt already redeemed (challengeId ${settled.challengeId})`);
|
|
105
|
+
}
|
|
106
|
+
if (config.requiredCapability) {
|
|
107
|
+
const caps = await readCapabilities(client, identityRegistry, settled.agentId);
|
|
108
|
+
if (!caps.includes(config.requiredCapability.toLowerCase())) {
|
|
109
|
+
return reject(`agent #${settled.agentId} does not declare capability "${config.requiredCapability}" ` +
|
|
110
|
+
`(card lists: ${caps.length ? caps.join(', ') : 'none'})`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
await seen.add(settled.challengeId);
|
|
114
|
+
log(`[verify-onchain] ✓ agent #${settled.agentId} settled ${settled.amount} to ${payTo} (tx ${txHash})`);
|
|
115
|
+
return true;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function resolveClient(config) {
|
|
119
|
+
if (config.publicClient)
|
|
120
|
+
return config.publicClient;
|
|
121
|
+
if (config.rpcUrl) {
|
|
122
|
+
return (0, viem_1.createPublicClient)({ transport: (0, viem_1.http)(config.rpcUrl) });
|
|
123
|
+
}
|
|
124
|
+
throw new Error('createOnchainVerifier: pass either a `publicClient` or an `rpcUrl`.');
|
|
125
|
+
}
|
|
126
|
+
/** Find + decode the `EnvoyFacilitator` `Settled` event among a receipt's logs. */
|
|
127
|
+
function decodeSettled(logs, facilitator) {
|
|
128
|
+
for (const lg of logs) {
|
|
129
|
+
if ((0, viem_1.getAddress)(lg.address) !== facilitator)
|
|
130
|
+
continue;
|
|
131
|
+
try {
|
|
132
|
+
const decoded = (0, viem_1.decodeEventLog)({
|
|
133
|
+
abi: contracts_1.ENVOY_FACILITATOR_ABI,
|
|
134
|
+
data: lg.data,
|
|
135
|
+
topics: lg.topics,
|
|
136
|
+
});
|
|
137
|
+
if (decoded.eventName === 'Settled') {
|
|
138
|
+
const a = decoded.args;
|
|
139
|
+
return {
|
|
140
|
+
challengeId: a.challengeId,
|
|
141
|
+
agentId: a.agentId,
|
|
142
|
+
merchant: a.merchant,
|
|
143
|
+
token: a.token,
|
|
144
|
+
amount: a.amount,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
/* not the Settled event — keep scanning */
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
/** Fetch a receipt, tolerating brief RPC propagation lag. Null if never seen. */
|
|
155
|
+
async function receiptWithRetry(client, hash, tries, delayMs) {
|
|
156
|
+
for (let i = 0; i < tries; i++) {
|
|
157
|
+
try {
|
|
158
|
+
return await client.getTransactionReceipt({ hash });
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
if (i < tries - 1)
|
|
162
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
/** Read an agent's declared capabilities from its on-chain ERC-8004 card. */
|
|
168
|
+
async function readCapabilities(client, registry, agentId) {
|
|
169
|
+
try {
|
|
170
|
+
const { tokenURI } = await identity_1.erc8004.getAgent(client, registry, agentId);
|
|
171
|
+
if (!tokenURI || !tokenURI.startsWith('data:'))
|
|
172
|
+
return [];
|
|
173
|
+
const comma = tokenURI.indexOf(',');
|
|
174
|
+
const meta = tokenURI.slice(5, comma);
|
|
175
|
+
const payload = tokenURI.slice(comma + 1);
|
|
176
|
+
const json = /;base64/i.test(meta)
|
|
177
|
+
? Buffer.from(payload, 'base64').toString('utf-8')
|
|
178
|
+
: decodeURIComponent(payload);
|
|
179
|
+
const card = JSON.parse(json);
|
|
180
|
+
return Array.isArray(card?.capabilities)
|
|
181
|
+
? card.capabilities
|
|
182
|
+
.filter((c) => typeof c === 'string')
|
|
183
|
+
.map((c) => c.toLowerCase())
|
|
184
|
+
: [];
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=verify-onchain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-onchain.js","sourceRoot":"","sources":["../../../src/server/verify-onchain.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,6 +25,16 @@ function createX402Gate(config) {
|
|
|
25
25
|
const log = config.logger ?? logger_1.noopLogger;
|
|
26
26
|
const version = config.x402Version ?? 2;
|
|
27
27
|
const scheme = config.scheme ?? 'exact';
|
|
28
|
+
// The built-in checks only confirm the proof is well-formed and self-consistent
|
|
29
|
+
// (payTo/amount echo the challenge) — they do NOT confirm the payment settled.
|
|
30
|
+
// Without `verifyPayment`, anyone can craft a proof and be served for free.
|
|
31
|
+
if (!config.verifyPayment && !config.facilitatorUrl && !config.allowUnverified) {
|
|
32
|
+
// eslint-disable-next-line no-console
|
|
33
|
+
console.warn('[x402-gate] ⚠ SECURITY: no `verifyPayment` configured — this gate accepts any ' +
|
|
34
|
+
'well-formed X-PAYMENT header WITHOUT confirming the payment settled on-chain. ' +
|
|
35
|
+
'Wire `createOnchainVerifier()` (envoy-pay/server) before charging real value, or ' +
|
|
36
|
+
'set `allowUnverified: true` to acknowledge and silence this. See SECURITY.md.');
|
|
37
|
+
}
|
|
28
38
|
return async (req, res, next) => {
|
|
29
39
|
// Check for existing X-PAYMENT header
|
|
30
40
|
const paymentHeader = req.headers['x-payment'] ||
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"x402-gate.js","sourceRoot":"","sources":["../../../src/server/x402-gate.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"x402-gate.js","sourceRoot":"","sources":["../../../src/server/x402-gate.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/server/index.js
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
22
|
export { createX402Gate } from './x402-gate.js';
|
|
23
|
+
export { createOnchainVerifier, } from './verify-onchain.js';
|
|
23
24
|
export { createMppGate } from './mpp-gate.js';
|
|
24
25
|
export { createPaymentGate } from './payment-gate.js';
|
|
25
26
|
export { createWebhookHandler } from './webhook.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,cAAc,EAAuC,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,aAAa,EAAsB,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAA0B,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAsB,MAAM,WAAW,CAAC;AACrE,OAAO,EAAE,YAAY,EAA4C,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,cAAc,EAAuC,MAAM,aAAa,CAAC;AAClF,OAAO,EACL,qBAAqB,GAGtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAsB,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAA0B,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAsB,MAAM,WAAW,CAAC;AACrE,OAAO,EAAE,YAAY,EAA4C,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-chain settlement verification for x402 gates.
|
|
3
|
+
*
|
|
4
|
+
* `createX402Gate`'s default does NOT confirm a payment settled on-chain — it
|
|
5
|
+
* only checks that the `X-PAYMENT` header is well-formed and self-consistent.
|
|
6
|
+
* That's fine for a demo, but unsafe for real value: a client could present a
|
|
7
|
+
* fabricated proof and be served for free. This helper closes that gap.
|
|
8
|
+
*
|
|
9
|
+
* It returns a `verifyPayment` function you pass straight into `createX402Gate`,
|
|
10
|
+
* which, given the proof a paying agent presents:
|
|
11
|
+
*
|
|
12
|
+
* 1. pulls the transaction the proof references (tolerating brief RPC lag),
|
|
13
|
+
* 2. confirms it succeeded and emitted the deployed `EnvoyFacilitator`'s
|
|
14
|
+
* `Settled` event,
|
|
15
|
+
* 3. checks it paid THIS merchant, in the expected token, for at least the
|
|
16
|
+
* asking amount,
|
|
17
|
+
* 4. replay-guards it — a `challengeId` is redeemable exactly once,
|
|
18
|
+
* 5. (optionally) reads the paying agent's ERC-8004 card and requires it to
|
|
19
|
+
* declare a given capability.
|
|
20
|
+
*
|
|
21
|
+
* This is the same verification the autonomous-loop example performs, lifted
|
|
22
|
+
* into the SDK so production gates don't have to re-implement it.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { createX402Gate, createOnchainVerifier } from 'envoy-pay/server';
|
|
27
|
+
* import { CELO_MAINNET } from 'envoy-pay';
|
|
28
|
+
*
|
|
29
|
+
* const verifyPayment = createOnchainVerifier({
|
|
30
|
+
* chainId: CELO_MAINNET,
|
|
31
|
+
* payTo: '0xYourTreasury',
|
|
32
|
+
* token: '0x765DE816845861e75A25fCA122bb6898B8B1282a', // cUSD on Celo
|
|
33
|
+
* minAmount: 500000000000000000n, // 0.5 cUSD (18 decimals)
|
|
34
|
+
* rpcUrl: process.env.CELO_RPC_URL, // or pass a viem publicClient
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
* app.post('/api/premium', createX402Gate({
|
|
38
|
+
* payTo: '0xYourTreasury',
|
|
39
|
+
* amount: '500000000000000000',
|
|
40
|
+
* asset: 'cUSD',
|
|
41
|
+
* network: 'eip155:42220',
|
|
42
|
+
* verifyPayment,
|
|
43
|
+
* }), handler);
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
import { createPublicClient, decodeEventLog, getAddress, http as viemHttp, } from 'viem';
|
|
47
|
+
import { getEnvoyAddresses, ENVOY_FACILITATOR_ABI } from '../contracts/index.js';
|
|
48
|
+
import { erc8004 } from '../identity/index.js';
|
|
49
|
+
import { noopLogger } from '../logger.js';
|
|
50
|
+
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
51
|
+
function memoryStore() {
|
|
52
|
+
const set = new Set();
|
|
53
|
+
return { has: (id) => set.has(id), add: (id) => void set.add(id) };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Build a `verifyPayment` function that confirms an x402 proof corresponds to a
|
|
57
|
+
* real `EnvoyFacilitator` settlement on-chain. Pass the result to
|
|
58
|
+
* `createX402Gate({ verifyPayment })`.
|
|
59
|
+
*/
|
|
60
|
+
export function createOnchainVerifier(config) {
|
|
61
|
+
const log = config.logger ?? noopLogger;
|
|
62
|
+
const deployed = getEnvoyAddresses(config.chainId);
|
|
63
|
+
const facilitator = getAddress(config.facilitator ?? deployed.facilitator);
|
|
64
|
+
const identityRegistry = getAddress(config.identityRegistry ?? deployed.identityRegistry);
|
|
65
|
+
const token = getAddress(config.token);
|
|
66
|
+
const payTo = getAddress(config.payTo);
|
|
67
|
+
const tries = config.receiptRetries ?? 5;
|
|
68
|
+
const delayMs = config.receiptRetryDelayMs ?? 2000;
|
|
69
|
+
const seen = config.seen ?? memoryStore();
|
|
70
|
+
if (facilitator === getAddress(ZERO_ADDRESS)) {
|
|
71
|
+
throw new Error(`createOnchainVerifier: no EnvoyFacilitator is deployed for chainId ${config.chainId} ` +
|
|
72
|
+
`(the facilitator is currently Celo Mainnet only). Pass an explicit \`facilitator\` if you have one.`);
|
|
73
|
+
}
|
|
74
|
+
const client = resolveClient(config);
|
|
75
|
+
return async function verifyPayment(proof) {
|
|
76
|
+
const reject = (why) => {
|
|
77
|
+
log(`[verify-onchain] ✗ payment rejected — ${why}`);
|
|
78
|
+
return false;
|
|
79
|
+
};
|
|
80
|
+
const txHash = proof?.payload?.transaction;
|
|
81
|
+
if (!txHash)
|
|
82
|
+
return reject('proof has no payload.transaction (tx hash)');
|
|
83
|
+
const receipt = await receiptWithRetry(client, txHash, tries, delayMs);
|
|
84
|
+
if (!receipt)
|
|
85
|
+
return reject(`tx ${txHash} not found on chain ${config.chainId}`);
|
|
86
|
+
if (receipt.status !== 'success')
|
|
87
|
+
return reject(`tx ${txHash} reverted`);
|
|
88
|
+
const settled = decodeSettled(receipt.logs, facilitator);
|
|
89
|
+
if (!settled)
|
|
90
|
+
return reject(`no EnvoyFacilitator Settled event in ${txHash}`);
|
|
91
|
+
if (getAddress(settled.merchant) !== payTo) {
|
|
92
|
+
return reject(`paid the wrong merchant (${settled.merchant}, expected ${payTo})`);
|
|
93
|
+
}
|
|
94
|
+
if (getAddress(settled.token) !== token) {
|
|
95
|
+
return reject(`paid in the wrong token (${settled.token}, expected ${token})`);
|
|
96
|
+
}
|
|
97
|
+
if (settled.amount < config.minAmount) {
|
|
98
|
+
return reject(`underpaid (${settled.amount} < ${config.minAmount})`);
|
|
99
|
+
}
|
|
100
|
+
if (await seen.has(settled.challengeId)) {
|
|
101
|
+
return reject(`receipt already redeemed (challengeId ${settled.challengeId})`);
|
|
102
|
+
}
|
|
103
|
+
if (config.requiredCapability) {
|
|
104
|
+
const caps = await readCapabilities(client, identityRegistry, settled.agentId);
|
|
105
|
+
if (!caps.includes(config.requiredCapability.toLowerCase())) {
|
|
106
|
+
return reject(`agent #${settled.agentId} does not declare capability "${config.requiredCapability}" ` +
|
|
107
|
+
`(card lists: ${caps.length ? caps.join(', ') : 'none'})`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
await seen.add(settled.challengeId);
|
|
111
|
+
log(`[verify-onchain] ✓ agent #${settled.agentId} settled ${settled.amount} to ${payTo} (tx ${txHash})`);
|
|
112
|
+
return true;
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function resolveClient(config) {
|
|
116
|
+
if (config.publicClient)
|
|
117
|
+
return config.publicClient;
|
|
118
|
+
if (config.rpcUrl) {
|
|
119
|
+
return createPublicClient({ transport: viemHttp(config.rpcUrl) });
|
|
120
|
+
}
|
|
121
|
+
throw new Error('createOnchainVerifier: pass either a `publicClient` or an `rpcUrl`.');
|
|
122
|
+
}
|
|
123
|
+
/** Find + decode the `EnvoyFacilitator` `Settled` event among a receipt's logs. */
|
|
124
|
+
function decodeSettled(logs, facilitator) {
|
|
125
|
+
for (const lg of logs) {
|
|
126
|
+
if (getAddress(lg.address) !== facilitator)
|
|
127
|
+
continue;
|
|
128
|
+
try {
|
|
129
|
+
const decoded = decodeEventLog({
|
|
130
|
+
abi: ENVOY_FACILITATOR_ABI,
|
|
131
|
+
data: lg.data,
|
|
132
|
+
topics: lg.topics,
|
|
133
|
+
});
|
|
134
|
+
if (decoded.eventName === 'Settled') {
|
|
135
|
+
const a = decoded.args;
|
|
136
|
+
return {
|
|
137
|
+
challengeId: a.challengeId,
|
|
138
|
+
agentId: a.agentId,
|
|
139
|
+
merchant: a.merchant,
|
|
140
|
+
token: a.token,
|
|
141
|
+
amount: a.amount,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
/* not the Settled event — keep scanning */
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
/** Fetch a receipt, tolerating brief RPC propagation lag. Null if never seen. */
|
|
152
|
+
async function receiptWithRetry(client, hash, tries, delayMs) {
|
|
153
|
+
for (let i = 0; i < tries; i++) {
|
|
154
|
+
try {
|
|
155
|
+
return await client.getTransactionReceipt({ hash });
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
if (i < tries - 1)
|
|
159
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
/** Read an agent's declared capabilities from its on-chain ERC-8004 card. */
|
|
165
|
+
async function readCapabilities(client, registry, agentId) {
|
|
166
|
+
try {
|
|
167
|
+
const { tokenURI } = await erc8004.getAgent(client, registry, agentId);
|
|
168
|
+
if (!tokenURI || !tokenURI.startsWith('data:'))
|
|
169
|
+
return [];
|
|
170
|
+
const comma = tokenURI.indexOf(',');
|
|
171
|
+
const meta = tokenURI.slice(5, comma);
|
|
172
|
+
const payload = tokenURI.slice(comma + 1);
|
|
173
|
+
const json = /;base64/i.test(meta)
|
|
174
|
+
? Buffer.from(payload, 'base64').toString('utf-8')
|
|
175
|
+
: decodeURIComponent(payload);
|
|
176
|
+
const card = JSON.parse(json);
|
|
177
|
+
return Array.isArray(card?.capabilities)
|
|
178
|
+
? card.capabilities
|
|
179
|
+
.filter((c) => typeof c === 'string')
|
|
180
|
+
.map((c) => c.toLowerCase())
|
|
181
|
+
: [];
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=verify-onchain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-onchain.js","sourceRoot":"","sources":["../../../src/server/verify-onchain.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,6 +22,16 @@ export function createX402Gate(config) {
|
|
|
22
22
|
const log = config.logger ?? noopLogger;
|
|
23
23
|
const version = config.x402Version ?? 2;
|
|
24
24
|
const scheme = config.scheme ?? 'exact';
|
|
25
|
+
// The built-in checks only confirm the proof is well-formed and self-consistent
|
|
26
|
+
// (payTo/amount echo the challenge) — they do NOT confirm the payment settled.
|
|
27
|
+
// Without `verifyPayment`, anyone can craft a proof and be served for free.
|
|
28
|
+
if (!config.verifyPayment && !config.facilitatorUrl && !config.allowUnverified) {
|
|
29
|
+
// eslint-disable-next-line no-console
|
|
30
|
+
console.warn('[x402-gate] ⚠ SECURITY: no `verifyPayment` configured — this gate accepts any ' +
|
|
31
|
+
'well-formed X-PAYMENT header WITHOUT confirming the payment settled on-chain. ' +
|
|
32
|
+
'Wire `createOnchainVerifier()` (envoy-pay/server) before charging real value, or ' +
|
|
33
|
+
'set `allowUnverified: true` to acknowledge and silence this. See SECURITY.md.');
|
|
34
|
+
}
|
|
25
35
|
return async (req, res, next) => {
|
|
26
36
|
// Check for existing X-PAYMENT header
|
|
27
37
|
const paymentHeader = req.headers['x-payment'] ||
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"x402-gate.js","sourceRoot":"","sources":["../../../src/server/x402-gate.ts"],"names":[],"mappings":"AACA,OAAO,EAAU,UAAU,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"x402-gate.js","sourceRoot":"","sources":["../../../src/server/x402-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
22
|
export { createX402Gate, type X402GateConfig, type X402Proof } from './x402-gate';
|
|
23
|
+
export { createOnchainVerifier, type OnchainVerifierConfig, type ReplayStore, } from './verify-onchain';
|
|
23
24
|
export { createMppGate, type MppGateConfig } from './mpp-gate';
|
|
24
25
|
export { createPaymentGate, type PaymentGateConfig } from './payment-gate';
|
|
25
26
|
export { createWebhookHandler, type WebhookConfig } from './webhook';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EACL,qBAAqB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,WAAW,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-chain settlement verification for x402 gates.
|
|
3
|
+
*
|
|
4
|
+
* `createX402Gate`'s default does NOT confirm a payment settled on-chain — it
|
|
5
|
+
* only checks that the `X-PAYMENT` header is well-formed and self-consistent.
|
|
6
|
+
* That's fine for a demo, but unsafe for real value: a client could present a
|
|
7
|
+
* fabricated proof and be served for free. This helper closes that gap.
|
|
8
|
+
*
|
|
9
|
+
* It returns a `verifyPayment` function you pass straight into `createX402Gate`,
|
|
10
|
+
* which, given the proof a paying agent presents:
|
|
11
|
+
*
|
|
12
|
+
* 1. pulls the transaction the proof references (tolerating brief RPC lag),
|
|
13
|
+
* 2. confirms it succeeded and emitted the deployed `EnvoyFacilitator`'s
|
|
14
|
+
* `Settled` event,
|
|
15
|
+
* 3. checks it paid THIS merchant, in the expected token, for at least the
|
|
16
|
+
* asking amount,
|
|
17
|
+
* 4. replay-guards it — a `challengeId` is redeemable exactly once,
|
|
18
|
+
* 5. (optionally) reads the paying agent's ERC-8004 card and requires it to
|
|
19
|
+
* declare a given capability.
|
|
20
|
+
*
|
|
21
|
+
* This is the same verification the autonomous-loop example performs, lifted
|
|
22
|
+
* into the SDK so production gates don't have to re-implement it.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { createX402Gate, createOnchainVerifier } from 'envoy-pay/server';
|
|
27
|
+
* import { CELO_MAINNET } from 'envoy-pay';
|
|
28
|
+
*
|
|
29
|
+
* const verifyPayment = createOnchainVerifier({
|
|
30
|
+
* chainId: CELO_MAINNET,
|
|
31
|
+
* payTo: '0xYourTreasury',
|
|
32
|
+
* token: '0x765DE816845861e75A25fCA122bb6898B8B1282a', // cUSD on Celo
|
|
33
|
+
* minAmount: 500000000000000000n, // 0.5 cUSD (18 decimals)
|
|
34
|
+
* rpcUrl: process.env.CELO_RPC_URL, // or pass a viem publicClient
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
* app.post('/api/premium', createX402Gate({
|
|
38
|
+
* payTo: '0xYourTreasury',
|
|
39
|
+
* amount: '500000000000000000',
|
|
40
|
+
* asset: 'cUSD',
|
|
41
|
+
* network: 'eip155:42220',
|
|
42
|
+
* verifyPayment,
|
|
43
|
+
* }), handler);
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
import { type Address, type PublicClient } from 'viem';
|
|
47
|
+
import { type Logger } from '../logger';
|
|
48
|
+
import type { X402Proof } from './x402-gate';
|
|
49
|
+
/**
|
|
50
|
+
* A redeemed-receipt store. A `challengeId` is honored exactly once. The default
|
|
51
|
+
* is an in-process `Set` — fine for a single instance, but NOT safe across a
|
|
52
|
+
* horizontally-scaled deployment, where two nodes could each redeem the same
|
|
53
|
+
* receipt. Pass a shared (e.g. Redis-backed) implementation in production.
|
|
54
|
+
*/
|
|
55
|
+
export interface ReplayStore {
|
|
56
|
+
has(challengeId: string): boolean | Promise<boolean>;
|
|
57
|
+
add(challengeId: string): void | Promise<void>;
|
|
58
|
+
}
|
|
59
|
+
export interface OnchainVerifierConfig {
|
|
60
|
+
/** EIP-155 chain id the payment settles on (e.g. 42220 — Celo Mainnet). */
|
|
61
|
+
chainId: number;
|
|
62
|
+
/** Merchant wallet that must be the `merchant` in the `Settled` event. */
|
|
63
|
+
payTo: Address;
|
|
64
|
+
/** Token the payment must be denominated in (e.g. cUSD on Celo). */
|
|
65
|
+
token: Address;
|
|
66
|
+
/** Minimum settled amount required to pass, in the token's smallest unit. */
|
|
67
|
+
minAmount: bigint;
|
|
68
|
+
/** A viem `PublicClient` for reads. Provide this OR `rpcUrl`. */
|
|
69
|
+
publicClient?: PublicClient;
|
|
70
|
+
/** RPC URL used to build a read-only client when `publicClient` is omitted. */
|
|
71
|
+
rpcUrl?: string;
|
|
72
|
+
/** `EnvoyFacilitator` address. Defaults to the deployed one for `chainId`. */
|
|
73
|
+
facilitator?: Address;
|
|
74
|
+
/**
|
|
75
|
+
* Optional ERC-8004 capability the paying agent's on-chain card must declare.
|
|
76
|
+
* When set, the agent's card is read and the request is rejected if it's absent.
|
|
77
|
+
*/
|
|
78
|
+
requiredCapability?: string;
|
|
79
|
+
/** ERC-8004 Identity registry, for the capability read. Defaults to deployed. */
|
|
80
|
+
identityRegistry?: Address;
|
|
81
|
+
/** Replay store. Defaults to an in-process `Set` (see {@link ReplayStore}). */
|
|
82
|
+
seen?: ReplayStore;
|
|
83
|
+
/** Receipt-fetch retries, to tolerate RPC propagation lag. Default 5. */
|
|
84
|
+
receiptRetries?: number;
|
|
85
|
+
/** Delay between receipt retries, in ms. Default 2000. */
|
|
86
|
+
receiptRetryDelayMs?: number;
|
|
87
|
+
/** Optional logger. Surfaces the reason a payment was rejected. */
|
|
88
|
+
logger?: Logger;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Build a `verifyPayment` function that confirms an x402 proof corresponds to a
|
|
92
|
+
* real `EnvoyFacilitator` settlement on-chain. Pass the result to
|
|
93
|
+
* `createX402Gate({ verifyPayment })`.
|
|
94
|
+
*/
|
|
95
|
+
export declare function createOnchainVerifier(config: OnchainVerifierConfig): (proof: X402Proof) => Promise<boolean>;
|
|
96
|
+
//# sourceMappingURL=verify-onchain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-onchain.d.ts","sourceRoot":"","sources":["../../../src/server/verify-onchain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,OAAO,EAKL,KAAK,OAAO,EAEZ,KAAK,YAAY,EAElB,MAAM,MAAM,CAAC;AAGd,OAAO,EAAE,KAAK,MAAM,EAAc,MAAM,WAAW,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI7C;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,KAAK,EAAE,OAAO,CAAC;IACf,oEAAoE;IACpE,KAAK,EAAE,OAAO,CAAC;IACf,6EAA6E;IAC7E,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,+EAA+E;IAC/E,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0DAA0D;IAC1D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,qBAAqB,GAC5B,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC,OAAO,CAAC,CAiExC"}
|
|
@@ -22,8 +22,14 @@ export interface X402GateConfig {
|
|
|
22
22
|
usdAmount?: number;
|
|
23
23
|
/** Facilitator URL for verification (optional). */
|
|
24
24
|
facilitatorUrl?: string;
|
|
25
|
-
/** Verification function. If provided, called to verify X-PAYMENT proof.
|
|
25
|
+
/** Verification function. If provided, called to verify X-PAYMENT proof.
|
|
26
|
+
* Use `createOnchainVerifier(...)` (envoy-pay/server) to confirm the payment
|
|
27
|
+
* actually settled on-chain — strongly recommended before charging real value. */
|
|
26
28
|
verifyPayment?: (proof: X402Proof) => Promise<boolean> | boolean;
|
|
29
|
+
/** Acknowledge running WITHOUT settlement verification (silences the security
|
|
30
|
+
* warning). The gate then trusts any well-formed proof — only safe for demos,
|
|
31
|
+
* testnets, or when a trusted facilitator verifies upstream. Default: false. */
|
|
32
|
+
allowUnverified?: boolean;
|
|
27
33
|
/** Logger function. */
|
|
28
34
|
logger?: Logger;
|
|
29
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"x402-gate.d.ts","sourceRoot":"","sources":["../../../src/server/x402-gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAc,MAAM,WAAW,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB
|
|
1
|
+
{"version":3,"file":"x402-gate.d.ts","sourceRoot":"","sources":["../../../src/server/x402-gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAc,MAAM,WAAW,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;uFAEmF;IACnF,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACjE;;qFAEiF;IACjF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,2CAA2C;AAC3C,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,OAAO,EAAE;QACP,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,oEAAoE;AACpE,UAAU,YAAa,SAAQ,eAAe;IAC5C,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,IAmBjD,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,mBAoF5B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "envoy-pay",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Celo-first agent payment SDK: x402 + MPP settlement, ERC-8004 identity, and on-chain spending policy via the EnvoyFacilitator. Optional Solana, Stellar, Stripe, DEX/bridge, and unified-wallet modules via subpath imports.",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
"open-wallet-standard"
|
|
144
144
|
],
|
|
145
145
|
"engines": {
|
|
146
|
-
"node": ">=
|
|
146
|
+
"node": ">=20"
|
|
147
147
|
},
|
|
148
148
|
"author": "Envoy",
|
|
149
149
|
"license": "Apache-2.0",
|