@algovoi/substrate 0.3.0 → 0.4.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 +20 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/settlement-binding.d.ts +61 -0
- package/dist/settlement-binding.d.ts.map +1 -0
- package/dist/settlement-binding.js +79 -0
- package/dist/settlement-binding.js.map +1 -0
- package/package.json +2 -2
- package/src/index.ts +7 -0
- package/src/settlement-binding.ts +110 -0
package/README.md
CHANGED
|
@@ -66,8 +66,11 @@ verifyAuditChain([row0, row1]);
|
|
|
66
66
|
|
|
67
67
|
## Substrate discipline
|
|
68
68
|
|
|
69
|
-
This package enforces the AlgoVoi-discipline rules
|
|
70
|
-
|
|
69
|
+
This package enforces the AlgoVoi-authored substrate-discipline rules
|
|
70
|
+
formalised in [IETF Internet-Draft `draft-hopley-x402-canonicalisation-jcs-v1`](https://datatracker.ietf.org/doc/draft-hopley-x402-canonicalisation-jcs-v1/)
|
|
71
|
+
(Independent Submission, Informational; sole AlgoVoi authorship) and
|
|
72
|
+
proposed for inclusion in `x402-foundation/x402` via [PR #2453](https://github.com/x402-foundation/x402/pull/2453)
|
|
73
|
+
(replaces closed [#2436](https://github.com/x402-foundation/x402/pull/2436)):
|
|
71
74
|
|
|
72
75
|
- **Rule 1.** `timestamp_ms` is an epoch-millisecond integer. Floats, ISO
|
|
73
76
|
8601 strings, and negative values are rejected at the source-side.
|
|
@@ -115,10 +118,21 @@ The reference exhibit for this substrate is AlgoVoi's
|
|
|
115
118
|
|
|
116
119
|
## Spec references
|
|
117
120
|
|
|
118
|
-
- [
|
|
119
|
-
- [
|
|
120
|
-
- [
|
|
121
|
-
- [
|
|
121
|
+
- [draft-hopley-x402-canonicalisation-jcs-v1](https://datatracker.ietf.org/doc/draft-hopley-x402-canonicalisation-jcs-v1/) -- IETF I-D (Independent Submission, Informational, sole AlgoVoi authorship). Specifies `urn:x402:canonicalisation:jcs-rfc8785-v1`.
|
|
122
|
+
- [docs.algovoi.co.uk/canonicalisation-substrate](https://docs.algovoi.co.uk/canonicalisation-substrate) -- v1 discipline reference page.
|
|
123
|
+
- [docs.algovoi.co.uk/canonicalisation-substrate-v2](https://docs.algovoi.co.uk/canonicalisation-substrate-v2) -- v2 (PQC-aware) additive successor.
|
|
124
|
+
- [PR #2453](https://github.com/x402-foundation/x402/pull/2453) -- live upstream spec PR for the canonicalisation discipline (sole AlgoVoi authorship; replaces closed #2436).
|
|
125
|
+
- [draft-vauban-x402-stark-receipts](https://datatracker.ietf.org/doc/draft-vauban-x402-stark-receipts/) -- third-party adopter-authored receipt format that anchors to the AlgoVoi canonicalisation discipline.
|
|
126
|
+
|
|
127
|
+
## Conformance to the canonicalisation discipline
|
|
128
|
+
|
|
129
|
+
This package emits receipts pinned to `canon_version: jcs-rfc8785-v1` in-band. Downstream verifiers (`algovoi-audit-verifier` and any conformant third-party verifier) read the pin to select the canonicalisation rule applied at emission.
|
|
130
|
+
|
|
131
|
+
The pin is the load-bearing primitive for the [Substrate Adopters Registry](https://docs.algovoi.co.uk/adopters): adopters anchoring to this discipline pin the same `canon_version` value in their own publicly-citable artefacts. AlgoVoi maintains the registry as a neutral observer; this package is recorded there as the AlgoVoi reference implementation.
|
|
132
|
+
|
|
133
|
+
## Substrate adopters
|
|
134
|
+
|
|
135
|
+
AlgoVoi is recorded in the [Substrate Adopters Registry](https://docs.algovoi.co.uk/adopters) as the substrate author (v1 and v2). Parties anchoring their own services or specifications to `canon_version: jcs-rfc8785-v1` are recorded in the registry via the [submission process](https://docs.algovoi.co.uk/adopters#how-to-submit-an-adoption-entry). AlgoVoi validates submissions against the artefact's canonical bytes and adds qualifying entries.
|
|
122
136
|
|
|
123
137
|
## Licence
|
|
124
138
|
|
package/dist/index.d.ts
CHANGED
|
@@ -22,4 +22,5 @@ export { CompositeTrustQueryError, type EmitterRow, compositeTrustQueryHash, } f
|
|
|
22
22
|
export { SCREEN_RESULTS, type ScreenResult, ComplianceReceiptError, type ComplianceReceipt, type BuildComplianceReceiptInput, buildComplianceReceipt, } from './compliance-receipt.js';
|
|
23
23
|
export { AuditChainError, type AuditChainRow, appendToChain, verifyAuditChain, } from './audit-chain.js';
|
|
24
24
|
export { TransactionalError, type TransitionPreimage, type TransitionInput, type TransitionRecord, type TransactionalChain, type TransactionalChainInput, transitionPreimage, transitionHash, buildTransactionalActionChain, } from './transactional.js';
|
|
25
|
+
export { SettlementBindingError, type SettlementBindingPreimage, settlementBindingPreimage, settlementActionBinding, } from './settlement-binding.js';
|
|
25
26
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,SAAS,GACV,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,SAAS,EACT,eAAe,GAChB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,wBAAwB,EACxB,KAAK,UAAU,EACf,uBAAuB,GACxB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,cAAc,EACd,KAAK,YAAY,EACjB,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EAChC,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,eAAe,EACf,KAAK,aAAa,EAClB,aAAa,EACb,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,kBAAkB,EAClB,cAAc,EACd,6BAA6B,GAC9B,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,SAAS,GACV,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,SAAS,EACT,eAAe,GAChB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,wBAAwB,EACxB,KAAK,UAAU,EACf,uBAAuB,GACxB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,cAAc,EACd,KAAK,YAAY,EACjB,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EAChC,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,eAAe,EACf,KAAK,aAAa,EAClB,aAAa,EACb,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,kBAAkB,EAClB,cAAc,EACd,6BAA6B,GAC9B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,sBAAsB,EACtB,KAAK,yBAAyB,EAC9B,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,yBAAyB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -22,4 +22,5 @@ export { CompositeTrustQueryError, compositeTrustQueryHash, } from './composite-
|
|
|
22
22
|
export { SCREEN_RESULTS, ComplianceReceiptError, buildComplianceReceipt, } from './compliance-receipt.js';
|
|
23
23
|
export { AuditChainError, appendToChain, verifyAuditChain, } from './audit-chain.js';
|
|
24
24
|
export { TransactionalError, transitionPreimage, transitionHash, buildTransactionalActionChain, } from './transactional.js';
|
|
25
|
+
export { SettlementBindingError, settlementBindingPreimage, settlementActionBinding, } from './settlement-binding.js';
|
|
25
26
|
//# 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":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,SAAS,GACV,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,cAAc,EAGd,SAAS,EACT,eAAe,GAChB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,wBAAwB,EAExB,uBAAuB,GACxB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,cAAc,EAEd,sBAAsB,EAGtB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,eAAe,EAEf,aAAa,EACb,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,kBAAkB,EAMlB,kBAAkB,EAClB,cAAc,EACd,6BAA6B,GAC9B,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,SAAS,GACV,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,cAAc,EAGd,SAAS,EACT,eAAe,GAChB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,wBAAwB,EAExB,uBAAuB,GACxB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,cAAc,EAEd,sBAAsB,EAGtB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,eAAe,EAEf,aAAa,EACb,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,kBAAkB,EAMlB,kBAAkB,EAClB,cAAc,EACd,6BAA6B,GAC9B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,sBAAsB,EAEtB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settlement-action binding (non-normative substrate extension).
|
|
3
|
+
*
|
|
4
|
+
* An x402/AP2/A2A settlement attestation proves a *payment* occurred. It does
|
|
5
|
+
* not, on its own, prove *which verified agent action* the payment corresponds
|
|
6
|
+
* to, nor that the correspondence is recorded in a tamper-evident chain. This
|
|
7
|
+
* module closes that post-settlement accountability gap with a single canonical
|
|
8
|
+
* reference binding four already-published substrate artifacts into one record:
|
|
9
|
+
*
|
|
10
|
+
* binding_ref = "sha256:" + SHA-256(JCS({
|
|
11
|
+
* action_ref, // the verified agent-action identity
|
|
12
|
+
* transition_hash, // the COMMITTED lifecycle transition (the "once")
|
|
13
|
+
* settlement_ref, // the settlement attestation content_hash
|
|
14
|
+
* retention_chain_ref, // the tamper-evident chain position recording it
|
|
15
|
+
* }))
|
|
16
|
+
*
|
|
17
|
+
* No new hashing primitive is introduced: the binding is the substrate's
|
|
18
|
+
* existing JCS + SHA-256 over the four references. Because action_ref and
|
|
19
|
+
* transition_hash are themselves computed from epoch-millisecond-integer
|
|
20
|
+
* preimages (Substrate Rule 2), any upstream RFC 3339 string timestamp produces
|
|
21
|
+
* a different action_ref, hence a different binding -- a non-conformant lineage
|
|
22
|
+
* cannot reproduce the binding bytes.
|
|
23
|
+
*
|
|
24
|
+
* The output carries the "sha256:" algorithm prefix, consistent with
|
|
25
|
+
* retention_chain_ref, signalling a content-addressed reference.
|
|
26
|
+
*/
|
|
27
|
+
export declare class SettlementBindingError extends Error {
|
|
28
|
+
constructor(message: string);
|
|
29
|
+
}
|
|
30
|
+
export interface SettlementBindingPreimage {
|
|
31
|
+
action_ref: string;
|
|
32
|
+
transition_hash: string;
|
|
33
|
+
settlement_ref: string;
|
|
34
|
+
retention_chain_ref: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Return the validated four-field binding preimage object.
|
|
38
|
+
*
|
|
39
|
+
* The shape is fixed at the substrate layer; each field cryptographically
|
|
40
|
+
* contributes to the binding so that no one component can be substituted
|
|
41
|
+
* without changing the binding_ref.
|
|
42
|
+
*/
|
|
43
|
+
export declare function settlementBindingPreimage(input: {
|
|
44
|
+
action_ref: string;
|
|
45
|
+
transition_hash: string;
|
|
46
|
+
settlement_ref: string;
|
|
47
|
+
retention_chain_ref: string;
|
|
48
|
+
}): SettlementBindingPreimage;
|
|
49
|
+
/**
|
|
50
|
+
* Return the binding_ref as a "sha256:"-prefixed content-addressed reference.
|
|
51
|
+
*
|
|
52
|
+
* binding_ref = "sha256:" + SHA-256(JCS({action_ref, transition_hash,
|
|
53
|
+
* settlement_ref, retention_chain_ref}))
|
|
54
|
+
*/
|
|
55
|
+
export declare function settlementActionBinding(input: {
|
|
56
|
+
action_ref: string;
|
|
57
|
+
transition_hash: string;
|
|
58
|
+
settlement_ref: string;
|
|
59
|
+
retention_chain_ref: string;
|
|
60
|
+
}): string;
|
|
61
|
+
//# sourceMappingURL=settlement-binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settlement-binding.d.ts","sourceRoot":"","sources":["../src/settlement-binding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAOH,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AA8BD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;CAC7B,GAAG,yBAAyB,CAO5B;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;CAC7B,GAAG,MAAM,CAGT"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settlement-action binding (non-normative substrate extension).
|
|
3
|
+
*
|
|
4
|
+
* An x402/AP2/A2A settlement attestation proves a *payment* occurred. It does
|
|
5
|
+
* not, on its own, prove *which verified agent action* the payment corresponds
|
|
6
|
+
* to, nor that the correspondence is recorded in a tamper-evident chain. This
|
|
7
|
+
* module closes that post-settlement accountability gap with a single canonical
|
|
8
|
+
* reference binding four already-published substrate artifacts into one record:
|
|
9
|
+
*
|
|
10
|
+
* binding_ref = "sha256:" + SHA-256(JCS({
|
|
11
|
+
* action_ref, // the verified agent-action identity
|
|
12
|
+
* transition_hash, // the COMMITTED lifecycle transition (the "once")
|
|
13
|
+
* settlement_ref, // the settlement attestation content_hash
|
|
14
|
+
* retention_chain_ref, // the tamper-evident chain position recording it
|
|
15
|
+
* }))
|
|
16
|
+
*
|
|
17
|
+
* No new hashing primitive is introduced: the binding is the substrate's
|
|
18
|
+
* existing JCS + SHA-256 over the four references. Because action_ref and
|
|
19
|
+
* transition_hash are themselves computed from epoch-millisecond-integer
|
|
20
|
+
* preimages (Substrate Rule 2), any upstream RFC 3339 string timestamp produces
|
|
21
|
+
* a different action_ref, hence a different binding -- a non-conformant lineage
|
|
22
|
+
* cannot reproduce the binding bytes.
|
|
23
|
+
*
|
|
24
|
+
* The output carries the "sha256:" algorithm prefix, consistent with
|
|
25
|
+
* retention_chain_ref, signalling a content-addressed reference.
|
|
26
|
+
*/
|
|
27
|
+
import { sha256Jcs } from './canonicalize.js';
|
|
28
|
+
const HEX64_RE = /^[0-9a-f]{64}$/;
|
|
29
|
+
const SHA256_REF_RE = /^sha256:[0-9a-f]{64}$/;
|
|
30
|
+
export class SettlementBindingError extends Error {
|
|
31
|
+
constructor(message) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = 'SettlementBindingError';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function requireHex64(field, value) {
|
|
37
|
+
if (typeof value !== 'string') {
|
|
38
|
+
throw new SettlementBindingError(`${field} must be string, got ${typeof value}`);
|
|
39
|
+
}
|
|
40
|
+
if (!HEX64_RE.test(value)) {
|
|
41
|
+
throw new SettlementBindingError(`${field} must be a lowercase 64-character SHA-256 hex string`);
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
function requireChainRef(value) {
|
|
46
|
+
if (typeof value !== 'string') {
|
|
47
|
+
throw new SettlementBindingError(`retention_chain_ref must be string, got ${typeof value}`);
|
|
48
|
+
}
|
|
49
|
+
if (!SHA256_REF_RE.test(value)) {
|
|
50
|
+
throw new SettlementBindingError("retention_chain_ref must be of the form 'sha256:<lowercase 64-char hex>'");
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Return the validated four-field binding preimage object.
|
|
56
|
+
*
|
|
57
|
+
* The shape is fixed at the substrate layer; each field cryptographically
|
|
58
|
+
* contributes to the binding so that no one component can be substituted
|
|
59
|
+
* without changing the binding_ref.
|
|
60
|
+
*/
|
|
61
|
+
export function settlementBindingPreimage(input) {
|
|
62
|
+
return {
|
|
63
|
+
action_ref: requireHex64('action_ref', input.action_ref),
|
|
64
|
+
transition_hash: requireHex64('transition_hash', input.transition_hash),
|
|
65
|
+
settlement_ref: requireHex64('settlement_ref', input.settlement_ref),
|
|
66
|
+
retention_chain_ref: requireChainRef(input.retention_chain_ref),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Return the binding_ref as a "sha256:"-prefixed content-addressed reference.
|
|
71
|
+
*
|
|
72
|
+
* binding_ref = "sha256:" + SHA-256(JCS({action_ref, transition_hash,
|
|
73
|
+
* settlement_ref, retention_chain_ref}))
|
|
74
|
+
*/
|
|
75
|
+
export function settlementActionBinding(input) {
|
|
76
|
+
const obj = settlementBindingPreimage(input);
|
|
77
|
+
return `sha256:${sha256Jcs(obj)}`;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=settlement-binding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settlement-binding.js","sourceRoot":"","sources":["../src/settlement-binding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,MAAM,QAAQ,GAAG,gBAAgB,CAAC;AAClC,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAE9C,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC/C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AASD,SAAS,YAAY,CAAC,KAAa,EAAE,KAAc;IACjD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,sBAAsB,CAC9B,GAAG,KAAK,wBAAwB,OAAO,KAAK,EAAE,CAC/C,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,sBAAsB,CAC9B,GAAG,KAAK,sDAAsD,CAC/D,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,sBAAsB,CAC9B,2CAA2C,OAAO,KAAK,EAAE,CAC1D,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,sBAAsB,CAC9B,0EAA0E,CAC3E,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAKzC;IACC,OAAO;QACL,UAAU,EAAE,YAAY,CAAC,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC;QACxD,eAAe,EAAE,YAAY,CAAC,iBAAiB,EAAE,KAAK,CAAC,eAAe,CAAC;QACvE,cAAc,EAAE,YAAY,CAAC,gBAAgB,EAAE,KAAK,CAAC,cAAc,CAAC;QACpE,mBAAmB,EAAE,eAAe,CAAC,KAAK,CAAC,mBAAmB,CAAC;KAChE,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAKvC;IACC,MAAM,GAAG,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;IAC7C,OAAO,UAAU,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;AACpC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@algovoi/substrate",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "AlgoVoi agentic-payments substrate -- JCS canonicalisation, action_ref, composite trust-query, compliance receipts, audit chain",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "AlgoVoi agentic-payments substrate -- JCS canonicalisation, action_ref, composite trust-query, compliance receipts, audit chain, settlement-action binding",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"x402",
|
|
7
7
|
"ap2",
|
package/src/index.ts
CHANGED
|
@@ -66,3 +66,10 @@ export {
|
|
|
66
66
|
transitionHash,
|
|
67
67
|
buildTransactionalActionChain,
|
|
68
68
|
} from './transactional.js';
|
|
69
|
+
|
|
70
|
+
export {
|
|
71
|
+
SettlementBindingError,
|
|
72
|
+
type SettlementBindingPreimage,
|
|
73
|
+
settlementBindingPreimage,
|
|
74
|
+
settlementActionBinding,
|
|
75
|
+
} from './settlement-binding.js';
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settlement-action binding (non-normative substrate extension).
|
|
3
|
+
*
|
|
4
|
+
* An x402/AP2/A2A settlement attestation proves a *payment* occurred. It does
|
|
5
|
+
* not, on its own, prove *which verified agent action* the payment corresponds
|
|
6
|
+
* to, nor that the correspondence is recorded in a tamper-evident chain. This
|
|
7
|
+
* module closes that post-settlement accountability gap with a single canonical
|
|
8
|
+
* reference binding four already-published substrate artifacts into one record:
|
|
9
|
+
*
|
|
10
|
+
* binding_ref = "sha256:" + SHA-256(JCS({
|
|
11
|
+
* action_ref, // the verified agent-action identity
|
|
12
|
+
* transition_hash, // the COMMITTED lifecycle transition (the "once")
|
|
13
|
+
* settlement_ref, // the settlement attestation content_hash
|
|
14
|
+
* retention_chain_ref, // the tamper-evident chain position recording it
|
|
15
|
+
* }))
|
|
16
|
+
*
|
|
17
|
+
* No new hashing primitive is introduced: the binding is the substrate's
|
|
18
|
+
* existing JCS + SHA-256 over the four references. Because action_ref and
|
|
19
|
+
* transition_hash are themselves computed from epoch-millisecond-integer
|
|
20
|
+
* preimages (Substrate Rule 2), any upstream RFC 3339 string timestamp produces
|
|
21
|
+
* a different action_ref, hence a different binding -- a non-conformant lineage
|
|
22
|
+
* cannot reproduce the binding bytes.
|
|
23
|
+
*
|
|
24
|
+
* The output carries the "sha256:" algorithm prefix, consistent with
|
|
25
|
+
* retention_chain_ref, signalling a content-addressed reference.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { sha256Jcs } from './canonicalize.js';
|
|
29
|
+
|
|
30
|
+
const HEX64_RE = /^[0-9a-f]{64}$/;
|
|
31
|
+
const SHA256_REF_RE = /^sha256:[0-9a-f]{64}$/;
|
|
32
|
+
|
|
33
|
+
export class SettlementBindingError extends Error {
|
|
34
|
+
constructor(message: string) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.name = 'SettlementBindingError';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface SettlementBindingPreimage {
|
|
41
|
+
action_ref: string;
|
|
42
|
+
transition_hash: string;
|
|
43
|
+
settlement_ref: string;
|
|
44
|
+
retention_chain_ref: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function requireHex64(field: string, value: unknown): string {
|
|
48
|
+
if (typeof value !== 'string') {
|
|
49
|
+
throw new SettlementBindingError(
|
|
50
|
+
`${field} must be string, got ${typeof value}`,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
if (!HEX64_RE.test(value)) {
|
|
54
|
+
throw new SettlementBindingError(
|
|
55
|
+
`${field} must be a lowercase 64-character SHA-256 hex string`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function requireChainRef(value: unknown): string {
|
|
62
|
+
if (typeof value !== 'string') {
|
|
63
|
+
throw new SettlementBindingError(
|
|
64
|
+
`retention_chain_ref must be string, got ${typeof value}`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
if (!SHA256_REF_RE.test(value)) {
|
|
68
|
+
throw new SettlementBindingError(
|
|
69
|
+
"retention_chain_ref must be of the form 'sha256:<lowercase 64-char hex>'",
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Return the validated four-field binding preimage object.
|
|
77
|
+
*
|
|
78
|
+
* The shape is fixed at the substrate layer; each field cryptographically
|
|
79
|
+
* contributes to the binding so that no one component can be substituted
|
|
80
|
+
* without changing the binding_ref.
|
|
81
|
+
*/
|
|
82
|
+
export function settlementBindingPreimage(input: {
|
|
83
|
+
action_ref: string;
|
|
84
|
+
transition_hash: string;
|
|
85
|
+
settlement_ref: string;
|
|
86
|
+
retention_chain_ref: string;
|
|
87
|
+
}): SettlementBindingPreimage {
|
|
88
|
+
return {
|
|
89
|
+
action_ref: requireHex64('action_ref', input.action_ref),
|
|
90
|
+
transition_hash: requireHex64('transition_hash', input.transition_hash),
|
|
91
|
+
settlement_ref: requireHex64('settlement_ref', input.settlement_ref),
|
|
92
|
+
retention_chain_ref: requireChainRef(input.retention_chain_ref),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Return the binding_ref as a "sha256:"-prefixed content-addressed reference.
|
|
98
|
+
*
|
|
99
|
+
* binding_ref = "sha256:" + SHA-256(JCS({action_ref, transition_hash,
|
|
100
|
+
* settlement_ref, retention_chain_ref}))
|
|
101
|
+
*/
|
|
102
|
+
export function settlementActionBinding(input: {
|
|
103
|
+
action_ref: string;
|
|
104
|
+
transition_hash: string;
|
|
105
|
+
settlement_ref: string;
|
|
106
|
+
retention_chain_ref: string;
|
|
107
|
+
}): string {
|
|
108
|
+
const obj = settlementBindingPreimage(input);
|
|
109
|
+
return `sha256:${sha256Jcs(obj)}`;
|
|
110
|
+
}
|