@cinchor/sdk 0.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.
@@ -0,0 +1,514 @@
1
+ import { ContractQueryResult, AbiArgument } from '@omne/sdk';
2
+
3
+ /**
4
+ * @cinchor/sdk — connection + deployment configuration.
5
+ *
6
+ * Everything that ties the SDK to a specific network and a specific deployed
7
+ * accountability contract is injected here, not hardcoded. A consumer points
8
+ * the SDK at their target network (devnet, testnet, mainnet) and the address of
9
+ * the deployed contract they were given.
10
+ */
11
+ /** Network coordinates the SDK talks to. */
12
+ interface NetworkConfig {
13
+ /** Human-readable network name (informational). */
14
+ name: string;
15
+ /** Omne chain id (Ignis devnet = 3). Signed into every transaction. */
16
+ chainId: number;
17
+ /** JSON-RPC endpoint URL. */
18
+ rpcUrl: string;
19
+ }
20
+ /**
21
+ * The deployed accountability contract the SDK calls.
22
+ *
23
+ * `name` is the on-chain contract module name; the runtime resolves calls via
24
+ * the full export path `axiom_contract::<name>::<function>`, which `exportPrefix`
25
+ * encodes. These are deployment details, not brand surfaces — point them at
26
+ * whatever contract instance you were given.
27
+ */
28
+ interface ContractConfig {
29
+ /** On-chain contract module name. */
30
+ name: string;
31
+ /** Deployed contract address (om1z bech32m). */
32
+ address: string;
33
+ /** Runtime export prefix: `axiom_contract::<name>::`. Derived if omitted. */
34
+ exportPrefix?: string;
35
+ }
36
+ /** Full SDK configuration. */
37
+ interface CinchorConfig {
38
+ network: NetworkConfig;
39
+ contract: ContractConfig;
40
+ /** Default gas limit for write calls. */
41
+ defaultGasLimit?: number;
42
+ /** Default gas price (quar) for write calls. Ignis devnet base fee = 5000. */
43
+ defaultGasPrice?: string;
44
+ }
45
+ /** Resolve a contract export prefix, deriving the default from the name. */
46
+ declare function exportPrefixFor(contract: ContractConfig): string;
47
+ declare const DEFAULT_GAS_LIMIT = 200000;
48
+ declare const DEFAULT_GAS_PRICE = "5000";
49
+ /**
50
+ * A never-minted 32-byte sentinel capability id (witness v2, 32 bytes of 0xDE).
51
+ * Used as the counterparty placeholder when allowlist enforcement is disabled.
52
+ */
53
+ declare const BURN_SENTINEL = "om1zmm0dahk7mm0dahk7mm0dahk7mm0dahk7mm0dahk7mm0dahk7mm0qdtuxap";
54
+ /** Convenience preset for the local Ignis devnet. */
55
+ declare const IGNIS_LOCAL: NetworkConfig;
56
+
57
+ /**
58
+ * @cinchor/sdk — shared types and on-chain outcome codes.
59
+ *
60
+ * These mirror the typed return codes the on-chain accountability contract
61
+ * (the substrate Policy Enforcement Point) emits. They are the contract of the
62
+ * substrate, surfaced to the developer as named outcomes rather than integers.
63
+ */
64
+ /** Lifecycle state of a capability (permission token). */
65
+ declare enum CapabilityStatus {
66
+ NotFound = 0,
67
+ Active = 1,
68
+ Revoked = 2
69
+ }
70
+ type CapabilityStatusLabel = 'not_found' | 'active' | 'revoked';
71
+ declare const CAPABILITY_STATUS_LABELS: readonly CapabilityStatusLabel[];
72
+ /**
73
+ * Result of an `enforce()` call — the substrate's authorize-or-refuse verdict
74
+ * for an action recorded under a capability. Code 1 is the only allow; every
75
+ * other code is a substrate-enforced refusal (no state mutation occurred).
76
+ */
77
+ declare enum EnforcementCode {
78
+ NotFound = 0,
79
+ Allowed = 1,
80
+ Revoked = 2,
81
+ Expired = 3,
82
+ OverBudget = 4,
83
+ OutOfAllowlist = 5
84
+ }
85
+ type EnforcementLabel = 'not_found' | 'allowed' | 'revoked' | 'expired' | 'over_budget' | 'out_of_allowlist';
86
+ declare const ENFORCEMENT_LABELS: Record<EnforcementCode, EnforcementLabel>;
87
+ /** Verdict committed alongside a decision attestation. */
88
+ declare enum Verdict {
89
+ InPolicy = 1,
90
+ OutOfPolicy = 2
91
+ }
92
+ /** A signer compatible with the Omne SDK's WalletAccount.
93
+ *
94
+ * Defined structurally so callers can pass any object exposing an om1z
95
+ * `address` and a `signTransaction` method — they need not import the Omne
96
+ * SDK's concrete `WalletAccount` type to use Cinchor.
97
+ */
98
+ interface Signer {
99
+ readonly address: string;
100
+ signTransaction(tx: Record<string, unknown>, opts?: {
101
+ chainId?: number;
102
+ }): {
103
+ from: string;
104
+ to: string;
105
+ value: string;
106
+ gasLimit: number;
107
+ gasPrice: string;
108
+ nonce: number;
109
+ chainId: number;
110
+ data?: string;
111
+ signature: string;
112
+ publicKey: string;
113
+ };
114
+ }
115
+ /** Receipt-shaped result returned from a committed (or pending) write. */
116
+ interface SubmitReceipt {
117
+ transactionHash: string | null;
118
+ status: string;
119
+ blockNumber: number | null;
120
+ note?: string;
121
+ }
122
+ /** The outcome of an `enforce()` call. */
123
+ interface EnforcementOutcome {
124
+ /** True only when the substrate authorized the action (code 1). */
125
+ allowed: boolean;
126
+ code: EnforcementCode;
127
+ reason: EnforcementLabel;
128
+ receipt: SubmitReceipt;
129
+ }
130
+ /** Full on-chain state of a capability. */
131
+ interface CapabilityState {
132
+ capabilityId: string;
133
+ status: CapabilityStatus;
134
+ statusLabel: CapabilityStatusLabel;
135
+ principal: string;
136
+ agent: string;
137
+ maxSpend: bigint;
138
+ validUntil: bigint;
139
+ totalSpent: bigint;
140
+ actionCount: bigint;
141
+ createdAt: bigint;
142
+ revokedAt: bigint;
143
+ }
144
+ /** On-chain record of a decision attestation (the tamper-evidence anchor). */
145
+ interface AttestationRecord {
146
+ exists: boolean;
147
+ contextHash: string;
148
+ policyVersion: bigint;
149
+ verdict: number;
150
+ time: bigint;
151
+ }
152
+
153
+ /**
154
+ * @cinchor/sdk — typed wrapper over the deployed accountability contract.
155
+ *
156
+ * Each method maps to a contract export, encoding arguments per the on-chain
157
+ * ABI and parsing the returned state. This is the low-level primitive layer;
158
+ * most consumers use the high-level {@link CinchorClient} facade instead.
159
+ *
160
+ * Read methods (query) work standalone — no wallet/signing required.
161
+ * Write methods (call) require a signer whose om1z address is funded to pay gas.
162
+ *
163
+ * Substrate-enforced invariants for an action (in precedence order):
164
+ * 0 = not_found, 1 = success, 2 = revoked, 3 = expired, 4 = over_budget,
165
+ * 5 = out_of_allowlist.
166
+ */
167
+
168
+ declare class CapabilityRegistry {
169
+ private readonly contract;
170
+ private readonly rpcUrl;
171
+ private readonly chainId;
172
+ private readonly contractAddress;
173
+ private readonly exportPrefix;
174
+ private readonly defaultGasLimit;
175
+ private readonly defaultGasPrice;
176
+ /** Per-signer next-nonce cache (see {@link sendSigned} for node nonce semantics). */
177
+ private readonly nonces;
178
+ private constructor();
179
+ static connect(config: CinchorConfig): Promise<CapabilityRegistry>;
180
+ private fn;
181
+ /** A single, non-retrying JSON-RPC POST. */
182
+ private rpc;
183
+ /**
184
+ * Build, SIGN, and submit a state-changing contract call. The Omne node
185
+ * mandates a valid ML-DSA-44 signature on every transaction; we encode the
186
+ * call data, build the transaction, sign it with the role's signer (chainId
187
+ * 3 = Ignis), and submit via a single raw JSON-RPC POST. The submitter
188
+ * ("from") must equal the signer's om1z address — the node re-derives the PQC
189
+ * address from the public key and checks it matches.
190
+ */
191
+ private sendSigned;
192
+ /** Fetch the signer's next nonce from the node (0 on this devnet). */
193
+ private fetchNonce;
194
+ /**
195
+ * Build a signed wire payload for a contract call at a given nonce, validating
196
+ * the ML-DSA-44 signature/pubkey/chainId lengths locally before submit so a
197
+ * malformed signed object fails fast here, not at the node.
198
+ */
199
+ private buildSignedWire;
200
+ /** Submit a signed wire payload with one non-retrying POST. */
201
+ private submitOnce;
202
+ /**
203
+ * Poll for a transaction receipt, tolerating the node's "receipt not found"
204
+ * RPC error while the tx is still in the mempool. 60s default: a 4-node BFT
205
+ * mesh confirms contract calls in ~20-30s.
206
+ */
207
+ private pollReceipt;
208
+ private queryNumber;
209
+ private queryBigInt;
210
+ private queryAddress;
211
+ getStatus(capabilityId: string): Promise<number>;
212
+ getMaxSpend(capabilityId: string): Promise<bigint>;
213
+ getValidUntil(capabilityId: string): Promise<bigint>;
214
+ getTotalSpent(capabilityId: string): Promise<bigint>;
215
+ getActionCount(capabilityId: string): Promise<bigint>;
216
+ getCreatedAt(capabilityId: string): Promise<bigint>;
217
+ getRevokedAt(capabilityId: string): Promise<bigint>;
218
+ getPolicyVersion(capabilityId: string): Promise<bigint>;
219
+ getAttestationCount(capabilityId: string): Promise<bigint>;
220
+ getAllowlistEnabled(capabilityId: string): Promise<boolean>;
221
+ isCounterpartyAllowed(capabilityId: string, counterparty: string): Promise<boolean>;
222
+ /** Read a decision attestation's on-chain record (the tamper-evidence anchor). */
223
+ getAttestation(attestationId: string): Promise<AttestationRecord>;
224
+ /** Fetch the complete state of a capability in one call. */
225
+ getCapabilityState(capabilityId: string): Promise<CapabilityState>;
226
+ /** Principal mints a scoped capability to an agent. Signed by the principal. */
227
+ mintPermission(opts: {
228
+ signer: Signer;
229
+ capabilityId: string;
230
+ principal: string;
231
+ agent: string;
232
+ maxSpend: bigint;
233
+ validUntil: bigint;
234
+ allowlistEnabled?: boolean;
235
+ currentTime: bigint;
236
+ gasLimit?: number;
237
+ }): Promise<SubmitReceipt>;
238
+ /** Principal authorizes a counterparty for a capability's allowlist. */
239
+ addAllowedCounterparty(opts: {
240
+ signer: Signer;
241
+ capabilityId: string;
242
+ counterparty: string;
243
+ currentTime: bigint;
244
+ gasLimit?: number;
245
+ }): Promise<SubmitReceipt>;
246
+ /** Principal updates a capability's policy (limits) and bumps its on-chain version. */
247
+ updatePolicy(opts: {
248
+ signer: Signer;
249
+ capabilityId: string;
250
+ newMaxSpend: bigint;
251
+ newValidUntil: bigint;
252
+ currentTime: bigint;
253
+ gasLimit?: number;
254
+ }): Promise<SubmitReceipt>;
255
+ /**
256
+ * Agent records a capability-bound action — the substrate Policy Enforcement
257
+ * Point. Signed by the agent. `counterparty` is ignored when the capability's
258
+ * allowlist is disabled; when enabled, the substrate refuses (code 5) unless
259
+ * the counterparty has been allowlisted.
260
+ */
261
+ recordAction(opts: {
262
+ signer: Signer;
263
+ capabilityId: string;
264
+ amountSpent: bigint;
265
+ counterparty?: string;
266
+ currentTime: bigint;
267
+ gasLimit?: number;
268
+ }): Promise<SubmitReceipt>;
269
+ /** Principal revokes a capability. Terminal. Signed by the principal. */
270
+ revokePermission(opts: {
271
+ signer: Signer;
272
+ capabilityId: string;
273
+ currentTime: bigint;
274
+ gasLimit?: number;
275
+ }): Promise<SubmitReceipt>;
276
+ /**
277
+ * Agent records a decision attestation (provable-after). Commits the
278
+ * decision's context_hash + verdict, bound to the capability's current policy
279
+ * version. Signed by the agent.
280
+ */
281
+ recordAttestation(opts: {
282
+ signer: Signer;
283
+ attestationId: string;
284
+ capabilityId: string;
285
+ contextHash: string;
286
+ verdict: number;
287
+ currentTime: bigint;
288
+ gasLimit?: number;
289
+ }): Promise<SubmitReceipt>;
290
+ }
291
+ /**
292
+ * Parse an address return value from a contract query. The chain is uniformly
293
+ * 32-byte (PQC, witness v2); we normalize to 32 bytes and re-encode to om1z. A
294
+ * short hex value is zero-padded to 32 bytes (never 20) so a runtime returning
295
+ * the wrong width surfaces as a clearly-wrong address, not a silently-valid one.
296
+ */
297
+ declare function parseAddressReturn(returnValue: ContractQueryResult['returnValue']): string;
298
+
299
+ /**
300
+ * @cinchor/sdk — the high-level developer facade.
301
+ *
302
+ * Two verbs carry the product:
303
+ * - enforce(action) — authorize-or-refuse a consequential action. The
304
+ * substrate is the Policy Enforcement Point: an
305
+ * out-of-scope action commits no state change.
306
+ * - attest(decision) — commit a tamper-evident, independently-verifiable
307
+ * record of a decision and its context.
308
+ *
309
+ * Plus the capability lifecycle (mint / revoke / update / allow-counterparty)
310
+ * and the audit reads a relying party uses to verify without trusting you.
311
+ *
312
+ * The chain is the substrate, not the product: callers `import` this, wrap
313
+ * their agent's decision points, and never manage a blockchain.
314
+ */
315
+
316
+ /** Current UNIX time in seconds, as the bigint the contract expects. */
317
+ declare function nowSecs(): bigint;
318
+ interface MintCapabilityOptions {
319
+ /** The principal granting authority. Signs the mint. */
320
+ principal: Signer;
321
+ /** om1z address of the agent being granted scoped authority. */
322
+ agent: string;
323
+ /** Spend ceiling (in the unit the action amounts are denominated in). */
324
+ maxSpend: bigint;
325
+ /** Absolute expiry (UNIX seconds). Provide this OR `ttlSeconds`. */
326
+ validUntil?: bigint;
327
+ /** Relative expiry from now (seconds). Used when `validUntil` is omitted. */
328
+ ttlSeconds?: number;
329
+ /** Enforce a counterparty allowlist on every action under this capability. */
330
+ allowlist?: boolean;
331
+ /** Uniqueness nonce for the derived id. Defaults to a random value. */
332
+ nonce?: number;
333
+ /** Override the recorded creation time (UNIX seconds). Defaults to now. */
334
+ currentTime?: bigint;
335
+ gasLimit?: number;
336
+ }
337
+ interface MintCapabilityResult {
338
+ capabilityId: string;
339
+ receipt: SubmitReceipt;
340
+ }
341
+ interface EnforceOptions {
342
+ /** The capability id authorizing this action. */
343
+ capability: string;
344
+ /** The agent performing the action. Signs the record. */
345
+ agent: Signer;
346
+ /** Amount this action spends against the capability's ceiling. */
347
+ amount: bigint;
348
+ /** om1z counterparty the action transacts with (required if allowlisted). */
349
+ counterparty?: string;
350
+ /** Override the action time (UNIX seconds). Defaults to now. */
351
+ currentTime?: bigint;
352
+ gasLimit?: number;
353
+ }
354
+ interface AttestOptions {
355
+ /** The capability the decision was made under (binds the policy version). */
356
+ capability: string;
357
+ /** The agent attesting. Signs the attestation. */
358
+ agent: Signer;
359
+ /** The full decision context. Hashed canonically; the hash is committed. */
360
+ context: unknown;
361
+ /** Verdict committed alongside the context. Defaults to in-policy. */
362
+ verdict?: Verdict;
363
+ /** Sequence number disambiguating multiple attestations. Defaults to 0. */
364
+ seq?: number;
365
+ currentTime?: bigint;
366
+ gasLimit?: number;
367
+ }
368
+ interface AttestResult {
369
+ attestationId: string;
370
+ contextHash: string;
371
+ verdict: Verdict;
372
+ receipt: SubmitReceipt;
373
+ }
374
+ declare class CinchorClient {
375
+ readonly registry: CapabilityRegistry;
376
+ private constructor();
377
+ /** Connect to a network + deployed accountability contract. */
378
+ static connect(config: CinchorConfig): Promise<CinchorClient>;
379
+ /**
380
+ * Mint a cryptographically-scoped capability to an agent: capability, spend
381
+ * ceiling, validity window, revocable at will. Returns the derived capability
382
+ * id and the commit receipt.
383
+ */
384
+ mintCapability(opts: MintCapabilityOptions): Promise<MintCapabilityResult>;
385
+ /** Revoke a capability. Terminal. Signed by the principal. */
386
+ revoke(opts: {
387
+ capability: string;
388
+ principal: Signer;
389
+ currentTime?: bigint;
390
+ gasLimit?: number;
391
+ }): Promise<SubmitReceipt>;
392
+ /** Update a capability's policy (limits) and bump its on-chain version. */
393
+ updatePolicy(opts: {
394
+ capability: string;
395
+ principal: Signer;
396
+ maxSpend: bigint;
397
+ validUntil: bigint;
398
+ currentTime?: bigint;
399
+ gasLimit?: number;
400
+ }): Promise<SubmitReceipt>;
401
+ /** Authorize a counterparty for a capability's allowlist. */
402
+ allowCounterparty(opts: {
403
+ capability: string;
404
+ principal: Signer;
405
+ counterparty: string;
406
+ currentTime?: bigint;
407
+ gasLimit?: number;
408
+ }): Promise<SubmitReceipt>;
409
+ /**
410
+ * Authorize-or-refuse a consequential action. The substrate enforces the
411
+ * capability's invariants atomically: an out-of-scope action commits no state
412
+ * change. The verdict is read back from committed state (a record_action
413
+ * receipt does not carry the contract's return code).
414
+ *
415
+ * Verdict classification assumes serial, single-signer use of the capability
416
+ * (one in-flight action at a time) — the documented integration pattern.
417
+ */
418
+ enforce(opts: EnforceOptions): Promise<EnforcementOutcome>;
419
+ private classify;
420
+ /**
421
+ * Commit a tamper-evident attestation of a decision. The full context is
422
+ * hashed canonically; the hash + verdict are committed on-chain, bound to the
423
+ * capability's current policy version. An auditor later re-hashes the
424
+ * off-chain artifact and confirms it matches (see {@link verifyAttestation}).
425
+ */
426
+ attest(opts: AttestOptions): Promise<AttestResult>;
427
+ /** Read the full on-chain state of a capability. */
428
+ getCapability(capabilityId: string): Promise<CapabilityState>;
429
+ /** Read a decision attestation's on-chain record. */
430
+ getAttestation(attestationId: string): Promise<AttestationRecord>;
431
+ /**
432
+ * Tamper check: re-hash a decision context and confirm it matches the
433
+ * attestation's on-chain commitment. Returns whether it matches, the
434
+ * recomputed hash, and the on-chain record.
435
+ */
436
+ verifyAttestation(context: unknown, attestationId: string): Promise<{
437
+ ok: boolean;
438
+ recomputed: string;
439
+ onChain: AttestationRecord;
440
+ }>;
441
+ }
442
+
443
+ /**
444
+ * @cinchor/sdk — Omne address + identifier encoding.
445
+ *
446
+ * The Omne chain is uniformly 32-byte (post-quantum). On-chain addresses and
447
+ * contract map-key identifiers (capability ids, attestation ids) are bech32m
448
+ * encodings of a 32-byte payload under witness version 2. This module produces
449
+ * ABI arguments in that on-chain format and derives the deterministic ids the
450
+ * accountability contract keys its state by.
451
+ *
452
+ * Format: bech32m("om", [0x02, ...toWords(32-byte payload)]) → 62-char "om1z…"
453
+ */
454
+
455
+ /** Decode an om1z bech32m address to its raw 32-byte payload. */
456
+ declare function decodeAddress(address: string): Uint8Array;
457
+ /** Encode a raw 32-byte payload as canonical om1z bech32m. Rejects non-32-byte input. */
458
+ declare function encodeAddress(payload: Uint8Array): string;
459
+ /**
460
+ * Build an ABI `Address` argument from an om1z string. Uses the 32-byte payload
461
+ * directly — the substrate runtime accepts the Address discriminant + 32-byte
462
+ * payload because that matches the on-chain representation.
463
+ */
464
+ declare function addressArg(address: string): AbiArgument;
465
+ /**
466
+ * Derive a deterministic capability id from (principal, agent, nonce, createdAt).
467
+ * Returns a 32-byte om1z address matching the chain's uniform width, so it
468
+ * round-trips through the contract's address-typed map key.
469
+ */
470
+ declare function deriveCapabilityId(principal: string, agent: string, nonce: number, createdAt: number): Promise<string>;
471
+ /**
472
+ * Derive the per-(capability, counterparty) allowlist key the contract stores
473
+ * and checks. The contract is agnostic to the derivation — it only compares
474
+ * stored keys — so the SDK owns it; minting an allowed counterparty and
475
+ * enforcing an action MUST use the same derivation. Capability-scoped (the id
476
+ * is in the preimage) so there is no cross-capability collision.
477
+ */
478
+ declare function counterpartyKey(capabilityId: string, counterparty: string): Promise<string>;
479
+
480
+ /**
481
+ * @cinchor/sdk — decision attestation (provable-after).
482
+ *
483
+ * A decision attestation commits, on-chain, the HASH of a decision's full
484
+ * context (inputs the agent saw, policy version, model, reasoning, output) plus
485
+ * a verdict — bound to the policy version in force at decision time. The full
486
+ * artifact lives off-chain; the tamper-evidence property is that anyone can
487
+ * re-hash the off-chain artifact and confirm it matches the on-chain
488
+ * context_hash. If a byte changed, the hashes diverge and tampering is detected.
489
+ *
490
+ * This is what makes non-payment decisions (claims denials, underwriting calls)
491
+ * accountable: provable after the fact to a party who does not trust the operator.
492
+ */
493
+ /**
494
+ * Deterministic JSON: object keys sorted recursively so the same logical
495
+ * context always serializes to the same bytes (stable hashing across machines).
496
+ */
497
+ declare function canonicalJson(value: unknown): string;
498
+ /** Hash a decision-context object to a 32-byte om1z commitment. */
499
+ declare function hashDecisionContext(context: unknown): Promise<string>;
500
+ /**
501
+ * Derive a deterministic attestation id from (capabilityId, contextHash, seq).
502
+ * The contract enforces first-write, so reuse fails. Returns a 32-byte om1z id.
503
+ */
504
+ declare function deriveAttestationId(capabilityId: string, contextHash: string, seq: number): Promise<string>;
505
+ /**
506
+ * Tamper check: re-hash a decision context and confirm it matches the on-chain
507
+ * commitment. Returns whether it matches and the recomputed hash.
508
+ */
509
+ declare function verifyDecisionContext(context: unknown, onChainContextHash: string): Promise<{
510
+ ok: boolean;
511
+ recomputed: string;
512
+ }>;
513
+
514
+ export { type AttestOptions, type AttestResult, type AttestationRecord, BURN_SENTINEL, CAPABILITY_STATUS_LABELS, CapabilityRegistry, type CapabilityState, CapabilityStatus, type CapabilityStatusLabel, CinchorClient, type CinchorConfig, type ContractConfig, DEFAULT_GAS_LIMIT, DEFAULT_GAS_PRICE, ENFORCEMENT_LABELS, type EnforceOptions, EnforcementCode, type EnforcementLabel, type EnforcementOutcome, IGNIS_LOCAL, type MintCapabilityOptions, type MintCapabilityResult, type NetworkConfig, type Signer, type SubmitReceipt, Verdict, addressArg, canonicalJson, counterpartyKey, decodeAddress, deriveAttestationId, deriveCapabilityId, encodeAddress, exportPrefixFor, hashDecisionContext, nowSecs, parseAddressReturn, verifyDecisionContext };