@ottochain/sdk 1.0.2 → 1.1.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/contracts/state-machines/contract.json +1 -29
- package/dist/cjs/apps/contracts/state-machines/escrow.json +2 -32
- package/dist/cjs/generated/index.js +11 -1
- package/dist/cjs/metakit/drop-nulls.js +50 -0
- package/dist/cjs/metakit/normalize.js +147 -0
- package/dist/cjs/ottochain/metagraph-client.js +147 -0
- package/dist/cjs/validation.js +1 -1
- package/dist/esm/apps/contracts/state-machines/contract.json +1 -29
- package/dist/esm/apps/contracts/state-machines/escrow.json +2 -32
- package/dist/esm/generated/index.js +11 -1
- package/dist/esm/metakit/drop-nulls.js +46 -0
- package/dist/esm/metakit/normalize.js +140 -0
- package/dist/esm/ottochain/metagraph-client.js +147 -0
- package/dist/esm/validation.js +1 -1
- package/dist/types/generated/index.d.ts +11 -1
- package/dist/types/metakit/drop-nulls.d.ts +29 -0
- package/dist/types/metakit/normalize.d.ts +67 -0
- package/dist/types/ottochain/index.d.ts +1 -1
- package/dist/types/ottochain/metagraph-client.d.ts +90 -0
- package/package.json +12 -12
- package/dist/apps/contracts/index.d.ts +0 -21
- package/dist/apps/contracts/index.js +0 -39
- package/dist/apps/contracts/types.d.ts +0 -24
- package/dist/apps/contracts/types.js +0 -48
- package/dist/apps/identity/index.d.ts +0 -22
- package/dist/apps/identity/index.js +0 -40
- package/dist/apps/identity/types.d.ts +0 -30
- package/dist/apps/identity/types.js +0 -53
- package/dist/apps/index.d.ts +0 -29
- package/dist/apps/index.js +0 -60
- package/dist/apps/markets/index.d.ts +0 -26
- package/dist/apps/markets/index.js +0 -46
- package/dist/apps/markets/types.d.ts +0 -185
- package/dist/apps/markets/types.js +0 -252
- package/dist/apps/oracles/index.d.ts +0 -26
- package/dist/apps/oracles/index.js +0 -46
- package/dist/apps/oracles/types.d.ts +0 -211
- package/dist/apps/oracles/types.js +0 -306
- package/dist/cjs/apps/contracts/types.js +0 -48
- package/dist/cjs/apps/corporate/types.js +0 -44
- package/dist/cjs/apps/governance/types.js +0 -42
- package/dist/cjs/apps/identity/types.js +0 -53
- package/dist/cjs/apps/markets/types.js +0 -219
- package/dist/cjs/apps/oracles/types.js +0 -282
- package/dist/cjs/generated/ottochain/apps/contracts/v1/contract_pb.js +0 -100
- package/dist/cjs/generated/ottochain/apps/corporate/v1/corporate_pb.js +0 -392
- package/dist/cjs/generated/ottochain/apps/governance/v1/governance_pb.js +0 -235
- package/dist/cjs/generated/ottochain/apps/identity/v1/agent_pb.js +0 -116
- package/dist/cjs/generated/ottochain/apps/identity/v1/attestation_pb.js +0 -79
- package/dist/cjs/generated/ottochain/apps/markets/v1/market_pb.js +0 -151
- package/dist/cjs/generated/ottochain/apps/oracles/v1/oracle_pb.js +0 -109
- package/dist/cjs/generated/ottochain/v1/common_pb.js +0 -37
- package/dist/cjs/generated/ottochain/v1/fiber_pb.js +0 -86
- package/dist/cjs/generated/ottochain/v1/messages_pb.js +0 -44
- package/dist/cjs/generated/ottochain/v1/records_pb.js +0 -44
- package/dist/errors.d.ts +0 -221
- package/dist/errors.js +0 -293
- package/dist/esm/apps/contracts/types.js +0 -44
- package/dist/esm/apps/corporate/types.js +0 -38
- package/dist/esm/apps/governance/types.js +0 -35
- package/dist/esm/apps/identity/types.js +0 -50
- package/dist/esm/apps/markets/types.js +0 -206
- package/dist/esm/apps/oracles/types.js +0 -267
- package/dist/esm/generated/ottochain/apps/contracts/v1/contract_pb.js +0 -97
- package/dist/esm/generated/ottochain/apps/corporate/v1/corporate_pb.js +0 -389
- package/dist/esm/generated/ottochain/apps/governance/v1/governance_pb.js +0 -232
- package/dist/esm/generated/ottochain/apps/identity/v1/agent_pb.js +0 -113
- package/dist/esm/generated/ottochain/apps/identity/v1/attestation_pb.js +0 -76
- package/dist/esm/generated/ottochain/apps/markets/v1/market_pb.js +0 -148
- package/dist/esm/generated/ottochain/apps/oracles/v1/oracle_pb.js +0 -106
- package/dist/esm/generated/ottochain/v1/common_pb.js +0 -34
- package/dist/esm/generated/ottochain/v1/fiber_pb.js +0 -83
- package/dist/esm/generated/ottochain/v1/messages_pb.js +0 -41
- package/dist/esm/generated/ottochain/v1/records_pb.js +0 -41
- package/dist/generated/index.d.ts +0 -15
- package/dist/generated/index.js +0 -34
- package/dist/generated/ottochain/apps/contracts/v1/contract_pb.d.ts +0 -274
- package/dist/generated/ottochain/apps/contracts/v1/contract_pb.js +0 -100
- package/dist/generated/ottochain/apps/identity/v1/agent_pb.d.ts +0 -211
- package/dist/generated/ottochain/apps/identity/v1/agent_pb.js +0 -116
- package/dist/generated/ottochain/apps/identity/v1/attestation_pb.d.ts +0 -238
- package/dist/generated/ottochain/apps/identity/v1/attestation_pb.js +0 -79
- package/dist/generated/ottochain/apps/markets/v1/market_pb.d.ts +0 -436
- package/dist/generated/ottochain/apps/markets/v1/market_pb.js +0 -151
- package/dist/generated/ottochain/apps/oracles/v1/oracle_pb.d.ts +0 -393
- package/dist/generated/ottochain/apps/oracles/v1/oracle_pb.js +0 -109
- package/dist/generated/ottochain/v1/common_pb.d.ts +0 -86
- package/dist/generated/ottochain/v1/common_pb.js +0 -37
- package/dist/generated/ottochain/v1/fiber_pb.d.ts +0 -292
- package/dist/generated/ottochain/v1/fiber_pb.js +0 -86
- package/dist/generated/ottochain/v1/messages_pb.d.ts +0 -190
- package/dist/generated/ottochain/v1/messages_pb.js +0 -44
- package/dist/generated/ottochain/v1/records_pb.d.ts +0 -221
- package/dist/generated/ottochain/v1/records_pb.js +0 -44
- package/dist/index.d.ts +0 -21
- package/dist/index.js +0 -77
- package/dist/metakit/binary.d.ts +0 -38
- package/dist/metakit/binary.js +0 -58
- package/dist/metakit/canonicalize.d.ts +0 -26
- package/dist/metakit/canonicalize.js +0 -40
- package/dist/metakit/codec.d.ts +0 -16
- package/dist/metakit/codec.js +0 -45
- package/dist/metakit/currency-transaction.d.ts +0 -157
- package/dist/metakit/currency-transaction.js +0 -319
- package/dist/metakit/currency-types.d.ts +0 -55
- package/dist/metakit/currency-types.js +0 -13
- package/dist/metakit/hash.d.ts +0 -50
- package/dist/metakit/hash.js +0 -84
- package/dist/metakit/index.d.ts +0 -23
- package/dist/metakit/index.js +0 -74
- package/dist/metakit/network/client.d.ts +0 -23
- package/dist/metakit/network/client.js +0 -78
- package/dist/metakit/network/currency-l1-client.d.ts +0 -71
- package/dist/metakit/network/currency-l1-client.js +0 -101
- package/dist/metakit/network/data-l1-client.d.ts +0 -57
- package/dist/metakit/network/data-l1-client.js +0 -76
- package/dist/metakit/network/index.d.ts +0 -10
- package/dist/metakit/network/index.js +0 -16
- package/dist/metakit/network/types.d.ts +0 -74
- package/dist/metakit/network/types.js +0 -20
- package/dist/metakit/sign.d.ts +0 -65
- package/dist/metakit/sign.js +0 -120
- package/dist/metakit/signed-object.d.ts +0 -66
- package/dist/metakit/signed-object.js +0 -100
- package/dist/metakit/types.d.ts +0 -67
- package/dist/metakit/types.js +0 -14
- package/dist/metakit/verify.d.ts +0 -55
- package/dist/metakit/verify.js +0 -217
- package/dist/metakit/wallet.d.ts +0 -70
- package/dist/metakit/wallet.js +0 -127
- package/dist/ottochain/index.d.ts +0 -13
- package/dist/ottochain/index.js +0 -45
- package/dist/ottochain/metagraph-client.d.ts +0 -111
- package/dist/ottochain/metagraph-client.js +0 -157
- package/dist/ottochain/snapshot.d.ts +0 -86
- package/dist/ottochain/snapshot.js +0 -110
- package/dist/ottochain/types.d.ts +0 -278
- package/dist/ottochain/types.js +0 -11
- package/dist/types/apps/contracts/types.d.ts +0 -24
- package/dist/types/apps/corporate/types.d.ts +0 -9861
- package/dist/types/apps/governance/types.d.ts +0 -344
- package/dist/types/apps/identity/types.d.ts +0 -30
- package/dist/types/apps/markets/types.d.ts +0 -155
- package/dist/types/apps/oracles/types.d.ts +0 -193
- package/dist/types/generated/ottochain/apps/contracts/v1/contract_pb.d.ts +0 -274
- package/dist/types/generated/ottochain/apps/corporate/v1/corporate_pb.d.ts +0 -1172
- package/dist/types/generated/ottochain/apps/governance/v1/governance_pb.d.ts +0 -772
- package/dist/types/generated/ottochain/apps/identity/v1/agent_pb.d.ts +0 -211
- package/dist/types/generated/ottochain/apps/identity/v1/attestation_pb.d.ts +0 -238
- package/dist/types/generated/ottochain/apps/markets/v1/market_pb.d.ts +0 -436
- package/dist/types/generated/ottochain/apps/oracles/v1/oracle_pb.d.ts +0 -393
- package/dist/types/generated/ottochain/v1/common_pb.d.ts +0 -86
- package/dist/types/generated/ottochain/v1/fiber_pb.d.ts +0 -292
- package/dist/types/generated/ottochain/v1/messages_pb.d.ts +0 -190
- package/dist/types/generated/ottochain/v1/records_pb.d.ts +0 -221
- package/dist/validation.d.ts +0 -449
- package/dist/validation.js +0 -312
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize OttoChain Messages for Signing
|
|
3
|
+
*
|
|
4
|
+
* Converts OttoChain message objects to the wire format expected by the
|
|
5
|
+
* Scala metagraph. Specifically, ensures all `Option[A]=None` fields are
|
|
6
|
+
* present as explicit `null` values, matching what circe's magnolia encoder
|
|
7
|
+
* produces on the Scala side.
|
|
8
|
+
*
|
|
9
|
+
* This is necessary because metakit's `JsonBinaryCodec.deriveDataUpdate`
|
|
10
|
+
* (rc.8) canonicalizes the circe-encoded JSON **including null fields**.
|
|
11
|
+
* If the TypeScript client omits optional fields (undefined), the canonical
|
|
12
|
+
* JSON won't match and signature verification will fail.
|
|
13
|
+
*
|
|
14
|
+
* Schema mapping (Scala → TypeScript):
|
|
15
|
+
* - `Option[A] = None` → `null` (must be explicit, not undefined/absent)
|
|
16
|
+
* - `Option[A] = Some(v)` → `v`
|
|
17
|
+
* - `List.empty` → `[]`
|
|
18
|
+
* - `Map.empty` → `{}`
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Normalize a State object for wire format
|
|
22
|
+
*/
|
|
23
|
+
function normalizeState(state) {
|
|
24
|
+
return {
|
|
25
|
+
id: state.id,
|
|
26
|
+
isFinal: state.isFinal ?? false,
|
|
27
|
+
metadata: state.metadata ?? null,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Normalize a Transition object for wire format
|
|
32
|
+
*/
|
|
33
|
+
function normalizeTransition(t) {
|
|
34
|
+
return {
|
|
35
|
+
from: t.from,
|
|
36
|
+
eventName: t.eventName,
|
|
37
|
+
to: t.to,
|
|
38
|
+
guard: t.guard ?? null,
|
|
39
|
+
actions: t.actions ?? null,
|
|
40
|
+
metadata: t.metadata ?? null,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Normalize a StateMachineDefinition for wire format
|
|
45
|
+
*/
|
|
46
|
+
function normalizeDefinition(def) {
|
|
47
|
+
const states = def.states;
|
|
48
|
+
const normalizedStates = {};
|
|
49
|
+
if (states) {
|
|
50
|
+
for (const [key, state] of Object.entries(states)) {
|
|
51
|
+
normalizedStates[key] = normalizeState(state);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const transitions = def.transitions ?? [];
|
|
55
|
+
return {
|
|
56
|
+
states: normalizedStates,
|
|
57
|
+
initialState: def.initialState,
|
|
58
|
+
transitions: transitions.map(normalizeTransition),
|
|
59
|
+
metadata: def.metadata ?? null,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Normalize a CreateStateMachine message for wire format
|
|
64
|
+
*
|
|
65
|
+
* Ensures all Option fields are explicit null:
|
|
66
|
+
* - definition.metadata
|
|
67
|
+
* - definition.states[*].metadata
|
|
68
|
+
* - definition.transitions[*].guard
|
|
69
|
+
* - definition.transitions[*].actions
|
|
70
|
+
* - definition.transitions[*].metadata
|
|
71
|
+
* - parentFiberId
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* const message = normalizeCreateStateMachine({
|
|
76
|
+
* fiberId: '...',
|
|
77
|
+
* definition: { states: { INIT: { id: { value: 'INIT' }, isFinal: false } }, ... },
|
|
78
|
+
* initialData: {}
|
|
79
|
+
* });
|
|
80
|
+
* // message now has parentFiberId: null, definition.metadata: null, etc.
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export function normalizeCreateStateMachine(msg) {
|
|
84
|
+
return {
|
|
85
|
+
fiberId: msg.fiberId,
|
|
86
|
+
definition: normalizeDefinition(msg.definition),
|
|
87
|
+
initialData: msg.initialData ?? {},
|
|
88
|
+
parentFiberId: msg.parentFiberId ?? null,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Normalize a TransitionStateMachine message for wire format
|
|
93
|
+
*/
|
|
94
|
+
export function normalizeTransitionStateMachine(msg) {
|
|
95
|
+
return {
|
|
96
|
+
fiberId: msg.fiberId,
|
|
97
|
+
eventName: msg.eventName,
|
|
98
|
+
eventData: msg.eventData ?? null,
|
|
99
|
+
fiberOrdinal: msg.fiberOrdinal,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Normalize an ArchiveStateMachine message for wire format
|
|
104
|
+
*/
|
|
105
|
+
export function normalizeArchiveStateMachine(msg) {
|
|
106
|
+
return {
|
|
107
|
+
fiberId: msg.fiberId,
|
|
108
|
+
reason: msg.reason ?? null,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Normalize any OttochainMessage wrapper for wire format.
|
|
113
|
+
*
|
|
114
|
+
* Detects the message type from the wrapper key and applies the
|
|
115
|
+
* appropriate normalization.
|
|
116
|
+
*
|
|
117
|
+
* @param message - OttochainMessage in wrapper format: `{ CreateStateMachine: {...} }`
|
|
118
|
+
* @returns Normalized message with all Option fields as explicit null
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* const normalized = normalizeMessage({
|
|
123
|
+
* CreateStateMachine: { fiberId: '...', definition: {...}, initialData: {} }
|
|
124
|
+
* });
|
|
125
|
+
* const signed = await signDataUpdate(normalized, privateKey);
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export function normalizeMessage(message) {
|
|
129
|
+
if ('CreateStateMachine' in message) {
|
|
130
|
+
return { CreateStateMachine: normalizeCreateStateMachine(message.CreateStateMachine) };
|
|
131
|
+
}
|
|
132
|
+
if ('TransitionStateMachine' in message) {
|
|
133
|
+
return { TransitionStateMachine: normalizeTransitionStateMachine(message.TransitionStateMachine) };
|
|
134
|
+
}
|
|
135
|
+
if ('ArchiveStateMachine' in message) {
|
|
136
|
+
return { ArchiveStateMachine: normalizeArchiveStateMachine(message.ArchiveStateMachine) };
|
|
137
|
+
}
|
|
138
|
+
// CreateScript and InvokeScript — pass through (no optional fields)
|
|
139
|
+
return message;
|
|
140
|
+
}
|
|
@@ -135,6 +135,153 @@ export class MetagraphClient {
|
|
|
135
135
|
return snapshot.value.ordinal;
|
|
136
136
|
}
|
|
137
137
|
// -------------------------------------------------------------------------
|
|
138
|
+
// Fiber state subscription
|
|
139
|
+
// -------------------------------------------------------------------------
|
|
140
|
+
/**
|
|
141
|
+
* Subscribe to state changes for a state machine fiber.
|
|
142
|
+
*
|
|
143
|
+
* Polls ML0 at the configured interval and compares `sequenceNumber` to
|
|
144
|
+
* detect changes. Fires the callback with `(current, previous)` on the
|
|
145
|
+
* first poll (if `fireImmediately` is true — the default) and on every
|
|
146
|
+
* subsequent change.
|
|
147
|
+
*
|
|
148
|
+
* ML0 consistency: state is read from snapshot-level `CalculatedState`
|
|
149
|
+
* (via `checkpointService.get`), so a poll never returns a mid-transition
|
|
150
|
+
* value — every observation is a fully committed state.
|
|
151
|
+
*
|
|
152
|
+
* Uses `setTimeout` recursion to prevent overlapping polls when a request
|
|
153
|
+
* takes longer than `pollIntervalMs`.
|
|
154
|
+
*
|
|
155
|
+
* @param fiberId - UUID of the state machine fiber to watch
|
|
156
|
+
* @param callback - Called on first observation and on every state change
|
|
157
|
+
* @param options - Polling interval, error handler, fireImmediately flag
|
|
158
|
+
* @returns Unsubscribe function — call to stop polling immediately
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* const unsub = client.subscribeFiberState(fiberId, (current, prev) => {
|
|
163
|
+
* if (current?.currentState === 'Completed') {
|
|
164
|
+
* unsub();
|
|
165
|
+
* }
|
|
166
|
+
* });
|
|
167
|
+
* // Later:
|
|
168
|
+
* unsub();
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
subscribeFiberState(fiberId, callback, options) {
|
|
172
|
+
const intervalMs = options?.pollIntervalMs ?? 2000;
|
|
173
|
+
const onError = options?.onError ?? ((e) => console.warn('[subscribeFiberState]', e));
|
|
174
|
+
const fireImmediately = options?.fireImmediately ?? true;
|
|
175
|
+
let previous = null;
|
|
176
|
+
let lastSeqNum = null;
|
|
177
|
+
let firstPoll = true; // Track first poll separately — handles null seqNum on missing fiber
|
|
178
|
+
let active = true;
|
|
179
|
+
const invokeCallback = (current, prev) => {
|
|
180
|
+
try {
|
|
181
|
+
callback(current, prev);
|
|
182
|
+
}
|
|
183
|
+
catch (cbErr) {
|
|
184
|
+
try {
|
|
185
|
+
onError(cbErr instanceof Error ? cbErr : new Error(String(cbErr)));
|
|
186
|
+
}
|
|
187
|
+
catch { /* ignore */ }
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
const poll = async () => {
|
|
191
|
+
if (!active)
|
|
192
|
+
return;
|
|
193
|
+
let current;
|
|
194
|
+
try {
|
|
195
|
+
current = await this.getStateMachine(fiberId);
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
// Network / timeout error — notify and reschedule
|
|
199
|
+
if (!active)
|
|
200
|
+
return;
|
|
201
|
+
try {
|
|
202
|
+
onError(err instanceof Error ? err : new Error(String(err)));
|
|
203
|
+
}
|
|
204
|
+
catch { /* ignore */ }
|
|
205
|
+
if (active)
|
|
206
|
+
setTimeout(poll, intervalMs);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
// Guard: unsubscribe may have been called while awaiting
|
|
210
|
+
if (!active)
|
|
211
|
+
return;
|
|
212
|
+
const currentSeq = current?.sequenceNumber ?? null;
|
|
213
|
+
if (firstPoll) {
|
|
214
|
+
firstPoll = false;
|
|
215
|
+
lastSeqNum = currentSeq;
|
|
216
|
+
previous = current;
|
|
217
|
+
if (fireImmediately) {
|
|
218
|
+
invokeCallback(current, null);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else if (currentSeq !== lastSeqNum) {
|
|
222
|
+
// State changed — sequenceNumber differs (handles null → value and value → null)
|
|
223
|
+
const prev = previous;
|
|
224
|
+
previous = current;
|
|
225
|
+
lastSeqNum = currentSeq;
|
|
226
|
+
invokeCallback(current, prev);
|
|
227
|
+
}
|
|
228
|
+
// No change → no callback
|
|
229
|
+
// Schedule next poll (setTimeout recursion prevents overlapping polls)
|
|
230
|
+
if (active)
|
|
231
|
+
setTimeout(poll, intervalMs);
|
|
232
|
+
};
|
|
233
|
+
// Start first poll via setTimeout(0) so Jest fake-timer control works correctly:
|
|
234
|
+
// callers can unsubscribe before the first poll runs, and each
|
|
235
|
+
// jest.runOnlyPendingTimersAsync() advances exactly one poll cycle.
|
|
236
|
+
setTimeout(poll, 0);
|
|
237
|
+
return () => { active = false; };
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Wait for a fiber to reach a specific state, with an optional timeout.
|
|
241
|
+
*
|
|
242
|
+
* Builds on `subscribeFiberState` — resolves with the fiber record once
|
|
243
|
+
* `currentState === targetState`, or resolves with `null` after `timeoutMs`.
|
|
244
|
+
* Always calls unsubscribe on resolution or timeout (no memory leaks).
|
|
245
|
+
*
|
|
246
|
+
* @param fiberId - UUID of the state machine fiber
|
|
247
|
+
* @param targetState - State name to wait for (e.g. `'Completed'`)
|
|
248
|
+
* @param timeoutMs - Maximum wait in milliseconds (default: 30 000)
|
|
249
|
+
* @returns Fiber record when target state reached, or `null` on timeout
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```typescript
|
|
253
|
+
* const result = await client.waitForState(fiberId, 'Completed', 15_000);
|
|
254
|
+
* if (result === null) console.warn('Timed out waiting for Completed');
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
waitForState(fiberId, targetState, timeoutMs = 30000, options) {
|
|
258
|
+
return new Promise((resolve) => {
|
|
259
|
+
let resolved = false;
|
|
260
|
+
let timer = null;
|
|
261
|
+
// unsub starts as a no-op so it's safe to call even if subscribeFiberState
|
|
262
|
+
// invokes the callback synchronously (before returning the real unsubscribe).
|
|
263
|
+
let unsub = () => { };
|
|
264
|
+
const done = (result) => {
|
|
265
|
+
if (resolved)
|
|
266
|
+
return;
|
|
267
|
+
resolved = true;
|
|
268
|
+
if (timer !== null)
|
|
269
|
+
clearTimeout(timer);
|
|
270
|
+
unsub(); // safe: either the real unsub or the initial no-op
|
|
271
|
+
resolve(result);
|
|
272
|
+
};
|
|
273
|
+
unsub = this.subscribeFiberState(fiberId, (current) => {
|
|
274
|
+
if (current?.currentState === targetState) {
|
|
275
|
+
done(current);
|
|
276
|
+
}
|
|
277
|
+
}, { fireImmediately: true, ...options });
|
|
278
|
+
// Only arm the timeout if the callback hasn't already resolved (synchronous case)
|
|
279
|
+
if (!resolved) {
|
|
280
|
+
timer = setTimeout(() => done(null), timeoutMs);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
// -------------------------------------------------------------------------
|
|
138
285
|
// DL1 data submission (framework POST /data)
|
|
139
286
|
// -------------------------------------------------------------------------
|
|
140
287
|
/**
|
package/dist/esm/validation.js
CHANGED
|
@@ -131,7 +131,7 @@ export const PlatformLinkSchema = z.object({
|
|
|
131
131
|
/**
|
|
132
132
|
* Schema for contract terms (flexible structure)
|
|
133
133
|
*/
|
|
134
|
-
export const ContractTermsSchema = z.record(z.unknown());
|
|
134
|
+
export const ContractTermsSchema = z.record(z.string(), z.unknown());
|
|
135
135
|
/**
|
|
136
136
|
* Schema for ProposeContractRequest
|
|
137
137
|
*/
|
|
@@ -2,9 +2,19 @@
|
|
|
2
2
|
* Generated Protobuf Types
|
|
3
3
|
*
|
|
4
4
|
* Auto-generated from proto/ definitions using ts-proto.
|
|
5
|
-
* DO NOT EDIT - regenerate with `
|
|
5
|
+
* DO NOT EDIT - regenerate with `npm run generate`
|
|
6
6
|
*
|
|
7
7
|
* @packageDocumentation
|
|
8
|
+
*
|
|
9
|
+
* NOTE — Dual-type architecture:
|
|
10
|
+
* These generated types use proto conventions (FIBER_STATUS_ACTIVE, StateId { value } wrappers).
|
|
11
|
+
* The wire-format REST API types in src/ottochain/types.ts use plain strings ('Active').
|
|
12
|
+
* Both coexist intentionally until PR #89 (Migrate fiber-engine to generated Scala types) merges.
|
|
13
|
+
*
|
|
14
|
+
* TODO PR #89 migration: after PR #89 merges and cluster confirms new format,
|
|
15
|
+
* migrate all state-machine JSON files in src/apps/ from Circe-format
|
|
16
|
+
* ({ value: '...' } wrapped initialState) to plain string format.
|
|
17
|
+
* See docs/type-architecture.md for full migration plan.
|
|
8
18
|
*/
|
|
9
19
|
export { FiberStatus, AccessControlPolicy, PublicAccess, WhitelistAccess, FiberOwnedAccess, StateMachineDefinition, EmittedEvent, EventReceipt, ScriptInvocation, FiberLogEntry, } from './ottochain/v1/fiber.js';
|
|
10
20
|
export { CreateStateMachine, TransitionStateMachine, ArchiveStateMachine, CreateScript, InvokeScript, OttochainMessage, } from './ottochain/v1/messages.js';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drop Null Values from JSON Objects
|
|
3
|
+
*
|
|
4
|
+
* Recursively removes null-valued keys from objects to match
|
|
5
|
+
* the Scala-side `JsonBinaryCodec.dropNulls` behavior in metakit.
|
|
6
|
+
*
|
|
7
|
+
* This ensures that the canonical JSON used for signing on the
|
|
8
|
+
* TypeScript side matches what the Scala metagraph produces when
|
|
9
|
+
* verifying signatures.
|
|
10
|
+
*
|
|
11
|
+
* Note: null values inside arrays are preserved (to maintain index
|
|
12
|
+
* positions). Only object field values that are null are removed.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Recursively remove null values from objects
|
|
16
|
+
*
|
|
17
|
+
* @param value - Any JSON-serializable value
|
|
18
|
+
* @returns A deep copy with null object fields removed
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* dropNulls({ a: 1, b: null, c: { d: null, e: 2 } })
|
|
23
|
+
* // => { a: 1, c: { e: 2 } }
|
|
24
|
+
*
|
|
25
|
+
* dropNulls([1, null, 3])
|
|
26
|
+
* // => [1, null, 3] (array nulls preserved)
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function dropNulls<T>(value: T): T;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize OttoChain Messages for Signing
|
|
3
|
+
*
|
|
4
|
+
* Converts OttoChain message objects to the wire format expected by the
|
|
5
|
+
* Scala metagraph. Specifically, ensures all `Option[A]=None` fields are
|
|
6
|
+
* present as explicit `null` values, matching what circe's magnolia encoder
|
|
7
|
+
* produces on the Scala side.
|
|
8
|
+
*
|
|
9
|
+
* This is necessary because metakit's `JsonBinaryCodec.deriveDataUpdate`
|
|
10
|
+
* (rc.8) canonicalizes the circe-encoded JSON **including null fields**.
|
|
11
|
+
* If the TypeScript client omits optional fields (undefined), the canonical
|
|
12
|
+
* JSON won't match and signature verification will fail.
|
|
13
|
+
*
|
|
14
|
+
* Schema mapping (Scala → TypeScript):
|
|
15
|
+
* - `Option[A] = None` → `null` (must be explicit, not undefined/absent)
|
|
16
|
+
* - `Option[A] = Some(v)` → `v`
|
|
17
|
+
* - `List.empty` → `[]`
|
|
18
|
+
* - `Map.empty` → `{}`
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Normalize a CreateStateMachine message for wire format
|
|
22
|
+
*
|
|
23
|
+
* Ensures all Option fields are explicit null:
|
|
24
|
+
* - definition.metadata
|
|
25
|
+
* - definition.states[*].metadata
|
|
26
|
+
* - definition.transitions[*].guard
|
|
27
|
+
* - definition.transitions[*].actions
|
|
28
|
+
* - definition.transitions[*].metadata
|
|
29
|
+
* - parentFiberId
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const message = normalizeCreateStateMachine({
|
|
34
|
+
* fiberId: '...',
|
|
35
|
+
* definition: { states: { INIT: { id: { value: 'INIT' }, isFinal: false } }, ... },
|
|
36
|
+
* initialData: {}
|
|
37
|
+
* });
|
|
38
|
+
* // message now has parentFiberId: null, definition.metadata: null, etc.
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function normalizeCreateStateMachine(msg: Record<string, unknown>): Record<string, unknown>;
|
|
42
|
+
/**
|
|
43
|
+
* Normalize a TransitionStateMachine message for wire format
|
|
44
|
+
*/
|
|
45
|
+
export declare function normalizeTransitionStateMachine(msg: Record<string, unknown>): Record<string, unknown>;
|
|
46
|
+
/**
|
|
47
|
+
* Normalize an ArchiveStateMachine message for wire format
|
|
48
|
+
*/
|
|
49
|
+
export declare function normalizeArchiveStateMachine(msg: Record<string, unknown>): Record<string, unknown>;
|
|
50
|
+
/**
|
|
51
|
+
* Normalize any OttochainMessage wrapper for wire format.
|
|
52
|
+
*
|
|
53
|
+
* Detects the message type from the wrapper key and applies the
|
|
54
|
+
* appropriate normalization.
|
|
55
|
+
*
|
|
56
|
+
* @param message - OttochainMessage in wrapper format: `{ CreateStateMachine: {...} }`
|
|
57
|
+
* @returns Normalized message with all Option fields as explicit null
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const normalized = normalizeMessage({
|
|
62
|
+
* CreateStateMachine: { fiberId: '...', definition: {...}, initialData: {} }
|
|
63
|
+
* });
|
|
64
|
+
* const signed = await signDataUpdate(normalized, privateKey);
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function normalizeMessage(message: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -9,5 +9,5 @@ export * as proto from '../generated/index.js';
|
|
|
9
9
|
export type { Address, FiberId, StateId, HashValue, FiberOrdinal, SnapshotOrdinal, JsonLogicValue, JsonLogicExpression, FiberStatus, AccessControlPolicy, StateMachineDefinition, EmittedEvent, EventReceipt, OracleInvocation, FiberLogEntry, StateMachineFiberRecord, ScriptFiberRecord, FiberRecord, FiberCommit, OnChain, CalculatedState, CreateStateMachine, TransitionStateMachine, ArchiveStateMachine, CreateScript, InvokeScript, OttochainMessage, } from './types.js';
|
|
10
10
|
export type { CurrencySnapshotResponse } from './snapshot.js';
|
|
11
11
|
export { decodeOnChainState, getSnapshotOnChainState, getLatestOnChainState, getLogsForFiber, getEventReceipts, getScriptInvocations, extractOnChainState, } from './snapshot.js';
|
|
12
|
-
export type { Checkpoint, MetagraphClientConfig } from './metagraph-client.js';
|
|
12
|
+
export type { Checkpoint, MetagraphClientConfig, SubscribeOptions, FiberStateCallback, Unsubscribe, } from './metagraph-client.js';
|
|
13
13
|
export { MetagraphClient } from './metagraph-client.js';
|
|
@@ -16,6 +16,45 @@ export interface Checkpoint {
|
|
|
16
16
|
ordinal: number;
|
|
17
17
|
state: CalculatedState;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Options for subscribeFiberState polling behaviour.
|
|
21
|
+
*/
|
|
22
|
+
export interface SubscribeOptions {
|
|
23
|
+
/**
|
|
24
|
+
* Polling interval in milliseconds.
|
|
25
|
+
* @default 2000
|
|
26
|
+
*/
|
|
27
|
+
pollIntervalMs?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Called when a poll fails (network error, timeout, etc.) or when the
|
|
30
|
+
* user-supplied callback throws. The subscription continues after an error.
|
|
31
|
+
* @default (e) => console.warn('[subscribeFiberState]', e)
|
|
32
|
+
*/
|
|
33
|
+
onError?: (error: Error) => void;
|
|
34
|
+
/**
|
|
35
|
+
* If true, fire the callback immediately after the very first poll even
|
|
36
|
+
* when no previous state exists (current vs. null).
|
|
37
|
+
* Set false to suppress the initial callback and only fire on changes.
|
|
38
|
+
*
|
|
39
|
+
* **Edge case:** When `fireImmediately` is false and the fiber never exists
|
|
40
|
+
* (getStateMachine always returns null), the callback will never fire because
|
|
41
|
+
* the sequence number stays null between polls (no change detected).
|
|
42
|
+
* @default true
|
|
43
|
+
*/
|
|
44
|
+
fireImmediately?: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Callback invoked when fiber state is first observed or changes.
|
|
48
|
+
*
|
|
49
|
+
* @param current - Current fiber state, or null if fiber not found
|
|
50
|
+
* @param previous - Previous fiber state, or null on first callback
|
|
51
|
+
*/
|
|
52
|
+
export type FiberStateCallback = (current: StateMachineFiberRecord | null, previous: StateMachineFiberRecord | null) => void;
|
|
53
|
+
/**
|
|
54
|
+
* Unsubscribe function returned by subscribeFiberState.
|
|
55
|
+
* Stops polling immediately and prevents any further callbacks. Idempotent.
|
|
56
|
+
*/
|
|
57
|
+
export type Unsubscribe = () => void;
|
|
19
58
|
/**
|
|
20
59
|
* Configuration for the MetagraphClient.
|
|
21
60
|
*/
|
|
@@ -98,6 +137,57 @@ export declare class MetagraphClient {
|
|
|
98
137
|
* Get the latest snapshot ordinal.
|
|
99
138
|
*/
|
|
100
139
|
getLatestOrdinal(): Promise<number>;
|
|
140
|
+
/**
|
|
141
|
+
* Subscribe to state changes for a state machine fiber.
|
|
142
|
+
*
|
|
143
|
+
* Polls ML0 at the configured interval and compares `sequenceNumber` to
|
|
144
|
+
* detect changes. Fires the callback with `(current, previous)` on the
|
|
145
|
+
* first poll (if `fireImmediately` is true — the default) and on every
|
|
146
|
+
* subsequent change.
|
|
147
|
+
*
|
|
148
|
+
* ML0 consistency: state is read from snapshot-level `CalculatedState`
|
|
149
|
+
* (via `checkpointService.get`), so a poll never returns a mid-transition
|
|
150
|
+
* value — every observation is a fully committed state.
|
|
151
|
+
*
|
|
152
|
+
* Uses `setTimeout` recursion to prevent overlapping polls when a request
|
|
153
|
+
* takes longer than `pollIntervalMs`.
|
|
154
|
+
*
|
|
155
|
+
* @param fiberId - UUID of the state machine fiber to watch
|
|
156
|
+
* @param callback - Called on first observation and on every state change
|
|
157
|
+
* @param options - Polling interval, error handler, fireImmediately flag
|
|
158
|
+
* @returns Unsubscribe function — call to stop polling immediately
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* const unsub = client.subscribeFiberState(fiberId, (current, prev) => {
|
|
163
|
+
* if (current?.currentState === 'Completed') {
|
|
164
|
+
* unsub();
|
|
165
|
+
* }
|
|
166
|
+
* });
|
|
167
|
+
* // Later:
|
|
168
|
+
* unsub();
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
subscribeFiberState(fiberId: string, callback: FiberStateCallback, options?: SubscribeOptions): Unsubscribe;
|
|
172
|
+
/**
|
|
173
|
+
* Wait for a fiber to reach a specific state, with an optional timeout.
|
|
174
|
+
*
|
|
175
|
+
* Builds on `subscribeFiberState` — resolves with the fiber record once
|
|
176
|
+
* `currentState === targetState`, or resolves with `null` after `timeoutMs`.
|
|
177
|
+
* Always calls unsubscribe on resolution or timeout (no memory leaks).
|
|
178
|
+
*
|
|
179
|
+
* @param fiberId - UUID of the state machine fiber
|
|
180
|
+
* @param targetState - State name to wait for (e.g. `'Completed'`)
|
|
181
|
+
* @param timeoutMs - Maximum wait in milliseconds (default: 30 000)
|
|
182
|
+
* @returns Fiber record when target state reached, or `null` on timeout
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```typescript
|
|
186
|
+
* const result = await client.waitForState(fiberId, 'Completed', 15_000);
|
|
187
|
+
* if (result === null) console.warn('Timed out waiting for Completed');
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
waitForState(fiberId: string, targetState: string, timeoutMs?: number, options?: Pick<SubscribeOptions, 'pollIntervalMs' | 'onError'>): Promise<StateMachineFiberRecord | null>;
|
|
101
191
|
/**
|
|
102
192
|
* Submit a signed data update to the DL1 node.
|
|
103
193
|
* The POST /data endpoint is framework-provided (no /v1 prefix).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ottochain/sdk",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "TypeScript SDK for ottochain metagraph operations - signing, encoding, and network interactions",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -55,6 +55,11 @@
|
|
|
55
55
|
"import": "./dist/esm/apps/index.js",
|
|
56
56
|
"require": "./dist/cjs/apps/index.js",
|
|
57
57
|
"types": "./dist/types/apps/index.d.ts"
|
|
58
|
+
},
|
|
59
|
+
"./generated": {
|
|
60
|
+
"import": "./dist/esm/generated/index.js",
|
|
61
|
+
"require": "./dist/cjs/generated/index.js",
|
|
62
|
+
"types": "./dist/types/generated/index.d.ts"
|
|
58
63
|
}
|
|
59
64
|
},
|
|
60
65
|
"files": [
|
|
@@ -107,21 +112,16 @@
|
|
|
107
112
|
"zod": "^3.22.0"
|
|
108
113
|
},
|
|
109
114
|
"devDependencies": {
|
|
110
|
-
"@
|
|
111
|
-
"@bufbuild/protoc-gen-es": "^2.11.0",
|
|
112
|
-
"@protobuf-ts/plugin": "^2.11.1",
|
|
113
|
-
"@protobuf-ts/runtime": "^2.11.1",
|
|
114
|
-
"@types/jest": "^29.5.0",
|
|
115
|
+
"@types/jest": "^30.0.0",
|
|
115
116
|
"@types/node": "^20.0.0",
|
|
116
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
117
|
-
"@typescript-eslint/parser": "^
|
|
118
|
-
"eslint": "^
|
|
119
|
-
"
|
|
120
|
-
"jest": "^29.0.0",
|
|
117
|
+
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
118
|
+
"@typescript-eslint/parser": "^8.56.1",
|
|
119
|
+
"eslint": "^9.39.3",
|
|
120
|
+
"jest": "^30.2.0",
|
|
121
121
|
"prettier": "^3.0.0",
|
|
122
122
|
"ts-jest": "^29.0.0",
|
|
123
123
|
"ts-proto": "^2.11.2",
|
|
124
|
-
"typedoc": "^0.
|
|
124
|
+
"typedoc": "^0.28.17",
|
|
125
125
|
"typescript": "^5.0.0"
|
|
126
126
|
},
|
|
127
127
|
"peerDependencies": {
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Contracts Application
|
|
3
|
-
*
|
|
4
|
-
* Types and utilities for the Contract system on OttoChain.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```typescript
|
|
8
|
-
* import { ContractState, ContractSchema } from '@ottochain/sdk/apps/contracts';
|
|
9
|
-
* import { create } from '@bufbuild/protobuf';
|
|
10
|
-
*
|
|
11
|
-
* const contract = create(ContractSchema, {
|
|
12
|
-
* id: 'fiber-123',
|
|
13
|
-
* contractId: 'contract-001',
|
|
14
|
-
* state: ContractState.PROPOSED,
|
|
15
|
-
* });
|
|
16
|
-
* ```
|
|
17
|
-
*
|
|
18
|
-
* @packageDocumentation
|
|
19
|
-
*/
|
|
20
|
-
export * from '../../generated/ottochain/apps/contracts/v1/contract_pb.js';
|
|
21
|
-
export * from './types.js';
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Contracts Application
|
|
4
|
-
*
|
|
5
|
-
* Types and utilities for the Contract system on OttoChain.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* import { ContractState, ContractSchema } from '@ottochain/sdk/apps/contracts';
|
|
10
|
-
* import { create } from '@bufbuild/protobuf';
|
|
11
|
-
*
|
|
12
|
-
* const contract = create(ContractSchema, {
|
|
13
|
-
* id: 'fiber-123',
|
|
14
|
-
* contractId: 'contract-001',
|
|
15
|
-
* state: ContractState.PROPOSED,
|
|
16
|
-
* });
|
|
17
|
-
* ```
|
|
18
|
-
*
|
|
19
|
-
* @packageDocumentation
|
|
20
|
-
*/
|
|
21
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
22
|
-
if (k2 === undefined) k2 = k;
|
|
23
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
24
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
25
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
26
|
-
}
|
|
27
|
-
Object.defineProperty(o, k2, desc);
|
|
28
|
-
}) : (function(o, m, k, k2) {
|
|
29
|
-
if (k2 === undefined) k2 = k;
|
|
30
|
-
o[k2] = m[k];
|
|
31
|
-
}));
|
|
32
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
33
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
34
|
-
};
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
// Re-export generated protobuf types
|
|
37
|
-
__exportStar(require("../../generated/ottochain/apps/contracts/v1/contract_pb.js"), exports);
|
|
38
|
-
// Re-export convenience types and constants
|
|
39
|
-
__exportStar(require("./types.js"), exports);
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Contract Utilities
|
|
3
|
-
*
|
|
4
|
-
* Constants and utilities for the Contract application.
|
|
5
|
-
* Core types are generated from protobuf - see the generated exports.
|
|
6
|
-
*
|
|
7
|
-
* @packageDocumentation
|
|
8
|
-
*/
|
|
9
|
-
import { ContractState } from '../../generated/ottochain/apps/contracts/v1/contract_pb.js';
|
|
10
|
-
/**
|
|
11
|
-
* Default contract configuration
|
|
12
|
-
*/
|
|
13
|
-
export declare const DEFAULT_CONTRACT_CONFIG: {
|
|
14
|
-
readonly requireBothSignatures: false;
|
|
15
|
-
readonly disputeWindowEpochs: 10;
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Valid transitions for each contract state
|
|
19
|
-
*/
|
|
20
|
-
export declare const CONTRACT_TRANSITIONS: Record<ContractState, readonly string[]>;
|
|
21
|
-
/**
|
|
22
|
-
* Check if a contract state is terminal (no further transitions allowed)
|
|
23
|
-
*/
|
|
24
|
-
export declare function isTerminalState(state: ContractState): boolean;
|