@xfuel/verify 0.1.1 → 0.3.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 +62 -17
- package/dist/anchor-witness.d.ts +138 -0
- package/dist/anchor-witness.d.ts.map +1 -0
- package/dist/anchor-witness.js +365 -0
- package/dist/anchor-witness.js.map +1 -0
- package/dist/base-payer.d.ts +8 -1
- package/dist/base-payer.d.ts.map +1 -1
- package/dist/base-payer.js +64 -20
- package/dist/base-payer.js.map +1 -1
- package/dist/canonical-preimage.d.ts +9 -0
- package/dist/canonical-preimage.d.ts.map +1 -0
- package/dist/canonical-preimage.js +25 -0
- package/dist/canonical-preimage.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +424 -25
- package/dist/cli.js.map +1 -1
- package/dist/head-binding.d.ts +24 -0
- package/dist/head-binding.d.ts.map +1 -0
- package/dist/head-binding.js +61 -0
- package/dist/head-binding.js.map +1 -0
- package/dist/index.d.ts +263 -48
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +919 -140
- package/dist/index.js.map +1 -1
- package/dist/issuer-history.d.ts +91 -0
- package/dist/issuer-history.d.ts.map +1 -0
- package/dist/issuer-history.js +292 -0
- package/dist/issuer-history.js.map +1 -0
- package/dist/jcs.d.ts +8 -0
- package/dist/jcs.d.ts.map +1 -0
- package/dist/jcs.js +64 -0
- package/dist/jcs.js.map +1 -0
- package/dist/jws.d.ts +23 -0
- package/dist/jws.d.ts.map +1 -1
- package/dist/jws.js +71 -1
- package/dist/jws.js.map +1 -1
- package/dist/payer.d.ts +16 -5
- package/dist/payer.d.ts.map +1 -1
- package/dist/payer.js +38 -26
- package/dist/payer.js.map +1 -1
- package/dist/preimage.d.ts +49 -0
- package/dist/preimage.d.ts.map +1 -0
- package/dist/preimage.js +203 -0
- package/dist/preimage.js.map +1 -0
- package/dist/receipt-lane.d.ts +234 -0
- package/dist/receipt-lane.d.ts.map +1 -0
- package/dist/receipt-lane.js +443 -0
- package/dist/receipt-lane.js.map +1 -0
- package/dist/refusal.d.ts +90 -0
- package/dist/refusal.d.ts.map +1 -0
- package/dist/refusal.js +226 -0
- package/dist/refusal.js.map +1 -0
- package/package.json +9 -5
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unsigned receipt-lane decision beside book_seq.
|
|
3
|
+
*
|
|
4
|
+
* Design by Turbo on 1F916 (post 6579, comments 88201 and 88403):
|
|
5
|
+
* freeze a receipt-lane row only when seq is present, settled_by is
|
|
6
|
+
* `receipt`, the anchored tree head changed after that row was bound, and
|
|
7
|
+
* the row is not settled. anchor_changed_since_binding alone does not freeze.
|
|
8
|
+
*
|
|
9
|
+
* Comment 88596 freezes that ordering — seq + settled_by + (anchor_changed
|
|
10
|
+
* AND not settled) — and states the boundary: complete over registry marks,
|
|
11
|
+
* blind to payments the registry never joined. A binding past expiry with
|
|
12
|
+
* settled_by, receipt_id, observed_tx_hash, and observed_transfer_id all
|
|
13
|
+
* null is unverifiable_from_registry, not unpaid.
|
|
14
|
+
*
|
|
15
|
+
* These fields are derived. They are not inside the payment JWS and not
|
|
16
|
+
* inside the signed book_seq claims. payload_version is unchanged.
|
|
17
|
+
*
|
|
18
|
+
* Keep this rule in lockstep with services/gateway/src/receipt-lane.js.
|
|
19
|
+
*/
|
|
20
|
+
export declare const RECEIPT_LANE_SCHEMA = "chit402.receipt_lane.v1";
|
|
21
|
+
export declare const RECEIPT_LANE_RULE: string;
|
|
22
|
+
/** Frozen partition order. `settled_by` here is the receipt-lane conjunct (value `receipt`). */
|
|
23
|
+
export declare const RECEIPT_LANE_ORDERING = "seq + settled_by + (anchor_changed AND not settled)";
|
|
24
|
+
/** The ordering reads registry marks only. A transfer the registry never joined is outside it. */
|
|
25
|
+
export declare const RECEIPT_LANE_BOUNDARY = "complete over registry marks, blind to payments the registry never joined";
|
|
26
|
+
/**
|
|
27
|
+
* Base mainnet USDC. Same contract as USDC_ADDRESSES.base in
|
|
28
|
+
* services/gateway/src/foreign-x402-ingest.js. The hint does not call RPC.
|
|
29
|
+
*/
|
|
30
|
+
export declare const BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
31
|
+
export type SettledBy = 'observed_transfer' | 'receipt' | null;
|
|
32
|
+
export type RegistryClassification = 'receipt' | 'observed_transfer' | 'anchor_changed_unsettled' | 'unsettled' | 'unverifiable_from_registry';
|
|
33
|
+
export interface LocalCheckHint {
|
|
34
|
+
method: 'base_usdc_transfer';
|
|
35
|
+
chain_id: 8453;
|
|
36
|
+
token: string;
|
|
37
|
+
payee: string;
|
|
38
|
+
amount_atomic: string;
|
|
39
|
+
claims_paid: false;
|
|
40
|
+
}
|
|
41
|
+
export interface AnchorIdentity {
|
|
42
|
+
root: string | null;
|
|
43
|
+
tree_size: number | null;
|
|
44
|
+
anchor_tx: string | null;
|
|
45
|
+
solana_signature: string | null;
|
|
46
|
+
}
|
|
47
|
+
export interface ReceiptLane {
|
|
48
|
+
schema: typeof RECEIPT_LANE_SCHEMA;
|
|
49
|
+
signed: false;
|
|
50
|
+
book_seq: number | null;
|
|
51
|
+
settled_by: SettledBy;
|
|
52
|
+
settled: boolean | null;
|
|
53
|
+
anchor_at_binding: AnchorIdentity | null;
|
|
54
|
+
anchor_current: AnchorIdentity | null;
|
|
55
|
+
anchor_changed_since_binding: boolean | null;
|
|
56
|
+
freeze: boolean;
|
|
57
|
+
reason: 'unsettled_anchor_changed' | null;
|
|
58
|
+
rule: string;
|
|
59
|
+
ordering: typeof RECEIPT_LANE_ORDERING;
|
|
60
|
+
boundary: typeof RECEIPT_LANE_BOUNDARY;
|
|
61
|
+
classification: RegistryClassification;
|
|
62
|
+
local_check: LocalCheckHint | null;
|
|
63
|
+
}
|
|
64
|
+
export interface LanePayer {
|
|
65
|
+
checked?: boolean;
|
|
66
|
+
valid?: boolean;
|
|
67
|
+
}
|
|
68
|
+
export interface LaneEntry {
|
|
69
|
+
book_seq?: number | null;
|
|
70
|
+
seq?: number | null;
|
|
71
|
+
book_chain?: {
|
|
72
|
+
seq?: number | null;
|
|
73
|
+
} | null;
|
|
74
|
+
payment?: {
|
|
75
|
+
ref?: string | null;
|
|
76
|
+
rail?: string | null;
|
|
77
|
+
collected?: boolean | null;
|
|
78
|
+
} | null;
|
|
79
|
+
payment_ref?: string | null;
|
|
80
|
+
rail?: string | null;
|
|
81
|
+
collected?: boolean | null;
|
|
82
|
+
evidence?: string | null;
|
|
83
|
+
source?: string | null;
|
|
84
|
+
foreign_x402?: boolean;
|
|
85
|
+
arrival_status?: string | null;
|
|
86
|
+
ingress_receipt?: {
|
|
87
|
+
ref?: string | null;
|
|
88
|
+
} | null;
|
|
89
|
+
settlement_status?: string | null;
|
|
90
|
+
usage_settled?: {
|
|
91
|
+
settlement_status?: string | null;
|
|
92
|
+
} | null;
|
|
93
|
+
expiry?: number | string | null;
|
|
94
|
+
receipt_id?: string | number | null;
|
|
95
|
+
observed_tx_hash?: string | null;
|
|
96
|
+
observed_transfer_id?: string | number | null;
|
|
97
|
+
settled_by?: SettledBy;
|
|
98
|
+
anchor_changed_since_binding?: boolean | null;
|
|
99
|
+
chain_id?: number | string | null;
|
|
100
|
+
chainId?: number | string | null;
|
|
101
|
+
token?: string | null;
|
|
102
|
+
asset?: string | null;
|
|
103
|
+
payout_address?: string | null;
|
|
104
|
+
address?: string | null;
|
|
105
|
+
payee?: string | null;
|
|
106
|
+
amount_atomic?: string | number | null;
|
|
107
|
+
docket_id?: string | null;
|
|
108
|
+
}
|
|
109
|
+
export interface ReceiptTreeHead {
|
|
110
|
+
root?: string | null;
|
|
111
|
+
tree_size?: number | null;
|
|
112
|
+
anchor_tx?: string | null;
|
|
113
|
+
anchor?: {
|
|
114
|
+
tx?: string | null;
|
|
115
|
+
status?: string | null;
|
|
116
|
+
} | null;
|
|
117
|
+
anchors?: {
|
|
118
|
+
base?: {
|
|
119
|
+
tx?: string | null;
|
|
120
|
+
status?: string | null;
|
|
121
|
+
} | null;
|
|
122
|
+
solana?: {
|
|
123
|
+
signature?: string | null;
|
|
124
|
+
status?: string | null;
|
|
125
|
+
} | null;
|
|
126
|
+
} | null;
|
|
127
|
+
}
|
|
128
|
+
export declare function normalizeRoot(root: string | null | undefined): string | null;
|
|
129
|
+
export declare function anchorIdentity(head: ReceiptTreeHead | null | undefined): AnchorIdentity | null;
|
|
130
|
+
export declare function anchorChangedSinceBinding(heads: ReceiptTreeHead[] | null | undefined, leafIndex: number | null | undefined): {
|
|
131
|
+
changed: boolean | null;
|
|
132
|
+
at: AnchorIdentity | null;
|
|
133
|
+
current: AnchorIdentity | null;
|
|
134
|
+
};
|
|
135
|
+
/** A 1F916 payout binding carries expiry plus a registry mark key. A book row does not. */
|
|
136
|
+
export declare function isPayoutBinding(input: LaneEntry | null | undefined): boolean;
|
|
137
|
+
/** Unix seconds, unix ms, or an ISO timestamp. Null when the field is absent or not a time. */
|
|
138
|
+
export declare function expiryMillis(expiry: number | string | null | undefined): number | null;
|
|
139
|
+
export declare function isPastExpiry(expiry: number | string | null | undefined, nowMs?: number): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Partition a row. Expired and unmarked is unverifiable_from_registry, ahead
|
|
142
|
+
* of the clean-unsettled and anchor-changed buckets, and behind a joined
|
|
143
|
+
* settled_by (receipt or observed_transfer).
|
|
144
|
+
*/
|
|
145
|
+
export declare function classifyReceiptLane({ entry, settled_by, settled, anchor_changed_since_binding, now, }?: {
|
|
146
|
+
entry?: LaneEntry | null;
|
|
147
|
+
settled_by?: SettledBy;
|
|
148
|
+
settled?: boolean | null;
|
|
149
|
+
anchor_changed_since_binding?: boolean | null;
|
|
150
|
+
now?: number;
|
|
151
|
+
}): RegistryClassification;
|
|
152
|
+
/**
|
|
153
|
+
* Payee and amount a stranger can feed to the existing per-tx Base USDC check.
|
|
154
|
+
* Null unless this row is Base mainnet USDC. Does not claim the transfer happened
|
|
155
|
+
* and does not read the chain.
|
|
156
|
+
*/
|
|
157
|
+
export declare function baseUsdcLocalCheckHint(entry: LaneEntry | null | undefined): LocalCheckHint | null;
|
|
158
|
+
export declare function deriveSettledBy(input: LaneEntry | null | undefined, { payer, issuerAssertsSettlement }?: {
|
|
159
|
+
payer?: LanePayer | null;
|
|
160
|
+
issuerAssertsSettlement?: boolean | null;
|
|
161
|
+
}): SettledBy;
|
|
162
|
+
export declare function deriveSettled(input: LaneEntry | null | undefined, { payer }?: {
|
|
163
|
+
payer?: LanePayer | null;
|
|
164
|
+
}): boolean | null;
|
|
165
|
+
export declare function bookSeqOf(input: LaneEntry | null | undefined): number | null;
|
|
166
|
+
export declare function receiptLaneDecision(input: {
|
|
167
|
+
book_seq: number | null;
|
|
168
|
+
settled_by: SettledBy;
|
|
169
|
+
settled: boolean | null;
|
|
170
|
+
anchor_changed_since_binding: boolean | null;
|
|
171
|
+
}): {
|
|
172
|
+
freeze: boolean;
|
|
173
|
+
reason: 'unsettled_anchor_changed' | null;
|
|
174
|
+
};
|
|
175
|
+
export declare function buildReceiptLane({ entry, payer, leafIndex, heads, issuerAssertsSettlement, anchorAtBinding, anchorCurrent, now, }?: {
|
|
176
|
+
entry?: LaneEntry | null;
|
|
177
|
+
payer?: LanePayer | null;
|
|
178
|
+
leafIndex?: number | null;
|
|
179
|
+
heads?: ReceiptTreeHead[] | null;
|
|
180
|
+
issuerAssertsSettlement?: boolean | null;
|
|
181
|
+
anchorAtBinding?: AnchorIdentity | null;
|
|
182
|
+
anchorCurrent?: AnchorIdentity | null;
|
|
183
|
+
now?: number;
|
|
184
|
+
}): ReceiptLane;
|
|
185
|
+
interface SignedClaims {
|
|
186
|
+
payment?: {
|
|
187
|
+
ref?: string | null;
|
|
188
|
+
rail?: string | null;
|
|
189
|
+
collected?: boolean | null;
|
|
190
|
+
} | null;
|
|
191
|
+
settlement?: {
|
|
192
|
+
kind?: string | null;
|
|
193
|
+
} | null;
|
|
194
|
+
}
|
|
195
|
+
interface ReceiptLaneSource {
|
|
196
|
+
book_seq?: number | null;
|
|
197
|
+
book_chain?: {
|
|
198
|
+
seq?: number | null;
|
|
199
|
+
} | null;
|
|
200
|
+
tree_head?: ReceiptTreeHead | null;
|
|
201
|
+
head?: ReceiptTreeHead | null;
|
|
202
|
+
expiry?: number | string | null;
|
|
203
|
+
receipt_id?: string | number | null;
|
|
204
|
+
observed_tx_hash?: string | null;
|
|
205
|
+
observed_transfer_id?: string | number | null;
|
|
206
|
+
settled_by?: SettledBy;
|
|
207
|
+
anchor_changed_since_binding?: boolean | null;
|
|
208
|
+
chain_id?: number | string | null;
|
|
209
|
+
token?: string | null;
|
|
210
|
+
payout_address?: string | null;
|
|
211
|
+
address?: string | null;
|
|
212
|
+
amount_atomic?: string | number | null;
|
|
213
|
+
docket_id?: string | null;
|
|
214
|
+
receipt_lane?: {
|
|
215
|
+
anchor_at_binding?: AnchorIdentity | null;
|
|
216
|
+
anchor_current?: AnchorIdentity | null;
|
|
217
|
+
freeze?: boolean;
|
|
218
|
+
anchor_changed_since_binding?: boolean | null;
|
|
219
|
+
} | null;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Stranger view. Uses verified signed claims and an on-chain payer check.
|
|
223
|
+
* Ignores a stamped freeze bit. Unsigned payment.ref is not an assertion.
|
|
224
|
+
*/
|
|
225
|
+
export declare function receiptLaneFromVerification({ receipt, claims, issuerValid, payer, head, now, }: {
|
|
226
|
+
receipt: ReceiptLaneSource | null | undefined;
|
|
227
|
+
claims?: SignedClaims | null;
|
|
228
|
+
issuerValid?: boolean;
|
|
229
|
+
payer?: LanePayer | null;
|
|
230
|
+
head?: ReceiptTreeHead | null;
|
|
231
|
+
now?: number;
|
|
232
|
+
}): ReceiptLane;
|
|
233
|
+
export {};
|
|
234
|
+
//# sourceMappingURL=receipt-lane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receipt-lane.d.ts","sourceRoot":"","sources":["../src/receipt-lane.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Unsigned receipt-lane decision beside book_seq.
|
|
4
|
+
*
|
|
5
|
+
* Design by Turbo on 1F916 (post 6579, comments 88201 and 88403):
|
|
6
|
+
* freeze a receipt-lane row only when seq is present, settled_by is
|
|
7
|
+
* `receipt`, the anchored tree head changed after that row was bound, and
|
|
8
|
+
* the row is not settled. anchor_changed_since_binding alone does not freeze.
|
|
9
|
+
*
|
|
10
|
+
* Comment 88596 freezes that ordering — seq + settled_by + (anchor_changed
|
|
11
|
+
* AND not settled) — and states the boundary: complete over registry marks,
|
|
12
|
+
* blind to payments the registry never joined. A binding past expiry with
|
|
13
|
+
* settled_by, receipt_id, observed_tx_hash, and observed_transfer_id all
|
|
14
|
+
* null is unverifiable_from_registry, not unpaid.
|
|
15
|
+
*
|
|
16
|
+
* These fields are derived. They are not inside the payment JWS and not
|
|
17
|
+
* inside the signed book_seq claims. payload_version is unchanged.
|
|
18
|
+
*
|
|
19
|
+
* Keep this rule in lockstep with services/gateway/src/receipt-lane.js.
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.BASE_USDC_ADDRESS = exports.RECEIPT_LANE_BOUNDARY = exports.RECEIPT_LANE_ORDERING = exports.RECEIPT_LANE_RULE = exports.RECEIPT_LANE_SCHEMA = void 0;
|
|
23
|
+
exports.normalizeRoot = normalizeRoot;
|
|
24
|
+
exports.anchorIdentity = anchorIdentity;
|
|
25
|
+
exports.anchorChangedSinceBinding = anchorChangedSinceBinding;
|
|
26
|
+
exports.isPayoutBinding = isPayoutBinding;
|
|
27
|
+
exports.expiryMillis = expiryMillis;
|
|
28
|
+
exports.isPastExpiry = isPastExpiry;
|
|
29
|
+
exports.classifyReceiptLane = classifyReceiptLane;
|
|
30
|
+
exports.baseUsdcLocalCheckHint = baseUsdcLocalCheckHint;
|
|
31
|
+
exports.deriveSettledBy = deriveSettledBy;
|
|
32
|
+
exports.deriveSettled = deriveSettled;
|
|
33
|
+
exports.bookSeqOf = bookSeqOf;
|
|
34
|
+
exports.receiptLaneDecision = receiptLaneDecision;
|
|
35
|
+
exports.buildReceiptLane = buildReceiptLane;
|
|
36
|
+
exports.receiptLaneFromVerification = receiptLaneFromVerification;
|
|
37
|
+
exports.RECEIPT_LANE_SCHEMA = 'chit402.receipt_lane.v1';
|
|
38
|
+
exports.RECEIPT_LANE_RULE = 'Freeze when book_seq is present, settled_by is receipt, anchor_changed_since_binding is true, and settled is false. '
|
|
39
|
+
+ 'anchor_changed_since_binding alone does not freeze. observed_transfer is outside the receipt lane.';
|
|
40
|
+
/** Frozen partition order. `settled_by` here is the receipt-lane conjunct (value `receipt`). */
|
|
41
|
+
exports.RECEIPT_LANE_ORDERING = 'seq + settled_by + (anchor_changed AND not settled)';
|
|
42
|
+
/** The ordering reads registry marks only. A transfer the registry never joined is outside it. */
|
|
43
|
+
exports.RECEIPT_LANE_BOUNDARY = 'complete over registry marks, blind to payments the registry never joined';
|
|
44
|
+
/**
|
|
45
|
+
* Base mainnet USDC. Same contract as USDC_ADDRESSES.base in
|
|
46
|
+
* services/gateway/src/foreign-x402-ingest.js. The hint does not call RPC.
|
|
47
|
+
*/
|
|
48
|
+
exports.BASE_USDC_ADDRESS = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
|
|
49
|
+
const BASE_CHAIN_ID = 8453;
|
|
50
|
+
const SETTLED_STATUS = new Set(['settled', 'idempotent_replay']);
|
|
51
|
+
const SETTLED_EVIDENCE = new Set([
|
|
52
|
+
'collected',
|
|
53
|
+
'foreign_ingest',
|
|
54
|
+
'refund_owed',
|
|
55
|
+
'board_close',
|
|
56
|
+
]);
|
|
57
|
+
const UNSETTLED_EVIDENCE = new Set([
|
|
58
|
+
'policy_blocked',
|
|
59
|
+
'UNVERIFIED',
|
|
60
|
+
'ARRIVAL_UNVERIFIED',
|
|
61
|
+
'inflow_claimed',
|
|
62
|
+
'inflow_correction',
|
|
63
|
+
'RECORDED_BY_SETTLE',
|
|
64
|
+
'openrouter_reported',
|
|
65
|
+
'a2a_escrow',
|
|
66
|
+
]);
|
|
67
|
+
const RECEIPT_ASSERTION_EVIDENCE = new Set([
|
|
68
|
+
'collected',
|
|
69
|
+
'RECORDED_BY_SETTLE',
|
|
70
|
+
'refund_owed',
|
|
71
|
+
'board_stamp',
|
|
72
|
+
'board_close',
|
|
73
|
+
]);
|
|
74
|
+
function normalizeRoot(root) {
|
|
75
|
+
if (root == null || root === '')
|
|
76
|
+
return null;
|
|
77
|
+
const hex = String(root).replace(/^0x/i, '').toLowerCase();
|
|
78
|
+
return /^[0-9a-f]{64}$/.test(hex) ? hex : String(root);
|
|
79
|
+
}
|
|
80
|
+
function anchorIdentity(head) {
|
|
81
|
+
if (!head || typeof head !== 'object')
|
|
82
|
+
return null;
|
|
83
|
+
const base = head.anchors?.base || head.anchor || null;
|
|
84
|
+
const sol = head.anchors?.solana || null;
|
|
85
|
+
const baseAnchored = !base || base.status == null || base.status === 'anchored';
|
|
86
|
+
const solAnchored = Boolean(sol && (sol.status == null || sol.status === 'anchored'));
|
|
87
|
+
const tx = baseAnchored ? (base?.tx || head.anchor_tx || null) : null;
|
|
88
|
+
const sig = solAnchored ? (sol?.signature || null) : null;
|
|
89
|
+
const root = head.root != null && head.root !== '' ? normalizeRoot(head.root) : null;
|
|
90
|
+
const size = Number(head.tree_size);
|
|
91
|
+
const treeSize = Number.isInteger(size) ? size : null;
|
|
92
|
+
if (root == null && !tx && !sig && treeSize == null)
|
|
93
|
+
return null;
|
|
94
|
+
return {
|
|
95
|
+
root,
|
|
96
|
+
tree_size: treeSize,
|
|
97
|
+
anchor_tx: tx || null,
|
|
98
|
+
solana_signature: sig || null,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function sameIdentity(a, b) {
|
|
102
|
+
if (!a || !b)
|
|
103
|
+
return null;
|
|
104
|
+
if (a.root == null || b.root == null)
|
|
105
|
+
return null;
|
|
106
|
+
return a.root === b.root
|
|
107
|
+
&& (a.anchor_tx || null) === (b.anchor_tx || null)
|
|
108
|
+
&& (a.solana_signature || null) === (b.solana_signature || null);
|
|
109
|
+
}
|
|
110
|
+
function anchorChangedSinceBinding(heads, leafIndex) {
|
|
111
|
+
if (!Array.isArray(heads) || heads.length === 0) {
|
|
112
|
+
return { changed: null, at: null, current: null };
|
|
113
|
+
}
|
|
114
|
+
const current = anchorIdentity(heads[heads.length - 1]);
|
|
115
|
+
const index = Number(leafIndex);
|
|
116
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
117
|
+
return { changed: null, at: null, current };
|
|
118
|
+
}
|
|
119
|
+
let binding = null;
|
|
120
|
+
for (const head of heads) {
|
|
121
|
+
const size = Number(head?.tree_size);
|
|
122
|
+
if (Number.isInteger(size) && size > index) {
|
|
123
|
+
binding = head;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (!binding)
|
|
128
|
+
return { changed: null, at: null, current };
|
|
129
|
+
const at = anchorIdentity(binding);
|
|
130
|
+
const same = sameIdentity(at, current);
|
|
131
|
+
return { changed: same == null ? null : same === false, at, current };
|
|
132
|
+
}
|
|
133
|
+
function paymentRefOf(input) {
|
|
134
|
+
const ref = input?.payment?.ref ?? input?.payment_ref ?? null;
|
|
135
|
+
if (ref == null)
|
|
136
|
+
return null;
|
|
137
|
+
const text = String(ref).trim();
|
|
138
|
+
return text || null;
|
|
139
|
+
}
|
|
140
|
+
function hasIngress(input) {
|
|
141
|
+
if (input.arrival_status === 'confirmed')
|
|
142
|
+
return true;
|
|
143
|
+
const ingress = input.ingress_receipt;
|
|
144
|
+
if (!ingress || typeof ingress !== 'object')
|
|
145
|
+
return false;
|
|
146
|
+
const ref = ingress.ref != null ? String(ingress.ref).trim() : '';
|
|
147
|
+
return ref.length > 0;
|
|
148
|
+
}
|
|
149
|
+
function isReported(input) {
|
|
150
|
+
if (input.evidence === 'openrouter_reported')
|
|
151
|
+
return true;
|
|
152
|
+
if (input.source === 'openrouter_broadcast')
|
|
153
|
+
return true;
|
|
154
|
+
const rail = String(input.rail || input.payment?.rail || '').toLowerCase();
|
|
155
|
+
return rail === 'reported';
|
|
156
|
+
}
|
|
157
|
+
const PAYOUT_BINDING_KEYS = [
|
|
158
|
+
'payout_address',
|
|
159
|
+
'address',
|
|
160
|
+
'docket_id',
|
|
161
|
+
'receipt_id',
|
|
162
|
+
'observed_tx_hash',
|
|
163
|
+
'observed_transfer_id',
|
|
164
|
+
'settled_by',
|
|
165
|
+
];
|
|
166
|
+
/** A 1F916 payout binding carries expiry plus a registry mark key. A book row does not. */
|
|
167
|
+
function isPayoutBinding(input) {
|
|
168
|
+
if (!input || typeof input !== 'object')
|
|
169
|
+
return false;
|
|
170
|
+
if (!Object.prototype.hasOwnProperty.call(input, 'expiry'))
|
|
171
|
+
return false;
|
|
172
|
+
return PAYOUT_BINDING_KEYS.some((key) => Object.prototype.hasOwnProperty.call(input, key));
|
|
173
|
+
}
|
|
174
|
+
function explicitSettledBy(input) {
|
|
175
|
+
const value = input?.settled_by;
|
|
176
|
+
if (value === 'observed_transfer' || value === 'receipt')
|
|
177
|
+
return value;
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
function blankMark(value) {
|
|
181
|
+
return value == null || String(value).trim() === '';
|
|
182
|
+
}
|
|
183
|
+
/** Unix seconds, unix ms, or an ISO timestamp. Null when the field is absent or not a time. */
|
|
184
|
+
function expiryMillis(expiry) {
|
|
185
|
+
if (blankMark(expiry))
|
|
186
|
+
return null;
|
|
187
|
+
if (typeof expiry === 'string' && /[T-]/.test(expiry)) {
|
|
188
|
+
const parsed = Date.parse(expiry);
|
|
189
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
190
|
+
}
|
|
191
|
+
const n = Number(expiry);
|
|
192
|
+
if (!Number.isFinite(n))
|
|
193
|
+
return null;
|
|
194
|
+
return n < 1e12 ? n * 1000 : n;
|
|
195
|
+
}
|
|
196
|
+
function isPastExpiry(expiry, nowMs = Date.now()) {
|
|
197
|
+
const at = expiryMillis(expiry);
|
|
198
|
+
if (at == null)
|
|
199
|
+
return false;
|
|
200
|
+
return nowMs >= at;
|
|
201
|
+
}
|
|
202
|
+
function registryUnmarked(input, settledBy) {
|
|
203
|
+
return settledBy == null
|
|
204
|
+
&& blankMark(input?.receipt_id)
|
|
205
|
+
&& blankMark(input?.observed_tx_hash)
|
|
206
|
+
&& blankMark(input?.observed_transfer_id);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Partition a row. Expired and unmarked is unverifiable_from_registry, ahead
|
|
210
|
+
* of the clean-unsettled and anchor-changed buckets, and behind a joined
|
|
211
|
+
* settled_by (receipt or observed_transfer).
|
|
212
|
+
*/
|
|
213
|
+
function classifyReceiptLane({ entry = null, settled_by = null, settled = null, anchor_changed_since_binding = null, now = Date.now(), } = {}) {
|
|
214
|
+
if (settled_by === 'receipt')
|
|
215
|
+
return 'receipt';
|
|
216
|
+
if (settled_by === 'observed_transfer')
|
|
217
|
+
return 'observed_transfer';
|
|
218
|
+
if (isPastExpiry(entry?.expiry, now) && registryUnmarked(entry, settled_by)) {
|
|
219
|
+
return 'unverifiable_from_registry';
|
|
220
|
+
}
|
|
221
|
+
if (anchor_changed_since_binding === true && settled !== true)
|
|
222
|
+
return 'anchor_changed_unsettled';
|
|
223
|
+
return 'unsettled';
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Payee and amount a stranger can feed to the existing per-tx Base USDC check.
|
|
227
|
+
* Null unless this row is Base mainnet USDC. Does not claim the transfer happened
|
|
228
|
+
* and does not read the chain.
|
|
229
|
+
*/
|
|
230
|
+
function baseUsdcLocalCheckHint(entry) {
|
|
231
|
+
if (!entry || typeof entry !== 'object')
|
|
232
|
+
return null;
|
|
233
|
+
const chain = entry.chain_id ?? entry.chainId ?? null;
|
|
234
|
+
const chainName = String(chain ?? '').toLowerCase();
|
|
235
|
+
const chainOk = chain === BASE_CHAIN_ID
|
|
236
|
+
|| chainName === String(BASE_CHAIN_ID)
|
|
237
|
+
|| chainName === 'base'
|
|
238
|
+
|| chainName === 'eip155:8453';
|
|
239
|
+
if (!chainOk)
|
|
240
|
+
return null;
|
|
241
|
+
const token = entry.token ?? entry.asset ?? null;
|
|
242
|
+
if (token == null || String(token).toLowerCase() !== exports.BASE_USDC_ADDRESS.toLowerCase())
|
|
243
|
+
return null;
|
|
244
|
+
const payee = entry.payout_address || entry.address || entry.payee || null;
|
|
245
|
+
const amount = entry.amount_atomic ?? null;
|
|
246
|
+
if (blankMark(payee) || blankMark(amount))
|
|
247
|
+
return null;
|
|
248
|
+
return {
|
|
249
|
+
method: 'base_usdc_transfer',
|
|
250
|
+
chain_id: BASE_CHAIN_ID,
|
|
251
|
+
token: exports.BASE_USDC_ADDRESS,
|
|
252
|
+
payee: String(payee),
|
|
253
|
+
amount_atomic: String(amount),
|
|
254
|
+
claims_paid: false,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function deriveSettledBy(input, { payer = null, issuerAssertsSettlement = null } = {}) {
|
|
258
|
+
if (!input || typeof input !== 'object')
|
|
259
|
+
return null;
|
|
260
|
+
if (isPayoutBinding(input))
|
|
261
|
+
return explicitSettledBy(input);
|
|
262
|
+
if (payer?.checked === true && payer.valid === true)
|
|
263
|
+
return 'observed_transfer';
|
|
264
|
+
if (isReported(input))
|
|
265
|
+
return null;
|
|
266
|
+
const ref = paymentRefOf(input);
|
|
267
|
+
const evidence = input.evidence || null;
|
|
268
|
+
if (ref && (evidence === 'foreign_ingest' || input.source === 'foreign_ingest' || input.foreign_x402 === true)) {
|
|
269
|
+
return 'observed_transfer';
|
|
270
|
+
}
|
|
271
|
+
if (hasIngress(input))
|
|
272
|
+
return 'observed_transfer';
|
|
273
|
+
if (issuerAssertsSettlement === true && ref)
|
|
274
|
+
return 'receipt';
|
|
275
|
+
if (issuerAssertsSettlement === false)
|
|
276
|
+
return null;
|
|
277
|
+
if (!ref)
|
|
278
|
+
return null;
|
|
279
|
+
if (input.payment?.collected === true || input.collected === true)
|
|
280
|
+
return 'receipt';
|
|
281
|
+
const status = input.settlement_status || input.usage_settled?.settlement_status || null;
|
|
282
|
+
if (status && SETTLED_STATUS.has(status))
|
|
283
|
+
return 'receipt';
|
|
284
|
+
if (evidence && RECEIPT_ASSERTION_EVIDENCE.has(evidence))
|
|
285
|
+
return 'receipt';
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
function deriveSettled(input, { payer = null } = {}) {
|
|
289
|
+
if (!input || typeof input !== 'object')
|
|
290
|
+
return null;
|
|
291
|
+
if (isPayoutBinding(input))
|
|
292
|
+
return explicitSettledBy(input) ? true : null;
|
|
293
|
+
if (payer?.checked === true && payer.valid === true)
|
|
294
|
+
return true;
|
|
295
|
+
if (payer?.checked === true && payer.valid === false)
|
|
296
|
+
return false;
|
|
297
|
+
if (isReported(input))
|
|
298
|
+
return false;
|
|
299
|
+
const status = input.settlement_status || input.usage_settled?.settlement_status || null;
|
|
300
|
+
if (status && SETTLED_STATUS.has(status))
|
|
301
|
+
return true;
|
|
302
|
+
const evidence = input.evidence || null;
|
|
303
|
+
if (evidence && UNSETTLED_EVIDENCE.has(evidence))
|
|
304
|
+
return false;
|
|
305
|
+
if (evidence && SETTLED_EVIDENCE.has(evidence))
|
|
306
|
+
return true;
|
|
307
|
+
if (input.payment?.collected === true || input.collected === true)
|
|
308
|
+
return true;
|
|
309
|
+
if (input.payment?.collected === false || input.collected === false)
|
|
310
|
+
return false;
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
function bookSeqOf(input) {
|
|
314
|
+
const raw = input?.book_seq ?? input?.seq ?? input?.book_chain?.seq ?? null;
|
|
315
|
+
if (raw == null || raw === '')
|
|
316
|
+
return null;
|
|
317
|
+
const n = Number(raw);
|
|
318
|
+
return Number.isInteger(n) && n > 0 ? n : null;
|
|
319
|
+
}
|
|
320
|
+
function receiptLaneDecision(input) {
|
|
321
|
+
const hasSeq = Number.isInteger(input.book_seq) && input.book_seq > 0;
|
|
322
|
+
const freeze = hasSeq
|
|
323
|
+
&& input.settled_by === 'receipt'
|
|
324
|
+
&& input.anchor_changed_since_binding === true
|
|
325
|
+
&& input.settled === false;
|
|
326
|
+
return {
|
|
327
|
+
freeze,
|
|
328
|
+
reason: freeze ? 'unsettled_anchor_changed' : null,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
function changedFromIdentities(at, current) {
|
|
332
|
+
const same = sameIdentity(at, current);
|
|
333
|
+
return {
|
|
334
|
+
changed: same == null ? null : same === false,
|
|
335
|
+
at: at || null,
|
|
336
|
+
current: current || null,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
function buildReceiptLane({ entry = null, payer = null, leafIndex = null, heads = null, issuerAssertsSettlement = null, anchorAtBinding = null, anchorCurrent = null, now = Date.now(), } = {}) {
|
|
340
|
+
const book_seq = bookSeqOf(entry);
|
|
341
|
+
const settled_by = deriveSettledBy(entry, { payer, issuerAssertsSettlement });
|
|
342
|
+
const settled = deriveSettled(entry, { payer });
|
|
343
|
+
let anchor;
|
|
344
|
+
if (Array.isArray(heads) && heads.length > 0 && leafIndex != null) {
|
|
345
|
+
anchor = anchorChangedSinceBinding(heads, leafIndex);
|
|
346
|
+
}
|
|
347
|
+
else if (anchorAtBinding || anchorCurrent) {
|
|
348
|
+
anchor = changedFromIdentities(anchorAtBinding ?? null, anchorCurrent ?? null);
|
|
349
|
+
}
|
|
350
|
+
else if (typeof entry?.anchor_changed_since_binding === 'boolean') {
|
|
351
|
+
anchor = { changed: entry.anchor_changed_since_binding, at: null, current: null };
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
anchor = changedFromIdentities(anchorAtBinding ?? null, anchorCurrent ?? null);
|
|
355
|
+
}
|
|
356
|
+
const decision = receiptLaneDecision({
|
|
357
|
+
book_seq,
|
|
358
|
+
settled_by,
|
|
359
|
+
settled,
|
|
360
|
+
anchor_changed_since_binding: anchor.changed,
|
|
361
|
+
});
|
|
362
|
+
const classification = classifyReceiptLane({
|
|
363
|
+
entry,
|
|
364
|
+
settled_by,
|
|
365
|
+
settled,
|
|
366
|
+
anchor_changed_since_binding: anchor.changed,
|
|
367
|
+
now,
|
|
368
|
+
});
|
|
369
|
+
return {
|
|
370
|
+
schema: exports.RECEIPT_LANE_SCHEMA,
|
|
371
|
+
signed: false,
|
|
372
|
+
book_seq,
|
|
373
|
+
settled_by,
|
|
374
|
+
settled,
|
|
375
|
+
anchor_at_binding: anchor.at,
|
|
376
|
+
anchor_current: anchor.current,
|
|
377
|
+
anchor_changed_since_binding: anchor.changed,
|
|
378
|
+
freeze: decision.freeze,
|
|
379
|
+
reason: decision.reason,
|
|
380
|
+
rule: exports.RECEIPT_LANE_RULE,
|
|
381
|
+
ordering: exports.RECEIPT_LANE_ORDERING,
|
|
382
|
+
boundary: exports.RECEIPT_LANE_BOUNDARY,
|
|
383
|
+
classification,
|
|
384
|
+
local_check: classification === 'unverifiable_from_registry' ? baseUsdcLocalCheckHint(entry) : null,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Stranger view. Uses verified signed claims and an on-chain payer check.
|
|
389
|
+
* Ignores a stamped freeze bit. Unsigned payment.ref is not an assertion.
|
|
390
|
+
*/
|
|
391
|
+
function receiptLaneFromVerification({ receipt, claims = null, issuerValid = false, payer = null, head = null, now = Date.now(), }) {
|
|
392
|
+
const kind = claims?.settlement?.kind ?? null;
|
|
393
|
+
const signedRef = claims?.payment?.ref ?? null;
|
|
394
|
+
const reported = kind === 'reported';
|
|
395
|
+
const asserts = issuerValid === true && !!signedRef && !reported;
|
|
396
|
+
const collected = kind === 'settled' || kind === 'inherited'
|
|
397
|
+
? true
|
|
398
|
+
: (kind === 'unsettled' || reported ? false : (claims?.payment?.collected ?? null));
|
|
399
|
+
const binding = receipt
|
|
400
|
+
&& Object.prototype.hasOwnProperty.call(receipt, 'expiry')
|
|
401
|
+
&& (Object.prototype.hasOwnProperty.call(receipt, 'docket_id')
|
|
402
|
+
|| Object.prototype.hasOwnProperty.call(receipt, 'payout_address')
|
|
403
|
+
|| Object.prototype.hasOwnProperty.call(receipt, 'authorization_hash'))
|
|
404
|
+
? receipt
|
|
405
|
+
: null;
|
|
406
|
+
const entry = {
|
|
407
|
+
book_seq: receipt?.book_seq ?? null,
|
|
408
|
+
book_chain: receipt?.book_chain ?? null,
|
|
409
|
+
payment: issuerValid ? {
|
|
410
|
+
ref: signedRef,
|
|
411
|
+
rail: claims?.payment?.rail ?? null,
|
|
412
|
+
collected,
|
|
413
|
+
} : null,
|
|
414
|
+
collected,
|
|
415
|
+
evidence: reported ? 'openrouter_reported' : null,
|
|
416
|
+
...(binding ? {
|
|
417
|
+
expiry: binding.expiry ?? null,
|
|
418
|
+
receipt_id: binding.receipt_id ?? null,
|
|
419
|
+
observed_tx_hash: binding.observed_tx_hash ?? null,
|
|
420
|
+
observed_transfer_id: binding.observed_transfer_id ?? null,
|
|
421
|
+
settled_by: binding.settled_by ?? null,
|
|
422
|
+
anchor_changed_since_binding: binding.anchor_changed_since_binding,
|
|
423
|
+
chain_id: binding.chain_id ?? null,
|
|
424
|
+
token: binding.token ?? null,
|
|
425
|
+
payout_address: binding.payout_address ?? binding.address ?? null,
|
|
426
|
+
amount_atomic: binding.amount_atomic ?? null,
|
|
427
|
+
docket_id: binding.docket_id ?? null,
|
|
428
|
+
} : {}),
|
|
429
|
+
};
|
|
430
|
+
const stamped = receipt?.receipt_lane || null;
|
|
431
|
+
const currentHead = head || receipt?.tree_head || receipt?.head || null;
|
|
432
|
+
const anchorCurrent = currentHead ? anchorIdentity(currentHead) : (stamped?.anchor_current ?? null);
|
|
433
|
+
const anchorAtBinding = stamped?.anchor_at_binding ?? null;
|
|
434
|
+
return buildReceiptLane({
|
|
435
|
+
entry,
|
|
436
|
+
payer,
|
|
437
|
+
issuerAssertsSettlement: asserts,
|
|
438
|
+
anchorAtBinding,
|
|
439
|
+
anchorCurrent,
|
|
440
|
+
now,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
//# sourceMappingURL=receipt-lane.js.map
|