@insumermodel/mppx-condition-gate 3.0.2 → 3.1.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/README.md +73 -8
- package/dist/index.d.ts +54 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +321 -38
- package/dist/index.js.map +1 -1
- package/package.json +5 -9
- package/src/index.ts +380 -41
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@ Free access requires a payer your payment method has **proven** controls the req
|
|
|
15
15
|
5. **Pass** → free receipt returned (`reference: "condition-gate:free:{attestationId}"`)
|
|
16
16
|
6. **Fail, or no proven payer** → the normal paid path runs
|
|
17
17
|
|
|
18
|
+
Each credential gets free access at most once. See [Single-use credentials](#single-use-credentials) for what the gate records and the limits of that guarantee.
|
|
19
|
+
|
|
18
20
|
The signed attestation is verifiable offline via [JWKS](https://insumermodel.com/.well-known/jwks.json). The adapter does not re-sign or wrap the result; the signature on the attestation is the one InsumerAPI produced. Since 2026-09-01 every attest response also carries an ML-DSA-65 post-quantum companion (`pqSig`, `pqKid`) beside `sig` and `kid`, added without changing them; the `InsumerAttestation` type declares `pqSig` and `pqKid` beside `sig` and `kid`, and `insumer-verify` 1.8.1+ reports the companion as a fifth verdict.
|
|
19
21
|
|
|
20
22
|
### Why you must supply the payer
|
|
@@ -32,18 +34,19 @@ npm install @insumermodel/mppx-condition-gate
|
|
|
32
34
|
## Usage
|
|
33
35
|
|
|
34
36
|
```ts
|
|
35
|
-
import { Mppx,
|
|
37
|
+
import { Mppx, evm } from 'mppx/server'
|
|
36
38
|
import { conditionGate } from '@insumermodel/mppx-condition-gate'
|
|
37
39
|
|
|
38
|
-
const
|
|
39
|
-
currency:
|
|
40
|
-
recipient: '0xYourAddress',
|
|
40
|
+
const evmCharge = evm.charge({
|
|
41
|
+
currency: evm.assets.base.USDC,
|
|
42
|
+
recipient: '0xYourAddress', // your checksummed receiving address
|
|
43
|
+
x402: { facilitator: 'https://your-facilitator.example' },
|
|
41
44
|
})
|
|
42
45
|
|
|
43
|
-
const gatedCharge = conditionGate(
|
|
46
|
+
const gatedCharge = conditionGate(evmCharge, {
|
|
44
47
|
apiKey: process.env.INSUMER_API_KEY,
|
|
45
48
|
// Return only a payer this method has PROVEN for this request, else null.
|
|
46
|
-
//
|
|
49
|
+
// mppx's EVM charge reports the signer it recovered as `payer`.
|
|
47
50
|
provenPayer: (details) => (details as { payer?: string }).payer ?? null,
|
|
48
51
|
conditions: [{
|
|
49
52
|
type: 'nft_ownership',
|
|
@@ -52,10 +55,69 @@ const gatedCharge = conditionGate(tempoCharge, {
|
|
|
52
55
|
}],
|
|
53
56
|
})
|
|
54
57
|
|
|
55
|
-
const mppx = Mppx.create({ methods: [gatedCharge] })
|
|
58
|
+
const mppx = Mppx.create({ methods: [gatedCharge], secretKey: process.env.MPP_SECRET_KEY })
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Works with any framework (Hono, Express, Elysia, Next.js). The adapter wraps `Method.Server`, so no middleware changes needed.
|
|
62
|
+
|
|
63
|
+
### Which credentials can get free access
|
|
64
|
+
|
|
65
|
+
Free access needs a method that exposes mppx's `validate` hook, a resolver that returns the payer that method proved, and a credential the gate can identify. mppx added `validate` in 0.8.14 for the Tempo charge and in 0.9.3 for the EVM charge; on older versions every request pays. In mppx 0.9.3:
|
|
66
|
+
|
|
67
|
+
- **EVM charge**, native and x402: EIP-3009 authorizations. The payer is the recovered signer, `details.payer`.
|
|
68
|
+
- **Tempo charge, proof credentials**: the payer is `details.sender`, checked against a signature over the challenge. Tempo accepts proofs only on zero-amount challenges.
|
|
69
|
+
- **Tempo hash and transaction credentials** are payments in their own right, a transfer already on chain or one waiting to be sent. They take the paid path, where the Tempo method's own replay protection applies.
|
|
70
|
+
- **Stripe** exposes no `validate` hook, so it is never gated.
|
|
71
|
+
|
|
72
|
+
## Single-use credentials
|
|
73
|
+
|
|
74
|
+
When a payment settles, mppx spends the credential: the on-chain nonce is used, or the method records it. A free grant never settles, so the gate keeps its own record:
|
|
75
|
+
|
|
76
|
+
- It records a credential when it grants free access. It also records an EIP-3009 authorization just before the paid path settles it, so a copy presented while that payment is in flight is refused.
|
|
77
|
+
- A recorded credential is refused with a verification error. It is not passed on to payment, which would charge the original holder for someone else's request.
|
|
78
|
+
- If settlement throws, that record is released, so the holder can retry with the same credential.
|
|
79
|
+
- An EIP-3009 authorization is identified by its signer and nonce, and a Tempo proof by its challenge and payer. Neither changes when a signature is re-encoded or the challenge is rebuilt, and two users never share one. A native credential signs its challenge, so the same wallet signing the same native challenge twice (in the same millisecond, or on a route with a fixed `expires`) produces one credential, and the second is refused. x402 clients choose a fresh nonce each time.
|
|
80
|
+
- A Tempo proof gets free access once, but a repeated proof is not refused, and a proof that takes the paid path is not recorded. Proofs are only accepted on zero-amount routes, which move no value, so the Tempo method and its own replay rules (its `store` option) decide whether it may be presented again.
|
|
81
|
+
|
|
82
|
+
A record is kept until the credential expires, plus 60 seconds. A credential whose remaining validity is longer than `maxCredentialLifetimeSeconds` (600 by default) gets no free access and takes the paid path:
|
|
83
|
+
|
|
84
|
+
- **EIP-3009 authorization:** its `validBefore`. An x402 client sets it from the route's `maxTimeoutSeconds` (300 by default), whatever the challenge expiry, but a client can sign a longer one. An x402 route whose `maxTimeoutSeconds` is above the cap gives qualifying visitors no free access unless you raise the option. A native client sets it to the challenge's `expires` (5 minutes by default), so a native route configured with an `expires` longer than the cap gives no free access unless you raise the option.
|
|
85
|
+
- **Tempo proof:** the challenge's `expires`.
|
|
86
|
+
|
|
87
|
+
### Limits of the guarantee
|
|
88
|
+
|
|
89
|
+
Each case below allows at most one extra use of a credential:
|
|
90
|
+
|
|
91
|
+
- **Settlement throws after the transfer actually happened.** The record is released, so the credential can be presented again. If its payer now meets the conditions, that presentation is free.
|
|
92
|
+
- **The default store's payment records are full** (100,000 live). Later payments are not recorded, so a settled credential can come back once for free access.
|
|
93
|
+
- **A caller-supplied store cannot be read or written.** The request gets no free access and pays without a record. A credential that already got free access can then be settled for a copy's request, charging its holder once, which is what bare mppx does with any credential that has not settled.
|
|
94
|
+
|
|
95
|
+
Concurrent copies of one credential may each spend an attestation before one of them is granted.
|
|
96
|
+
|
|
97
|
+
### The default store
|
|
98
|
+
|
|
99
|
+
The default record lives in memory and is **shared by every gated route in the process**. It holds up to 100,000 live free grants, at most 5,000 per wallet, and up to 100,000 payment records. A wallet over its share, or any wallet once the free-grant capacity is full, pays instead.
|
|
100
|
+
|
|
101
|
+
The default store is not a defense against someone determined to deny free access to others. Free credentials cost nothing to sign, so about 20 qualifying addresses can fill the free-grant capacity. So can one qualifying asset moved between 20 addresses, because a passing attestation is cached for `cacheTtlSeconds`. Every other qualifying visitor in that process then pays the route price until those credentials expire, up to `maxCredentialLifetimeSeconds` plus a minute. Use the default store for development and low-stakes routes.
|
|
102
|
+
|
|
103
|
+
**For production traffic, or when the route runs on more than one instance, pass a shared store with its own capacity.** The store must claim atomically and remove expired entries. Options:
|
|
104
|
+
|
|
105
|
+
- `Store.redis`, `Store.upstash` or `Store.cloudflare`, built from a client that exposes an atomic `update`. Confirm that your backend expires keys.
|
|
106
|
+
- Any store with an atomic `tryClaim`.
|
|
107
|
+
|
|
108
|
+
mppx's `Store.memory()` never removes expired entries, so use it only in tests. A store that is not atomic lets concurrent presentations through. Give the store `delete` (or `update`) so a failed payment can be released.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { Store } from 'mppx/server'
|
|
112
|
+
|
|
113
|
+
const gatedCharge = conditionGate(evmCharge, {
|
|
114
|
+
provenPayer: (details) => (details as { payer?: string }).payer ?? null,
|
|
115
|
+
conditions: [ ... ],
|
|
116
|
+
replayStore: Store.redis(atomicRedisClient), // the client must provide `update`
|
|
117
|
+
})
|
|
56
118
|
```
|
|
57
119
|
|
|
58
|
-
|
|
120
|
+
Refusals are mppx's own `VerificationFailedError`, returned as HTTP 402. mppx is a peer dependency; if your install ends up with two copies of it, a refusal surfaces as an internal error (HTTP 500) instead.
|
|
59
121
|
|
|
60
122
|
## Condition types
|
|
61
123
|
|
|
@@ -182,6 +244,9 @@ Either way, set `INSUMER_API_KEY` as an environment variable in your runtime.
|
|
|
182
244
|
| `matchMode` | `'any' \| 'all'` | `'any'` | Wallet must satisfy any or all conditions |
|
|
183
245
|
| `cacheTtlSeconds` | `number` | `300` | In-memory cache TTL |
|
|
184
246
|
| `apiBaseUrl` | `string` | `https://api.insumermodel.com` | API base URL override |
|
|
247
|
+
| `provenPayer` | `(details) => ProvenPayer` | none | Returns the payer the method proved; required for free access |
|
|
248
|
+
| `replayStore` | `AtomicStore` | bounded in-memory, per process | Records used credentials; must be atomic; share it across instances |
|
|
249
|
+
| `maxCredentialLifetimeSeconds` | `number` | `600` | Longest remaining validity a credential may have and still get free access |
|
|
185
250
|
|
|
186
251
|
## Supported chains
|
|
187
252
|
|
package/dist/index.d.ts
CHANGED
|
@@ -133,6 +133,47 @@ export type ConditionGateOptions = {
|
|
|
133
133
|
* with `format: "jwt"` directly if you need the `jwt` and `pqJwt` tokens.
|
|
134
134
|
*/
|
|
135
135
|
jwt?: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Where the gate records credentials it has accepted, so each one gets
|
|
138
|
+
* through at most once. Defaults to a bounded in-process store.
|
|
139
|
+
*
|
|
140
|
+
* Pass a shared store when the route runs on more than one instance, or a
|
|
141
|
+
* credential used on one instance can be presented again on another. The
|
|
142
|
+
* store must claim atomically and remove expired entries: `Store.redis`,
|
|
143
|
+
* `Store.upstash` or `Store.cloudflare` from `mppx/server` built from a client
|
|
144
|
+
* that exposes an atomic `update`, or any store with an atomic `tryClaim`.
|
|
145
|
+
* mppx's `Store.memory()` never removes expired entries; use it only in tests.
|
|
146
|
+
*/
|
|
147
|
+
replayStore?: ReplayStore;
|
|
148
|
+
/**
|
|
149
|
+
* Longest remaining validity, in seconds, a credential may have and still be
|
|
150
|
+
* given free access. Defaults to 600. The gate has to remember a credential
|
|
151
|
+
* until it expires, and x402 clients choose their own expiry, so longer-lived
|
|
152
|
+
* credentials take the paid path instead.
|
|
153
|
+
*/
|
|
154
|
+
maxCredentialLifetimeSeconds?: number;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* An atomic claim store. Structurally compatible with mppx's `AtomicStore`:
|
|
158
|
+
* `tryClaim` is used when present, otherwise `update`. `get`, when present,
|
|
159
|
+
* lets the gate refuse a repeat before spending an attestation on it, and
|
|
160
|
+
* `delete` (or `update`) lets it release a credential whose payment failed.
|
|
161
|
+
*/
|
|
162
|
+
export type ReplayStore = {
|
|
163
|
+
get?: (key: string) => unknown | Promise<unknown>;
|
|
164
|
+
delete?: (key: string) => void | Promise<void>;
|
|
165
|
+
tryClaim?: (key: string, expires: number) => boolean | Promise<boolean>;
|
|
166
|
+
update?: <result>(key: string, fn: (current: any) => {
|
|
167
|
+
op: 'noop';
|
|
168
|
+
result: result;
|
|
169
|
+
} | {
|
|
170
|
+
op: 'set';
|
|
171
|
+
value: any;
|
|
172
|
+
result: result;
|
|
173
|
+
} | {
|
|
174
|
+
op: 'delete';
|
|
175
|
+
result: result;
|
|
176
|
+
}) => Promise<result>;
|
|
136
177
|
};
|
|
137
178
|
export type InsumerAttestation = {
|
|
138
179
|
ok: boolean;
|
|
@@ -174,7 +215,7 @@ export type InsumerAttestation = {
|
|
|
174
215
|
creditsCharged: number;
|
|
175
216
|
};
|
|
176
217
|
};
|
|
177
|
-
/** Clear the in-memory ownership cache. Useful in tests. */
|
|
218
|
+
/** Clear the in-memory ownership cache and the default replay store. Useful in tests. */
|
|
178
219
|
export declare function clearConditionGateCache(): void;
|
|
179
220
|
/**
|
|
180
221
|
* Extracts an EVM address from a `did:pkh:eip155:{chainId}:{address}` string.
|
|
@@ -212,6 +253,16 @@ export declare function normalizeProvenPayer(payer: ProvenPayer): {
|
|
|
212
253
|
* credential that fails validation, conditions not met, or an attestation
|
|
213
254
|
* error. There is no path from an unproven wallet to a free receipt.
|
|
214
255
|
*
|
|
256
|
+
* Each credential gets free access at most once. The gate records a
|
|
257
|
+
* credential when it grants free access, and records an authorization just
|
|
258
|
+
* before the paid path settles it; a recorded credential is refused with a
|
|
259
|
+
* verification error rather than passed on to payment. A payment that fails is
|
|
260
|
+
* released, so it can be retried. See the README for the limits of this. Free access is given only to credentials the gate can identify
|
|
261
|
+
* (EIP-3009 authorizations and Tempo proofs) whose remaining validity is within
|
|
262
|
+
* `maxCredentialLifetimeSeconds`. The default store is bounded and shared by
|
|
263
|
+
* every gated route in the process; pass a shared `replayStore` for production
|
|
264
|
+
* traffic or when the route runs on more than one instance.
|
|
265
|
+
*
|
|
215
266
|
* Conditions are evaluated across the 35 chains this adapter reaches (32 EVM +
|
|
216
267
|
* Solana + XRPL + Bitcoin; the engine itself covers 38). Six condition types
|
|
217
268
|
* are typed here: token_balance, nft_ownership, eas_attestation, farcaster_id,
|
|
@@ -226,8 +277,9 @@ export declare function normalizeProvenPayer(payer: ProvenPayer): {
|
|
|
226
277
|
* ```ts
|
|
227
278
|
* import { conditionGate } from '@insumermodel/mppx-condition-gate'
|
|
228
279
|
*
|
|
229
|
-
* const gated = conditionGate(
|
|
280
|
+
* const gated = conditionGate(evmCharge, {
|
|
230
281
|
* // Return only a payer this method has proven for THIS request.
|
|
282
|
+
* // mppx's EVM charge reports the recovered signer as `payer`.
|
|
231
283
|
* provenPayer: (details) => (details as { payer?: string }).payer ?? null,
|
|
232
284
|
* conditions: [
|
|
233
285
|
* { type: 'eas_attestation', template: 'coinbase_verified_account', chainId: 8453 },
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Errors } from 'mppx';
|
|
1
2
|
const cache = new Map();
|
|
2
3
|
function conditionSortKey(c) {
|
|
3
4
|
if (c.type === 'farcaster_id')
|
|
@@ -15,9 +16,184 @@ function cacheKey(address, conditions) {
|
|
|
15
16
|
});
|
|
16
17
|
return `${address.toLowerCase()}:${JSON.stringify(sorted)}`;
|
|
17
18
|
}
|
|
18
|
-
/** Clear the in-memory ownership cache. Useful in tests. */
|
|
19
|
+
/** Clear the in-memory ownership cache and the default replay store. Useful in tests. */
|
|
19
20
|
export function clearConditionGateCache() {
|
|
20
21
|
cache.clear();
|
|
22
|
+
defaultMarkers.clear();
|
|
23
|
+
freeCountByOwner.clear();
|
|
24
|
+
freeCount = 0;
|
|
25
|
+
paidCount = 0;
|
|
26
|
+
nextSweepAt = 0;
|
|
27
|
+
}
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Single-use credentials
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// mppx makes a credential single-use when it settles: the on-chain nonce is
|
|
32
|
+
// spent, or the method claims the hash or proof in its store. `validate` is
|
|
33
|
+
// non-mutating by design, so a credential that is granted free access and
|
|
34
|
+
// never settled would otherwise stay usable by anyone who holds a copy.
|
|
35
|
+
/** Kept this long past the credential's own expiry, to absorb clock skew. */
|
|
36
|
+
const REPLAY_SKEW_MS = 60 * 1000;
|
|
37
|
+
const DEFAULT_MAX_CREDENTIAL_LIFETIME_SECONDS = 600;
|
|
38
|
+
/** Default store: live free grants across the process, and per wallet. */
|
|
39
|
+
const DEFAULT_STORE_MAX_FREE = 100_000;
|
|
40
|
+
const DEFAULT_STORE_MAX_FREE_PER_WALLET = 5_000;
|
|
41
|
+
/** Default store: payments it remembers. Past this it stops recording payments. */
|
|
42
|
+
const DEFAULT_STORE_MAX_PAID = 100_000;
|
|
43
|
+
const DEFAULT_STORE_SWEEP_MS = 60_000;
|
|
44
|
+
const defaultMarkers = new Map();
|
|
45
|
+
const freeCountByOwner = new Map();
|
|
46
|
+
let freeCount = 0;
|
|
47
|
+
let paidCount = 0;
|
|
48
|
+
let nextSweepAt = 0;
|
|
49
|
+
function forgetDefault(key) {
|
|
50
|
+
const marker = defaultMarkers.get(key);
|
|
51
|
+
if (!marker)
|
|
52
|
+
return;
|
|
53
|
+
defaultMarkers.delete(key);
|
|
54
|
+
if (marker.kind === 'paid') {
|
|
55
|
+
paidCount--;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
freeCount--;
|
|
59
|
+
const remaining = (freeCountByOwner.get(marker.owner) ?? 1) - 1;
|
|
60
|
+
if (remaining <= 0)
|
|
61
|
+
freeCountByOwner.delete(marker.owner);
|
|
62
|
+
else
|
|
63
|
+
freeCountByOwner.set(marker.owner, remaining);
|
|
64
|
+
}
|
|
65
|
+
const defaultRecorder = {
|
|
66
|
+
async isTaken(key) {
|
|
67
|
+
const marker = defaultMarkers.get(key);
|
|
68
|
+
return marker !== undefined && marker.expires > Date.now();
|
|
69
|
+
},
|
|
70
|
+
async claim(key, expires, owner, kind) {
|
|
71
|
+
const now = Date.now();
|
|
72
|
+
if (now >= nextSweepAt) {
|
|
73
|
+
for (const [k, marker] of defaultMarkers)
|
|
74
|
+
if (marker.expires <= now)
|
|
75
|
+
forgetDefault(k);
|
|
76
|
+
nextSweepAt = now + DEFAULT_STORE_SWEEP_MS;
|
|
77
|
+
}
|
|
78
|
+
const current = defaultMarkers.get(key);
|
|
79
|
+
if (current !== undefined) {
|
|
80
|
+
if (current.expires > now)
|
|
81
|
+
return false;
|
|
82
|
+
forgetDefault(key);
|
|
83
|
+
}
|
|
84
|
+
if (kind === 'free') {
|
|
85
|
+
const held = freeCountByOwner.get(owner) ?? 0;
|
|
86
|
+
if (freeCount >= DEFAULT_STORE_MAX_FREE || held >= DEFAULT_STORE_MAX_FREE_PER_WALLET) {
|
|
87
|
+
throw new Error('mppx-condition-gate: default replay store has no room for this wallet');
|
|
88
|
+
}
|
|
89
|
+
freeCount++;
|
|
90
|
+
freeCountByOwner.set(owner, held + 1);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
if (paidCount >= DEFAULT_STORE_MAX_PAID) {
|
|
94
|
+
throw new Error('mppx-condition-gate: default replay store is full');
|
|
95
|
+
}
|
|
96
|
+
paidCount++;
|
|
97
|
+
}
|
|
98
|
+
defaultMarkers.set(key, { expires, owner, kind });
|
|
99
|
+
return true;
|
|
100
|
+
},
|
|
101
|
+
async release(key) {
|
|
102
|
+
forgetDefault(key);
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
function isReplayMarker(value) {
|
|
106
|
+
return (typeof value === 'object' &&
|
|
107
|
+
value !== null &&
|
|
108
|
+
typeof value.expires === 'number' &&
|
|
109
|
+
value.type === 'mppx:replay');
|
|
110
|
+
}
|
|
111
|
+
async function tryClaim(store, key, expires) {
|
|
112
|
+
if (typeof store.tryClaim === 'function')
|
|
113
|
+
return store.tryClaim(key, expires);
|
|
114
|
+
// Same marker as mppx's Store.tryClaim. A live marker, or any other stored
|
|
115
|
+
// value, counts as taken; an empty slot or an expired marker does not.
|
|
116
|
+
return store.update(key, (current) => {
|
|
117
|
+
const empty = current === null || current === undefined || current === false;
|
|
118
|
+
const taken = !empty && (!isReplayMarker(current) || current.expires > Date.now());
|
|
119
|
+
return taken
|
|
120
|
+
? { op: 'noop', result: false }
|
|
121
|
+
: { op: 'set', value: { expires, type: 'mppx:replay' }, result: true };
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function storeRecorder(store) {
|
|
125
|
+
return {
|
|
126
|
+
async isTaken(key) {
|
|
127
|
+
// Advisory only: the atomic claim decides. Anything but a live marker reads as free.
|
|
128
|
+
if (typeof store.get !== 'function')
|
|
129
|
+
return false;
|
|
130
|
+
const current = await store.get(key);
|
|
131
|
+
return isReplayMarker(current) && current.expires > Date.now();
|
|
132
|
+
},
|
|
133
|
+
async claim(key, expires) {
|
|
134
|
+
return tryClaim(store, key, expires);
|
|
135
|
+
},
|
|
136
|
+
async release(key) {
|
|
137
|
+
if (typeof store.delete === 'function') {
|
|
138
|
+
await store.delete(key);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (typeof store.update === 'function') {
|
|
142
|
+
await store.update(key, (current) => isReplayMarker(current)
|
|
143
|
+
? { op: 'delete', result: undefined }
|
|
144
|
+
: { op: 'noop', result: undefined });
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function lowerHex(value) {
|
|
150
|
+
return typeof value === 'string' && /^0x[0-9a-fA-F]+$/.test(value) ? value.toLowerCase() : null;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* One key that identifies the credential, or null when the gate cannot
|
|
154
|
+
* identify it safely, in which case it gets no free access.
|
|
155
|
+
*
|
|
156
|
+
* - EIP-3009 authorization (mppx EVM charge, native and x402): signer + nonce.
|
|
157
|
+
* Neither changes when the signature is re-encoded or the challenge is
|
|
158
|
+
* rebuilt, and two users never share one.
|
|
159
|
+
* - Tempo proof: challenge id + proven payer. The proof signs the challenge
|
|
160
|
+
* id, so it cannot be moved to another challenge.
|
|
161
|
+
*
|
|
162
|
+
* Other credential types are payments in their own right (a Tempo hash is a
|
|
163
|
+
* transfer already on chain, a Tempo transaction is one waiting to be sent),
|
|
164
|
+
* so they take the paid path, where the method's own replay protection applies.
|
|
165
|
+
*/
|
|
166
|
+
function credentialKey(methodName, credential, payerAddress) {
|
|
167
|
+
const payload = credential?.payload;
|
|
168
|
+
if (payload === null || typeof payload !== 'object')
|
|
169
|
+
return null;
|
|
170
|
+
let id = null;
|
|
171
|
+
if (payload.type === 'authorization') {
|
|
172
|
+
const from = lowerHex(payload.from);
|
|
173
|
+
const nonce = lowerHex(payload.nonce);
|
|
174
|
+
if (from && nonce)
|
|
175
|
+
id = `authorization:${from}:${nonce}`;
|
|
176
|
+
}
|
|
177
|
+
else if (payload.type === 'proof') {
|
|
178
|
+
const challengeId = credential?.challenge?.id;
|
|
179
|
+
if (typeof challengeId === 'string' && challengeId.length > 0) {
|
|
180
|
+
id = `proof:${challengeId}:${payerAddress.toLowerCase()}`;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return id === null ? null : `mppx-condition-gate:${methodName}:${id}`;
|
|
184
|
+
}
|
|
185
|
+
/** The latest moment the credential could still be accepted, or null if unknown. */
|
|
186
|
+
function credentialExpiry(credential) {
|
|
187
|
+
const payload = credential?.payload;
|
|
188
|
+
if (payload?.type === 'authorization') {
|
|
189
|
+
// An authorization is bounded by its own validBefore. For x402 the
|
|
190
|
+
// challenge is rebuilt on every request, so its expiry says nothing about
|
|
191
|
+
// the credential; a native credential's validBefore is its challenge's expiry.
|
|
192
|
+
const validBefore = Number(payload.validBefore);
|
|
193
|
+
return Number.isFinite(validBefore) && validBefore > 0 ? validBefore * 1000 : null;
|
|
194
|
+
}
|
|
195
|
+
const challengeExpires = Date.parse(credential?.challenge?.expires);
|
|
196
|
+
return Number.isFinite(challengeExpires) ? challengeExpires : null;
|
|
21
197
|
}
|
|
22
198
|
// ---------------------------------------------------------------------------
|
|
23
199
|
// DID parsing
|
|
@@ -225,6 +401,16 @@ export function normalizeProvenPayer(payer) {
|
|
|
225
401
|
* credential that fails validation, conditions not met, or an attestation
|
|
226
402
|
* error. There is no path from an unproven wallet to a free receipt.
|
|
227
403
|
*
|
|
404
|
+
* Each credential gets free access at most once. The gate records a
|
|
405
|
+
* credential when it grants free access, and records an authorization just
|
|
406
|
+
* before the paid path settles it; a recorded credential is refused with a
|
|
407
|
+
* verification error rather than passed on to payment. A payment that fails is
|
|
408
|
+
* released, so it can be retried. See the README for the limits of this. Free access is given only to credentials the gate can identify
|
|
409
|
+
* (EIP-3009 authorizations and Tempo proofs) whose remaining validity is within
|
|
410
|
+
* `maxCredentialLifetimeSeconds`. The default store is bounded and shared by
|
|
411
|
+
* every gated route in the process; pass a shared `replayStore` for production
|
|
412
|
+
* traffic or when the route runs on more than one instance.
|
|
413
|
+
*
|
|
228
414
|
* Conditions are evaluated across the 35 chains this adapter reaches (32 EVM +
|
|
229
415
|
* Solana + XRPL + Bitcoin; the engine itself covers 38). Six condition types
|
|
230
416
|
* are typed here: token_balance, nft_ownership, eas_attestation, farcaster_id,
|
|
@@ -239,8 +425,9 @@ export function normalizeProvenPayer(payer) {
|
|
|
239
425
|
* ```ts
|
|
240
426
|
* import { conditionGate } from '@insumermodel/mppx-condition-gate'
|
|
241
427
|
*
|
|
242
|
-
* const gated = conditionGate(
|
|
428
|
+
* const gated = conditionGate(evmCharge, {
|
|
243
429
|
* // Return only a payer this method has proven for THIS request.
|
|
430
|
+
* // mppx's EVM charge reports the recovered signer as `payer`.
|
|
244
431
|
* provenPayer: (details) => (details as { payer?: string }).payer ?? null,
|
|
245
432
|
* conditions: [
|
|
246
433
|
* { type: 'eas_attestation', template: 'coinbase_verified_account', chainId: 8453 },
|
|
@@ -254,6 +441,18 @@ export function normalizeProvenPayer(payer) {
|
|
|
254
441
|
*/
|
|
255
442
|
export function conditionGate(server, options) {
|
|
256
443
|
const { conditions, matchMode = 'any', cacheTtlSeconds = 300, provenPayer } = options;
|
|
444
|
+
const lifetimeSeconds = options.maxCredentialLifetimeSeconds ?? DEFAULT_MAX_CREDENTIAL_LIFETIME_SECONDS;
|
|
445
|
+
if (typeof lifetimeSeconds !== 'number' || !Number.isFinite(lifetimeSeconds) || lifetimeSeconds < 0) {
|
|
446
|
+
throw new Error('mppx-condition-gate: maxCredentialLifetimeSeconds must be a finite number of seconds, 0 or more.');
|
|
447
|
+
}
|
|
448
|
+
const maxLifetimeMs = lifetimeSeconds * 1000;
|
|
449
|
+
const { replayStore } = options;
|
|
450
|
+
if (replayStore !== undefined &&
|
|
451
|
+
typeof replayStore.tryClaim !== 'function' &&
|
|
452
|
+
typeof replayStore.update !== 'function') {
|
|
453
|
+
throw new Error('mppx-condition-gate: replayStore must provide an atomic tryClaim or update (an mppx AtomicStore).');
|
|
454
|
+
}
|
|
455
|
+
const recorder = replayStore ? storeRecorder(replayStore) : defaultRecorder;
|
|
257
456
|
const anyServer = server;
|
|
258
457
|
const originalVerify = anyServer.verify;
|
|
259
458
|
const originalBroadcast = anyServer.broadcast;
|
|
@@ -263,10 +462,30 @@ export function conditionGate(server, options) {
|
|
|
263
462
|
// without `validate` (legacy verify-only, or broadcast-without-validate) has
|
|
264
463
|
// no safe pre-check, so it is never gated.
|
|
265
464
|
const canGate = typeof provenPayer === 'function' && typeof originalValidate === 'function';
|
|
266
|
-
|
|
465
|
+
const refuse = () => new Errors.VerificationFailedError({ reason: 'this credential has already been presented' });
|
|
466
|
+
/** Attestation result for a payer, from the cache or a fresh call. Throws on API error. */
|
|
467
|
+
async function evaluate(payer) {
|
|
468
|
+
const key = cacheKey(payer.address, conditions);
|
|
469
|
+
const cached = cache.get(key);
|
|
470
|
+
if (cached && cached.expiresAt > Date.now())
|
|
471
|
+
return cached;
|
|
472
|
+
const result = await callAttest(payer.address, payer.type, conditions, options);
|
|
473
|
+
const attestation = result.data.attestation;
|
|
474
|
+
const pass = matchMode === 'all'
|
|
475
|
+
? attestation.pass
|
|
476
|
+
: attestation.results.some((r) => r.met);
|
|
477
|
+
const entry = {
|
|
478
|
+
pass,
|
|
479
|
+
attestationId: attestation.id,
|
|
480
|
+
expiresAt: Date.now() + cacheTtlSeconds * 1000,
|
|
481
|
+
};
|
|
482
|
+
cache.set(key, entry);
|
|
483
|
+
return entry;
|
|
484
|
+
}
|
|
485
|
+
/** Decides between a free receipt and the paid path. Throws to refuse a repeat. */
|
|
267
486
|
async function tryFree(params) {
|
|
268
487
|
if (!canGate)
|
|
269
|
-
return
|
|
488
|
+
return { free: false };
|
|
270
489
|
let details;
|
|
271
490
|
try {
|
|
272
491
|
const validation = await originalValidate(params);
|
|
@@ -274,60 +493,124 @@ export function conditionGate(server, options) {
|
|
|
274
493
|
}
|
|
275
494
|
catch {
|
|
276
495
|
// Credential is not currently acceptable → let the payment method decide.
|
|
277
|
-
return
|
|
496
|
+
return { free: false };
|
|
278
497
|
}
|
|
279
498
|
let resolved;
|
|
280
499
|
try {
|
|
281
500
|
resolved = await provenPayer(details);
|
|
282
501
|
}
|
|
283
502
|
catch {
|
|
284
|
-
return
|
|
503
|
+
return { free: false };
|
|
285
504
|
}
|
|
286
505
|
const payer = normalizeProvenPayer(resolved);
|
|
287
506
|
if (!payer)
|
|
288
|
-
return
|
|
289
|
-
const
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
507
|
+
return { free: false };
|
|
508
|
+
const credential = params?.credential;
|
|
509
|
+
const key = credentialKey(server.name, credential, payer.address);
|
|
510
|
+
const expiry = credentialExpiry(credential);
|
|
511
|
+
if (key === null || expiry === null)
|
|
512
|
+
return { free: false };
|
|
513
|
+
const record = {
|
|
514
|
+
key,
|
|
515
|
+
owner: payer.address.toLowerCase(),
|
|
516
|
+
expires: Math.min(expiry + REPLAY_SKEW_MS, Number.MAX_SAFE_INTEGER),
|
|
517
|
+
// Only an authorization moves value; a Tempo proof is accepted on zero-amount routes.
|
|
518
|
+
payment: credential?.payload?.type === 'authorization',
|
|
519
|
+
};
|
|
520
|
+
// A recorded credential is refused before any attestation is spent on it.
|
|
521
|
+
let taken;
|
|
522
|
+
try {
|
|
523
|
+
taken = await recorder.isTaken(key);
|
|
524
|
+
}
|
|
525
|
+
catch {
|
|
526
|
+
return { free: false, record };
|
|
527
|
+
}
|
|
528
|
+
if (taken) {
|
|
529
|
+
// A repeated Tempo proof moves no value, so the method decides; a payment is refused.
|
|
530
|
+
if (!record.payment)
|
|
531
|
+
return { free: false };
|
|
532
|
+
throw refuse();
|
|
300
533
|
}
|
|
534
|
+
if (expiry - Date.now() > maxLifetimeMs)
|
|
535
|
+
return { free: false, record };
|
|
536
|
+
let evaluation;
|
|
301
537
|
try {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
538
|
+
evaluation = await evaluate(payer);
|
|
539
|
+
}
|
|
540
|
+
catch {
|
|
541
|
+
// Attestation error → paid path.
|
|
542
|
+
return { free: false, record };
|
|
543
|
+
}
|
|
544
|
+
if (!evaluation.pass)
|
|
545
|
+
return { free: false, record };
|
|
546
|
+
let claimed;
|
|
547
|
+
try {
|
|
548
|
+
claimed = await recorder.claim(key, record.expires, record.owner, 'free');
|
|
549
|
+
}
|
|
550
|
+
catch {
|
|
551
|
+
// The store cannot record the credential, so it gets no free access.
|
|
552
|
+
return { free: false, record };
|
|
553
|
+
}
|
|
554
|
+
if (!claimed) {
|
|
555
|
+
if (!record.payment)
|
|
556
|
+
return { free: false };
|
|
557
|
+
throw refuse();
|
|
558
|
+
}
|
|
559
|
+
return {
|
|
560
|
+
free: true,
|
|
561
|
+
receipt: {
|
|
315
562
|
method: server.name,
|
|
316
|
-
reference: `condition-gate:free:${
|
|
563
|
+
reference: `condition-gate:free:${evaluation.attestationId}`,
|
|
317
564
|
status: 'success',
|
|
318
565
|
timestamp: new Date().toISOString(),
|
|
319
|
-
}
|
|
566
|
+
},
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
/** Runs the gate, then the original method on the paid path. */
|
|
570
|
+
async function gated(original, params) {
|
|
571
|
+
const attempt = await tryFree(params);
|
|
572
|
+
if (attempt.free)
|
|
573
|
+
return attempt.receipt;
|
|
574
|
+
const record = attempt.record;
|
|
575
|
+
let claimed = false;
|
|
576
|
+
// Only a payment is recorded on this path. A Tempo proof moves no value, so
|
|
577
|
+
// the method's own rules decide whether it may be presented again.
|
|
578
|
+
if (record && record.payment) {
|
|
579
|
+
// Claimed before settlement, so a copy presented while this payment is
|
|
580
|
+
// in flight is refused too. Kept until the credential itself expires.
|
|
581
|
+
let result;
|
|
582
|
+
try {
|
|
583
|
+
result = await recorder.claim(record.key, record.expires, record.owner, 'paid');
|
|
584
|
+
}
|
|
585
|
+
catch {
|
|
586
|
+
// Cannot record: pay as bare mppx would; the method's own replay protection applies.
|
|
587
|
+
result = null;
|
|
588
|
+
}
|
|
589
|
+
if (result === false)
|
|
590
|
+
throw refuse();
|
|
591
|
+
claimed = result === true;
|
|
320
592
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
593
|
+
try {
|
|
594
|
+
return await original(params);
|
|
595
|
+
}
|
|
596
|
+
catch (error) {
|
|
597
|
+
// A payment that fails is released, so the holder can retry with the same credential.
|
|
598
|
+
if (claimed) {
|
|
599
|
+
try {
|
|
600
|
+
await recorder.release(record.key);
|
|
601
|
+
}
|
|
602
|
+
catch {
|
|
603
|
+
// Stays recorded until it expires.
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
throw error;
|
|
324
607
|
}
|
|
325
608
|
}
|
|
326
609
|
const wrapped = { ...server };
|
|
327
610
|
if (typeof originalBroadcast === 'function') {
|
|
328
|
-
wrapped.broadcast = async (params) => (
|
|
611
|
+
wrapped.broadcast = async (params) => gated(originalBroadcast, params);
|
|
329
612
|
}
|
|
330
|
-
wrapped.verify = async (params) => (
|
|
613
|
+
wrapped.verify = async (params) => gated(originalVerify, params);
|
|
331
614
|
return wrapped;
|
|
332
615
|
}
|
|
333
616
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@insumermodel/mppx-condition-gate",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "Condition-based access for mppx routes. Wallet auth via signed attestations. Six condition types: token balance, NFT ownership, EAS attestation, Farcaster ID, ratio_to_amount, ratio_to_supply.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -45,16 +45,12 @@
|
|
|
45
45
|
"url": "git+https://github.com/douglasborthwick-crypto/mppx-condition-gate.git"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"mppx": ">=0.
|
|
49
|
-
},
|
|
50
|
-
"peerDependenciesMeta": {
|
|
51
|
-
"mppx": {
|
|
52
|
-
"optional": true
|
|
53
|
-
}
|
|
48
|
+
"mppx": ">=0.8.14"
|
|
54
49
|
},
|
|
55
50
|
"devDependencies": {
|
|
56
51
|
"@types/node": "^25.5.0",
|
|
57
|
-
"mppx": "
|
|
58
|
-
"typescript": "^5.7.0"
|
|
52
|
+
"mppx": "0.9.3",
|
|
53
|
+
"typescript": "^5.7.0",
|
|
54
|
+
"viem": "2.56.5"
|
|
59
55
|
}
|
|
60
56
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Method, Receipt } from 'mppx'
|
|
2
|
+
import { Errors } from 'mppx'
|
|
2
3
|
|
|
3
4
|
// ---------------------------------------------------------------------------
|
|
4
5
|
// Types
|
|
@@ -160,6 +161,44 @@ export type ConditionGateOptions = {
|
|
|
160
161
|
* with `format: "jwt"` directly if you need the `jwt` and `pqJwt` tokens.
|
|
161
162
|
*/
|
|
162
163
|
jwt?: boolean
|
|
164
|
+
/**
|
|
165
|
+
* Where the gate records credentials it has accepted, so each one gets
|
|
166
|
+
* through at most once. Defaults to a bounded in-process store.
|
|
167
|
+
*
|
|
168
|
+
* Pass a shared store when the route runs on more than one instance, or a
|
|
169
|
+
* credential used on one instance can be presented again on another. The
|
|
170
|
+
* store must claim atomically and remove expired entries: `Store.redis`,
|
|
171
|
+
* `Store.upstash` or `Store.cloudflare` from `mppx/server` built from a client
|
|
172
|
+
* that exposes an atomic `update`, or any store with an atomic `tryClaim`.
|
|
173
|
+
* mppx's `Store.memory()` never removes expired entries; use it only in tests.
|
|
174
|
+
*/
|
|
175
|
+
replayStore?: ReplayStore
|
|
176
|
+
/**
|
|
177
|
+
* Longest remaining validity, in seconds, a credential may have and still be
|
|
178
|
+
* given free access. Defaults to 600. The gate has to remember a credential
|
|
179
|
+
* until it expires, and x402 clients choose their own expiry, so longer-lived
|
|
180
|
+
* credentials take the paid path instead.
|
|
181
|
+
*/
|
|
182
|
+
maxCredentialLifetimeSeconds?: number
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* An atomic claim store. Structurally compatible with mppx's `AtomicStore`:
|
|
187
|
+
* `tryClaim` is used when present, otherwise `update`. `get`, when present,
|
|
188
|
+
* lets the gate refuse a repeat before spending an attestation on it, and
|
|
189
|
+
* `delete` (or `update`) lets it release a credential whose payment failed.
|
|
190
|
+
*/
|
|
191
|
+
export type ReplayStore = {
|
|
192
|
+
get?: (key: string) => unknown | Promise<unknown>
|
|
193
|
+
delete?: (key: string) => void | Promise<void>
|
|
194
|
+
tryClaim?: (key: string, expires: number) => boolean | Promise<boolean>
|
|
195
|
+
update?: <result>(
|
|
196
|
+
key: string,
|
|
197
|
+
fn: (current: any) =>
|
|
198
|
+
| { op: 'noop'; result: result }
|
|
199
|
+
| { op: 'set'; value: any; result: result }
|
|
200
|
+
| { op: 'delete'; result: result },
|
|
201
|
+
) => Promise<result>
|
|
163
202
|
}
|
|
164
203
|
|
|
165
204
|
export type InsumerAttestation = {
|
|
@@ -232,9 +271,199 @@ function cacheKey(address: string, conditions: Condition[]): string {
|
|
|
232
271
|
return `${address.toLowerCase()}:${JSON.stringify(sorted)}`
|
|
233
272
|
}
|
|
234
273
|
|
|
235
|
-
/** Clear the in-memory ownership cache. Useful in tests. */
|
|
274
|
+
/** Clear the in-memory ownership cache and the default replay store. Useful in tests. */
|
|
236
275
|
export function clearConditionGateCache(): void {
|
|
237
276
|
cache.clear()
|
|
277
|
+
defaultMarkers.clear()
|
|
278
|
+
freeCountByOwner.clear()
|
|
279
|
+
freeCount = 0
|
|
280
|
+
paidCount = 0
|
|
281
|
+
nextSweepAt = 0
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ---------------------------------------------------------------------------
|
|
285
|
+
// Single-use credentials
|
|
286
|
+
// ---------------------------------------------------------------------------
|
|
287
|
+
|
|
288
|
+
// mppx makes a credential single-use when it settles: the on-chain nonce is
|
|
289
|
+
// spent, or the method claims the hash or proof in its store. `validate` is
|
|
290
|
+
// non-mutating by design, so a credential that is granted free access and
|
|
291
|
+
// never settled would otherwise stay usable by anyone who holds a copy.
|
|
292
|
+
|
|
293
|
+
/** Kept this long past the credential's own expiry, to absorb clock skew. */
|
|
294
|
+
const REPLAY_SKEW_MS = 60 * 1000
|
|
295
|
+
const DEFAULT_MAX_CREDENTIAL_LIFETIME_SECONDS = 600
|
|
296
|
+
/** Default store: live free grants across the process, and per wallet. */
|
|
297
|
+
const DEFAULT_STORE_MAX_FREE = 100_000
|
|
298
|
+
const DEFAULT_STORE_MAX_FREE_PER_WALLET = 5_000
|
|
299
|
+
/** Default store: payments it remembers. Past this it stops recording payments. */
|
|
300
|
+
const DEFAULT_STORE_MAX_PAID = 100_000
|
|
301
|
+
const DEFAULT_STORE_SWEEP_MS = 60_000
|
|
302
|
+
|
|
303
|
+
type RecordKind = 'free' | 'paid'
|
|
304
|
+
type DefaultMarker = { expires: number; owner: string; kind: RecordKind }
|
|
305
|
+
|
|
306
|
+
const defaultMarkers = new Map<string, DefaultMarker>()
|
|
307
|
+
const freeCountByOwner = new Map<string, number>()
|
|
308
|
+
let freeCount = 0
|
|
309
|
+
let paidCount = 0
|
|
310
|
+
let nextSweepAt = 0
|
|
311
|
+
|
|
312
|
+
function forgetDefault(key: string): void {
|
|
313
|
+
const marker = defaultMarkers.get(key)
|
|
314
|
+
if (!marker) return
|
|
315
|
+
defaultMarkers.delete(key)
|
|
316
|
+
if (marker.kind === 'paid') {
|
|
317
|
+
paidCount--
|
|
318
|
+
return
|
|
319
|
+
}
|
|
320
|
+
freeCount--
|
|
321
|
+
const remaining = (freeCountByOwner.get(marker.owner) ?? 1) - 1
|
|
322
|
+
if (remaining <= 0) freeCountByOwner.delete(marker.owner)
|
|
323
|
+
else freeCountByOwner.set(marker.owner, remaining)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/** What the gate needs from a store. The default store and a caller's store both sit behind it. */
|
|
327
|
+
type Recorder = {
|
|
328
|
+
isTaken(key: string): Promise<boolean>
|
|
329
|
+
/** true when claimed, false when already taken; throws when it cannot record. */
|
|
330
|
+
claim(key: string, expires: number, owner: string, kind: RecordKind): Promise<boolean>
|
|
331
|
+
release(key: string): Promise<void>
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const defaultRecorder: Recorder = {
|
|
335
|
+
async isTaken(key) {
|
|
336
|
+
const marker = defaultMarkers.get(key)
|
|
337
|
+
return marker !== undefined && marker.expires > Date.now()
|
|
338
|
+
},
|
|
339
|
+
async claim(key, expires, owner, kind) {
|
|
340
|
+
const now = Date.now()
|
|
341
|
+
if (now >= nextSweepAt) {
|
|
342
|
+
for (const [k, marker] of defaultMarkers) if (marker.expires <= now) forgetDefault(k)
|
|
343
|
+
nextSweepAt = now + DEFAULT_STORE_SWEEP_MS
|
|
344
|
+
}
|
|
345
|
+
const current = defaultMarkers.get(key)
|
|
346
|
+
if (current !== undefined) {
|
|
347
|
+
if (current.expires > now) return false
|
|
348
|
+
forgetDefault(key)
|
|
349
|
+
}
|
|
350
|
+
if (kind === 'free') {
|
|
351
|
+
const held = freeCountByOwner.get(owner) ?? 0
|
|
352
|
+
if (freeCount >= DEFAULT_STORE_MAX_FREE || held >= DEFAULT_STORE_MAX_FREE_PER_WALLET) {
|
|
353
|
+
throw new Error('mppx-condition-gate: default replay store has no room for this wallet')
|
|
354
|
+
}
|
|
355
|
+
freeCount++
|
|
356
|
+
freeCountByOwner.set(owner, held + 1)
|
|
357
|
+
} else {
|
|
358
|
+
if (paidCount >= DEFAULT_STORE_MAX_PAID) {
|
|
359
|
+
throw new Error('mppx-condition-gate: default replay store is full')
|
|
360
|
+
}
|
|
361
|
+
paidCount++
|
|
362
|
+
}
|
|
363
|
+
defaultMarkers.set(key, { expires, owner, kind })
|
|
364
|
+
return true
|
|
365
|
+
},
|
|
366
|
+
async release(key) {
|
|
367
|
+
forgetDefault(key)
|
|
368
|
+
},
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function isReplayMarker(value: unknown): value is { expires: number; type: 'mppx:replay' } {
|
|
372
|
+
return (
|
|
373
|
+
typeof value === 'object' &&
|
|
374
|
+
value !== null &&
|
|
375
|
+
typeof (value as { expires?: unknown }).expires === 'number' &&
|
|
376
|
+
(value as { type?: unknown }).type === 'mppx:replay'
|
|
377
|
+
)
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async function tryClaim(store: ReplayStore, key: string, expires: number): Promise<boolean> {
|
|
381
|
+
if (typeof store.tryClaim === 'function') return store.tryClaim(key, expires)
|
|
382
|
+
// Same marker as mppx's Store.tryClaim. A live marker, or any other stored
|
|
383
|
+
// value, counts as taken; an empty slot or an expired marker does not.
|
|
384
|
+
return store.update!(key, (current) => {
|
|
385
|
+
const empty = current === null || current === undefined || current === false
|
|
386
|
+
const taken = !empty && (!isReplayMarker(current) || current.expires > Date.now())
|
|
387
|
+
return taken
|
|
388
|
+
? { op: 'noop', result: false }
|
|
389
|
+
: { op: 'set', value: { expires, type: 'mppx:replay' }, result: true }
|
|
390
|
+
})
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function storeRecorder(store: ReplayStore): Recorder {
|
|
394
|
+
return {
|
|
395
|
+
async isTaken(key) {
|
|
396
|
+
// Advisory only: the atomic claim decides. Anything but a live marker reads as free.
|
|
397
|
+
if (typeof store.get !== 'function') return false
|
|
398
|
+
const current = await store.get(key)
|
|
399
|
+
return isReplayMarker(current) && current.expires > Date.now()
|
|
400
|
+
},
|
|
401
|
+
async claim(key, expires) {
|
|
402
|
+
return tryClaim(store, key, expires)
|
|
403
|
+
},
|
|
404
|
+
async release(key) {
|
|
405
|
+
if (typeof store.delete === 'function') {
|
|
406
|
+
await store.delete(key)
|
|
407
|
+
return
|
|
408
|
+
}
|
|
409
|
+
if (typeof store.update === 'function') {
|
|
410
|
+
await store.update(key, (current) =>
|
|
411
|
+
isReplayMarker(current)
|
|
412
|
+
? { op: 'delete', result: undefined }
|
|
413
|
+
: { op: 'noop', result: undefined },
|
|
414
|
+
)
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function lowerHex(value: unknown): string | null {
|
|
421
|
+
return typeof value === 'string' && /^0x[0-9a-fA-F]+$/.test(value) ? value.toLowerCase() : null
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* One key that identifies the credential, or null when the gate cannot
|
|
426
|
+
* identify it safely, in which case it gets no free access.
|
|
427
|
+
*
|
|
428
|
+
* - EIP-3009 authorization (mppx EVM charge, native and x402): signer + nonce.
|
|
429
|
+
* Neither changes when the signature is re-encoded or the challenge is
|
|
430
|
+
* rebuilt, and two users never share one.
|
|
431
|
+
* - Tempo proof: challenge id + proven payer. The proof signs the challenge
|
|
432
|
+
* id, so it cannot be moved to another challenge.
|
|
433
|
+
*
|
|
434
|
+
* Other credential types are payments in their own right (a Tempo hash is a
|
|
435
|
+
* transfer already on chain, a Tempo transaction is one waiting to be sent),
|
|
436
|
+
* so they take the paid path, where the method's own replay protection applies.
|
|
437
|
+
*/
|
|
438
|
+
function credentialKey(methodName: string, credential: any, payerAddress: string): string | null {
|
|
439
|
+
const payload = credential?.payload
|
|
440
|
+
if (payload === null || typeof payload !== 'object') return null
|
|
441
|
+
let id: string | null = null
|
|
442
|
+
if (payload.type === 'authorization') {
|
|
443
|
+
const from = lowerHex(payload.from)
|
|
444
|
+
const nonce = lowerHex(payload.nonce)
|
|
445
|
+
if (from && nonce) id = `authorization:${from}:${nonce}`
|
|
446
|
+
} else if (payload.type === 'proof') {
|
|
447
|
+
const challengeId = credential?.challenge?.id
|
|
448
|
+
if (typeof challengeId === 'string' && challengeId.length > 0) {
|
|
449
|
+
id = `proof:${challengeId}:${payerAddress.toLowerCase()}`
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return id === null ? null : `mppx-condition-gate:${methodName}:${id}`
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/** The latest moment the credential could still be accepted, or null if unknown. */
|
|
456
|
+
function credentialExpiry(credential: any): number | null {
|
|
457
|
+
const payload = credential?.payload
|
|
458
|
+
if (payload?.type === 'authorization') {
|
|
459
|
+
// An authorization is bounded by its own validBefore. For x402 the
|
|
460
|
+
// challenge is rebuilt on every request, so its expiry says nothing about
|
|
461
|
+
// the credential; a native credential's validBefore is its challenge's expiry.
|
|
462
|
+
const validBefore = Number(payload.validBefore)
|
|
463
|
+
return Number.isFinite(validBefore) && validBefore > 0 ? validBefore * 1000 : null
|
|
464
|
+
}
|
|
465
|
+
const challengeExpires = Date.parse(credential?.challenge?.expires)
|
|
466
|
+
return Number.isFinite(challengeExpires) ? challengeExpires : null
|
|
238
467
|
}
|
|
239
468
|
|
|
240
469
|
// ---------------------------------------------------------------------------
|
|
@@ -438,6 +667,16 @@ export function normalizeProvenPayer(
|
|
|
438
667
|
* credential that fails validation, conditions not met, or an attestation
|
|
439
668
|
* error. There is no path from an unproven wallet to a free receipt.
|
|
440
669
|
*
|
|
670
|
+
* Each credential gets free access at most once. The gate records a
|
|
671
|
+
* credential when it grants free access, and records an authorization just
|
|
672
|
+
* before the paid path settles it; a recorded credential is refused with a
|
|
673
|
+
* verification error rather than passed on to payment. A payment that fails is
|
|
674
|
+
* released, so it can be retried. See the README for the limits of this. Free access is given only to credentials the gate can identify
|
|
675
|
+
* (EIP-3009 authorizations and Tempo proofs) whose remaining validity is within
|
|
676
|
+
* `maxCredentialLifetimeSeconds`. The default store is bounded and shared by
|
|
677
|
+
* every gated route in the process; pass a shared `replayStore` for production
|
|
678
|
+
* traffic or when the route runs on more than one instance.
|
|
679
|
+
*
|
|
441
680
|
* Conditions are evaluated across the 35 chains this adapter reaches (32 EVM +
|
|
442
681
|
* Solana + XRPL + Bitcoin; the engine itself covers 38). Six condition types
|
|
443
682
|
* are typed here: token_balance, nft_ownership, eas_attestation, farcaster_id,
|
|
@@ -452,8 +691,9 @@ export function normalizeProvenPayer(
|
|
|
452
691
|
* ```ts
|
|
453
692
|
* import { conditionGate } from '@insumermodel/mppx-condition-gate'
|
|
454
693
|
*
|
|
455
|
-
* const gated = conditionGate(
|
|
694
|
+
* const gated = conditionGate(evmCharge, {
|
|
456
695
|
* // Return only a payer this method has proven for THIS request.
|
|
696
|
+
* // mppx's EVM charge reports the recovered signer as `payer`.
|
|
457
697
|
* provenPayer: (details) => (details as { payer?: string }).payer ?? null,
|
|
458
698
|
* conditions: [
|
|
459
699
|
* { type: 'eas_attestation', template: 'coinbase_verified_account', chainId: 8453 },
|
|
@@ -470,6 +710,21 @@ export function conditionGate(
|
|
|
470
710
|
options: ConditionGateOptions,
|
|
471
711
|
): Method.AnyServer {
|
|
472
712
|
const { conditions, matchMode = 'any', cacheTtlSeconds = 300, provenPayer } = options
|
|
713
|
+
const lifetimeSeconds = options.maxCredentialLifetimeSeconds ?? DEFAULT_MAX_CREDENTIAL_LIFETIME_SECONDS
|
|
714
|
+
if (typeof lifetimeSeconds !== 'number' || !Number.isFinite(lifetimeSeconds) || lifetimeSeconds < 0) {
|
|
715
|
+
throw new Error('mppx-condition-gate: maxCredentialLifetimeSeconds must be a finite number of seconds, 0 or more.')
|
|
716
|
+
}
|
|
717
|
+
const maxLifetimeMs = lifetimeSeconds * 1000
|
|
718
|
+
|
|
719
|
+
const { replayStore } = options
|
|
720
|
+
if (
|
|
721
|
+
replayStore !== undefined &&
|
|
722
|
+
typeof replayStore.tryClaim !== 'function' &&
|
|
723
|
+
typeof replayStore.update !== 'function'
|
|
724
|
+
) {
|
|
725
|
+
throw new Error('mppx-condition-gate: replayStore must provide an atomic tryClaim or update (an mppx AtomicStore).')
|
|
726
|
+
}
|
|
727
|
+
const recorder = replayStore ? storeRecorder(replayStore) : defaultRecorder
|
|
473
728
|
|
|
474
729
|
const anyServer = server as unknown as {
|
|
475
730
|
verify: (params: any) => Promise<any>
|
|
@@ -488,9 +743,37 @@ export function conditionGate(
|
|
|
488
743
|
const canGate =
|
|
489
744
|
typeof provenPayer === 'function' && typeof originalValidate === 'function'
|
|
490
745
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
746
|
+
const refuse = () =>
|
|
747
|
+
new Errors.VerificationFailedError({ reason: 'this credential has already been presented' })
|
|
748
|
+
|
|
749
|
+
/** Attestation result for a payer, from the cache or a fresh call. Throws on API error. */
|
|
750
|
+
async function evaluate(payer: { address: string; type: WalletType }) {
|
|
751
|
+
const key = cacheKey(payer.address, conditions)
|
|
752
|
+
const cached = cache.get(key)
|
|
753
|
+
if (cached && cached.expiresAt > Date.now()) return cached
|
|
754
|
+
|
|
755
|
+
const result = await callAttest(payer.address, payer.type, conditions, options)
|
|
756
|
+
const attestation = result.data.attestation
|
|
757
|
+
const pass =
|
|
758
|
+
matchMode === 'all'
|
|
759
|
+
? attestation.pass
|
|
760
|
+
: attestation.results.some((r) => r.met)
|
|
761
|
+
const entry = {
|
|
762
|
+
pass,
|
|
763
|
+
attestationId: attestation.id,
|
|
764
|
+
expiresAt: Date.now() + cacheTtlSeconds * 1000,
|
|
765
|
+
}
|
|
766
|
+
cache.set(key, entry)
|
|
767
|
+
return entry
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
type Attempt =
|
|
771
|
+
| { free: true; receipt: any }
|
|
772
|
+
| { free: false; record?: { key: string; expires: number; owner: string; payment: boolean } }
|
|
773
|
+
|
|
774
|
+
/** Decides between a free receipt and the paid path. Throws to refuse a repeat. */
|
|
775
|
+
async function tryFree(params: any): Promise<Attempt> {
|
|
776
|
+
if (!canGate) return { free: false }
|
|
494
777
|
|
|
495
778
|
let details: unknown
|
|
496
779
|
try {
|
|
@@ -498,68 +781,124 @@ export function conditionGate(
|
|
|
498
781
|
details = (validation as { details?: unknown } | undefined)?.details
|
|
499
782
|
} catch {
|
|
500
783
|
// Credential is not currently acceptable → let the payment method decide.
|
|
501
|
-
return
|
|
784
|
+
return { free: false }
|
|
502
785
|
}
|
|
503
786
|
|
|
504
787
|
let resolved: ProvenPayer
|
|
505
788
|
try {
|
|
506
789
|
resolved = await provenPayer!(details)
|
|
507
790
|
} catch {
|
|
508
|
-
return
|
|
791
|
+
return { free: false }
|
|
509
792
|
}
|
|
510
793
|
|
|
511
794
|
const payer = normalizeProvenPayer(resolved)
|
|
512
|
-
if (!payer) return
|
|
795
|
+
if (!payer) return { free: false }
|
|
796
|
+
|
|
797
|
+
const credential = params?.credential
|
|
798
|
+
const key = credentialKey(server.name, credential, payer.address)
|
|
799
|
+
const expiry = credentialExpiry(credential)
|
|
800
|
+
if (key === null || expiry === null) return { free: false }
|
|
801
|
+
|
|
802
|
+
const record = {
|
|
803
|
+
key,
|
|
804
|
+
owner: payer.address.toLowerCase(),
|
|
805
|
+
expires: Math.min(expiry + REPLAY_SKEW_MS, Number.MAX_SAFE_INTEGER),
|
|
806
|
+
// Only an authorization moves value; a Tempo proof is accepted on zero-amount routes.
|
|
807
|
+
payment: credential?.payload?.type === 'authorization',
|
|
808
|
+
}
|
|
513
809
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
810
|
+
// A recorded credential is refused before any attestation is spent on it.
|
|
811
|
+
let taken: boolean
|
|
812
|
+
try {
|
|
813
|
+
taken = await recorder.isTaken(key)
|
|
814
|
+
} catch {
|
|
815
|
+
return { free: false, record }
|
|
816
|
+
}
|
|
817
|
+
if (taken) {
|
|
818
|
+
// A repeated Tempo proof moves no value, so the method decides; a payment is refused.
|
|
819
|
+
if (!record.payment) return { free: false }
|
|
820
|
+
throw refuse()
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if (expiry - Date.now() > maxLifetimeMs) return { free: false, record }
|
|
824
|
+
|
|
825
|
+
let evaluation: CacheEntry
|
|
826
|
+
try {
|
|
827
|
+
evaluation = await evaluate(payer)
|
|
828
|
+
} catch {
|
|
829
|
+
// Attestation error → paid path.
|
|
830
|
+
return { free: false, record }
|
|
831
|
+
}
|
|
832
|
+
if (!evaluation.pass) return { free: false, record }
|
|
833
|
+
|
|
834
|
+
let claimed: boolean
|
|
835
|
+
try {
|
|
836
|
+
claimed = await recorder.claim(key, record.expires, record.owner, 'free')
|
|
837
|
+
} catch {
|
|
838
|
+
// The store cannot record the credential, so it gets no free access.
|
|
839
|
+
return { free: false, record }
|
|
840
|
+
}
|
|
841
|
+
if (!claimed) {
|
|
842
|
+
if (!record.payment) return { free: false }
|
|
843
|
+
throw refuse()
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
return {
|
|
847
|
+
free: true,
|
|
848
|
+
receipt: {
|
|
519
849
|
method: server.name,
|
|
520
|
-
reference: `condition-gate:free:${
|
|
850
|
+
reference: `condition-gate:free:${evaluation.attestationId}`,
|
|
521
851
|
status: 'success' as const,
|
|
522
852
|
timestamp: new Date().toISOString(),
|
|
853
|
+
},
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/** Runs the gate, then the original method on the paid path. */
|
|
858
|
+
async function gated(original: (params: any) => Promise<any>, params: any) {
|
|
859
|
+
const attempt = await tryFree(params)
|
|
860
|
+
if (attempt.free) return attempt.receipt
|
|
861
|
+
|
|
862
|
+
const record = attempt.record
|
|
863
|
+
let claimed = false
|
|
864
|
+
// Only a payment is recorded on this path. A Tempo proof moves no value, so
|
|
865
|
+
// the method's own rules decide whether it may be presented again.
|
|
866
|
+
if (record && record.payment) {
|
|
867
|
+
// Claimed before settlement, so a copy presented while this payment is
|
|
868
|
+
// in flight is refused too. Kept until the credential itself expires.
|
|
869
|
+
let result: boolean | null
|
|
870
|
+
try {
|
|
871
|
+
result = await recorder.claim(record.key, record.expires, record.owner, 'paid')
|
|
872
|
+
} catch {
|
|
873
|
+
// Cannot record: pay as bare mppx would; the method's own replay protection applies.
|
|
874
|
+
result = null
|
|
523
875
|
}
|
|
876
|
+
if (result === false) throw refuse()
|
|
877
|
+
claimed = result === true
|
|
524
878
|
}
|
|
525
879
|
|
|
526
880
|
try {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
pass,
|
|
537
|
-
attestationId: attestation.id,
|
|
538
|
-
expiresAt: Date.now() + cacheTtlSeconds * 1000,
|
|
539
|
-
})
|
|
540
|
-
|
|
541
|
-
if (!pass) return null
|
|
542
|
-
return {
|
|
543
|
-
method: server.name,
|
|
544
|
-
reference: `condition-gate:free:${attestation.id}`,
|
|
545
|
-
status: 'success' as const,
|
|
546
|
-
timestamp: new Date().toISOString(),
|
|
881
|
+
return await original(params)
|
|
882
|
+
} catch (error) {
|
|
883
|
+
// A payment that fails is released, so the holder can retry with the same credential.
|
|
884
|
+
if (claimed) {
|
|
885
|
+
try {
|
|
886
|
+
await recorder.release(record!.key)
|
|
887
|
+
} catch {
|
|
888
|
+
// Stays recorded until it expires.
|
|
889
|
+
}
|
|
547
890
|
}
|
|
548
|
-
|
|
549
|
-
// Attestation error → paid path.
|
|
550
|
-
return null
|
|
891
|
+
throw error
|
|
551
892
|
}
|
|
552
893
|
}
|
|
553
894
|
|
|
554
895
|
const wrapped = { ...server } as unknown as Record<string, unknown>
|
|
555
896
|
|
|
556
897
|
if (typeof originalBroadcast === 'function') {
|
|
557
|
-
wrapped.broadcast = async (params: any) =>
|
|
558
|
-
(await tryFree(params)) ?? originalBroadcast(params)
|
|
898
|
+
wrapped.broadcast = async (params: any) => gated(originalBroadcast, params)
|
|
559
899
|
}
|
|
560
900
|
|
|
561
|
-
wrapped.verify = async (params: any) =>
|
|
562
|
-
(await tryFree(params)) ?? originalVerify(params)
|
|
901
|
+
wrapped.verify = async (params: any) => gated(originalVerify, params)
|
|
563
902
|
|
|
564
903
|
return wrapped as unknown as Method.AnyServer
|
|
565
904
|
}
|