@ottochain/sdk 2.5.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 +9 -2
- package/dist/cjs/ottochain/index.js +11 -1
- package/dist/cjs/ottochain/metagraph-client.js +47 -3
- 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 +43 -6
- package/dist/cjs/schema/fiber-app.js +7 -2
- package/dist/cjs/schema/guard-lint.js +102 -0
- package/dist/esm/apps/lending/assets.js +11 -1
- package/dist/esm/index.js +4 -1
- package/dist/esm/ottochain/index.js +4 -0
- package/dist/esm/ottochain/metagraph-client.js +47 -3
- 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 +41 -5
- package/dist/esm/schema/fiber-app.js +7 -2
- 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 +5 -1
- package/dist/types/ottochain/index.d.ts +7 -1
- package/dist/types/ottochain/metagraph-client.d.ts +69 -15
- 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 +39 -5
- package/dist/types/schema/guard-lint.d.ts +6 -0
- package/package.json +6 -6
|
@@ -32,6 +32,11 @@
|
|
|
32
32
|
*
|
|
33
33
|
* leading-dot — `{"var":".foo"}` resolves to null on chain.
|
|
34
34
|
*
|
|
35
|
+
* H1 — a `_spawn` whose child `owners` are not provably a SUBSET of the spawning
|
|
36
|
+
* parent's owners. The chain now fails-closed (aborts the transition) under
|
|
37
|
+
* every spawnOwnerPolicy when child owners ⊄ parent owners; this advisory
|
|
38
|
+
* flags the strong not-subset signals (hardcoded / `event.*`-derived owners).
|
|
39
|
+
*
|
|
35
40
|
* This is a STANDALONE validator. It is deliberately NOT wired into
|
|
36
41
|
* `defineFiberApp` / `toProtoDefinition`: doing so would break the build until
|
|
37
42
|
* every app is remediated. Run it via `scripts/lint-apps.mjs`.
|
|
@@ -50,6 +55,7 @@ export const LINT_CODES = {
|
|
|
50
55
|
WITNESS_IN_TRANSITION: 'witness-in-transition', // rule 3
|
|
51
56
|
DROPPED_DIRECTIVE: 'dropped-directive', // rule 4 (A3)
|
|
52
57
|
LEADING_DOT_VAR: 'leading-dot-var', // rule 5
|
|
58
|
+
SPAWN_OWNERS: 'spawn-owners', // rule 6 (H1) — child owners not provably ⊆ parent
|
|
53
59
|
};
|
|
54
60
|
// =============================================================================
|
|
55
61
|
// Rule data
|
|
@@ -287,6 +293,101 @@ function lintTransitionStructure(t, app, transition, path) {
|
|
|
287
293
|
return out;
|
|
288
294
|
}
|
|
289
295
|
// =============================================================================
|
|
296
|
+
// _spawn owner-subset rule (rule 6 / H1)
|
|
297
|
+
// =============================================================================
|
|
298
|
+
/** Collect every string `var` reference (path or `[path, default]` head) at or below `node`. */
|
|
299
|
+
function collectVarRefs(node, acc) {
|
|
300
|
+
if (Array.isArray(node)) {
|
|
301
|
+
node.forEach((child) => collectVarRefs(child, acc));
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (node === null || typeof node !== 'object')
|
|
305
|
+
return;
|
|
306
|
+
const obj = node;
|
|
307
|
+
const keys = Object.keys(obj);
|
|
308
|
+
if (keys.length === 1 && keys[0] === 'var') {
|
|
309
|
+
const ref = obj.var;
|
|
310
|
+
if (typeof ref === 'string')
|
|
311
|
+
acc.push(ref);
|
|
312
|
+
else if (Array.isArray(ref)) {
|
|
313
|
+
if (typeof ref[0] === 'string')
|
|
314
|
+
acc.push(ref[0]);
|
|
315
|
+
if (ref.length > 1)
|
|
316
|
+
collectVarRefs(ref[1], acc);
|
|
317
|
+
}
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
for (const k of keys)
|
|
321
|
+
collectVarRefs(obj[k], acc);
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Classify a `_spawn` child `owners` expression for the H1 subset risk. Returns a short reason string when
|
|
325
|
+
* the owners are NOT provably ⊆ the parent's owners from the definition alone, else `undefined`.
|
|
326
|
+
*
|
|
327
|
+
* The linter cannot see the parent fiber's runtime `owners` (they are set at `create()` time, not in the
|
|
328
|
+
* definition), so it flags only the two STRONG "not-subset" signals — keeping false positives low:
|
|
329
|
+
* - a literal array carrying ≥1 concrete address string (a hardcoded external owner list); and
|
|
330
|
+
* - any `event.*` reference (caller-supplied — the exact H1 owner-forgery vector).
|
|
331
|
+
* Owners derived purely from the parent's own `state.*` / `machineId` / `$`-context are assumed in-set and
|
|
332
|
+
* are NOT flagged.
|
|
333
|
+
*/
|
|
334
|
+
function spawnOwnersRisk(owners) {
|
|
335
|
+
if (Array.isArray(owners) && owners.some((o) => typeof o === 'string' && o.length > 0)) {
|
|
336
|
+
return 'a literal array with hardcoded owner address(es)';
|
|
337
|
+
}
|
|
338
|
+
const refs = [];
|
|
339
|
+
collectVarRefs(owners, refs);
|
|
340
|
+
if (refs.some((r) => r === 'event' || r.startsWith('event.'))) {
|
|
341
|
+
return "an 'event' reference (caller-supplied owners)";
|
|
342
|
+
}
|
|
343
|
+
return undefined;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* rule 6 (H1) — scan a transition effect for `_spawn` directives whose child `owners` are not provably a
|
|
347
|
+
* SUBSET of the spawning parent's owners. The chain now fails-closed (aborts the transition) under every
|
|
348
|
+
* `spawnOwnerPolicy` when a child's resolved owners are not ⊆ the parent's. Advisory (warn): the linter
|
|
349
|
+
* cannot prove the subset statically, so it flags only the strong not-subset signals (see
|
|
350
|
+
* {@link spawnOwnersRisk}).
|
|
351
|
+
*/
|
|
352
|
+
function lintSpawnOwners(node, app, transition, path) {
|
|
353
|
+
const out = [];
|
|
354
|
+
if (Array.isArray(node)) {
|
|
355
|
+
node.forEach((child, i) => out.push(...lintSpawnOwners(child, app, transition, `${path}[${i}]`)));
|
|
356
|
+
return out;
|
|
357
|
+
}
|
|
358
|
+
if (node === null || typeof node !== 'object')
|
|
359
|
+
return out;
|
|
360
|
+
const obj = node;
|
|
361
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
362
|
+
if (k === '_spawn' && Array.isArray(v)) {
|
|
363
|
+
v.forEach((entry, i) => {
|
|
364
|
+
if (entry && typeof entry === 'object' && !Array.isArray(entry) && 'owners' in entry) {
|
|
365
|
+
const reason = spawnOwnersRisk(entry.owners);
|
|
366
|
+
if (reason) {
|
|
367
|
+
out.push({
|
|
368
|
+
app,
|
|
369
|
+
transition,
|
|
370
|
+
severity: 'warn',
|
|
371
|
+
code: LINT_CODES.SPAWN_OWNERS,
|
|
372
|
+
message: `_spawn child 'owners' must be a SUBSET of the spawning parent fiber's owners — the chain ` +
|
|
373
|
+
`now FAILS-CLOSED (aborts the transition) under every spawnOwnerPolicy if they are not ⊆ the ` +
|
|
374
|
+
`parent's (audit H1). This 'owners' is ${reason} and cannot be proven ⊆ the parent. Admit ` +
|
|
375
|
+
`later participants via the child's own transitions / authorizedSigners / acceptedCallers ` +
|
|
376
|
+
`instead of listing non-parent owners.`,
|
|
377
|
+
path: `${path}.${k}[${i}].owners`,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
// Do not descend into the spawn entry (its nested child definition's owners are relative to that
|
|
383
|
+
// child, not to this parent).
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
out.push(...lintSpawnOwners(v, app, transition, `${path}.${k}`));
|
|
387
|
+
}
|
|
388
|
+
return out;
|
|
389
|
+
}
|
|
390
|
+
// =============================================================================
|
|
290
391
|
// Top-level entry point
|
|
291
392
|
// =============================================================================
|
|
292
393
|
function appLabel(def) {
|
|
@@ -317,6 +418,7 @@ export function lintFiberApp(def) {
|
|
|
317
418
|
}
|
|
318
419
|
if (t.effect !== undefined) {
|
|
319
420
|
out.push(...lintGuardExpression(t.effect, ctx, `${tPath}.effect`));
|
|
421
|
+
out.push(...lintSpawnOwners(t.effect, app, transition, `${tPath}.effect`));
|
|
320
422
|
}
|
|
321
423
|
out.push(...lintTransitionStructure(t, app, transition, tPath));
|
|
322
424
|
});
|
|
@@ -180,6 +180,11 @@ export interface ApplyMorphismMessage {
|
|
|
180
180
|
/**
|
|
181
181
|
* Apply a typed morphism (Transfer / Burn / Compose / ...). asset-model.md §7.
|
|
182
182
|
* Transfer = `{ kind: "Transfer", recipient }`; Burn (repay) = `{ kind: "Burn" }`.
|
|
183
|
+
*
|
|
184
|
+
* C2 — a `Compose`/`Pool` that folds in a counter-party the signer does NOT own is now rejected on-chain
|
|
185
|
+
* unless a live `AuthorizeCompose` nonce authorizes it: pass that nonce here (`nonce`) and build the commit
|
|
186
|
+
* half with {@link createAuthorizeComposePayload}. A same-holder compose (all parts signer-owned) needs no
|
|
187
|
+
* nonce. `otherAssets` must be duplicate-free and must not include `assetId`.
|
|
183
188
|
*/
|
|
184
189
|
export declare function createApplyMorphismPayload(params: ApplyMorphismParams): ApplyMorphismMessage;
|
|
185
190
|
export interface AuthorizeComposeParams {
|
|
@@ -198,7 +203,12 @@ export interface AuthorizeComposeMessage {
|
|
|
198
203
|
targetSequenceNumber: number;
|
|
199
204
|
};
|
|
200
205
|
}
|
|
201
|
-
/**
|
|
206
|
+
/**
|
|
207
|
+
* Commit half of a two-party (cross-holder) compose. asset-model.md §7/§8. As of chain finding C2 this
|
|
208
|
+
* handshake is MANDATORY: a cross-holder `Compose`/`Pool` is rejected unless a matching, unexpired nonce
|
|
209
|
+
* from this call is live for the counter-party. The composing party then echoes `nonce` in its
|
|
210
|
+
* `ApplyMorphism`. A same-holder compose (all parts owned by the signer) does not need this.
|
|
211
|
+
*/
|
|
202
212
|
export declare function createAuthorizeComposePayload(params: AuthorizeComposeParams): AuthorizeComposeMessage;
|
|
203
213
|
/**
|
|
204
214
|
* The collateral vault policy: an NFT-like custodial holding (no fungible split) whose
|
package/dist/types/index.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ export type { RequestOptions, TransactionStatus, PendingTransaction, PostTransac
|
|
|
24
24
|
export * from './types.js';
|
|
25
25
|
export * from './ottochain/transaction.js';
|
|
26
26
|
export { dropNulls } from './ottochain/drop-nulls.js';
|
|
27
|
+
export { lintApplyMorphism, MORPHISM_LINT_CODES } from './ottochain/morphism-lint.js';
|
|
28
|
+
export type { LintViolation, LintSeverity } from './ottochain/morphism-lint.js';
|
|
27
29
|
export { buildGenesisManifest, GENESIS_MANIFEST_VERSION } from './ottochain/genesis-manifest.js';
|
|
28
30
|
export type { GenesisManifest, GenesisPackage, GenesisMachineShape, GenesisMessageShape, GenesisFieldShape, GenesisStateMachineDefinition, } from './ottochain/index.js';
|
|
29
31
|
export * from './generated/index.js';
|
|
@@ -31,8 +33,10 @@ export { OttoChainError, NetworkError, ValidationError, SigningError, Transactio
|
|
|
31
33
|
export { DagAddressSchema, PrivateKeySchema, PublicKeySchema, KeyPairSchema, SignatureProofSchema, SignedSchema, TransactionReferenceSchema, CurrencyTransactionValueSchema, CurrencyTransactionSchema, TransferParamsSchema, AgentIdentityRegistrationSchema, PlatformLinkSchema, ContractTermsSchema, ProposeContractRequestSchema, AcceptContractRequestSchema, CompleteContractRequestSchema, validate, validatePrivateKey, validatePublicKey, validateAddress, validateKeyPair, safeParse, assert, type ValidatedKeyPair, type ValidatedSignatureProof, type ValidatedCurrencyTransaction, type ValidatedTransferParams, type ValidatedAgentIdentityRegistration, type ValidatedPlatformLink, type ValidatedProposeContractRequest, type ValidatedAcceptContractRequest, type ValidatedCompleteContractRequest, } from './validation.js';
|
|
32
34
|
export { MetagraphClient as OttoMetagraphClient } from './ottochain/metagraph-client.js';
|
|
33
35
|
export type { MetagraphClientConfig, Checkpoint, SubscribeOptions, FiberStateCallback, Unsubscribe, } from './ottochain/metagraph-client.js';
|
|
36
|
+
export type { SnapshotNotification, NotificationStats, SnapshotRejection } from './ottochain/webhook-notifications.js';
|
|
37
|
+
export { SNAPSHOT_FINALIZED_EVENT } from './ottochain/webhook-notifications.js';
|
|
34
38
|
export { toProtoDefinition, defineFiberApp, constrained, unconstrained, immutable, IMMUTABLE_POLICY, projectFiberPolicy, type ProtoStateMachineDefinition, type FiberAppDefinition, type FiberAppMetadata, type FiberPolicy, type FiberPolicyDials, type ImmutablePolicy, type EffectKind, type SpawnOwnerPolicy, type DependencyMode, type TransferPolicy, type DependencyPolicy, type MigrationAuthority, type UpgradePolicy, type VersionRange, type StateDefinition, type StdStateMetadata, type StateCategory, type Transition, } from './schema/fiber-app.js';
|
|
35
39
|
export { type GuardRule, signerIsParty, signerIsAnyParty, signerInSet, signerIsNotParty, signerHasEntry, assetSignerIs, actorIsSigner, actorInSet, actorHasEntry, signerHasReputation, signerHasRole, signerHasReputationVia, signerHasRoleVia, depInState, actorNotInArray, } from './schema/guards.js';
|
|
36
|
-
export { addDependency, setDependencyActive, transferAsset, triggers, spawn, emit, toFiber, toWallet, RESERVED_EFFECT_KEYS, } from './schema/effects.js';
|
|
40
|
+
export { addDependency, setDependencyActive, transferAsset, triggers, spawn, emit, scriptCall, toFiber, toWallet, RESERVED_EFFECT_KEYS, } from './schema/effects.js';
|
|
37
41
|
export { shieldApp, SHIELDED_POOL_STATE, type ShieldOptions } from './privacy/shield-app.js';
|
|
38
42
|
export type { paths as ApiPaths, operations as ApiOperations, components as ApiComponents, VersionInfo, TransitionFeeEstimate, ScriptFeeEstimate, SubscribeRequest, SubscribeResponse, Subscriber, SubscriberList, } from './openapi.js';
|
|
@@ -10,10 +10,16 @@ export type { Address, FiberId, StateId, HashValue, FiberOrdinal, SnapshotOrdina
|
|
|
10
10
|
export { OTTOCHAIN_MESSAGE_TYPES, TOKEN_BEHAVIOR_BITS } from './types.js';
|
|
11
11
|
export type { CurrencySnapshotResponse } from './snapshot.js';
|
|
12
12
|
export { decodeOnChainState, getSnapshotOnChainState, getLatestOnChainState, getLogsForFiber, getEventReceipts, getScriptInvocations, extractOnChainState, } from './snapshot.js';
|
|
13
|
-
export type { Checkpoint, StateProof, FeeEstimate, MetagraphClientConfig, SubscribeOptions, FiberStateCallback, Unsubscribe, } from './metagraph-client.js';
|
|
13
|
+
export type { Checkpoint, StateProof, FeeEstimate, TransitionFeeEstimate, ScriptFeeEstimate, VersionInfo, SubscribeRequest, SubscribeResponse, SubscriberList, MetagraphClientConfig, SubscribeOptions, FiberStateCallback, Unsubscribe, } from './metagraph-client.js';
|
|
14
14
|
export { MetagraphClient } from './metagraph-client.js';
|
|
15
|
+
export type { MptWitnessNode, MptInclusionProof, StateProofVerification } from './state-proof.js';
|
|
16
|
+
export { verifyStateProof, verifyMptInclusion, commitKeyPath } from './state-proof.js';
|
|
17
|
+
export type { SnapshotNotification, NotificationStats, SnapshotRejection } from './webhook-notifications.js';
|
|
18
|
+
export { SNAPSHOT_FINALIZED_EVENT } from './webhook-notifications.js';
|
|
15
19
|
export { createTransitionPayload, createArchivePayload, createInvokeScriptPayload, signTransaction, addTransactionSignature, getPublicKeyForRegistration, createStateMachinePayload, createScriptPayload, createDataTransactionRequest, createAssetPolicyPayload, createMintAssetPayload, createApplyMorphismPayload, createAuthorizeComposePayload, } from './transaction.js';
|
|
16
20
|
export type { CreateStateMachineParams, CreateStateMachineMessage, CreateScriptParams, CreateScriptMessage, DataTransactionRequest, TransitionParams, TransitionStateMachineMessage, ArchiveParams, ArchiveStateMachineMessage, InvokeScriptParams, InvokeScriptMessage, } from './transaction.js';
|
|
21
|
+
export { lintApplyMorphism, MORPHISM_LINT_CODES } from './morphism-lint.js';
|
|
22
|
+
export type { LintViolation, LintSeverity } from './morphism-lint.js';
|
|
17
23
|
export { dropNulls } from './drop-nulls.js';
|
|
18
24
|
export { buildGenesisManifest, GENESIS_MANIFEST_VERSION } from './genesis-manifest.js';
|
|
19
25
|
export type { GenesisManifest, GenesisPackage, MachineShape as GenesisMachineShape, MessageShape as GenesisMessageShape, FieldShape as GenesisFieldShape, StateMachineDefinition as GenesisStateMachineDefinition, } from './genesis-manifest.js';
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { Signed } from '@constellation-network/metagraph-sdk';
|
|
12
12
|
import type { OnChain, CalculatedState, StateMachineFiberRecord, ScriptFiberRecord, EventReceipt, ScriptInvocation, FiberStatus, RegistryEntry } from './types.js';
|
|
13
|
+
import type { VersionInfo, TransitionFeeEstimate, ScriptFeeEstimate, SubscribeRequest, SubscribeResponse, SubscriberList } from '../openapi.js';
|
|
14
|
+
export type { VersionInfo, TransitionFeeEstimate, ScriptFeeEstimate, SubscribeRequest, SubscribeResponse, SubscriberList, } from '../openapi.js';
|
|
13
15
|
/**
|
|
14
16
|
* Checkpoint response from the metagraph (ordinal + calculated state).
|
|
15
17
|
*/
|
|
@@ -23,22 +25,39 @@ export interface Checkpoint {
|
|
|
23
25
|
* endpoints.
|
|
24
26
|
*/
|
|
25
27
|
export interface StateProof {
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
+
/**
|
|
29
|
+
* The trie key the proof is keyed on — the fiber/asset id (optionally suffixed with the requested
|
|
30
|
+
* field). Chain: `StateProofResponse.key: String` (required).
|
|
31
|
+
*/
|
|
32
|
+
key: string;
|
|
33
|
+
ordinal: number;
|
|
28
34
|
/** The committed-state combined root (= the snapshot's `calculatedStateProof`). */
|
|
29
35
|
committedRoot: string;
|
|
30
36
|
/** The Merkle-Patricia trie root. */
|
|
31
37
|
mptRoot: string;
|
|
32
|
-
|
|
38
|
+
/** The record (or projected field) the proof attests to. */
|
|
39
|
+
record: unknown;
|
|
33
40
|
/** The Merkle-Patricia inclusion proof. */
|
|
34
41
|
proof: unknown;
|
|
42
|
+
/**
|
|
43
|
+
* The `stateData` field name that was projected, present ONLY when a `?field=` was requested
|
|
44
|
+
* (chain `field: Option[String]`, `dropNullValues`-stripped otherwise).
|
|
45
|
+
*/
|
|
46
|
+
field?: string;
|
|
47
|
+
/**
|
|
48
|
+
* The value of the projected `field`, present ONLY when a `?field=` was requested
|
|
49
|
+
* (chain `fieldValue: Option[Json]`, `dropNullValues`-stripped otherwise).
|
|
50
|
+
*/
|
|
51
|
+
fieldValue?: unknown;
|
|
35
52
|
}
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
53
|
+
/**
|
|
54
|
+
* A static fee/gas estimate. The wire is one of two per-endpoint shapes — {@link TransitionFeeEstimate}
|
|
55
|
+
* (state-machine transition) or {@link ScriptFeeEstimate} (script invocation) — that mirror the chain's
|
|
56
|
+
* `FeeEstimates.scala` case classes byte-for-byte. Prefer the per-endpoint types on
|
|
57
|
+
* {@link MetagraphClient.estimateTransitionFee} / {@link MetagraphClient.estimateScriptFee}; this union is
|
|
58
|
+
* a convenience for code that handles either.
|
|
59
|
+
*/
|
|
60
|
+
export type FeeEstimate = TransitionFeeEstimate | ScriptFeeEstimate;
|
|
42
61
|
/**
|
|
43
62
|
* Options for subscribeFiberState polling behaviour.
|
|
44
63
|
*/
|
|
@@ -151,8 +170,12 @@ export declare class MetagraphClient {
|
|
|
151
170
|
* Get script invocations from the current ordinal's logs.
|
|
152
171
|
*/
|
|
153
172
|
getScriptInvocations(scriptId: string): Promise<ScriptInvocation[]>;
|
|
154
|
-
/**
|
|
155
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Get the node's service identity + build metadata. The chain's `GET …/version` returns a
|
|
175
|
+
* `VersionInfo` OBJECT (`{ service, version, name, scalaVersion, sbtVersion, gitCommit, buildTime,
|
|
176
|
+
* tessellationVersion }`) — chain `ServiceMeta.scala` — NOT a bare string.
|
|
177
|
+
*/
|
|
178
|
+
getVersion(): Promise<VersionInfo>;
|
|
156
179
|
/** Get the full registry namespace, keyed by full registry name `labels.tld`. */
|
|
157
180
|
getRegistry(): Promise<Record<string, RegistryEntry>>;
|
|
158
181
|
/** Resolve a single registry entry by full name (`labels.tld`), or null if unregistered. */
|
|
@@ -167,10 +190,41 @@ export declare class MetagraphClient {
|
|
|
167
190
|
getScriptStateProof(fiberId: string, field: string): Promise<StateProof>;
|
|
168
191
|
/** Light-client state proof for a field of an asset instance. */
|
|
169
192
|
getAssetStateProof(assetId: string, field: string): Promise<StateProof>;
|
|
170
|
-
/**
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Estimate the fee/gas for a transition event on a state-machine fiber. Returns a
|
|
195
|
+
* {@link TransitionFeeEstimate} (`{ fiberId, currentState, event, gasEstimate, opCount, maxDepth,
|
|
196
|
+
* candidateTransitions, note }`) — chain `FeeEstimates.scala`.
|
|
197
|
+
*/
|
|
198
|
+
estimateTransitionFee(fiberId: string, eventName: string): Promise<TransitionFeeEstimate>;
|
|
199
|
+
/**
|
|
200
|
+
* Estimate the fee/gas for invoking a script fiber. Returns a {@link ScriptFeeEstimate}
|
|
201
|
+
* (`{ scriptId, gasEstimate, opCount, maxDepth, note }`) — chain `FeeEstimates.scala`.
|
|
202
|
+
*/
|
|
203
|
+
estimateScriptFee(fiberId: string): Promise<ScriptFeeEstimate>;
|
|
204
|
+
/**
|
|
205
|
+
* Subscribe a callback URL to snapshot-notification webhooks.
|
|
206
|
+
*
|
|
207
|
+
* `POST …/webhooks/subscribe` with `SubscribeRequest { callbackUrl, secret? }`; the chain replies
|
|
208
|
+
* `201 Created` with `SubscribeResponse { id, callbackUrl, createdAt }`. Chain: `ML0Routes.scala`
|
|
209
|
+
* (`webhook.subscribe`) + `webhooks/Subscriber.scala`.
|
|
210
|
+
*/
|
|
211
|
+
subscribeWebhook(request: SubscribeRequest): Promise<SubscribeResponse>;
|
|
212
|
+
/**
|
|
213
|
+
* Unsubscribe a webhook by its subscriber id.
|
|
214
|
+
*
|
|
215
|
+
* `DELETE …/webhooks/subscribe/{id}` → `204 No Content` (empty body) on success, or `404` if the id is
|
|
216
|
+
* unknown. Chain: `ML0Routes.scala` (`webhook.unsubscribe`). The vendored `HttpClient` exposes only
|
|
217
|
+
* `get`/`post`, so this reuses its shared private `request` helper — same `NetworkError`/timeout
|
|
218
|
+
* handling as every other call — to issue the DELETE.
|
|
219
|
+
*/
|
|
220
|
+
unsubscribeWebhook(id: string): Promise<void>;
|
|
221
|
+
/**
|
|
222
|
+
* List the current webhook subscribers (secrets are redacted server-side).
|
|
223
|
+
*
|
|
224
|
+
* `GET …/webhooks/subscribers` → `SubscriberList { subscribers: Subscriber[] }`. Chain:
|
|
225
|
+
* `ML0Routes.scala` (`webhook.list`) + `webhooks/Subscriber.scala`.
|
|
226
|
+
*/
|
|
227
|
+
listWebhookSubscribers(): Promise<SubscriberList>;
|
|
174
228
|
/**
|
|
175
229
|
* Get the latest snapshot and decode its on-chain state.
|
|
176
230
|
*/
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message-layer advisory lint for an {@link ApplyMorphism} transaction (asset-model.md §7; chain
|
|
3
|
+
* audit finding C2, enforced in `AssetCombiner`).
|
|
4
|
+
*
|
|
5
|
+
* Purpose
|
|
6
|
+
* -------
|
|
7
|
+
* The definition-scoped {@link ../schema/guard-lint.ts | guard-lint} walks fiber-app DEFINITIONS; it
|
|
8
|
+
* never sees an `ApplyMorphism` MESSAGE, so a malformed / no-consent `Compose` slips past it. This
|
|
9
|
+
* linter closes that gap at the transaction-builder layer: hand it the `ApplyMorphism` you are about
|
|
10
|
+
* to sign and it flags the two classes of C2 mistake the chain rejects.
|
|
11
|
+
*
|
|
12
|
+
* The chain rule being mirrored (C2, `Compose`/`Pool` only):
|
|
13
|
+
* - `otherAssetIds` must be free of duplicates and must NOT include the source `assetId`
|
|
14
|
+
* (the old self/duplicate-inflation path — rejected unconditionally, holder-independent).
|
|
15
|
+
* - every counter-party the signer does NOT hold requires a live {@link AuthorizeCompose} `nonce`;
|
|
16
|
+
* a same-holder / all-signer-owned compose needs none.
|
|
17
|
+
*
|
|
18
|
+
* ERRORS are statically certain (the chain rejects regardless of who holds what). WARNINGS are
|
|
19
|
+
* heuristic — the signer's holdings/ownership are unknown at build time, so a missing consent nonce
|
|
20
|
+
* cannot be proven fatal (a same-holder compose is legitimately nonce-less).
|
|
21
|
+
*
|
|
22
|
+
* This is a PURE, non-throwing advisory. It is deliberately NOT wired into
|
|
23
|
+
* {@link createApplyMorphismPayload} (which must stay non-breaking and side-effect-free); call it
|
|
24
|
+
* explicitly before signing, or in your app's own pre-flight checks.
|
|
25
|
+
*/
|
|
26
|
+
import type { ApplyMorphism } from './types.js';
|
|
27
|
+
import type { LintViolation } from '../schema/guard-lint.js';
|
|
28
|
+
export type { LintViolation, LintSeverity } from '../schema/guard-lint.js';
|
|
29
|
+
/** Stable rule codes for {@link lintApplyMorphism} — referenced by tests and report tooling. */
|
|
30
|
+
export declare const MORPHISM_LINT_CODES: {
|
|
31
|
+
/** `otherAssetIds` contains a duplicate id (chain rejects — inflation path). */
|
|
32
|
+
readonly DUPLICATE_OTHER_ID: "morphism-duplicate-other-id";
|
|
33
|
+
/** `otherAssetIds` includes the source `assetId` (self-composition — chain rejects). */
|
|
34
|
+
readonly SELF_COMPOSE: "morphism-self-compose";
|
|
35
|
+
/** `otherAssetIds` is non-empty but `kind` ignores it (not Compose/Pool — likely a mistake). */
|
|
36
|
+
readonly OTHER_IDS_IGNORED: "morphism-other-ids-ignored";
|
|
37
|
+
/** Compose/Pool with counter-parties and no consent `nonce` (rejected IF any part is not signer-owned). */
|
|
38
|
+
readonly COMPOSE_NO_NONCE: "morphism-compose-no-nonce";
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Lint a single {@link ApplyMorphism} message. Pure and non-throwing. Returns every finding
|
|
42
|
+
* (`error` + `warn`); callers decide the policy (e.g. block on any `error`, surface `warn`s).
|
|
43
|
+
*
|
|
44
|
+
* ERRORS (statically certain — the chain rejects unconditionally, holder-independent):
|
|
45
|
+
* - {@link MORPHISM_LINT_CODES.DUPLICATE_OTHER_ID} — `otherAssetIds` contains a duplicate id.
|
|
46
|
+
* - {@link MORPHISM_LINT_CODES.SELF_COMPOSE} — `otherAssetIds` includes the source `assetId`.
|
|
47
|
+
* - {@link MORPHISM_LINT_CODES.OTHER_IDS_IGNORED} — `otherAssetIds` is non-empty but `kind` is not
|
|
48
|
+
* `COMPOSE`/`POOL` (the field is ignored for other kinds — a likely authoring mistake).
|
|
49
|
+
*
|
|
50
|
+
* WARNINGS (heuristic — holder/ownership unknown at build time):
|
|
51
|
+
* - {@link MORPHISM_LINT_CODES.COMPOSE_NO_NONCE} — a `COMPOSE`/`POOL` with a non-empty
|
|
52
|
+
* `otherAssetIds` and NO `nonce`. IF any counter-party is not signer-owned the chain rejects it
|
|
53
|
+
* (C2); attach the reveal half of an {@link AuthorizeCompose} handshake as `nonce`. A same-holder
|
|
54
|
+
* compose (all parts signer-owned) is legitimately nonce-less — hence a warning, not an error.
|
|
55
|
+
*/
|
|
56
|
+
export declare function lintApplyMorphism(msg: ApplyMorphism): LintViolation[];
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { StateProof } from './metagraph-client.js';
|
|
2
|
+
/** One commitment node of a Merkle-Patricia inclusion witness (wire form, leaf-first). */
|
|
3
|
+
export interface MptWitnessNode {
|
|
4
|
+
type: 'Leaf' | 'Branch' | 'Extension';
|
|
5
|
+
contents: {
|
|
6
|
+
/** Leaf: the path nibbles left below the last branch. */
|
|
7
|
+
remaining?: string;
|
|
8
|
+
/** Leaf: sha256(JCS(dropNulls(value))) of the committed record. */
|
|
9
|
+
dataDigest?: string;
|
|
10
|
+
/** Branch: nibble → child node digest. */
|
|
11
|
+
pathsDigest?: Record<string, string>;
|
|
12
|
+
/** Extension: the shared nibble run. */
|
|
13
|
+
shared?: string;
|
|
14
|
+
/** Extension: digest of the child branch. */
|
|
15
|
+
childDigest?: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/** The `proof` field of a {@link StateProof}, typed. */
|
|
19
|
+
export interface MptInclusionProof {
|
|
20
|
+
/** Trie path = hex(utf8(committed key)). */
|
|
21
|
+
path: string;
|
|
22
|
+
witness: MptWitnessNode[];
|
|
23
|
+
}
|
|
24
|
+
/** Verification outcome: `ok`, or the first failed binding with a human-readable reason. */
|
|
25
|
+
export type StateProofVerification = {
|
|
26
|
+
ok: true;
|
|
27
|
+
} | {
|
|
28
|
+
ok: false;
|
|
29
|
+
reason: string;
|
|
30
|
+
};
|
|
31
|
+
/** The MPT trie path of a committed key — `hex(utf8(key))` (metakit `CommitKey.toHex`). */
|
|
32
|
+
export declare function commitKeyPath(key: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Verify a Merkle-Patricia inclusion proof: `record` is committed at `key` under `mptRoot`.
|
|
35
|
+
*
|
|
36
|
+
* Pure and side-effect free; never throws on malformed input (returns `{ ok: false }`).
|
|
37
|
+
*/
|
|
38
|
+
export declare function verifyMptInclusion(mptRoot: string, key: string, record: unknown, proof: MptInclusionProof): StateProofVerification;
|
|
39
|
+
/**
|
|
40
|
+
* Verify a whole {@link StateProof} response for a committed key.
|
|
41
|
+
*
|
|
42
|
+
* Checks the trie inclusion of `record` at `key` under the response's `mptRoot` (see
|
|
43
|
+
* {@link verifyMptInclusion}). The caller supplies the key it EXPECTS (`fiber/<id>`,
|
|
44
|
+
* `script/<id>`, `asset/<id>`, …) so a proof for some other record cannot be substituted;
|
|
45
|
+
* the response's own `key` field must agree.
|
|
46
|
+
*
|
|
47
|
+
* Trust anchor: `committedRoot` (= `sha256(mptRoot ++ catalogRoot)`) rides in the
|
|
48
|
+
* consensus-signed snapshot as `calculatedStateProof`; binding `mptRoot` to a snapshot is
|
|
49
|
+
* the caller's (or a snapshot-following light client's) responsibility.
|
|
50
|
+
*/
|
|
51
|
+
export declare function verifyStateProof(resp: StateProof, expectedKey: string): StateProofVerification;
|
|
@@ -194,7 +194,13 @@ export declare function createAssetPolicyPayload(params: CreateAssetPolicy): {
|
|
|
194
194
|
export declare function createMintAssetPayload(params: MintAsset): {
|
|
195
195
|
MintAsset: MintAsset;
|
|
196
196
|
};
|
|
197
|
-
/**
|
|
197
|
+
/**
|
|
198
|
+
* Wrap an {@link ApplyMorphism} (apply a typed morphism to an asset instance).
|
|
199
|
+
*
|
|
200
|
+
* @see lintApplyMorphism (`./morphism-lint.ts`) — pure, non-throwing advisory that flags the
|
|
201
|
+
* Compose/Pool mistakes the chain rejects (duplicate / self-referential `otherAssetIds`; a
|
|
202
|
+
* cross-holder compose with no consent `nonce`). Run it on `params` before signing.
|
|
203
|
+
*/
|
|
198
204
|
export declare function createApplyMorphismPayload(params: ApplyMorphism): {
|
|
199
205
|
ApplyMorphism: ApplyMorphism;
|
|
200
206
|
};
|
|
@@ -741,15 +741,32 @@ export interface MintAsset {
|
|
|
741
741
|
* Optional fields carry per-kind directives (recipient for Transfer/Wrap; otherAssetIds + compositeId
|
|
742
742
|
* for Compose; shardIds for Fractionalize; nonce for a commit-reveal symmetric Compose;
|
|
743
743
|
* priorComponents is the Decompose reveal witness).
|
|
744
|
+
*
|
|
745
|
+
* C2 — cross-holder Compose/Pool consent is MANDATORY. As of the fiber-engine permissionless-hardening
|
|
746
|
+
* (chain branch `fix/fiber-engine-permissionless-hardening`, audit finding C2) a `Compose`/`Pool` that
|
|
747
|
+
* folds in a counter-party the signer does NOT hold is REJECTED (graceful `CombineRejected`) UNLESS a
|
|
748
|
+
* live {@link AuthorizeCompose} nonce authorizes that counter-party. A SAME-holder compose (every part in
|
|
749
|
+
* `otherAssetIds` is signer-owned) still needs no nonce. `otherAssetIds` may no longer contain duplicates
|
|
750
|
+
* or the `assetId` itself (the old self/duplicate-inflation path is rejected).
|
|
744
751
|
*/
|
|
745
752
|
export interface ApplyMorphism {
|
|
746
753
|
assetId: string;
|
|
747
754
|
kind: MorphismKind;
|
|
748
755
|
targetSequenceNumber: number;
|
|
749
756
|
recipient?: AssetHolder;
|
|
757
|
+
/**
|
|
758
|
+
* Compose/Pool counter-party asset ids folded into the composite. Each id the signer does NOT hold is a
|
|
759
|
+
* CROSS-HOLDER part and now REQUIRES a live {@link AuthorizeCompose} nonce (see `nonce`) authorizing it
|
|
760
|
+
* — else the whole morphism is rejected (C2). Must be free of duplicates and must not include `assetId`.
|
|
761
|
+
*/
|
|
750
762
|
otherAssetIds?: string[];
|
|
751
763
|
compositeId?: string;
|
|
752
764
|
shardIds?: string[];
|
|
765
|
+
/**
|
|
766
|
+
* The cross-holder Compose consent nonce: the reveal half of the {@link AuthorizeCompose} handshake.
|
|
767
|
+
* REQUIRED whenever any `otherAssetIds` entry is not signer-owned (C2); omit it only for a same-holder
|
|
768
|
+
* compose. A nonce-less cross-holder compose is no longer accepted.
|
|
769
|
+
*/
|
|
753
770
|
nonce?: number;
|
|
754
771
|
priorComponents?: ComponentWitness[];
|
|
755
772
|
/** ZkVerify-gated morphism: optional witness a `Governed` morphism's guard reads (see {@link MorphismSpec}). */
|
|
@@ -758,6 +775,11 @@ export interface ApplyMorphism {
|
|
|
758
775
|
/**
|
|
759
776
|
* Authorize a counter-party policy to Compose with this asset (the commit half of the commit-reveal
|
|
760
777
|
* symmetric-compose handshake). `nonce` and `expiresAt` are REQUIRED (no sentinel defaults).
|
|
778
|
+
*
|
|
779
|
+
* C2 — this consent is now MANDATORY, not opt-in. A `Compose`/`Pool` ({@link ApplyMorphism}) that consumes
|
|
780
|
+
* a counter-party the signer does not own is rejected unless a matching, unexpired `AuthorizeCompose` nonce
|
|
781
|
+
* is live for that counter-party (chain branch `fix/fiber-engine-permissionless-hardening`, finding C2).
|
|
782
|
+
* The composing party echoes this `nonce` in `ApplyMorphism.nonce`. A same-holder compose needs none.
|
|
761
783
|
*/
|
|
762
784
|
export interface AuthorizeCompose {
|
|
763
785
|
assetId: string;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook notification PAYLOAD types — the server-initiated push the chain POSTs to a subscribed
|
|
3
|
+
* callback, NOT part of the client's request surface.
|
|
4
|
+
*
|
|
5
|
+
* These are hand-authored (not generated from the OpenAPI contract) because the push is an OUTBOUND
|
|
6
|
+
* POST from the metagraph to the subscriber's callback URL — it is not an endpoint the chain's tapir
|
|
7
|
+
* `ApiEndpoints` serves, so it never appears in `openapi/ottochain-openapi-ml0.json`. They mirror the
|
|
8
|
+
* chain's shared network DTOs byte-for-byte:
|
|
9
|
+
*
|
|
10
|
+
* chain: modules/models/src/main/scala/xyz/kd5ujc/schema/api/webhooks/Subscriber.scala
|
|
11
|
+
* (SnapshotNotification / NotificationStats / SnapshotRejection)
|
|
12
|
+
* emit: modules/l0/.../webhooks/WebhookDispatcher.scala — `notification.asJson.noSpaces`
|
|
13
|
+
*
|
|
14
|
+
* Field-shape notes tied to the chain source:
|
|
15
|
+
* - The dispatcher serializes with a plain derived encoder (`.asJson`, NO `dropNullValues`), so an
|
|
16
|
+
* `Option[Long]` that is `None` is emitted as an explicit `null` — the KEY is always present, the
|
|
17
|
+
* VALUE is nullable. Hence `number | null` (a required key), not `number | undefined` (an optional
|
|
18
|
+
* key). Consumers must handle `null`.
|
|
19
|
+
* - `Long` → JSON number; `Instant` → ISO-8601 string; `UUID` → string.
|
|
20
|
+
* - The dispatcher only ever emits `"snapshot.finalized"` today (there is a dead, never-dispatched
|
|
21
|
+
* `RejectionNotification`/`transaction.rejected` type in the chain models — deliberately NOT mirrored
|
|
22
|
+
* here, because the SDK should model only what is actually sent). Rejections now ride the finalized
|
|
23
|
+
* snapshot's `rejections[]`, drained from its committed `RejectionReceipt`s.
|
|
24
|
+
*
|
|
25
|
+
* @see modules/models/.../schema/api/webhooks/Subscriber.scala
|
|
26
|
+
* @see modules/l0/.../webhooks/WebhookDispatcher.scala
|
|
27
|
+
* @packageDocumentation
|
|
28
|
+
*/
|
|
29
|
+
/** The only event the chain's `WebhookDispatcher` currently emits. */
|
|
30
|
+
export declare const SNAPSHOT_FINALIZED_EVENT: "snapshot.finalized";
|
|
31
|
+
/**
|
|
32
|
+
* Aggregate counters for the finalized snapshot, mirrors chain `NotificationStats`.
|
|
33
|
+
*/
|
|
34
|
+
export interface NotificationStats {
|
|
35
|
+
/** Number of data updates processed into this snapshot. */
|
|
36
|
+
updatesProcessed: number;
|
|
37
|
+
/** Count of active state-machine fibers after this snapshot. */
|
|
38
|
+
stateMachinesActive: number;
|
|
39
|
+
/** Count of active script fibers after this snapshot. */
|
|
40
|
+
scriptsActive: number;
|
|
41
|
+
/** Number of updates rejected while combining this snapshot (== `rejections.length`). */
|
|
42
|
+
rejectedCount: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A single post-finalization rejection, batched onto the `snapshot.finalized` notification. Drained
|
|
46
|
+
* from the committed snapshot's `RejectionReceipt`s, so it reflects committed state (not a pre-combine
|
|
47
|
+
* guess). Mirrors chain `SnapshotRejection`.
|
|
48
|
+
*/
|
|
49
|
+
export interface SnapshotRejection {
|
|
50
|
+
/** The rejected update's type, e.g. `"TransitionStateMachine"`, `"CreateStateMachine"`. */
|
|
51
|
+
updateType: string;
|
|
52
|
+
/** UUID of the target fiber. */
|
|
53
|
+
fiberId: string;
|
|
54
|
+
/**
|
|
55
|
+
* The transition's target sequence number, or `null` for non-sequenced updates. Chain
|
|
56
|
+
* `Option[Long]`, emitted as an explicit `null` when absent (dispatcher does not drop nulls).
|
|
57
|
+
*/
|
|
58
|
+
targetSequenceNumber: number | null;
|
|
59
|
+
/**
|
|
60
|
+
* The fiber's actual sequence number at rejection time (for a sequence mismatch), or `null`. Chain
|
|
61
|
+
* `Option[Long]`, emitted as an explicit `null` when absent.
|
|
62
|
+
*/
|
|
63
|
+
actualSequenceNumber: number | null;
|
|
64
|
+
/** Human-readable rejection reason (the combiner's `CombineRejected` code/message). */
|
|
65
|
+
reason: string;
|
|
66
|
+
/** Hash of the signed update, for correlation with a submitted transaction. */
|
|
67
|
+
updateHash: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The payload POSTed to a subscribed webhook callback when a snapshot finalizes — the confirm TICK.
|
|
71
|
+
* Mirrors chain `SnapshotNotification`.
|
|
72
|
+
*
|
|
73
|
+
* There is NO per-update "accepted" event: an update is accepted iff its `updateHash` lands in a
|
|
74
|
+
* finalized snapshot AND is absent from every `rejections[]` of the snapshots up to that ordinal.
|
|
75
|
+
*/
|
|
76
|
+
export interface SnapshotNotification {
|
|
77
|
+
/** Always `"snapshot.finalized"`. */
|
|
78
|
+
event: typeof SNAPSHOT_FINALIZED_EVENT;
|
|
79
|
+
/** The finalized snapshot ordinal. Chain `Long`. */
|
|
80
|
+
ordinal: number;
|
|
81
|
+
/** The finalized snapshot hash. */
|
|
82
|
+
hash: string;
|
|
83
|
+
/** ISO-8601 dispatch timestamp. Chain `Instant`. */
|
|
84
|
+
timestamp: string;
|
|
85
|
+
/** The metagraph token identifier this notification is for. */
|
|
86
|
+
metagraphId: string;
|
|
87
|
+
/** Aggregate counters for the snapshot. */
|
|
88
|
+
stats: NotificationStats;
|
|
89
|
+
/** Updates rejected while combining this snapshot (empty if none). */
|
|
90
|
+
rejections: SnapshotRejection[];
|
|
91
|
+
}
|
|
@@ -108,11 +108,20 @@ export declare const triggers: (ts: {
|
|
|
108
108
|
* MUST be a literal {@link ProtoStateMachineDefinition} (e.g. a nested `machine().wireDefinition()` /
|
|
109
109
|
* `toProtoDefinition(child)` output) — NOT an expression the engine would evaluate at runtime.
|
|
110
110
|
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
111
|
+
* H1 constraint — child `owners` MUST be a SUBSET of the SPAWNING PARENT fiber's `owners`. As of the
|
|
112
|
+
* fiber-engine permissionless-hardening (chain branch `fix/fiber-engine-permissionless-hardening`, audit
|
|
113
|
+
* finding H1) the chain FAILS-CLOSED — it aborts the whole transition under EVERY `spawnOwnerPolicy` — if
|
|
114
|
+
* a `_spawn`'s resolved child `owners` are not ⊆ the parent's owners. Assigning arbitrary, unsigned owners
|
|
115
|
+
* (the old "auction owned by all its bidders" pattern, where the bidders are NOT parent owners) is no
|
|
116
|
+
* longer valid: those events are not silently rejected, the spawn itself is rejected.
|
|
117
|
+
*
|
|
118
|
+
* So DO NOT try to enroll later participants by listing them here. A spawned child's transitions are gated
|
|
119
|
+
* by `owners ∪ authorizedSigners` for the DIRECT (wallet-signed) path; admit additional drivers through
|
|
120
|
+
* the child's OWN transitions (`authorizedSigners`), or drive it via the cascade (`_triggers`) subject to
|
|
121
|
+
* its `acceptedCallers` — never by widening `owners` beyond the parent's set. `owners` may be a literal id
|
|
122
|
+
* array or an expression (e.g. `{ var: "state.owners" }` — resolve it WITHIN the parent's owners), but a
|
|
123
|
+
* value the parent does not own (e.g. `{ var: "event.auctionOwners" }` supplied by the caller) will be
|
|
124
|
+
* rejected on-chain. `childId` / `initialData` likewise accept literals or expressions.
|
|
116
125
|
*/
|
|
117
126
|
export declare const spawn: (ds: {
|
|
118
127
|
childId: JsonLogicValue;
|
|
@@ -131,6 +140,31 @@ export declare const emit: (es: {
|
|
|
131
140
|
data: JsonLogicValue;
|
|
132
141
|
destination?: string;
|
|
133
142
|
}[]) => Record<string, unknown>;
|
|
143
|
+
/**
|
|
144
|
+
* `_scriptCall`: invoke a SCRIPT fiber's `method` from an effect. Unlike the array-valued directives,
|
|
145
|
+
* `_scriptCall` is a SINGLE object `{ fiberId, method, args }` (chain `ReservedKeys.scala` `SCRIPT_CALL` /
|
|
146
|
+
* `EffectExtractor.extractScriptCall`). `fiberId` is the target script's UUID (a literal or an expression,
|
|
147
|
+
* e.g. `{ var: "state.resolverId" }`); `method` is the script method NAME; `args` is the argument body —
|
|
148
|
+
* a JSON-Logic value the chain EVALUATES against the transition context before dispatch.
|
|
149
|
+
*
|
|
150
|
+
* The chain's extractor requires ALL THREE fields — if `args` is absent the whole call is silently DROPPED
|
|
151
|
+
* (fail-silent, like the other extractors). So the builder ALWAYS emits `args`, defaulting an omitted one
|
|
152
|
+
* to `{}` (no-args), mirroring how {@link triggers} defaults an absent `payload`. Authoring this as a
|
|
153
|
+
* builder makes a typo'd `_scriptcall` / wrong field a TypeScript error rather than a silently-merged
|
|
154
|
+
* state field. Place the fragment INSIDE the effect's state-update map so it rides in the evaluated result.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* effect: { merge: [ { var: "state" }, {
|
|
158
|
+
* status: "resolving",
|
|
159
|
+
* ...scriptCall({ fiberId: { var: "state.resolverId" }, method: "resolve",
|
|
160
|
+
* args: { marketId: { var: "machineId" } } }),
|
|
161
|
+
* } ] }
|
|
162
|
+
*/
|
|
163
|
+
export declare const scriptCall: (call: {
|
|
164
|
+
fiberId: JsonLogicValue;
|
|
165
|
+
method: string;
|
|
166
|
+
args?: JsonLogicValue;
|
|
167
|
+
}) => Record<string, unknown>;
|
|
134
168
|
/**
|
|
135
169
|
* The complete set of `_`-prefixed RESERVED effect keys the chain's `EffectExtractor` consumes and
|
|
136
170
|
* `StateMerger` strips from state (`ReservedKeys.scala:12-49`). Exported so a validator (Proposal 01)
|