@ottochain/sdk 2.6.0 → 2.7.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/dist/cjs/apps/lending/assets.js +11 -1
- package/dist/cjs/index.js +8 -2
- package/dist/cjs/ottochain/index.js +11 -1
- package/dist/cjs/ottochain/morphism-lint.js +99 -0
- package/dist/cjs/ottochain/state-proof.js +118 -0
- package/dist/cjs/ottochain/transaction.js +7 -1
- package/dist/cjs/ottochain/webhook-notifications.js +33 -0
- package/dist/cjs/schema/effects.js +14 -5
- package/dist/cjs/schema/guard-lint.js +102 -0
- package/dist/esm/apps/lending/assets.js +11 -1
- package/dist/esm/index.js +3 -0
- package/dist/esm/ottochain/index.js +4 -0
- package/dist/esm/ottochain/morphism-lint.js +95 -0
- package/dist/esm/ottochain/state-proof.js +113 -0
- package/dist/esm/ottochain/transaction.js +7 -1
- package/dist/esm/ottochain/webhook-notifications.js +30 -0
- package/dist/esm/schema/effects.js +14 -5
- package/dist/esm/schema/guard-lint.js +102 -0
- package/dist/types/apps/lending/assets.d.ts +11 -1
- package/dist/types/index.d.ts +4 -0
- package/dist/types/ottochain/index.d.ts +6 -0
- package/dist/types/ottochain/morphism-lint.d.ts +56 -0
- package/dist/types/ottochain/state-proof.d.ts +51 -0
- package/dist/types/ottochain/transaction.d.ts +7 -1
- package/dist/types/ottochain/types.d.ts +22 -0
- package/dist/types/ottochain/webhook-notifications.d.ts +91 -0
- package/dist/types/schema/effects.d.ts +14 -5
- package/dist/types/schema/guard-lint.d.ts +6 -0
- package/package.json +6 -6
|
@@ -112,6 +112,11 @@ function createMintAssetPayload(params) {
|
|
|
112
112
|
/**
|
|
113
113
|
* Apply a typed morphism (Transfer / Burn / Compose / ...). asset-model.md §7.
|
|
114
114
|
* Transfer = `{ kind: "Transfer", recipient }`; Burn (repay) = `{ kind: "Burn" }`.
|
|
115
|
+
*
|
|
116
|
+
* C2 — a `Compose`/`Pool` that folds in a counter-party the signer does NOT own is now rejected on-chain
|
|
117
|
+
* unless a live `AuthorizeCompose` nonce authorizes it: pass that nonce here (`nonce`) and build the commit
|
|
118
|
+
* half with {@link createAuthorizeComposePayload}. A same-holder compose (all parts signer-owned) needs no
|
|
119
|
+
* nonce. `otherAssets` must be duplicate-free and must not include `assetId`.
|
|
115
120
|
*/
|
|
116
121
|
function createApplyMorphismPayload(params) {
|
|
117
122
|
return {
|
|
@@ -128,7 +133,12 @@ function createApplyMorphismPayload(params) {
|
|
|
128
133
|
},
|
|
129
134
|
};
|
|
130
135
|
}
|
|
131
|
-
/**
|
|
136
|
+
/**
|
|
137
|
+
* Commit half of a two-party (cross-holder) compose. asset-model.md §7/§8. As of chain finding C2 this
|
|
138
|
+
* handshake is MANDATORY: a cross-holder `Compose`/`Pool` is rejected unless a matching, unexpired nonce
|
|
139
|
+
* from this call is live for the counter-party. The composing party then echoes `nonce` in its
|
|
140
|
+
* `ApplyMorphism`. A same-holder compose (all parts owned by the signer) does not need this.
|
|
141
|
+
*/
|
|
132
142
|
function createAuthorizeComposePayload(params) {
|
|
133
143
|
return {
|
|
134
144
|
AuthorizeCompose: {
|
package/dist/cjs/index.js
CHANGED
|
@@ -31,8 +31,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
31
31
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
32
32
|
};
|
|
33
33
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
-
exports.
|
|
35
|
-
exports.SHIELDED_POOL_STATE = exports.shieldApp = exports.RESERVED_EFFECT_KEYS = exports.toWallet = exports.toFiber = exports.scriptCall = exports.emit = exports.spawn = exports.triggers = exports.transferAsset = exports.setDependencyActive = exports.addDependency = exports.actorNotInArray = exports.depInState = exports.signerHasRoleVia = exports.signerHasReputationVia = exports.signerHasRole = exports.signerHasReputation = exports.actorHasEntry = exports.actorInSet = exports.actorIsSigner = exports.assetSignerIs = exports.signerHasEntry = exports.signerIsNotParty = exports.signerInSet = exports.signerIsAnyParty = exports.signerIsParty = exports.projectFiberPolicy = void 0;
|
|
34
|
+
exports.constrained = exports.defineFiberApp = exports.toProtoDefinition = exports.SNAPSHOT_FINALIZED_EVENT = exports.OttoMetagraphClient = exports.assert = exports.safeParse = exports.validateKeyPair = exports.validateAddress = exports.validatePublicKey = exports.validatePrivateKey = exports.validate = exports.CompleteContractRequestSchema = exports.AcceptContractRequestSchema = exports.ProposeContractRequestSchema = exports.ContractTermsSchema = exports.PlatformLinkSchema = exports.AgentIdentityRegistrationSchema = exports.TransferParamsSchema = exports.CurrencyTransactionSchema = exports.CurrencyTransactionValueSchema = exports.TransactionReferenceSchema = exports.SignedSchema = exports.SignatureProofSchema = exports.KeyPairSchema = exports.PublicKeySchema = exports.PrivateKeySchema = exports.DagAddressSchema = exports.wrapError = exports.isErrorCode = exports.ErrorCode = exports.TransactionError = exports.SigningError = exports.ValidationError = exports.NetworkError = exports.OttoChainError = exports.GENESIS_MANIFEST_VERSION = exports.buildGenesisManifest = exports.MORPHISM_LINT_CODES = exports.lintApplyMorphism = exports.dropNulls = exports.MetagraphNetworkError = exports.HttpClient = exports.createMetagraphClient = exports.MetagraphClient = exports.batchSign = exports.addSignature = exports.createSignedObject = exports.signDataUpdate = exports.verify = void 0;
|
|
35
|
+
exports.SHIELDED_POOL_STATE = exports.shieldApp = exports.RESERVED_EFFECT_KEYS = exports.toWallet = exports.toFiber = exports.scriptCall = exports.emit = exports.spawn = exports.triggers = exports.transferAsset = exports.setDependencyActive = exports.addDependency = exports.actorNotInArray = exports.depInState = exports.signerHasRoleVia = exports.signerHasReputationVia = exports.signerHasRole = exports.signerHasReputation = exports.actorHasEntry = exports.actorInSet = exports.actorIsSigner = exports.assetSignerIs = exports.signerHasEntry = exports.signerIsNotParty = exports.signerInSet = exports.signerIsAnyParty = exports.signerIsParty = exports.projectFiberPolicy = exports.IMMUTABLE_POLICY = exports.immutable = exports.unconstrained = void 0;
|
|
36
36
|
// ─── Core metagraph SDK ───────────────────────────────────────────────────────
|
|
37
37
|
// Consumers can also import directly from '@constellation-network/metagraph-sdk'
|
|
38
38
|
__exportStar(require("@constellation-network/metagraph-sdk"), exports);
|
|
@@ -62,6 +62,10 @@ __exportStar(require("./types.js"), exports);
|
|
|
62
62
|
__exportStar(require("./ottochain/transaction.js"), exports);
|
|
63
63
|
var drop_nulls_js_1 = require("./ottochain/drop-nulls.js");
|
|
64
64
|
Object.defineProperty(exports, "dropNulls", { enumerable: true, get: function () { return drop_nulls_js_1.dropNulls; } });
|
|
65
|
+
// Message-layer advisory lint for ApplyMorphism (Compose/Pool consent + inflation checks).
|
|
66
|
+
var morphism_lint_js_1 = require("./ottochain/morphism-lint.js");
|
|
67
|
+
Object.defineProperty(exports, "lintApplyMorphism", { enumerable: true, get: function () { return morphism_lint_js_1.lintApplyMorphism; } });
|
|
68
|
+
Object.defineProperty(exports, "MORPHISM_LINT_CODES", { enumerable: true, get: function () { return morphism_lint_js_1.MORPHISM_LINT_CODES; } });
|
|
65
69
|
// ─── Genesis manifest exporter (std-app pre-registration content) ─────────────
|
|
66
70
|
var genesis_manifest_js_1 = require("./ottochain/genesis-manifest.js");
|
|
67
71
|
Object.defineProperty(exports, "buildGenesisManifest", { enumerable: true, get: function () { return genesis_manifest_js_1.buildGenesisManifest; } });
|
|
@@ -108,6 +112,8 @@ Object.defineProperty(exports, "assert", { enumerable: true, get: function () {
|
|
|
108
112
|
// ─── OttoChain metagraph client ───────────────────────────────────────────────
|
|
109
113
|
var metagraph_client_js_1 = require("./ottochain/metagraph-client.js");
|
|
110
114
|
Object.defineProperty(exports, "OttoMetagraphClient", { enumerable: true, get: function () { return metagraph_client_js_1.MetagraphClient; } });
|
|
115
|
+
var webhook_notifications_js_1 = require("./ottochain/webhook-notifications.js");
|
|
116
|
+
Object.defineProperty(exports, "SNAPSHOT_FINALIZED_EVENT", { enumerable: true, get: function () { return webhook_notifications_js_1.SNAPSHOT_FINALIZED_EVENT; } });
|
|
111
117
|
// Proto definition helper
|
|
112
118
|
var fiber_app_js_1 = require("./schema/fiber-app.js");
|
|
113
119
|
Object.defineProperty(exports, "toProtoDefinition", { enumerable: true, get: function () { return fiber_app_js_1.toProtoDefinition; } });
|
|
@@ -40,7 +40,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
40
40
|
};
|
|
41
41
|
})();
|
|
42
42
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
-
exports.GENESIS_MANIFEST_VERSION = exports.buildGenesisManifest = exports.dropNulls = exports.createAuthorizeComposePayload = exports.createApplyMorphismPayload = exports.createMintAssetPayload = exports.createAssetPolicyPayload = exports.createDataTransactionRequest = exports.createScriptPayload = exports.createStateMachinePayload = exports.getPublicKeyForRegistration = exports.addTransactionSignature = exports.signTransaction = exports.createInvokeScriptPayload = exports.createArchivePayload = exports.createTransitionPayload = exports.MetagraphClient = exports.extractOnChainState = exports.getScriptInvocations = exports.getEventReceipts = exports.getLogsForFiber = exports.getLatestOnChainState = exports.getSnapshotOnChainState = exports.decodeOnChainState = exports.TOKEN_BEHAVIOR_BITS = exports.OTTOCHAIN_MESSAGE_TYPES = exports.proto = void 0;
|
|
43
|
+
exports.GENESIS_MANIFEST_VERSION = exports.buildGenesisManifest = exports.dropNulls = exports.MORPHISM_LINT_CODES = exports.lintApplyMorphism = exports.createAuthorizeComposePayload = exports.createApplyMorphismPayload = exports.createMintAssetPayload = exports.createAssetPolicyPayload = exports.createDataTransactionRequest = exports.createScriptPayload = exports.createStateMachinePayload = exports.getPublicKeyForRegistration = exports.addTransactionSignature = exports.signTransaction = exports.createInvokeScriptPayload = exports.createArchivePayload = exports.createTransitionPayload = exports.SNAPSHOT_FINALIZED_EVENT = exports.commitKeyPath = exports.verifyMptInclusion = exports.verifyStateProof = exports.MetagraphClient = exports.extractOnChainState = exports.getScriptInvocations = exports.getEventReceipts = exports.getLogsForFiber = exports.getLatestOnChainState = exports.getSnapshotOnChainState = exports.decodeOnChainState = exports.TOKEN_BEHAVIOR_BITS = exports.OTTOCHAIN_MESSAGE_TYPES = exports.proto = void 0;
|
|
44
44
|
// Re-export generated protobuf types (for binary encoding)
|
|
45
45
|
exports.proto = __importStar(require("../generated/index.js"));
|
|
46
46
|
// Runtime message type validation
|
|
@@ -57,6 +57,12 @@ Object.defineProperty(exports, "getScriptInvocations", { enumerable: true, get:
|
|
|
57
57
|
Object.defineProperty(exports, "extractOnChainState", { enumerable: true, get: function () { return snapshot_js_1.extractOnChainState; } });
|
|
58
58
|
var metagraph_client_js_1 = require("./metagraph-client.js");
|
|
59
59
|
Object.defineProperty(exports, "MetagraphClient", { enumerable: true, get: function () { return metagraph_client_js_1.MetagraphClient; } });
|
|
60
|
+
var state_proof_js_1 = require("./state-proof.js");
|
|
61
|
+
Object.defineProperty(exports, "verifyStateProof", { enumerable: true, get: function () { return state_proof_js_1.verifyStateProof; } });
|
|
62
|
+
Object.defineProperty(exports, "verifyMptInclusion", { enumerable: true, get: function () { return state_proof_js_1.verifyMptInclusion; } });
|
|
63
|
+
Object.defineProperty(exports, "commitKeyPath", { enumerable: true, get: function () { return state_proof_js_1.commitKeyPath; } });
|
|
64
|
+
var webhook_notifications_js_1 = require("./webhook-notifications.js");
|
|
65
|
+
Object.defineProperty(exports, "SNAPSHOT_FINALIZED_EVENT", { enumerable: true, get: function () { return webhook_notifications_js_1.SNAPSHOT_FINALIZED_EVENT; } });
|
|
60
66
|
// Transaction helpers (state machine payloads, signing)
|
|
61
67
|
var transaction_js_1 = require("./transaction.js");
|
|
62
68
|
Object.defineProperty(exports, "createTransitionPayload", { enumerable: true, get: function () { return transaction_js_1.createTransitionPayload; } });
|
|
@@ -72,6 +78,10 @@ Object.defineProperty(exports, "createAssetPolicyPayload", { enumerable: true, g
|
|
|
72
78
|
Object.defineProperty(exports, "createMintAssetPayload", { enumerable: true, get: function () { return transaction_js_1.createMintAssetPayload; } });
|
|
73
79
|
Object.defineProperty(exports, "createApplyMorphismPayload", { enumerable: true, get: function () { return transaction_js_1.createApplyMorphismPayload; } });
|
|
74
80
|
Object.defineProperty(exports, "createAuthorizeComposePayload", { enumerable: true, get: function () { return transaction_js_1.createAuthorizeComposePayload; } });
|
|
81
|
+
// Message-layer advisory lint for ApplyMorphism (Compose/Pool C2 mistakes the chain rejects).
|
|
82
|
+
var morphism_lint_js_1 = require("./morphism-lint.js");
|
|
83
|
+
Object.defineProperty(exports, "lintApplyMorphism", { enumerable: true, get: function () { return morphism_lint_js_1.lintApplyMorphism; } });
|
|
84
|
+
Object.defineProperty(exports, "MORPHISM_LINT_CODES", { enumerable: true, get: function () { return morphism_lint_js_1.MORPHISM_LINT_CODES; } });
|
|
75
85
|
// Data utilities
|
|
76
86
|
var drop_nulls_js_1 = require("./drop-nulls.js");
|
|
77
87
|
Object.defineProperty(exports, "dropNulls", { enumerable: true, get: function () { return drop_nulls_js_1.dropNulls; } });
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Message-layer advisory lint for an {@link ApplyMorphism} transaction (asset-model.md §7; chain
|
|
4
|
+
* audit finding C2, enforced in `AssetCombiner`).
|
|
5
|
+
*
|
|
6
|
+
* Purpose
|
|
7
|
+
* -------
|
|
8
|
+
* The definition-scoped {@link ../schema/guard-lint.ts | guard-lint} walks fiber-app DEFINITIONS; it
|
|
9
|
+
* never sees an `ApplyMorphism` MESSAGE, so a malformed / no-consent `Compose` slips past it. This
|
|
10
|
+
* linter closes that gap at the transaction-builder layer: hand it the `ApplyMorphism` you are about
|
|
11
|
+
* to sign and it flags the two classes of C2 mistake the chain rejects.
|
|
12
|
+
*
|
|
13
|
+
* The chain rule being mirrored (C2, `Compose`/`Pool` only):
|
|
14
|
+
* - `otherAssetIds` must be free of duplicates and must NOT include the source `assetId`
|
|
15
|
+
* (the old self/duplicate-inflation path — rejected unconditionally, holder-independent).
|
|
16
|
+
* - every counter-party the signer does NOT hold requires a live {@link AuthorizeCompose} `nonce`;
|
|
17
|
+
* a same-holder / all-signer-owned compose needs none.
|
|
18
|
+
*
|
|
19
|
+
* ERRORS are statically certain (the chain rejects regardless of who holds what). WARNINGS are
|
|
20
|
+
* heuristic — the signer's holdings/ownership are unknown at build time, so a missing consent nonce
|
|
21
|
+
* cannot be proven fatal (a same-holder compose is legitimately nonce-less).
|
|
22
|
+
*
|
|
23
|
+
* This is a PURE, non-throwing advisory. It is deliberately NOT wired into
|
|
24
|
+
* {@link createApplyMorphismPayload} (which must stay non-breaking and side-effect-free); call it
|
|
25
|
+
* explicitly before signing, or in your app's own pre-flight checks.
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.MORPHISM_LINT_CODES = void 0;
|
|
29
|
+
exports.lintApplyMorphism = lintApplyMorphism;
|
|
30
|
+
/** Stable rule codes for {@link lintApplyMorphism} — referenced by tests and report tooling. */
|
|
31
|
+
exports.MORPHISM_LINT_CODES = {
|
|
32
|
+
/** `otherAssetIds` contains a duplicate id (chain rejects — inflation path). */
|
|
33
|
+
DUPLICATE_OTHER_ID: 'morphism-duplicate-other-id',
|
|
34
|
+
/** `otherAssetIds` includes the source `assetId` (self-composition — chain rejects). */
|
|
35
|
+
SELF_COMPOSE: 'morphism-self-compose',
|
|
36
|
+
/** `otherAssetIds` is non-empty but `kind` ignores it (not Compose/Pool — likely a mistake). */
|
|
37
|
+
OTHER_IDS_IGNORED: 'morphism-other-ids-ignored',
|
|
38
|
+
/** Compose/Pool with counter-parties and no consent `nonce` (rejected IF any part is not signer-owned). */
|
|
39
|
+
COMPOSE_NO_NONCE: 'morphism-compose-no-nonce',
|
|
40
|
+
};
|
|
41
|
+
/** The morphism kinds whose semantics READ `otherAssetIds` (fold counter-party parts into a composite). */
|
|
42
|
+
const COMPOSING_KINDS = new Set(['COMPOSE', 'POOL']);
|
|
43
|
+
function finding(severity, code, message, path) {
|
|
44
|
+
return { severity, code, message, path };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Lint a single {@link ApplyMorphism} message. Pure and non-throwing. Returns every finding
|
|
48
|
+
* (`error` + `warn`); callers decide the policy (e.g. block on any `error`, surface `warn`s).
|
|
49
|
+
*
|
|
50
|
+
* ERRORS (statically certain — the chain rejects unconditionally, holder-independent):
|
|
51
|
+
* - {@link MORPHISM_LINT_CODES.DUPLICATE_OTHER_ID} — `otherAssetIds` contains a duplicate id.
|
|
52
|
+
* - {@link MORPHISM_LINT_CODES.SELF_COMPOSE} — `otherAssetIds` includes the source `assetId`.
|
|
53
|
+
* - {@link MORPHISM_LINT_CODES.OTHER_IDS_IGNORED} — `otherAssetIds` is non-empty but `kind` is not
|
|
54
|
+
* `COMPOSE`/`POOL` (the field is ignored for other kinds — a likely authoring mistake).
|
|
55
|
+
*
|
|
56
|
+
* WARNINGS (heuristic — holder/ownership unknown at build time):
|
|
57
|
+
* - {@link MORPHISM_LINT_CODES.COMPOSE_NO_NONCE} — a `COMPOSE`/`POOL` with a non-empty
|
|
58
|
+
* `otherAssetIds` and NO `nonce`. IF any counter-party is not signer-owned the chain rejects it
|
|
59
|
+
* (C2); attach the reveal half of an {@link AuthorizeCompose} handshake as `nonce`. A same-holder
|
|
60
|
+
* compose (all parts signer-owned) is legitimately nonce-less — hence a warning, not an error.
|
|
61
|
+
*/
|
|
62
|
+
function lintApplyMorphism(msg) {
|
|
63
|
+
const out = [];
|
|
64
|
+
const ids = msg.otherAssetIds ?? [];
|
|
65
|
+
const isComposing = COMPOSING_KINDS.has(msg.kind);
|
|
66
|
+
// ---- error: duplicate ids in otherAssetIds ---------------------------------
|
|
67
|
+
// One finding per DISTINCT duplicated id (path points at its first repeat occurrence).
|
|
68
|
+
const seen = new Set();
|
|
69
|
+
const dupReported = new Set();
|
|
70
|
+
ids.forEach((id, i) => {
|
|
71
|
+
if (seen.has(id) && !dupReported.has(id)) {
|
|
72
|
+
dupReported.add(id);
|
|
73
|
+
out.push(finding('error', exports.MORPHISM_LINT_CODES.DUPLICATE_OTHER_ID, `otherAssetIds contains duplicate id "${id}". The chain rejects a Compose/Pool whose ` +
|
|
74
|
+
`otherAssetIds has duplicates (the old inflation path). List each counter-party asset once.`, `otherAssetIds[${i}]`));
|
|
75
|
+
}
|
|
76
|
+
seen.add(id);
|
|
77
|
+
});
|
|
78
|
+
// ---- error: otherAssetIds includes the source assetId (self-composition) ----
|
|
79
|
+
const selfIdx = ids.indexOf(msg.assetId);
|
|
80
|
+
if (selfIdx !== -1) {
|
|
81
|
+
out.push(finding('error', exports.MORPHISM_LINT_CODES.SELF_COMPOSE, `otherAssetIds includes the source assetId "${msg.assetId}" (self-composition). The chain ` +
|
|
82
|
+
`rejects this unconditionally. otherAssetIds must list only the OTHER parts folded into the composite.`, `otherAssetIds[${selfIdx}]`));
|
|
83
|
+
}
|
|
84
|
+
// ---- error: otherAssetIds set but kind ignores it ---------------------------
|
|
85
|
+
if (ids.length > 0 && !isComposing) {
|
|
86
|
+
out.push(finding('error', exports.MORPHISM_LINT_CODES.OTHER_IDS_IGNORED, `otherAssetIds is non-empty but kind is "${msg.kind}", which ignores otherAssetIds entirely ` +
|
|
87
|
+
`(only COMPOSE/POOL fold in counter-party parts). This is almost certainly a mistake — set ` +
|
|
88
|
+
`kind to COMPOSE/POOL, or drop otherAssetIds.`, 'otherAssetIds'));
|
|
89
|
+
}
|
|
90
|
+
// ---- warn: composing with counter-parties but no consent nonce --------------
|
|
91
|
+
// nonce === 0 is a valid live nonce; only an OMITTED nonce (undefined/null) triggers the warning.
|
|
92
|
+
if (isComposing && ids.length > 0 && msg.nonce == null) {
|
|
93
|
+
out.push(finding('warn', exports.MORPHISM_LINT_CODES.COMPOSE_NO_NONCE, `${msg.kind} folds in otherAssetIds but carries no consent nonce. If ANY counter-party asset ` +
|
|
94
|
+
`is not held by the signer, the chain REJECTS this (C2): attach the reveal half of an ` +
|
|
95
|
+
`AuthorizeCompose handshake as \`nonce\`. A same-holder compose (all parts signer-owned) ` +
|
|
96
|
+
`needs none, so this is advisory.`, 'nonce'));
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.commitKeyPath = commitKeyPath;
|
|
4
|
+
exports.verifyMptInclusion = verifyMptInclusion;
|
|
5
|
+
exports.verifyStateProof = verifyStateProof;
|
|
6
|
+
/**
|
|
7
|
+
* Light-client verification of committed state proofs.
|
|
8
|
+
*
|
|
9
|
+
* The chain's `/state-machines|scripts|assets/{id}/state-proof` endpoints return a
|
|
10
|
+
* {@link StateProof}: the record plus a Merkle-Patricia inclusion proof against `mptRoot`,
|
|
11
|
+
* whose combined hash IS the snapshot's consensus-signed `calculatedStateProof`. Verifying
|
|
12
|
+
* the proof locally means trusting NO serving node — only snapshot consensus.
|
|
13
|
+
*
|
|
14
|
+
* The fold mirrors metakit's `MerklePatriciaVerifier` byte-for-byte (validated against live
|
|
15
|
+
* cluster proofs):
|
|
16
|
+
*
|
|
17
|
+
* - the response `witness` is LEAF-FIRST; verification walks it reversed (root-first);
|
|
18
|
+
* - every node's digest = `sha256(typePrefix ++ utf8(JCS(dropNulls(contents))))` over the
|
|
19
|
+
* commitment's SUBTYPE (contents-only) encoding — prefixes: leaf `0x00`, branch `0x01`,
|
|
20
|
+
* extension `0x02`;
|
|
21
|
+
* - a Branch consumes one path nibble via `pathsDigest`; an Extension consumes its `shared`
|
|
22
|
+
* nibbles and continues at `childDigest`;
|
|
23
|
+
* - the terminal Leaf must match the remaining path (`remaining`) and bind
|
|
24
|
+
* `dataDigest == sha256(JCS(dropNulls(record)))` (no prefix);
|
|
25
|
+
* - the trie path of a committed key is `hex(utf8(key))` (metakit `CommitKey.toHex`), e.g.
|
|
26
|
+
* `fiber/<uuid>` → `66696265722f…`.
|
|
27
|
+
*
|
|
28
|
+
* NOTE: this intentionally does NOT route through the JLVM `mpt_verify` opcode — the
|
|
29
|
+
* TypeScript port of that opcode mis-canonicalizes non-scalar leaf values (fiber records)
|
|
30
|
+
* and returns false; its conformance vectors only cover scalar leaves. The Scala (chain)
|
|
31
|
+
* side is correct. Once the port is fixed upstream this helper stays valid either way: it
|
|
32
|
+
* is the same algorithm without the JsonLogic value-domain round-trip.
|
|
33
|
+
*/
|
|
34
|
+
const metagraph_sdk_1 = require("@constellation-network/metagraph-sdk");
|
|
35
|
+
const sha256_js_1 = require("@noble/hashes/sha256.js");
|
|
36
|
+
const utf8 = (s) => new TextEncoder().encode(s);
|
|
37
|
+
const toHexStr = (b) => Array.from(b, (x) => x.toString(16).padStart(2, '0')).join('');
|
|
38
|
+
/** `sha256(prefixByte? ++ utf8(JCS(dropNulls(value))))` — the chain's content-digest rule. */
|
|
39
|
+
function jcsSha256(value, prefix) {
|
|
40
|
+
const canonical = utf8((0, metagraph_sdk_1.canonicalize)(value));
|
|
41
|
+
if (prefix === undefined)
|
|
42
|
+
return toHexStr((0, sha256_js_1.sha256)(canonical));
|
|
43
|
+
const framed = new Uint8Array(1 + canonical.length);
|
|
44
|
+
framed[0] = prefix;
|
|
45
|
+
framed.set(canonical, 1);
|
|
46
|
+
return toHexStr((0, sha256_js_1.sha256)(framed));
|
|
47
|
+
}
|
|
48
|
+
/** The MPT trie path of a committed key — `hex(utf8(key))` (metakit `CommitKey.toHex`). */
|
|
49
|
+
function commitKeyPath(key) {
|
|
50
|
+
return toHexStr(utf8(key));
|
|
51
|
+
}
|
|
52
|
+
const NODE_PREFIX = { Leaf: 0, Branch: 1, Extension: 2 };
|
|
53
|
+
/**
|
|
54
|
+
* Verify a Merkle-Patricia inclusion proof: `record` is committed at `key` under `mptRoot`.
|
|
55
|
+
*
|
|
56
|
+
* Pure and side-effect free; never throws on malformed input (returns `{ ok: false }`).
|
|
57
|
+
*/
|
|
58
|
+
function verifyMptInclusion(mptRoot, key, record, proof) {
|
|
59
|
+
const fail = (reason) => ({ ok: false, reason });
|
|
60
|
+
if (!proof || typeof proof.path !== 'string' || !Array.isArray(proof.witness) || proof.witness.length === 0)
|
|
61
|
+
return fail('malformed proof (missing path/witness)');
|
|
62
|
+
const expectedPath = commitKeyPath(key);
|
|
63
|
+
if (proof.path.toLowerCase() !== expectedPath)
|
|
64
|
+
return fail(`trie path != hex(utf8("${key}"))`);
|
|
65
|
+
let digest = String(mptRoot).replace(/^0x/, '').toLowerCase();
|
|
66
|
+
let path = proof.path.toLowerCase();
|
|
67
|
+
const nodes = [...proof.witness].reverse(); // response is leaf-first; fold root-first
|
|
68
|
+
for (const [depth, node] of nodes.entries()) {
|
|
69
|
+
const isLast = depth === nodes.length - 1;
|
|
70
|
+
const prefix = NODE_PREFIX[node?.type];
|
|
71
|
+
if (prefix === undefined)
|
|
72
|
+
return fail(`unknown witness node type '${String(node?.type)}'`);
|
|
73
|
+
if (jcsSha256(node.contents, prefix) !== digest)
|
|
74
|
+
return fail(`${node.type.toLowerCase()} commitment mismatch at depth ${depth}`);
|
|
75
|
+
if (node.type === 'Branch') {
|
|
76
|
+
const child = node.contents.pathsDigest?.[path[0]];
|
|
77
|
+
if (!child)
|
|
78
|
+
return fail(`branch has no child at nibble '${path[0]}' (depth ${depth})`);
|
|
79
|
+
digest = child.toLowerCase();
|
|
80
|
+
path = path.slice(1);
|
|
81
|
+
}
|
|
82
|
+
else if (node.type === 'Extension') {
|
|
83
|
+
const shared = String(node.contents.shared ?? '');
|
|
84
|
+
if (!path.startsWith(shared.toLowerCase()))
|
|
85
|
+
return fail(`extension shared-nibble mismatch at depth ${depth}`);
|
|
86
|
+
path = path.slice(shared.length);
|
|
87
|
+
digest = String(node.contents.childDigest ?? '').toLowerCase();
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// Leaf
|
|
91
|
+
if (!isLast)
|
|
92
|
+
return fail('leaf before end of witness');
|
|
93
|
+
if (String(node.contents.remaining ?? '').toLowerCase() !== path)
|
|
94
|
+
return fail('leaf remaining-path mismatch');
|
|
95
|
+
if (String(node.contents.dataDigest ?? '').toLowerCase() !== jcsSha256(record))
|
|
96
|
+
return fail('leaf dataDigest != sha256(JCS(record))');
|
|
97
|
+
return { ok: true };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return fail('witness does not terminate in a leaf');
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Verify a whole {@link StateProof} response for a committed key.
|
|
104
|
+
*
|
|
105
|
+
* Checks the trie inclusion of `record` at `key` under the response's `mptRoot` (see
|
|
106
|
+
* {@link verifyMptInclusion}). The caller supplies the key it EXPECTS (`fiber/<id>`,
|
|
107
|
+
* `script/<id>`, `asset/<id>`, …) so a proof for some other record cannot be substituted;
|
|
108
|
+
* the response's own `key` field must agree.
|
|
109
|
+
*
|
|
110
|
+
* Trust anchor: `committedRoot` (= `sha256(mptRoot ++ catalogRoot)`) rides in the
|
|
111
|
+
* consensus-signed snapshot as `calculatedStateProof`; binding `mptRoot` to a snapshot is
|
|
112
|
+
* the caller's (or a snapshot-following light client's) responsibility.
|
|
113
|
+
*/
|
|
114
|
+
function verifyStateProof(resp, expectedKey) {
|
|
115
|
+
if (resp.key !== expectedKey)
|
|
116
|
+
return { ok: false, reason: `response key '${resp.key}' != expected '${expectedKey}'` };
|
|
117
|
+
return verifyMptInclusion(String(resp.mptRoot), expectedKey, resp.record, resp.proof);
|
|
118
|
+
}
|
|
@@ -166,7 +166,13 @@ function createAssetPolicyPayload(params) {
|
|
|
166
166
|
function createMintAssetPayload(params) {
|
|
167
167
|
return { MintAsset: params };
|
|
168
168
|
}
|
|
169
|
-
/**
|
|
169
|
+
/**
|
|
170
|
+
* Wrap an {@link ApplyMorphism} (apply a typed morphism to an asset instance).
|
|
171
|
+
*
|
|
172
|
+
* @see lintApplyMorphism (`./morphism-lint.ts`) — pure, non-throwing advisory that flags the
|
|
173
|
+
* Compose/Pool mistakes the chain rejects (duplicate / self-referential `otherAssetIds`; a
|
|
174
|
+
* cross-holder compose with no consent `nonce`). Run it on `params` before signing.
|
|
175
|
+
*/
|
|
170
176
|
function createApplyMorphismPayload(params) {
|
|
171
177
|
return { ApplyMorphism: params };
|
|
172
178
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Webhook notification PAYLOAD types — the server-initiated push the chain POSTs to a subscribed
|
|
4
|
+
* callback, NOT part of the client's request surface.
|
|
5
|
+
*
|
|
6
|
+
* These are hand-authored (not generated from the OpenAPI contract) because the push is an OUTBOUND
|
|
7
|
+
* POST from the metagraph to the subscriber's callback URL — it is not an endpoint the chain's tapir
|
|
8
|
+
* `ApiEndpoints` serves, so it never appears in `openapi/ottochain-openapi-ml0.json`. They mirror the
|
|
9
|
+
* chain's shared network DTOs byte-for-byte:
|
|
10
|
+
*
|
|
11
|
+
* chain: modules/models/src/main/scala/xyz/kd5ujc/schema/api/webhooks/Subscriber.scala
|
|
12
|
+
* (SnapshotNotification / NotificationStats / SnapshotRejection)
|
|
13
|
+
* emit: modules/l0/.../webhooks/WebhookDispatcher.scala — `notification.asJson.noSpaces`
|
|
14
|
+
*
|
|
15
|
+
* Field-shape notes tied to the chain source:
|
|
16
|
+
* - The dispatcher serializes with a plain derived encoder (`.asJson`, NO `dropNullValues`), so an
|
|
17
|
+
* `Option[Long]` that is `None` is emitted as an explicit `null` — the KEY is always present, the
|
|
18
|
+
* VALUE is nullable. Hence `number | null` (a required key), not `number | undefined` (an optional
|
|
19
|
+
* key). Consumers must handle `null`.
|
|
20
|
+
* - `Long` → JSON number; `Instant` → ISO-8601 string; `UUID` → string.
|
|
21
|
+
* - The dispatcher only ever emits `"snapshot.finalized"` today (there is a dead, never-dispatched
|
|
22
|
+
* `RejectionNotification`/`transaction.rejected` type in the chain models — deliberately NOT mirrored
|
|
23
|
+
* here, because the SDK should model only what is actually sent). Rejections now ride the finalized
|
|
24
|
+
* snapshot's `rejections[]`, drained from its committed `RejectionReceipt`s.
|
|
25
|
+
*
|
|
26
|
+
* @see modules/models/.../schema/api/webhooks/Subscriber.scala
|
|
27
|
+
* @see modules/l0/.../webhooks/WebhookDispatcher.scala
|
|
28
|
+
* @packageDocumentation
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.SNAPSHOT_FINALIZED_EVENT = void 0;
|
|
32
|
+
/** The only event the chain's `WebhookDispatcher` currently emits. */
|
|
33
|
+
exports.SNAPSHOT_FINALIZED_EVENT = 'snapshot.finalized';
|
|
@@ -121,11 +121,20 @@ exports.triggers = triggers;
|
|
|
121
121
|
* MUST be a literal {@link ProtoStateMachineDefinition} (e.g. a nested `machine().wireDefinition()` /
|
|
122
122
|
* `toProtoDefinition(child)` output) — NOT an expression the engine would evaluate at runtime.
|
|
123
123
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
124
|
+
* H1 constraint — child `owners` MUST be a SUBSET of the SPAWNING PARENT fiber's `owners`. As of the
|
|
125
|
+
* fiber-engine permissionless-hardening (chain branch `fix/fiber-engine-permissionless-hardening`, audit
|
|
126
|
+
* finding H1) the chain FAILS-CLOSED — it aborts the whole transition under EVERY `spawnOwnerPolicy` — if
|
|
127
|
+
* a `_spawn`'s resolved child `owners` are not ⊆ the parent's owners. Assigning arbitrary, unsigned owners
|
|
128
|
+
* (the old "auction owned by all its bidders" pattern, where the bidders are NOT parent owners) is no
|
|
129
|
+
* longer valid: those events are not silently rejected, the spawn itself is rejected.
|
|
130
|
+
*
|
|
131
|
+
* So DO NOT try to enroll later participants by listing them here. A spawned child's transitions are gated
|
|
132
|
+
* by `owners ∪ authorizedSigners` for the DIRECT (wallet-signed) path; admit additional drivers through
|
|
133
|
+
* the child's OWN transitions (`authorizedSigners`), or drive it via the cascade (`_triggers`) subject to
|
|
134
|
+
* its `acceptedCallers` — never by widening `owners` beyond the parent's set. `owners` may be a literal id
|
|
135
|
+
* array or an expression (e.g. `{ var: "state.owners" }` — resolve it WITHIN the parent's owners), but a
|
|
136
|
+
* value the parent does not own (e.g. `{ var: "event.auctionOwners" }` supplied by the caller) will be
|
|
137
|
+
* rejected on-chain. `childId` / `initialData` likewise accept literals or expressions.
|
|
129
138
|
*/
|
|
130
139
|
const spawn = (ds) => ({ _spawn: ds });
|
|
131
140
|
exports.spawn = spawn;
|
|
@@ -33,6 +33,11 @@
|
|
|
33
33
|
*
|
|
34
34
|
* leading-dot — `{"var":".foo"}` resolves to null on chain.
|
|
35
35
|
*
|
|
36
|
+
* H1 — a `_spawn` whose child `owners` are not provably a SUBSET of the spawning
|
|
37
|
+
* parent's owners. The chain now fails-closed (aborts the transition) under
|
|
38
|
+
* every spawnOwnerPolicy when child owners ⊄ parent owners; this advisory
|
|
39
|
+
* flags the strong not-subset signals (hardcoded / `event.*`-derived owners).
|
|
40
|
+
*
|
|
36
41
|
* This is a STANDALONE validator. It is deliberately NOT wired into
|
|
37
42
|
* `defineFiberApp` / `toProtoDefinition`: doing so would break the build until
|
|
38
43
|
* every app is remediated. Run it via `scripts/lint-apps.mjs`.
|
|
@@ -56,6 +61,7 @@ exports.LINT_CODES = {
|
|
|
56
61
|
WITNESS_IN_TRANSITION: 'witness-in-transition', // rule 3
|
|
57
62
|
DROPPED_DIRECTIVE: 'dropped-directive', // rule 4 (A3)
|
|
58
63
|
LEADING_DOT_VAR: 'leading-dot-var', // rule 5
|
|
64
|
+
SPAWN_OWNERS: 'spawn-owners', // rule 6 (H1) — child owners not provably ⊆ parent
|
|
59
65
|
};
|
|
60
66
|
// =============================================================================
|
|
61
67
|
// Rule data
|
|
@@ -293,6 +299,101 @@ function lintTransitionStructure(t, app, transition, path) {
|
|
|
293
299
|
return out;
|
|
294
300
|
}
|
|
295
301
|
// =============================================================================
|
|
302
|
+
// _spawn owner-subset rule (rule 6 / H1)
|
|
303
|
+
// =============================================================================
|
|
304
|
+
/** Collect every string `var` reference (path or `[path, default]` head) at or below `node`. */
|
|
305
|
+
function collectVarRefs(node, acc) {
|
|
306
|
+
if (Array.isArray(node)) {
|
|
307
|
+
node.forEach((child) => collectVarRefs(child, acc));
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (node === null || typeof node !== 'object')
|
|
311
|
+
return;
|
|
312
|
+
const obj = node;
|
|
313
|
+
const keys = Object.keys(obj);
|
|
314
|
+
if (keys.length === 1 && keys[0] === 'var') {
|
|
315
|
+
const ref = obj.var;
|
|
316
|
+
if (typeof ref === 'string')
|
|
317
|
+
acc.push(ref);
|
|
318
|
+
else if (Array.isArray(ref)) {
|
|
319
|
+
if (typeof ref[0] === 'string')
|
|
320
|
+
acc.push(ref[0]);
|
|
321
|
+
if (ref.length > 1)
|
|
322
|
+
collectVarRefs(ref[1], acc);
|
|
323
|
+
}
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
for (const k of keys)
|
|
327
|
+
collectVarRefs(obj[k], acc);
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Classify a `_spawn` child `owners` expression for the H1 subset risk. Returns a short reason string when
|
|
331
|
+
* the owners are NOT provably ⊆ the parent's owners from the definition alone, else `undefined`.
|
|
332
|
+
*
|
|
333
|
+
* The linter cannot see the parent fiber's runtime `owners` (they are set at `create()` time, not in the
|
|
334
|
+
* definition), so it flags only the two STRONG "not-subset" signals — keeping false positives low:
|
|
335
|
+
* - a literal array carrying ≥1 concrete address string (a hardcoded external owner list); and
|
|
336
|
+
* - any `event.*` reference (caller-supplied — the exact H1 owner-forgery vector).
|
|
337
|
+
* Owners derived purely from the parent's own `state.*` / `machineId` / `$`-context are assumed in-set and
|
|
338
|
+
* are NOT flagged.
|
|
339
|
+
*/
|
|
340
|
+
function spawnOwnersRisk(owners) {
|
|
341
|
+
if (Array.isArray(owners) && owners.some((o) => typeof o === 'string' && o.length > 0)) {
|
|
342
|
+
return 'a literal array with hardcoded owner address(es)';
|
|
343
|
+
}
|
|
344
|
+
const refs = [];
|
|
345
|
+
collectVarRefs(owners, refs);
|
|
346
|
+
if (refs.some((r) => r === 'event' || r.startsWith('event.'))) {
|
|
347
|
+
return "an 'event' reference (caller-supplied owners)";
|
|
348
|
+
}
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* rule 6 (H1) — scan a transition effect for `_spawn` directives whose child `owners` are not provably a
|
|
353
|
+
* SUBSET of the spawning parent's owners. The chain now fails-closed (aborts the transition) under every
|
|
354
|
+
* `spawnOwnerPolicy` when a child's resolved owners are not ⊆ the parent's. Advisory (warn): the linter
|
|
355
|
+
* cannot prove the subset statically, so it flags only the strong not-subset signals (see
|
|
356
|
+
* {@link spawnOwnersRisk}).
|
|
357
|
+
*/
|
|
358
|
+
function lintSpawnOwners(node, app, transition, path) {
|
|
359
|
+
const out = [];
|
|
360
|
+
if (Array.isArray(node)) {
|
|
361
|
+
node.forEach((child, i) => out.push(...lintSpawnOwners(child, app, transition, `${path}[${i}]`)));
|
|
362
|
+
return out;
|
|
363
|
+
}
|
|
364
|
+
if (node === null || typeof node !== 'object')
|
|
365
|
+
return out;
|
|
366
|
+
const obj = node;
|
|
367
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
368
|
+
if (k === '_spawn' && Array.isArray(v)) {
|
|
369
|
+
v.forEach((entry, i) => {
|
|
370
|
+
if (entry && typeof entry === 'object' && !Array.isArray(entry) && 'owners' in entry) {
|
|
371
|
+
const reason = spawnOwnersRisk(entry.owners);
|
|
372
|
+
if (reason) {
|
|
373
|
+
out.push({
|
|
374
|
+
app,
|
|
375
|
+
transition,
|
|
376
|
+
severity: 'warn',
|
|
377
|
+
code: exports.LINT_CODES.SPAWN_OWNERS,
|
|
378
|
+
message: `_spawn child 'owners' must be a SUBSET of the spawning parent fiber's owners — the chain ` +
|
|
379
|
+
`now FAILS-CLOSED (aborts the transition) under every spawnOwnerPolicy if they are not ⊆ the ` +
|
|
380
|
+
`parent's (audit H1). This 'owners' is ${reason} and cannot be proven ⊆ the parent. Admit ` +
|
|
381
|
+
`later participants via the child's own transitions / authorizedSigners / acceptedCallers ` +
|
|
382
|
+
`instead of listing non-parent owners.`,
|
|
383
|
+
path: `${path}.${k}[${i}].owners`,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
// Do not descend into the spawn entry (its nested child definition's owners are relative to that
|
|
389
|
+
// child, not to this parent).
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
out.push(...lintSpawnOwners(v, app, transition, `${path}.${k}`));
|
|
393
|
+
}
|
|
394
|
+
return out;
|
|
395
|
+
}
|
|
396
|
+
// =============================================================================
|
|
296
397
|
// Top-level entry point
|
|
297
398
|
// =============================================================================
|
|
298
399
|
function appLabel(def) {
|
|
@@ -323,6 +424,7 @@ function lintFiberApp(def) {
|
|
|
323
424
|
}
|
|
324
425
|
if (t.effect !== undefined) {
|
|
325
426
|
out.push(...lintGuardExpression(t.effect, ctx, `${tPath}.effect`));
|
|
427
|
+
out.push(...lintSpawnOwners(t.effect, app, transition, `${tPath}.effect`));
|
|
326
428
|
}
|
|
327
429
|
out.push(...lintTransitionStructure(t, app, transition, tPath));
|
|
328
430
|
});
|
|
@@ -96,6 +96,11 @@ export function createMintAssetPayload(params) {
|
|
|
96
96
|
/**
|
|
97
97
|
* Apply a typed morphism (Transfer / Burn / Compose / ...). asset-model.md §7.
|
|
98
98
|
* Transfer = `{ kind: "Transfer", recipient }`; Burn (repay) = `{ kind: "Burn" }`.
|
|
99
|
+
*
|
|
100
|
+
* C2 — a `Compose`/`Pool` that folds in a counter-party the signer does NOT own is now rejected on-chain
|
|
101
|
+
* unless a live `AuthorizeCompose` nonce authorizes it: pass that nonce here (`nonce`) and build the commit
|
|
102
|
+
* half with {@link createAuthorizeComposePayload}. A same-holder compose (all parts signer-owned) needs no
|
|
103
|
+
* nonce. `otherAssets` must be duplicate-free and must not include `assetId`.
|
|
99
104
|
*/
|
|
100
105
|
export function createApplyMorphismPayload(params) {
|
|
101
106
|
return {
|
|
@@ -112,7 +117,12 @@ export function createApplyMorphismPayload(params) {
|
|
|
112
117
|
},
|
|
113
118
|
};
|
|
114
119
|
}
|
|
115
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* Commit half of a two-party (cross-holder) compose. asset-model.md §7/§8. As of chain finding C2 this
|
|
122
|
+
* handshake is MANDATORY: a cross-holder `Compose`/`Pool` is rejected unless a matching, unexpired nonce
|
|
123
|
+
* from this call is live for the counter-party. The composing party then echoes `nonce` in its
|
|
124
|
+
* `ApplyMorphism`. A same-holder compose (all parts owned by the signer) does not need this.
|
|
125
|
+
*/
|
|
116
126
|
export function createAuthorizeComposePayload(params) {
|
|
117
127
|
return {
|
|
118
128
|
AuthorizeCompose: {
|
package/dist/esm/index.js
CHANGED
|
@@ -34,6 +34,8 @@ export * from './types.js';
|
|
|
34
34
|
// ─── OttoChain-specific transaction helpers ───────────────────────────────────
|
|
35
35
|
export * from './ottochain/transaction.js';
|
|
36
36
|
export { dropNulls } from './ottochain/drop-nulls.js';
|
|
37
|
+
// Message-layer advisory lint for ApplyMorphism (Compose/Pool consent + inflation checks).
|
|
38
|
+
export { lintApplyMorphism, MORPHISM_LINT_CODES } from './ottochain/morphism-lint.js';
|
|
37
39
|
// ─── Genesis manifest exporter (std-app pre-registration content) ─────────────
|
|
38
40
|
export { buildGenesisManifest, GENESIS_MANIFEST_VERSION } from './ottochain/genesis-manifest.js';
|
|
39
41
|
// ─── Generated protobuf types (canonical definitions) ────────────────────────
|
|
@@ -48,6 +50,7 @@ DagAddressSchema, PrivateKeySchema, PublicKeySchema, KeyPairSchema, SignaturePro
|
|
|
48
50
|
validate, validatePrivateKey, validatePublicKey, validateAddress, validateKeyPair, safeParse, assert, } from './validation.js';
|
|
49
51
|
// ─── OttoChain metagraph client ───────────────────────────────────────────────
|
|
50
52
|
export { MetagraphClient as OttoMetagraphClient } from './ottochain/metagraph-client.js';
|
|
53
|
+
export { SNAPSHOT_FINALIZED_EVENT } from './ottochain/webhook-notifications.js';
|
|
51
54
|
// Proto definition helper
|
|
52
55
|
export { toProtoDefinition, defineFiberApp,
|
|
53
56
|
// Fiber policy (the fiber constitution): mirrors the chain ADT
|
|
@@ -11,8 +11,12 @@ export * as proto from '../generated/index.js';
|
|
|
11
11
|
export { OTTOCHAIN_MESSAGE_TYPES, TOKEN_BEHAVIOR_BITS } from './types.js';
|
|
12
12
|
export { decodeOnChainState, getSnapshotOnChainState, getLatestOnChainState, getLogsForFiber, getEventReceipts, getScriptInvocations, extractOnChainState, } from './snapshot.js';
|
|
13
13
|
export { MetagraphClient } from './metagraph-client.js';
|
|
14
|
+
export { verifyStateProof, verifyMptInclusion, commitKeyPath } from './state-proof.js';
|
|
15
|
+
export { SNAPSHOT_FINALIZED_EVENT } from './webhook-notifications.js';
|
|
14
16
|
// Transaction helpers (state machine payloads, signing)
|
|
15
17
|
export { createTransitionPayload, createArchivePayload, createInvokeScriptPayload, signTransaction, addTransactionSignature, getPublicKeyForRegistration, createStateMachinePayload, createScriptPayload, createDataTransactionRequest, createAssetPolicyPayload, createMintAssetPayload, createApplyMorphismPayload, createAuthorizeComposePayload, } from './transaction.js';
|
|
18
|
+
// Message-layer advisory lint for ApplyMorphism (Compose/Pool C2 mistakes the chain rejects).
|
|
19
|
+
export { lintApplyMorphism, MORPHISM_LINT_CODES } from './morphism-lint.js';
|
|
16
20
|
// Data utilities
|
|
17
21
|
export { dropNulls } from './drop-nulls.js';
|
|
18
22
|
// Genesis manifest exporter (std-app pre-registration content)
|