payid 1.0.5 → 2.0.3
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 +478 -15
- package/dist/chunk-AXLZUAYL.js +104 -0
- package/dist/{chunk-HKHRYRD6.js → chunk-F2KQGW76.js} +26 -96
- package/dist/{chunk-4UQKUVO5.js → chunk-K2B5UHYA.js} +4 -2
- package/dist/{chunk-ESTGPUEQ.js → chunk-WQEZYX4X.js} +4 -2
- package/dist/core/client/index.d.ts +3 -2
- package/dist/core/client/index.js +3 -2
- package/dist/core/server/index.d.ts +3 -2
- package/dist/core/server/index.js +3 -2
- package/dist/decision-proof/index.d.ts +23 -0
- package/dist/decision-proof/index.js +9 -0
- package/dist/{index-DSxDlF9J.d.ts → index-DpGIg0Hu.d.ts} +2 -1
- package/dist/{index-CsynGAGv.d.ts → index-IjgtzYO2.d.ts} +2 -1
- package/dist/index.d.ts +9 -6
- package/dist/index.js +14 -10
- package/dist/types-CSZ5F9J7.d.ts +23 -0
- package/dist/types-cnCPtnaV.d.ts +29 -0
- package/package.json +13 -3
- package/dist/types-i4eTkhWa.d.ts +0 -50
package/README.md
CHANGED
|
@@ -1,15 +1,478 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
# PayID SDK — `payid`
|
|
2
|
+
|
|
3
|
+
Policy-driven payment engine for EVM chains. Define **rules** that evaluate payment context off-chain, then submit a cryptographic **Decision Proof** on-chain for verification.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add payid ethers
|
|
9
|
+
# or
|
|
10
|
+
npm install payid ethers
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { PayIDClient } from "payid/client";
|
|
19
|
+
import { ethers } from "ethers";
|
|
20
|
+
|
|
21
|
+
const client = new PayIDClient();
|
|
22
|
+
|
|
23
|
+
const result = await client.evaluateAndProve({
|
|
24
|
+
context: {
|
|
25
|
+
tx: {
|
|
26
|
+
sender: "0xSender...",
|
|
27
|
+
receiver: "0xReceiver...",
|
|
28
|
+
asset: "0x0000000000000000000000000000000000000000", // native token
|
|
29
|
+
amount: "1000000000000000000", // 1 ETH in wei
|
|
30
|
+
chainId: 42161, // Arbitrum
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
authorityRule: myRuleConfig,
|
|
34
|
+
payId: "user@pay.id",
|
|
35
|
+
payer: "0xSender...",
|
|
36
|
+
receiver: "0xReceiver...",
|
|
37
|
+
asset: "0x0000000000000000000000000000000000000000",
|
|
38
|
+
amount: 1_000_000_000_000_000_000n,
|
|
39
|
+
signer: wallet,
|
|
40
|
+
verifyingContract: "0xPayWithPayID...",
|
|
41
|
+
ruleAuthority: "0xRuleAuthority...",
|
|
42
|
+
chainId: 42161,
|
|
43
|
+
blockTimestamp: Math.floor(Date.now() / 1000),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (result.result.decision === "ALLOW") {
|
|
47
|
+
// submit result.proof to PayWithPayID.payNative() on-chain
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Rule Language
|
|
54
|
+
|
|
55
|
+
Rules define **what conditions must be true** for a payment to be allowed. They are evaluated off-chain, and the outcome is signed into a Decision Proof that the smart contract verifies.
|
|
56
|
+
|
|
57
|
+
### Rule Config
|
|
58
|
+
|
|
59
|
+
Every rule set starts with a `RuleConfig`:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
interface RuleConfig {
|
|
63
|
+
logic: "AND" | "OR"; // how top-level rules are combined
|
|
64
|
+
rules: AnyRule[]; // list of rules
|
|
65
|
+
requires?: string[]; // required context namespaces (e.g. ["state", "risk"])
|
|
66
|
+
message?: string; // custom message on root rejection
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- **`AND`** — all rules must pass
|
|
71
|
+
- **`OR`** — at least one rule must pass
|
|
72
|
+
- Max nesting depth: **10 levels**
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### Rule Formats
|
|
77
|
+
|
|
78
|
+
There are three rule formats that can be mixed freely.
|
|
79
|
+
|
|
80
|
+
#### Format A — Simple Rule
|
|
81
|
+
|
|
82
|
+
One condition, one rule.
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
{
|
|
86
|
+
id: "min-amount",
|
|
87
|
+
if: { field: "tx.amount", op: ">=", value: "100000000000000000" },
|
|
88
|
+
message: "Minimum transfer is 0.1 ETH"
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### Format B — Multi-Condition Rule
|
|
93
|
+
|
|
94
|
+
Multiple conditions combined with `AND` / `OR`.
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
{
|
|
98
|
+
id: "business-hours",
|
|
99
|
+
logic: "AND",
|
|
100
|
+
conditions: [
|
|
101
|
+
{ field: "env.timestamp|hour", op: ">=", value: "9" },
|
|
102
|
+
{ field: "env.timestamp|hour", op: "<", value: "17" },
|
|
103
|
+
],
|
|
104
|
+
message: "Transfers only allowed during business hours (9–17 UTC)"
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### Format C — Nested Rule
|
|
109
|
+
|
|
110
|
+
Groups of rules combined with `AND` / `OR`. Can be nested up to 10 levels deep.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
{
|
|
114
|
+
id: "whitelist-or-small",
|
|
115
|
+
logic: "OR",
|
|
116
|
+
rules: [
|
|
117
|
+
{ id: "in-whitelist", if: { field: "tx.sender", op: "in", value: ["0xAlice", "0xBob"] } },
|
|
118
|
+
{ id: "small-amount", if: { field: "tx.amount", op: "<=", value: "50000000000000000" } }
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
### Conditions
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
interface RuleCondition {
|
|
129
|
+
field: string; // dot-notation path into the context
|
|
130
|
+
op: string; // operator
|
|
131
|
+
value: any; // literal value or "$field.reference"
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### Fields (Context Paths)
|
|
138
|
+
|
|
139
|
+
Fields use dot-notation to navigate the payment context.
|
|
140
|
+
|
|
141
|
+
#### Core Context (`tx`)
|
|
142
|
+
|
|
143
|
+
| Field | Type | Description |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| `tx.amount` | `string` (wei) | Transfer amount in smallest unit |
|
|
146
|
+
| `tx.amountUsd` | `string` | USD equivalent (if oracle provided) |
|
|
147
|
+
| `tx.asset` | `string` | Token contract address; `0x000...000` for native |
|
|
148
|
+
| `tx.sender` | `string` | Sender address |
|
|
149
|
+
| `tx.receiver` | `string` | Receiver address |
|
|
150
|
+
| `tx.chainId` | `number` | EVM chain ID |
|
|
151
|
+
|
|
152
|
+
#### Pay.ID Context (`payId`)
|
|
153
|
+
|
|
154
|
+
| Field | Type | Description |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| `payId.id` | `string` | The Pay.ID handle (e.g. `user@pay.id`) |
|
|
157
|
+
| `payId.owner` | `string` | Address that owns this Pay.ID |
|
|
158
|
+
|
|
159
|
+
#### Intent Context (`intent`)
|
|
160
|
+
|
|
161
|
+
| Field | Type | Description |
|
|
162
|
+
|---|---|---|
|
|
163
|
+
| `intent.type` | `"QR" \| "DIRECT" \| "API"` | How payment was initiated |
|
|
164
|
+
| `intent.expiresAt` | `number` | Unix timestamp when intent expires |
|
|
165
|
+
| `intent.issuer` | `string` | Who issued the intent |
|
|
166
|
+
|
|
167
|
+
#### Environment Context (`env`) — V2
|
|
168
|
+
|
|
169
|
+
| Field | Type | Description |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| `env.timestamp` | `number` | Current block timestamp (Unix seconds) |
|
|
172
|
+
|
|
173
|
+
#### State Context (`state`) — V2
|
|
174
|
+
|
|
175
|
+
| Field | Type | Description |
|
|
176
|
+
|---|---|---|
|
|
177
|
+
| `state.spentToday` | `string` | Total amount spent today (wei) |
|
|
178
|
+
| `state.period` | `string` | Current period identifier |
|
|
179
|
+
|
|
180
|
+
#### Oracle Context (`oracle`) — V2
|
|
181
|
+
|
|
182
|
+
Custom key-value data from an off-chain oracle. Example: `oracle.ethPrice`, `oracle.gasPrice`.
|
|
183
|
+
|
|
184
|
+
#### Risk Context (`risk`) — V2
|
|
185
|
+
|
|
186
|
+
| Field | Type | Description |
|
|
187
|
+
|---|---|---|
|
|
188
|
+
| `risk.score` | `number` | Risk score 0–1000 |
|
|
189
|
+
| `risk.category` | `string` | Risk category label |
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
### Field Transforms
|
|
194
|
+
|
|
195
|
+
Append `|transform` to a field to transform its value before comparison.
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
"env.timestamp|hour" → hour of day (0–23)
|
|
199
|
+
"tx.amount|div:1e18" → amount divided by 1e18
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
| Transform | Syntax | Description |
|
|
203
|
+
|---|---|---|
|
|
204
|
+
| `div` | `field\|div:N` | Divide by N (integer) |
|
|
205
|
+
| `mod` | `field\|mod:N` | Modulo N |
|
|
206
|
+
| `abs` | `field\|abs` | Absolute value |
|
|
207
|
+
| `hour` | `field\|hour` | Hour of day from Unix timestamp (0–23) |
|
|
208
|
+
| `day` | `field\|day` | Day of week from Unix timestamp (0=Mon, 6=Sun) |
|
|
209
|
+
| `date` | `field\|date` | Day of month (1–31) |
|
|
210
|
+
| `month` | `field\|month` | Month of year (1–12) |
|
|
211
|
+
| `len` | `field\|len` | String length |
|
|
212
|
+
| `lower` | `field\|lower` | Lowercase string |
|
|
213
|
+
| `upper` | `field\|upper` | Uppercase string |
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
### Operators
|
|
218
|
+
|
|
219
|
+
#### Numeric
|
|
220
|
+
|
|
221
|
+
| Operator | Description | Example |
|
|
222
|
+
|---|---|---|
|
|
223
|
+
| `>=` | Greater than or equal | `amount >= 1000` |
|
|
224
|
+
| `<=` | Less than or equal | `amount <= 50000` |
|
|
225
|
+
| `>` | Greater than | `amount > 0` |
|
|
226
|
+
| `<` | Less than | `risk.score < 700` |
|
|
227
|
+
| `between` | Inclusive range `[min, max]` | `value: ["100", "5000"]` |
|
|
228
|
+
| `not_between` | Outside range | `value: ["100", "5000"]` |
|
|
229
|
+
| `mod_eq` | `field % divisor == remainder` | `value: ["7", "0"]` (divisible by 7) |
|
|
230
|
+
| `mod_ne` | `field % divisor != remainder` | |
|
|
231
|
+
|
|
232
|
+
#### Equality
|
|
233
|
+
|
|
234
|
+
| Operator | Description |
|
|
235
|
+
|---|---|
|
|
236
|
+
| `==` | Loose equality (string + numeric coercion) |
|
|
237
|
+
| `!=` | Not equal |
|
|
238
|
+
| `in` | Value is in array |
|
|
239
|
+
| `not_in` | Value is not in array |
|
|
240
|
+
|
|
241
|
+
#### String
|
|
242
|
+
|
|
243
|
+
| Operator | Description |
|
|
244
|
+
|---|---|
|
|
245
|
+
| `contains` | String contains substring |
|
|
246
|
+
| `not_contains` | String does not contain substring |
|
|
247
|
+
| `starts_with` | String starts with prefix |
|
|
248
|
+
| `ends_with` | String ends with suffix |
|
|
249
|
+
| `regex` | Matches regex pattern (ReDoS-safe, max 200 chars) |
|
|
250
|
+
| `not_regex` | Does not match regex |
|
|
251
|
+
|
|
252
|
+
#### Existence
|
|
253
|
+
|
|
254
|
+
| Operator | Description |
|
|
255
|
+
|---|---|
|
|
256
|
+
| `exists` | Field is present and not null |
|
|
257
|
+
| `not_exists` | Field is absent or null |
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
### Cross-Field References
|
|
262
|
+
|
|
263
|
+
Prefix a value with `$` to compare against another field in the context.
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// Reject if spending more than today's limit
|
|
267
|
+
{ field: "tx.amount", op: "<=", value: "$state.dailyLimit" }
|
|
268
|
+
|
|
269
|
+
// Only allow if sender equals the Pay.ID owner
|
|
270
|
+
{ field: "tx.sender", op: "==", value: "$payId.owner" }
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
### Message Interpolation
|
|
276
|
+
|
|
277
|
+
Rule messages support `{field}` interpolation using the same dot-notation and transforms.
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
{
|
|
281
|
+
id: "amount-cap",
|
|
282
|
+
if: { field: "tx.amount", op: "<=", value: "1000000000000000000" },
|
|
283
|
+
message: "Rejected: amount {tx.amount} exceeds 1 ETH cap"
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Complete Examples
|
|
290
|
+
|
|
291
|
+
### 1. Simple Amount Cap
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
const rule: RuleConfig = {
|
|
295
|
+
logic: "AND",
|
|
296
|
+
rules: [
|
|
297
|
+
{
|
|
298
|
+
id: "max-per-tx",
|
|
299
|
+
if: { field: "tx.amount", op: "<=", value: "5000000000000000000" },
|
|
300
|
+
message: "Max 5 ETH per transaction"
|
|
301
|
+
}
|
|
302
|
+
]
|
|
303
|
+
};
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### 2. Daily Spending Limit
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
const rule: RuleConfig = {
|
|
310
|
+
logic: "AND",
|
|
311
|
+
requires: ["state"],
|
|
312
|
+
rules: [
|
|
313
|
+
{
|
|
314
|
+
id: "daily-limit",
|
|
315
|
+
if: { field: "state.spentToday", op: "<=", value: "10000000000000000000" },
|
|
316
|
+
message: "Daily limit of 10 ETH exceeded"
|
|
317
|
+
}
|
|
318
|
+
]
|
|
319
|
+
};
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### 3. Business Hours Only
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
const rule: RuleConfig = {
|
|
326
|
+
logic: "AND",
|
|
327
|
+
requires: ["env"],
|
|
328
|
+
rules: [
|
|
329
|
+
{
|
|
330
|
+
id: "business-hours",
|
|
331
|
+
logic: "AND",
|
|
332
|
+
conditions: [
|
|
333
|
+
{ field: "env.timestamp|hour", op: ">=", value: "9" },
|
|
334
|
+
{ field: "env.timestamp|hour", op: "<", value: "17" }
|
|
335
|
+
],
|
|
336
|
+
message: "Transfers only allowed 09:00–17:00 UTC"
|
|
337
|
+
}
|
|
338
|
+
]
|
|
339
|
+
};
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### 4. Whitelist OR Small Amount
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
const rule: RuleConfig = {
|
|
346
|
+
logic: "AND",
|
|
347
|
+
rules: [
|
|
348
|
+
{
|
|
349
|
+
id: "whitelist-or-small",
|
|
350
|
+
logic: "OR",
|
|
351
|
+
rules: [
|
|
352
|
+
{
|
|
353
|
+
id: "is-whitelisted",
|
|
354
|
+
if: {
|
|
355
|
+
field: "tx.sender",
|
|
356
|
+
op: "in",
|
|
357
|
+
value: ["0xAlice...", "0xBob...", "0xCharlie..."]
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
id: "small-amount",
|
|
362
|
+
if: { field: "tx.amount", op: "<=", value: "100000000000000000" }
|
|
363
|
+
}
|
|
364
|
+
],
|
|
365
|
+
message: "Sender not whitelisted and amount exceeds 0.1 ETH"
|
|
366
|
+
}
|
|
367
|
+
]
|
|
368
|
+
};
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### 5. Multi-Condition Risk Gate
|
|
372
|
+
|
|
373
|
+
```typescript
|
|
374
|
+
const rule: RuleConfig = {
|
|
375
|
+
logic: "AND",
|
|
376
|
+
requires: ["risk"],
|
|
377
|
+
rules: [
|
|
378
|
+
{
|
|
379
|
+
id: "risk-gate",
|
|
380
|
+
logic: "AND",
|
|
381
|
+
conditions: [
|
|
382
|
+
{ field: "risk.score", op: "<", value: "700" },
|
|
383
|
+
{ field: "risk.category", op: "!=", value: "SANCTIONED" }
|
|
384
|
+
],
|
|
385
|
+
message: "Payment blocked: risk score too high or sender sanctioned"
|
|
386
|
+
}
|
|
387
|
+
]
|
|
388
|
+
};
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### 6. Recurring Payment (Weekdays Only)
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
const rule: RuleConfig = {
|
|
395
|
+
logic: "AND",
|
|
396
|
+
requires: ["env"],
|
|
397
|
+
rules: [
|
|
398
|
+
{
|
|
399
|
+
id: "weekday-only",
|
|
400
|
+
// day transform: 0=Mon, 4=Fri, 5=Sat, 6=Sun
|
|
401
|
+
logic: "AND",
|
|
402
|
+
conditions: [
|
|
403
|
+
{ field: "env.timestamp|day", op: ">=", value: "0" },
|
|
404
|
+
{ field: "env.timestamp|day", op: "<=", value: "4" }
|
|
405
|
+
],
|
|
406
|
+
message: "Only weekday payments allowed"
|
|
407
|
+
}
|
|
408
|
+
]
|
|
409
|
+
};
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Evaluate Only (No Proof)
|
|
415
|
+
|
|
416
|
+
```typescript
|
|
417
|
+
import { evaluate } from "payid";
|
|
418
|
+
|
|
419
|
+
const result = await evaluate(context, ruleConfig);
|
|
420
|
+
// result.decision === "ALLOW" | "REJECT"
|
|
421
|
+
// result.code — rule ID that triggered the decision
|
|
422
|
+
// result.reason — human-readable message
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## Server-Side Usage
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
import { PayIDServer } from "payid/server";
|
|
431
|
+
import { ethers } from "ethers";
|
|
432
|
+
|
|
433
|
+
const server = new PayIDServer(
|
|
434
|
+
new ethers.Wallet(process.env.SIGNER_KEY!),
|
|
435
|
+
new Set(["0xTrustedIssuer..."]) // trusted attestation issuers
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
const { result, proof } = await server.evaluateAndProve({
|
|
439
|
+
context,
|
|
440
|
+
authorityRule: ruleConfig,
|
|
441
|
+
payId: "merchant@pay.id",
|
|
442
|
+
payer: "0xPayer...",
|
|
443
|
+
receiver: "0xMerchant...",
|
|
444
|
+
asset: "0x0000000000000000000000000000000000000000",
|
|
445
|
+
amount: 1_000_000_000_000_000_000n,
|
|
446
|
+
verifyingContract: "0xPayWithPayID...",
|
|
447
|
+
ruleAuthority: "0xRuleAuthority...",
|
|
448
|
+
chainId: 42161,
|
|
449
|
+
blockTimestamp: Math.floor(Date.now() / 1000),
|
|
450
|
+
});
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## Exports
|
|
456
|
+
|
|
457
|
+
| Import path | Contents |
|
|
458
|
+
|---|---|
|
|
459
|
+
| `payid` | `evaluate()` |
|
|
460
|
+
| `payid/client` | `PayIDClient` |
|
|
461
|
+
| `payid/server` | `PayIDServer` |
|
|
462
|
+
| `payid/decision-proof` | `generateDecisionProof()` |
|
|
463
|
+
| `payid/rule` | `combineRules()`, `canonicalizeRuleSet()` |
|
|
464
|
+
| `payid/issuer` | `signAttestation()` |
|
|
465
|
+
| `payid/context` | Context types |
|
|
466
|
+
| `payid/sessionPolicy` | `decodeSessionPolicy()`, `decodeSessionPolicyV2()` |
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## Limits
|
|
471
|
+
|
|
472
|
+
| Constraint | Value |
|
|
473
|
+
|---|---|
|
|
474
|
+
| Max rule nesting depth | 10 levels |
|
|
475
|
+
| Max regex pattern length | 200 chars |
|
|
476
|
+
| Nested quantifiers in regex | Rejected (ReDoS protection) |
|
|
477
|
+
| Decision Proof TTL (default) | 300 seconds |
|
|
478
|
+
| Decision Proof TTL (max recommended) | 3600 seconds |
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import {
|
|
2
|
+
hashContext,
|
|
3
|
+
hashRuleSet
|
|
4
|
+
} from "./chunk-X7NYQ47Y.js";
|
|
5
|
+
import {
|
|
6
|
+
randomHex
|
|
7
|
+
} from "./chunk-KDC67LIN.js";
|
|
8
|
+
|
|
9
|
+
// src/decision-proof/generate.ts
|
|
10
|
+
import { ethers, ZeroAddress } from "ethers";
|
|
11
|
+
var hash = (v) => ethers.keccak256(ethers.toUtf8Bytes(v));
|
|
12
|
+
async function generateDecisionProof(params) {
|
|
13
|
+
if (!params.payId || typeof params.payId !== "string" || params.payId.trim() === "") {
|
|
14
|
+
throw new Error("payId must not be empty");
|
|
15
|
+
}
|
|
16
|
+
if (!ethers.isAddress(params.payer) || params.payer === ethers.ZeroAddress) {
|
|
17
|
+
throw new Error("GENERATE_PROOF: payer address is invalid or zero");
|
|
18
|
+
}
|
|
19
|
+
if (!ethers.isAddress(params.receiver) || params.receiver === ethers.ZeroAddress) {
|
|
20
|
+
throw new Error("GENERATE_PROOF: receiver address is invalid or zero");
|
|
21
|
+
}
|
|
22
|
+
if (!ethers.isAddress(params.verifyingContract) || params.verifyingContract === ethers.ZeroAddress) {
|
|
23
|
+
throw new Error("GENERATE_PROOF: verifyingContract is invalid or zero");
|
|
24
|
+
}
|
|
25
|
+
if (!ethers.isAddress(params.ruleAuthority)) {
|
|
26
|
+
throw new Error("GENERATE_PROOF: ruleAuthority is not a valid address");
|
|
27
|
+
}
|
|
28
|
+
if (params.asset !== void 0 && !ethers.isAddress(params.asset)) {
|
|
29
|
+
throw new Error("GENERATE_PROOF: asset is not a valid address");
|
|
30
|
+
}
|
|
31
|
+
if (params.amount <= 0n) {
|
|
32
|
+
throw new Error("amount must be > 0");
|
|
33
|
+
}
|
|
34
|
+
if (params.ttlSeconds !== void 0 && (params.ttlSeconds <= 0 || !Number.isInteger(params.ttlSeconds))) {
|
|
35
|
+
throw new Error("GENERATE_PROOF: ttlSeconds must be a positive integer");
|
|
36
|
+
}
|
|
37
|
+
if (params.blockTimestamp !== void 0 && params.blockTimestamp <= 0) {
|
|
38
|
+
throw new Error("GENERATE_PROOF: blockTimestamp is invalid");
|
|
39
|
+
}
|
|
40
|
+
const now = params.blockTimestamp ?? Math.floor(Date.now() / 1e3);
|
|
41
|
+
const issuedAt = now - 30;
|
|
42
|
+
const expiresAt = now + (params.ttlSeconds ?? 300);
|
|
43
|
+
let chainId = params.chainId;
|
|
44
|
+
if (!chainId && params.signer.provider) {
|
|
45
|
+
const network = await params.signer.provider.getNetwork();
|
|
46
|
+
chainId = Number(network.chainId);
|
|
47
|
+
}
|
|
48
|
+
if (!chainId || chainId <= 0 || !Number.isInteger(chainId)) {
|
|
49
|
+
throw new Error(`GENERATE_PROOF: chainId is invalid: ${chainId}`);
|
|
50
|
+
}
|
|
51
|
+
const requiresAttestation = Array.isArray(params.ruleConfig?.requires) && params.ruleConfig.requires.length > 0;
|
|
52
|
+
const attestationUIDsHash = params.attestationUIDs ? ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode(["bytes32[]"], [params.attestationUIDs])) : ethers.ZeroHash;
|
|
53
|
+
const payload = {
|
|
54
|
+
version: hash("2"),
|
|
55
|
+
payId: hash(params.payId),
|
|
56
|
+
payer: params.payer,
|
|
57
|
+
receiver: params.receiver,
|
|
58
|
+
asset: params.asset,
|
|
59
|
+
amount: params.amount,
|
|
60
|
+
contextHash: hashContext(params.context),
|
|
61
|
+
ruleSetHash: params.ruleSetHashOverride ?? hashRuleSet(params.ruleConfig),
|
|
62
|
+
ruleAuthority: params.ruleAuthority ?? ZeroAddress,
|
|
63
|
+
issuedAt: BigInt(issuedAt),
|
|
64
|
+
expiresAt: BigInt(expiresAt),
|
|
65
|
+
nonce: randomHex(32),
|
|
66
|
+
requiresAttestation,
|
|
67
|
+
attestationUIDsHash
|
|
68
|
+
};
|
|
69
|
+
const domain = {
|
|
70
|
+
name: "PAY.ID Decision",
|
|
71
|
+
version: "2",
|
|
72
|
+
chainId,
|
|
73
|
+
verifyingContract: params.verifyingContract
|
|
74
|
+
};
|
|
75
|
+
const types = {
|
|
76
|
+
Decision: [
|
|
77
|
+
{ name: "version", type: "bytes32" },
|
|
78
|
+
{ name: "payId", type: "bytes32" },
|
|
79
|
+
{ name: "payer", type: "address" },
|
|
80
|
+
{ name: "receiver", type: "address" },
|
|
81
|
+
{ name: "asset", type: "address" },
|
|
82
|
+
{ name: "amount", type: "uint256" },
|
|
83
|
+
{ name: "contextHash", type: "bytes32" },
|
|
84
|
+
{ name: "ruleSetHash", type: "bytes32" },
|
|
85
|
+
{ name: "ruleAuthority", type: "address" },
|
|
86
|
+
{ name: "issuedAt", type: "uint64" },
|
|
87
|
+
{ name: "expiresAt", type: "uint64" },
|
|
88
|
+
{ name: "nonce", type: "bytes32" },
|
|
89
|
+
{ name: "requiresAttestation", type: "bool" },
|
|
90
|
+
{ name: "attestationUIDsHash", type: "bytes32" }
|
|
91
|
+
]
|
|
92
|
+
};
|
|
93
|
+
const signature = await params.signer.signTypedData(domain, types, payload);
|
|
94
|
+
const recovered = ethers.verifyTypedData(domain, types, payload, signature);
|
|
95
|
+
const signerAddress = await params.signer.getAddress();
|
|
96
|
+
if (recovered.toLowerCase() !== signerAddress.toLowerCase()) {
|
|
97
|
+
throw new Error("SIGNATURE_MISMATCH");
|
|
98
|
+
}
|
|
99
|
+
return { payload, signature };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export {
|
|
103
|
+
generateDecisionProof
|
|
104
|
+
};
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
hashContext,
|
|
3
|
-
hashRuleSet
|
|
4
|
-
} from "./chunk-X7NYQ47Y.js";
|
|
5
|
-
import {
|
|
6
|
-
randomHex
|
|
7
|
-
} from "./chunk-KDC67LIN.js";
|
|
8
|
-
|
|
9
1
|
// src/attestation/verify.ts
|
|
10
2
|
import { ethers, keccak256, toUtf8Bytes, toBeArray } from "ethers";
|
|
11
3
|
function verifyAttestation(payload, proof, trustedIssuers) {
|
|
@@ -137,29 +129,33 @@ async function runWasmRule(context, config, wasmBinary) {
|
|
|
137
129
|
async function runWasmRule2(context, config, _wasmBinary) {
|
|
138
130
|
return evaluateRule(context, config);
|
|
139
131
|
}
|
|
132
|
+
var MAX_RULE_DEPTH = 10;
|
|
140
133
|
function evaluateRule(context, config) {
|
|
141
134
|
const rules = config?.rules;
|
|
142
135
|
if (!Array.isArray(rules) || rules.length === 0) {
|
|
143
136
|
return { decision: "ALLOW", code: "NO_RULES", reason: "no rules defined" };
|
|
144
137
|
}
|
|
145
138
|
const logic = config?.logic ?? "AND";
|
|
146
|
-
return evalRules(context, rules, logic);
|
|
139
|
+
return evalRules(context, rules, logic, 0);
|
|
147
140
|
}
|
|
148
|
-
function evalRules(context, rules, logic) {
|
|
141
|
+
function evalRules(context, rules, logic, depth) {
|
|
142
|
+
if (depth > MAX_RULE_DEPTH) {
|
|
143
|
+
return { decision: "REJECT", code: "MAX_DEPTH_EXCEEDED", reason: `rule nesting exceeds the limit of ${MAX_RULE_DEPTH}` };
|
|
144
|
+
}
|
|
149
145
|
for (const rule of rules) {
|
|
150
|
-
const res = evalOneRule(context, rule);
|
|
146
|
+
const res = evalOneRule(context, rule, depth);
|
|
151
147
|
if (res.decision === "REJECT" && logic === "AND") return res;
|
|
152
148
|
if (res.decision === "ALLOW" && logic === "OR") return res;
|
|
153
149
|
}
|
|
154
150
|
if (logic === "AND") return { decision: "ALLOW", code: "OK", reason: "all rules passed" };
|
|
155
151
|
return { decision: "REJECT", code: "NO_RULE_MATCH", reason: "no rule matched in OR group" };
|
|
156
152
|
}
|
|
157
|
-
function evalOneRule(context, rule) {
|
|
153
|
+
function evalOneRule(context, rule, depth) {
|
|
158
154
|
const ruleId = rule?.id ?? "UNKNOWN_RULE";
|
|
159
155
|
const message = rule?.message ?? "";
|
|
160
156
|
if (Array.isArray(rule?.rules)) {
|
|
161
157
|
const subLogic = rule?.logic ?? "AND";
|
|
162
|
-
const res = evalRules(context, rule.rules, subLogic);
|
|
158
|
+
const res = evalRules(context, rule.rules, subLogic, depth + 1);
|
|
163
159
|
if (res.decision === "REJECT" && message) {
|
|
164
160
|
return { decision: "REJECT", code: ruleId, reason: message };
|
|
165
161
|
}
|
|
@@ -572,9 +568,22 @@ async function evaluate(context, ruleConfig, options, wasmBinary) {
|
|
|
572
568
|
if (!context.tx) {
|
|
573
569
|
throw new Error("evaluate(): context.tx is required");
|
|
574
570
|
}
|
|
571
|
+
if (context.tx.chainId !== void 0 && (!Number.isInteger(context.tx.chainId) || context.tx.chainId <= 0)) {
|
|
572
|
+
throw new Error(`chainId is invalid: ${context.tx.chainId}`);
|
|
573
|
+
}
|
|
574
|
+
if (context.tx.amount !== void 0) {
|
|
575
|
+
const amt = BigInt(context.tx.amount);
|
|
576
|
+
if (amt <= 0n) throw new Error("amount must be > 0");
|
|
577
|
+
}
|
|
575
578
|
if (!ruleConfig || typeof ruleConfig !== "object") {
|
|
576
579
|
throw new Error("evaluate(): ruleConfig is required");
|
|
577
580
|
}
|
|
581
|
+
if (ruleConfig.logic !== "AND" && ruleConfig.logic !== "OR") {
|
|
582
|
+
throw new Error(`ruleConfig.logic must be "AND" or "OR", got: ${ruleConfig.logic}`);
|
|
583
|
+
}
|
|
584
|
+
if (!Array.isArray(ruleConfig.rules) || ruleConfig.rules.length === 0) {
|
|
585
|
+
throw new Error("ruleConfig.rules must be a non-empty array");
|
|
586
|
+
}
|
|
578
587
|
let result;
|
|
579
588
|
try {
|
|
580
589
|
const preparedContext = options?.trustedIssuers ? preprocessContextV2(context, ruleConfig, options.trustedIssuers) : context;
|
|
@@ -610,84 +619,6 @@ async function evaluate(context, ruleConfig, options, wasmBinary) {
|
|
|
610
619
|
return baseResult;
|
|
611
620
|
}
|
|
612
621
|
|
|
613
|
-
// src/decision-proof/generate.ts
|
|
614
|
-
import { ethers as ethers2, ZeroAddress } from "ethers";
|
|
615
|
-
var hash = (v) => ethers2.keccak256(ethers2.toUtf8Bytes(v));
|
|
616
|
-
async function generateDecisionProof(params) {
|
|
617
|
-
if (!ethers2.isAddress(params.payer) || params.payer === ethers2.ZeroAddress) {
|
|
618
|
-
throw new Error("GENERATE_PROOF: payer address tidak valid atau zero");
|
|
619
|
-
}
|
|
620
|
-
if (!ethers2.isAddress(params.receiver) || params.receiver === ethers2.ZeroAddress) {
|
|
621
|
-
throw new Error("GENERATE_PROOF: receiver address tidak valid atau zero");
|
|
622
|
-
}
|
|
623
|
-
if (!ethers2.isAddress(params.verifyingContract) || params.verifyingContract === ethers2.ZeroAddress) {
|
|
624
|
-
throw new Error("GENERATE_PROOF: verifyingContract tidak valid atau zero");
|
|
625
|
-
}
|
|
626
|
-
if (params.amount <= 0n) {
|
|
627
|
-
throw new Error("GENERATE_PROOF: amount harus > 0");
|
|
628
|
-
}
|
|
629
|
-
const now = params.blockTimestamp ?? Math.floor(Date.now() / 1e3);
|
|
630
|
-
const issuedAt = now - 30;
|
|
631
|
-
const expiresAt = now + (params.ttlSeconds ?? 300);
|
|
632
|
-
let chainId = params.chainId;
|
|
633
|
-
if (!chainId && params.signer.provider) {
|
|
634
|
-
const network = await params.signer.provider.getNetwork();
|
|
635
|
-
chainId = Number(network.chainId);
|
|
636
|
-
}
|
|
637
|
-
if (!chainId || chainId <= 0 || !Number.isInteger(chainId)) {
|
|
638
|
-
throw new Error(`GENERATE_PROOF: chainId tidak valid: ${chainId}`);
|
|
639
|
-
}
|
|
640
|
-
const requiresAttestation = Array.isArray(params.ruleConfig?.requires) && params.ruleConfig.requires.length > 0;
|
|
641
|
-
const attestationUIDsHash = params.attestationUIDs ? ethers2.keccak256(ethers2.AbiCoder.defaultAbiCoder().encode(["bytes32[]"], [params.attestationUIDs])) : ethers2.ZeroHash;
|
|
642
|
-
const payload = {
|
|
643
|
-
version: hash("2"),
|
|
644
|
-
payId: hash(params.payId),
|
|
645
|
-
payer: params.payer,
|
|
646
|
-
receiver: params.receiver,
|
|
647
|
-
asset: params.asset,
|
|
648
|
-
amount: params.amount,
|
|
649
|
-
contextHash: hashContext(params.context),
|
|
650
|
-
ruleSetHash: params.ruleSetHashOverride ?? hashRuleSet(params.ruleConfig),
|
|
651
|
-
ruleAuthority: params.ruleAuthority ?? ZeroAddress,
|
|
652
|
-
issuedAt: BigInt(issuedAt),
|
|
653
|
-
expiresAt: BigInt(expiresAt),
|
|
654
|
-
nonce: randomHex(32),
|
|
655
|
-
requiresAttestation,
|
|
656
|
-
attestationUIDsHash
|
|
657
|
-
};
|
|
658
|
-
const domain = {
|
|
659
|
-
name: "PAY.ID Decision",
|
|
660
|
-
version: "2",
|
|
661
|
-
chainId,
|
|
662
|
-
verifyingContract: params.verifyingContract
|
|
663
|
-
};
|
|
664
|
-
const types = {
|
|
665
|
-
Decision: [
|
|
666
|
-
{ name: "version", type: "bytes32" },
|
|
667
|
-
{ name: "payId", type: "bytes32" },
|
|
668
|
-
{ name: "payer", type: "address" },
|
|
669
|
-
{ name: "receiver", type: "address" },
|
|
670
|
-
{ name: "asset", type: "address" },
|
|
671
|
-
{ name: "amount", type: "uint256" },
|
|
672
|
-
{ name: "contextHash", type: "bytes32" },
|
|
673
|
-
{ name: "ruleSetHash", type: "bytes32" },
|
|
674
|
-
{ name: "ruleAuthority", type: "address" },
|
|
675
|
-
{ name: "issuedAt", type: "uint64" },
|
|
676
|
-
{ name: "expiresAt", type: "uint64" },
|
|
677
|
-
{ name: "nonce", type: "bytes32" },
|
|
678
|
-
{ name: "requiresAttestation", type: "bool" },
|
|
679
|
-
{ name: "attestationUIDsHash", type: "bytes32" }
|
|
680
|
-
]
|
|
681
|
-
};
|
|
682
|
-
const signature = await params.signer.signTypedData(domain, types, payload);
|
|
683
|
-
const recovered = ethers2.verifyTypedData(domain, types, payload, signature);
|
|
684
|
-
const signerAddress = await params.signer.getAddress();
|
|
685
|
-
if (recovered.toLowerCase() !== signerAddress.toLowerCase()) {
|
|
686
|
-
throw new Error("SIGNATURE_MISMATCH");
|
|
687
|
-
}
|
|
688
|
-
return { payload, signature };
|
|
689
|
-
}
|
|
690
|
-
|
|
691
622
|
// src/utils/subtle.ts
|
|
692
623
|
var subtleCrypto = globalThis.crypto.subtle;
|
|
693
624
|
|
|
@@ -717,7 +648,7 @@ function bufferToHex(buffer) {
|
|
|
717
648
|
// src/resolver/resolver.ts
|
|
718
649
|
var DEFAULT_ZG_INDEXER = "https://indexer-testnet.0g.ai";
|
|
719
650
|
async function resolveRule(source, options) {
|
|
720
|
-
const { uri, hash
|
|
651
|
+
const { uri, hash } = source;
|
|
721
652
|
if (uri.startsWith("inline://")) {
|
|
722
653
|
const encoded = uri.replace("inline://", "");
|
|
723
654
|
const json = JSON.parse(atob(encoded));
|
|
@@ -726,18 +657,18 @@ async function resolveRule(source, options) {
|
|
|
726
657
|
if (uri.startsWith("ipfs://")) {
|
|
727
658
|
const cid = uri.replace("ipfs://", "");
|
|
728
659
|
const url = `https://ipfs.io/ipfs/${cid}`;
|
|
729
|
-
const config = await fetchJsonWithHashCheck(url,
|
|
660
|
+
const config = await fetchJsonWithHashCheck(url, hash);
|
|
730
661
|
return { config, source };
|
|
731
662
|
}
|
|
732
663
|
if (uri.startsWith("http://") || uri.startsWith("https://")) {
|
|
733
|
-
const config = await fetchJsonWithHashCheck(uri,
|
|
664
|
+
const config = await fetchJsonWithHashCheck(uri, hash);
|
|
734
665
|
return { config, source };
|
|
735
666
|
}
|
|
736
667
|
if (uri.startsWith("0g://")) {
|
|
737
668
|
const rootHash = uri.replace("0g://", "");
|
|
738
669
|
const indexerUrl = options?.zgIndexerUrl ?? globalThis.PAYID_ZGS_INDEXER_URL ?? DEFAULT_ZG_INDEXER;
|
|
739
670
|
const url = `${indexerUrl}/blob/${rootHash}`;
|
|
740
|
-
const config = await fetchJsonWithHashCheck(url,
|
|
671
|
+
const config = await fetchJsonWithHashCheck(url, hash);
|
|
741
672
|
return { config, source };
|
|
742
673
|
}
|
|
743
674
|
throw new Error("UNSUPPORTED_RULE_URI");
|
|
@@ -747,6 +678,5 @@ export {
|
|
|
747
678
|
loadWasm,
|
|
748
679
|
verifyAttestation,
|
|
749
680
|
evaluate,
|
|
750
|
-
generateDecisionProof,
|
|
751
681
|
resolveRule
|
|
752
682
|
};
|
|
@@ -7,10 +7,12 @@ import {
|
|
|
7
7
|
} from "./chunk-BC77BLFK.js";
|
|
8
8
|
import {
|
|
9
9
|
evaluate,
|
|
10
|
-
generateDecisionProof,
|
|
11
10
|
loadWasm,
|
|
12
11
|
resolveRule
|
|
13
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-F2KQGW76.js";
|
|
13
|
+
import {
|
|
14
|
+
generateDecisionProof
|
|
15
|
+
} from "./chunk-AXLZUAYL.js";
|
|
14
16
|
import {
|
|
15
17
|
__export
|
|
16
18
|
} from "./chunk-MLKGABMK.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export { P as PayIDClient, c as createPayID, c as createPayIDClient } from '../../index-
|
|
1
|
+
export { P as PayIDClient, c as createPayID, c as createPayIDClient } from '../../index-IjgtzYO2.js';
|
|
2
2
|
import '../../rule-a_5ed-93.js';
|
|
3
3
|
import '../../context.v1-C1m-tz0o.js';
|
|
4
|
-
import '../../types-
|
|
4
|
+
import '../../types-cnCPtnaV.js';
|
|
5
5
|
import 'ethers';
|
|
6
|
+
import '../../types-CSZ5F9J7.js';
|
|
6
7
|
import '../../types-D2o6XS7a.js';
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PayIDClient,
|
|
3
3
|
createPayIDClient
|
|
4
|
-
} from "../../chunk-
|
|
4
|
+
} from "../../chunk-K2B5UHYA.js";
|
|
5
5
|
import "../../chunk-GG34PNTF.js";
|
|
6
6
|
import "../../chunk-BC77BLFK.js";
|
|
7
7
|
import "../../chunk-6VPSJFO4.js";
|
|
8
|
-
import "../../chunk-
|
|
8
|
+
import "../../chunk-F2KQGW76.js";
|
|
9
|
+
import "../../chunk-AXLZUAYL.js";
|
|
9
10
|
import "../../chunk-X7NYQ47Y.js";
|
|
10
11
|
import "../../chunk-KDC67LIN.js";
|
|
11
12
|
import "../../chunk-MLKGABMK.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { P as PayIDServer, c as createPayIDServer } from '../../index-
|
|
1
|
+
export { P as PayIDServer, c as createPayIDServer } from '../../index-DpGIg0Hu.js';
|
|
2
2
|
import 'ethers';
|
|
3
3
|
import '../../rule-a_5ed-93.js';
|
|
4
4
|
import '../../context.v1-C1m-tz0o.js';
|
|
5
|
-
import '../../types-
|
|
5
|
+
import '../../types-cnCPtnaV.js';
|
|
6
|
+
import '../../types-CSZ5F9J7.js';
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PayIDServer,
|
|
3
3
|
createPayIDServer
|
|
4
|
-
} from "../../chunk-
|
|
5
|
-
import "../../chunk-
|
|
4
|
+
} from "../../chunk-WQEZYX4X.js";
|
|
5
|
+
import "../../chunk-F2KQGW76.js";
|
|
6
|
+
import "../../chunk-AXLZUAYL.js";
|
|
6
7
|
import "../../chunk-X7NYQ47Y.js";
|
|
7
8
|
import "../../chunk-KDC67LIN.js";
|
|
8
9
|
import "../../chunk-MLKGABMK.js";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { a as DecisionProof } from '../types-CSZ5F9J7.js';
|
|
2
|
+
export { D as DecisionPayload, b as DecisionValue } from '../types-CSZ5F9J7.js';
|
|
3
|
+
import { ethers } from 'ethers';
|
|
4
|
+
|
|
5
|
+
declare function generateDecisionProof(params: {
|
|
6
|
+
payId: string;
|
|
7
|
+
payer: string;
|
|
8
|
+
receiver: string;
|
|
9
|
+
asset: string;
|
|
10
|
+
amount: bigint;
|
|
11
|
+
context: any;
|
|
12
|
+
ruleConfig: any;
|
|
13
|
+
ruleSetHashOverride?: string;
|
|
14
|
+
signer: ethers.Signer;
|
|
15
|
+
ruleAuthority: string;
|
|
16
|
+
verifyingContract: string;
|
|
17
|
+
ttlSeconds?: number;
|
|
18
|
+
chainId?: number;
|
|
19
|
+
blockTimestamp?: number;
|
|
20
|
+
attestationUIDs?: string[];
|
|
21
|
+
}): Promise<DecisionProof>;
|
|
22
|
+
|
|
23
|
+
export { DecisionProof, generateDecisionProof };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ethers } from 'ethers';
|
|
2
2
|
import { b as RuleConfig } from './rule-a_5ed-93.js';
|
|
3
3
|
import { R as RuleContext } from './context.v1-C1m-tz0o.js';
|
|
4
|
-
import { R as ResolverOptions,
|
|
4
|
+
import { R as ResolverOptions, d as RuleSource, b as RuleResult } from './types-cnCPtnaV.js';
|
|
5
|
+
import { a as DecisionProof } from './types-CSZ5F9J7.js';
|
|
5
6
|
|
|
6
7
|
interface UserOperation {
|
|
7
8
|
sender: string;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { b as RuleConfig } from './rule-a_5ed-93.js';
|
|
2
2
|
import { R as RuleContext } from './context.v1-C1m-tz0o.js';
|
|
3
|
-
import { R as ResolverOptions,
|
|
3
|
+
import { R as ResolverOptions, d as RuleSource, b as RuleResult } from './types-cnCPtnaV.js';
|
|
4
4
|
import { ethers } from 'ethers';
|
|
5
|
+
import { a as DecisionProof } from './types-CSZ5F9J7.js';
|
|
5
6
|
import { P as PayIDSessionPolicyPayloadV1, S as SessionPolicyV2 } from './types-D2o6XS7a.js';
|
|
6
7
|
|
|
7
8
|
declare class PayIDClient {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import { P as PayIDClient$1 } from './index-
|
|
2
|
-
export { i as client } from './index-
|
|
3
|
-
import { Z as ZGStorage, P as PayIDServer$1, U as UserOperation } from './index-
|
|
4
|
-
export { i as server, z as storage } from './index-
|
|
1
|
+
import { P as PayIDClient$1 } from './index-IjgtzYO2.js';
|
|
2
|
+
export { i as client } from './index-IjgtzYO2.js';
|
|
3
|
+
import { Z as ZGStorage, P as PayIDServer$1, U as UserOperation } from './index-DpGIg0Hu.js';
|
|
4
|
+
export { i as server, z as storage } from './index-DpGIg0Hu.js';
|
|
5
5
|
import { ethers } from 'ethers';
|
|
6
|
-
import { R as ResolverOptions,
|
|
7
|
-
export {
|
|
6
|
+
import { R as ResolverOptions, d as RuleSource, b as RuleResult } from './types-cnCPtnaV.js';
|
|
7
|
+
export { a as RuleDecisionDebug, c as RuleResultDebug, e as RuleTraceEntry } from './types-cnCPtnaV.js';
|
|
8
8
|
import { b as RuleConfig } from './rule-a_5ed-93.js';
|
|
9
9
|
export { A as AnyRule, M as MultiConditionRule, N as NestedRule, R as Rule, a as RuleCondition, S as SimpleRule, i as isMultiConditionRule, c as isNestedRule, d as isSimpleRule } from './rule-a_5ed-93.js';
|
|
10
10
|
import { R as RuleContext } from './context.v1-C1m-tz0o.js';
|
|
11
11
|
export { C as ContextV1, P as PayIdContext, T as TxContext } from './context.v1-C1m-tz0o.js';
|
|
12
|
+
import { a as DecisionProof } from './types-CSZ5F9J7.js';
|
|
13
|
+
export { D as DecisionPayload } from './types-CSZ5F9J7.js';
|
|
12
14
|
import { S as SessionPolicyV2 } from './types-D2o6XS7a.js';
|
|
15
|
+
export { generateDecisionProof } from './decision-proof/index.js';
|
|
13
16
|
import { A as Attestation } from './context.v2-DIzPotmW.js';
|
|
14
17
|
export { C as ContextV2, E as EnvContext, O as OracleContext, R as RiskContext, S as StateContext } from './context.v2-DIzPotmW.js';
|
|
15
18
|
export { i as sessionPolicy } from './index-G_1SiZJo.js';
|
package/dist/index.js
CHANGED
|
@@ -1,30 +1,33 @@
|
|
|
1
1
|
import {
|
|
2
2
|
context_exports
|
|
3
3
|
} from "./chunk-BFCPKJ46.js";
|
|
4
|
-
import {
|
|
5
|
-
issuer_exports
|
|
6
|
-
} from "./chunk-E6VQETBC.js";
|
|
7
|
-
import "./chunk-YKCMGGYB.js";
|
|
8
4
|
import {
|
|
9
5
|
rule_exports
|
|
10
6
|
} from "./chunk-FZNMDGVK.js";
|
|
11
|
-
import {
|
|
12
|
-
sessionPolicy_exports
|
|
13
|
-
} from "./chunk-R674DZJS.js";
|
|
14
7
|
import {
|
|
15
8
|
PayIDClient,
|
|
16
9
|
client_exports
|
|
17
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-K2B5UHYA.js";
|
|
18
11
|
import "./chunk-GG34PNTF.js";
|
|
12
|
+
import {
|
|
13
|
+
sessionPolicy_exports
|
|
14
|
+
} from "./chunk-R674DZJS.js";
|
|
19
15
|
import "./chunk-BC77BLFK.js";
|
|
20
16
|
import "./chunk-6VPSJFO4.js";
|
|
17
|
+
import {
|
|
18
|
+
issuer_exports
|
|
19
|
+
} from "./chunk-E6VQETBC.js";
|
|
20
|
+
import "./chunk-YKCMGGYB.js";
|
|
21
21
|
import {
|
|
22
22
|
PayIDServer,
|
|
23
23
|
server_exports
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-WQEZYX4X.js";
|
|
25
25
|
import {
|
|
26
26
|
verifyAttestation
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-F2KQGW76.js";
|
|
28
|
+
import {
|
|
29
|
+
generateDecisionProof
|
|
30
|
+
} from "./chunk-AXLZUAYL.js";
|
|
28
31
|
import "./chunk-X7NYQ47Y.js";
|
|
29
32
|
import "./chunk-KDC67LIN.js";
|
|
30
33
|
import {
|
|
@@ -696,6 +699,7 @@ export {
|
|
|
696
699
|
draftCache,
|
|
697
700
|
eas_exports as eas,
|
|
698
701
|
formatUsdValue,
|
|
702
|
+
generateDecisionProof,
|
|
699
703
|
getCacheStats,
|
|
700
704
|
historyCache,
|
|
701
705
|
isMultiConditionRule,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type DecisionValue = 0 | 1;
|
|
2
|
+
interface DecisionPayload {
|
|
3
|
+
version: string;
|
|
4
|
+
payId: string;
|
|
5
|
+
payer: string;
|
|
6
|
+
receiver: string;
|
|
7
|
+
asset: string;
|
|
8
|
+
amount: bigint;
|
|
9
|
+
contextHash: string;
|
|
10
|
+
ruleSetHash: string;
|
|
11
|
+
ruleAuthority: string;
|
|
12
|
+
issuedAt: bigint;
|
|
13
|
+
expiresAt: bigint;
|
|
14
|
+
nonce: string;
|
|
15
|
+
requiresAttestation: boolean;
|
|
16
|
+
attestationUIDsHash: string;
|
|
17
|
+
}
|
|
18
|
+
interface DecisionProof {
|
|
19
|
+
payload: DecisionPayload;
|
|
20
|
+
signature: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type { DecisionPayload as D, DecisionProof as a, DecisionValue as b };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
interface RuleResult {
|
|
2
|
+
decision: "ALLOW" | "REJECT";
|
|
3
|
+
code: string;
|
|
4
|
+
reason?: string;
|
|
5
|
+
}
|
|
6
|
+
interface RuleTraceEntry {
|
|
7
|
+
ruleId: string;
|
|
8
|
+
field: string;
|
|
9
|
+
op: string;
|
|
10
|
+
expected: any;
|
|
11
|
+
actual: any;
|
|
12
|
+
result: "PASS" | "FAIL";
|
|
13
|
+
}
|
|
14
|
+
interface RuleDecisionDebug {
|
|
15
|
+
trace: RuleTraceEntry[];
|
|
16
|
+
}
|
|
17
|
+
interface RuleResultDebug extends RuleResult {
|
|
18
|
+
debug?: RuleDecisionDebug;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface RuleSource {
|
|
22
|
+
uri: string;
|
|
23
|
+
hash?: string;
|
|
24
|
+
}
|
|
25
|
+
interface ResolverOptions {
|
|
26
|
+
zgIndexerUrl?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type { ResolverOptions as R, RuleDecisionDebug as a, RuleResult as b, RuleResultDebug as c, RuleSource as d, RuleTraceEntry as e };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payid",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -47,6 +47,12 @@
|
|
|
47
47
|
"import": "./dist/core/server/index.js",
|
|
48
48
|
"require": "./dist/core/server/index.js",
|
|
49
49
|
"default": "./dist/core/server/index.js"
|
|
50
|
+
},
|
|
51
|
+
"./decision-proof": {
|
|
52
|
+
"types": "./dist/decision-proof/index.d.ts",
|
|
53
|
+
"import": "./dist/decision-proof/index.js",
|
|
54
|
+
"require": "./dist/decision-proof/index.js",
|
|
55
|
+
"default": "./dist/decision-proof/index.js"
|
|
50
56
|
}
|
|
51
57
|
},
|
|
52
58
|
"files": [
|
|
@@ -56,7 +62,7 @@
|
|
|
56
62
|
"scripts": {
|
|
57
63
|
"build": "tsup",
|
|
58
64
|
"type-check": "tsc --noEmit",
|
|
59
|
-
"test": "
|
|
65
|
+
"test": "bun test",
|
|
60
66
|
"prepublishOnly": "bun run type-check && bun run test && bun run build",
|
|
61
67
|
"release": "release-it",
|
|
62
68
|
"release:dry": "release-it --dry-run",
|
|
@@ -74,8 +80,12 @@
|
|
|
74
80
|
},
|
|
75
81
|
"devDependencies": {
|
|
76
82
|
"@types/bun": "latest",
|
|
83
|
+
"@wagmi/core": "^3.4.12",
|
|
84
|
+
"react": "^19.2.6",
|
|
77
85
|
"release-it": "^20.0.1",
|
|
78
|
-
"tsup": "^8.5.1"
|
|
86
|
+
"tsup": "^8.5.1",
|
|
87
|
+
"viem": "^2.49.3",
|
|
88
|
+
"wagmi": "^3.6.15"
|
|
79
89
|
},
|
|
80
90
|
"description": "PAY.ID policy engine — evaluate payment rules and generate EIP-712 Decision Proofs",
|
|
81
91
|
"repository": {
|
package/dist/types-i4eTkhWa.d.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
interface RuleResult {
|
|
2
|
-
decision: "ALLOW" | "REJECT";
|
|
3
|
-
code: string;
|
|
4
|
-
reason?: string;
|
|
5
|
-
}
|
|
6
|
-
interface RuleTraceEntry {
|
|
7
|
-
ruleId: string;
|
|
8
|
-
field: string;
|
|
9
|
-
op: string;
|
|
10
|
-
expected: any;
|
|
11
|
-
actual: any;
|
|
12
|
-
result: "PASS" | "FAIL";
|
|
13
|
-
}
|
|
14
|
-
interface RuleDecisionDebug {
|
|
15
|
-
trace: RuleTraceEntry[];
|
|
16
|
-
}
|
|
17
|
-
interface RuleResultDebug extends RuleResult {
|
|
18
|
-
debug?: RuleDecisionDebug;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface DecisionPayload {
|
|
22
|
-
version: string;
|
|
23
|
-
payId: string;
|
|
24
|
-
payer: string;
|
|
25
|
-
receiver: string;
|
|
26
|
-
asset: string;
|
|
27
|
-
amount: bigint;
|
|
28
|
-
contextHash: string;
|
|
29
|
-
ruleSetHash: string;
|
|
30
|
-
ruleAuthority: string;
|
|
31
|
-
issuedAt: bigint;
|
|
32
|
-
expiresAt: bigint;
|
|
33
|
-
nonce: string;
|
|
34
|
-
requiresAttestation: boolean;
|
|
35
|
-
attestationUIDsHash: string;
|
|
36
|
-
}
|
|
37
|
-
interface DecisionProof {
|
|
38
|
-
payload: DecisionPayload;
|
|
39
|
-
signature: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
interface RuleSource {
|
|
43
|
-
uri: string;
|
|
44
|
-
hash?: string;
|
|
45
|
-
}
|
|
46
|
-
interface ResolverOptions {
|
|
47
|
-
zgIndexerUrl?: string;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export type { DecisionPayload as D, ResolverOptions as R, DecisionProof as a, RuleDecisionDebug as b, RuleResult as c, RuleResultDebug as d, RuleSource as e, RuleTraceEntry as f };
|