@kynesyslabs/demosdk 4.0.11 → 4.0.13
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/build/abstraction/Identities.js +10 -2
- package/build/abstraction/Identities.js.map +1 -1
- package/build/l2ps/channel/finalize.d.ts +63 -0
- package/build/l2ps/channel/finalize.js +85 -0
- package/build/l2ps/channel/finalize.js.map +1 -0
- package/build/l2ps/channel/index.d.ts +3 -0
- package/build/l2ps/channel/index.js +3 -0
- package/build/l2ps/channel/index.js.map +1 -1
- package/build/l2ps/channel/negotiate.d.ts +106 -0
- package/build/l2ps/channel/negotiate.js +206 -0
- package/build/l2ps/channel/negotiate.js.map +1 -0
- package/build/l2ps/channel/transport.d.ts +117 -0
- package/build/l2ps/channel/transport.js +178 -0
- package/build/l2ps/channel/transport.js.map +1 -0
- package/build/websdk/BroadcastFailedError.js.map +1 -1
- package/build/websdk/DemosTransactions.d.ts +2 -2
- package/build/websdk/DemosTransactions.js +3 -3
- package/build/websdk/TransportError.js.map +1 -1
- package/build/websdk/demosclass.d.ts +81 -1
- package/build/websdk/demosclass.js +84 -1
- package/build/websdk/demosclass.js.map +1 -1
- package/build/websdk/index.d.ts +1 -0
- package/build/websdk/index.js +3 -0
- package/build/websdk/index.js.map +1 -1
- package/build/websdk/programmatic/ProgrammaticTx.d.ts +118 -0
- package/build/websdk/programmatic/ProgrammaticTx.js +56 -0
- package/build/websdk/programmatic/ProgrammaticTx.js.map +1 -0
- package/build/websdk/programmatic/attest.d.ts +396 -0
- package/build/websdk/programmatic/attest.js +398 -0
- package/build/websdk/programmatic/attest.js.map +1 -0
- package/build/websdk/programmatic/bridge.d.ts +36 -0
- package/build/websdk/programmatic/bridge.js +37 -0
- package/build/websdk/programmatic/bridge.js.map +1 -0
- package/build/websdk/programmatic/context.d.ts +26 -0
- package/build/websdk/programmatic/context.js +9 -0
- package/build/websdk/programmatic/context.js.map +1 -0
- package/build/websdk/programmatic/contracts.d.ts +79 -0
- package/build/websdk/programmatic/contracts.js +81 -0
- package/build/websdk/programmatic/contracts.js.map +1 -0
- package/build/websdk/programmatic/d402.d.ts +33 -0
- package/build/websdk/programmatic/d402.js +35 -0
- package/build/websdk/programmatic/d402.js.map +1 -0
- package/build/websdk/programmatic/demoswork.d.ts +37 -0
- package/build/websdk/programmatic/demoswork.js +38 -0
- package/build/websdk/programmatic/demoswork.js.map +1 -0
- package/build/websdk/programmatic/errors.d.ts +20 -0
- package/build/websdk/programmatic/errors.js +24 -0
- package/build/websdk/programmatic/errors.js.map +1 -0
- package/build/websdk/programmatic/escrow.d.ts +75 -0
- package/build/websdk/programmatic/escrow.js +74 -0
- package/build/websdk/programmatic/escrow.js.map +1 -0
- package/build/websdk/programmatic/governance.d.ts +59 -0
- package/build/websdk/programmatic/governance.js +44 -0
- package/build/websdk/programmatic/governance.js.map +1 -0
- package/build/websdk/programmatic/index.d.ts +30 -0
- package/build/websdk/programmatic/index.js +31 -0
- package/build/websdk/programmatic/index.js.map +1 -0
- package/build/websdk/programmatic/ipfs.d.ts +74 -0
- package/build/websdk/programmatic/ipfs.js +103 -0
- package/build/websdk/programmatic/ipfs.js.map +1 -0
- package/build/websdk/programmatic/pay.d.ts +36 -0
- package/build/websdk/programmatic/pay.js +37 -0
- package/build/websdk/programmatic/pay.js.map +1 -0
- package/build/websdk/programmatic/runner.d.ts +30 -0
- package/build/websdk/programmatic/runner.js +186 -0
- package/build/websdk/programmatic/runner.js.map +1 -0
- package/build/websdk/programmatic/storage.d.ts +49 -0
- package/build/websdk/programmatic/storage.js +49 -0
- package/build/websdk/programmatic/storage.js.map +1 -0
- package/build/websdk/programmatic/tokens.d.ts +155 -0
- package/build/websdk/programmatic/tokens.js +157 -0
- package/build/websdk/programmatic/tokens.js.map +1 -0
- package/build/websdk/programmatic/types.d.ts +95 -0
- package/build/websdk/programmatic/types.js +8 -0
- package/build/websdk/programmatic/types.js.map +1 -0
- package/build/websdk/programmatic/validator.d.ts +63 -0
- package/build/websdk/programmatic/validator.js +64 -0
- package/build/websdk/programmatic/validator.js.map +1 -0
- package/build/websdk/programmatic/xm.d.ts +36 -0
- package/build/websdk/programmatic/xm.js +37 -0
- package/build/websdk/programmatic/xm.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"negotiate.js","sourceRoot":"","sources":["../../../../src/l2ps/channel/negotiate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SR-4 WI-A — Channel-over-L2PS transport adapter.
|
|
3
|
+
*
|
|
4
|
+
* The DACS channel layer (`ChannelSession`) is transport-agnostic: it
|
|
5
|
+
* produces signed `ChannelMessage` envelopes and verifies incoming ones,
|
|
6
|
+
* but does not move bytes. The L2PS instant-messaging layer
|
|
7
|
+
* (`L2PSMessagingPeer`) moves encrypted bytes between subnet members but
|
|
8
|
+
* knows nothing about channel envelopes. This adapter bridges the two:
|
|
9
|
+
* it serialises + encrypts an outgoing envelope onto the messaging
|
|
10
|
+
* transport, and on the receive side decrypts, deserialises, and feeds
|
|
11
|
+
* envelopes into the session **in strict sequence order**.
|
|
12
|
+
*
|
|
13
|
+
* Why a reorder buffer is mandatory:
|
|
14
|
+
* `ChannelSession.receiveIncoming` accepts any sequence strictly greater
|
|
15
|
+
* than the highest it has seen and then advances its counter to that
|
|
16
|
+
* value — so a *gap* (seq N+2 arriving before N+1) is not rejected, it
|
|
17
|
+
* permanently skips the missing messages. The L2PS transport delivers by
|
|
18
|
+
* timestamp and replays an offline queue, so out-of-order arrival is
|
|
19
|
+
* normal. This adapter therefore only hands the session the next
|
|
20
|
+
* contiguous sequence and buffers anything ahead of the gap until it
|
|
21
|
+
* fills.
|
|
22
|
+
*
|
|
23
|
+
* Scope / assumptions:
|
|
24
|
+
* - The shared per-channel sequence counter assumes turn-based messaging
|
|
25
|
+
* (DACS negotiation is offer → counter → accept; a party waits for the
|
|
26
|
+
* counter before replying). Two parties emitting the same sequence
|
|
27
|
+
* concurrently is out of scope for SR-4 v1; such a colliding inbound
|
|
28
|
+
* message (seq <= already-applied) is dropped as a duplicate.
|
|
29
|
+
* - Membership is the channel's `members`; the transport sends to every
|
|
30
|
+
* member except self. Confidentiality is the subnet AES key (only
|
|
31
|
+
* members hold it) — CH-2.
|
|
32
|
+
*/
|
|
33
|
+
import type { ChannelMessage, ChannelMessageType } from "./types";
|
|
34
|
+
/**
|
|
35
|
+
* Minimal surface of `ChannelSession` the adapter depends on. Declared
|
|
36
|
+
* structurally so tests can inject a fake without real signing keys.
|
|
37
|
+
*/
|
|
38
|
+
export interface ChannelSessionLike {
|
|
39
|
+
readonly channelId: string;
|
|
40
|
+
sendOutgoing(opts: {
|
|
41
|
+
type: ChannelMessageType;
|
|
42
|
+
body: unknown;
|
|
43
|
+
sentAt?: number;
|
|
44
|
+
repliesTo?: number;
|
|
45
|
+
}): Promise<ChannelMessage>;
|
|
46
|
+
receiveIncoming(msg: ChannelMessage): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
/** Wire shape the L2PS messaging transport carries (ciphertext + nonce, base64). */
|
|
49
|
+
export interface SerializedEncryptedMessage {
|
|
50
|
+
ciphertext: string;
|
|
51
|
+
nonce: string;
|
|
52
|
+
ephemeralKey?: string;
|
|
53
|
+
}
|
|
54
|
+
/** Incoming payload the messaging peer hands to an onMessage handler. */
|
|
55
|
+
export interface IncomingMessagePayload {
|
|
56
|
+
from: string;
|
|
57
|
+
encrypted: SerializedEncryptedMessage;
|
|
58
|
+
messageHash: string;
|
|
59
|
+
offline?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Minimal surface of `L2PSMessagingPeer` the adapter depends on.
|
|
63
|
+
* Declared structurally for the same reason as `ChannelSessionLike`.
|
|
64
|
+
*/
|
|
65
|
+
export interface L2PSMessagingPeerLike {
|
|
66
|
+
send(to: string, encrypted: SerializedEncryptedMessage, messageHash: string): Promise<unknown>;
|
|
67
|
+
onMessage(handler: (payload: IncomingMessagePayload) => void): void;
|
|
68
|
+
}
|
|
69
|
+
export interface L2PSChannelTransportOpts {
|
|
70
|
+
session: ChannelSessionLike;
|
|
71
|
+
peer: L2PSMessagingPeerLike;
|
|
72
|
+
/** Subnet AES-256 key (raw 32 bytes) — only members hold it (CH-2). */
|
|
73
|
+
sharedKey: Uint8Array;
|
|
74
|
+
/**
|
|
75
|
+
* Recipient public keys to deliver to (every channel member except
|
|
76
|
+
* self), in the format the messaging peer routes on.
|
|
77
|
+
*/
|
|
78
|
+
recipients: string[];
|
|
79
|
+
/** Called with each envelope once it has been applied in order. */
|
|
80
|
+
onMessage?: (msg: ChannelMessage) => void;
|
|
81
|
+
/** Called on a decrypt / parse / verification failure. */
|
|
82
|
+
onError?: (err: Error) => void;
|
|
83
|
+
}
|
|
84
|
+
export declare class L2PSChannelTransport {
|
|
85
|
+
private readonly session;
|
|
86
|
+
private readonly peer;
|
|
87
|
+
private readonly sharedKey;
|
|
88
|
+
private readonly recipients;
|
|
89
|
+
private readonly onMessage?;
|
|
90
|
+
private readonly onError?;
|
|
91
|
+
/** Sequences seen ahead of the gap, awaiting contiguous application. */
|
|
92
|
+
private readonly buffer;
|
|
93
|
+
/** Highest contiguous sequence applied locally (sent or received). */
|
|
94
|
+
private appliedSeq;
|
|
95
|
+
/** Serialises drain() so concurrent inbound frames can't interleave. */
|
|
96
|
+
private draining;
|
|
97
|
+
private started;
|
|
98
|
+
constructor(opts: L2PSChannelTransportOpts);
|
|
99
|
+
/** Wire the peer's inbound handler. Call once. */
|
|
100
|
+
start(): void;
|
|
101
|
+
/**
|
|
102
|
+
* Build + sign the next outgoing envelope via the session, encrypt
|
|
103
|
+
* it under the subnet key, and deliver to every recipient.
|
|
104
|
+
*/
|
|
105
|
+
send(opts: {
|
|
106
|
+
type: ChannelMessageType;
|
|
107
|
+
body: unknown;
|
|
108
|
+
repliesTo?: number;
|
|
109
|
+
}): Promise<ChannelMessage>;
|
|
110
|
+
private ingest;
|
|
111
|
+
/** Apply every buffered message that is now contiguous with appliedSeq. */
|
|
112
|
+
private drain;
|
|
113
|
+
/** Count of out-of-order messages currently held awaiting the gap. */
|
|
114
|
+
get bufferedCount(): number;
|
|
115
|
+
private encrypt;
|
|
116
|
+
private decrypt;
|
|
117
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SR-4 WI-A — Channel-over-L2PS transport adapter.
|
|
3
|
+
*
|
|
4
|
+
* The DACS channel layer (`ChannelSession`) is transport-agnostic: it
|
|
5
|
+
* produces signed `ChannelMessage` envelopes and verifies incoming ones,
|
|
6
|
+
* but does not move bytes. The L2PS instant-messaging layer
|
|
7
|
+
* (`L2PSMessagingPeer`) moves encrypted bytes between subnet members but
|
|
8
|
+
* knows nothing about channel envelopes. This adapter bridges the two:
|
|
9
|
+
* it serialises + encrypts an outgoing envelope onto the messaging
|
|
10
|
+
* transport, and on the receive side decrypts, deserialises, and feeds
|
|
11
|
+
* envelopes into the session **in strict sequence order**.
|
|
12
|
+
*
|
|
13
|
+
* Why a reorder buffer is mandatory:
|
|
14
|
+
* `ChannelSession.receiveIncoming` accepts any sequence strictly greater
|
|
15
|
+
* than the highest it has seen and then advances its counter to that
|
|
16
|
+
* value — so a *gap* (seq N+2 arriving before N+1) is not rejected, it
|
|
17
|
+
* permanently skips the missing messages. The L2PS transport delivers by
|
|
18
|
+
* timestamp and replays an offline queue, so out-of-order arrival is
|
|
19
|
+
* normal. This adapter therefore only hands the session the next
|
|
20
|
+
* contiguous sequence and buffers anything ahead of the gap until it
|
|
21
|
+
* fills.
|
|
22
|
+
*
|
|
23
|
+
* Scope / assumptions:
|
|
24
|
+
* - The shared per-channel sequence counter assumes turn-based messaging
|
|
25
|
+
* (DACS negotiation is offer → counter → accept; a party waits for the
|
|
26
|
+
* counter before replying). Two parties emitting the same sequence
|
|
27
|
+
* concurrently is out of scope for SR-4 v1; such a colliding inbound
|
|
28
|
+
* message (seq <= already-applied) is dropped as a duplicate.
|
|
29
|
+
* - Membership is the channel's `members`; the transport sends to every
|
|
30
|
+
* member except self. Confidentiality is the subnet AES key (only
|
|
31
|
+
* members hold it) — CH-2.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Max number of sequences a buffered inbound frame may sit ahead of the
|
|
35
|
+
* current contiguous point before it is dropped, bounding reorder-buffer
|
|
36
|
+
* memory. Turn-based negotiation never legitimately exceeds this.
|
|
37
|
+
*/
|
|
38
|
+
const MAX_REORDER_AHEAD = 256;
|
|
39
|
+
export class L2PSChannelTransport {
|
|
40
|
+
constructor(opts) {
|
|
41
|
+
/** Sequences seen ahead of the gap, awaiting contiguous application. */
|
|
42
|
+
this.buffer = new Map();
|
|
43
|
+
/** Highest contiguous sequence applied locally (sent or received). */
|
|
44
|
+
this.appliedSeq = 0;
|
|
45
|
+
/** Serialises drain() so concurrent inbound frames can't interleave. */
|
|
46
|
+
this.draining = Promise.resolve();
|
|
47
|
+
this.started = false;
|
|
48
|
+
this.session = opts.session;
|
|
49
|
+
this.peer = opts.peer;
|
|
50
|
+
this.sharedKey = opts.sharedKey;
|
|
51
|
+
this.recipients = opts.recipients;
|
|
52
|
+
this.onMessage = opts.onMessage;
|
|
53
|
+
this.onError = opts.onError;
|
|
54
|
+
}
|
|
55
|
+
/** Wire the peer's inbound handler. Call once. */
|
|
56
|
+
start() {
|
|
57
|
+
if (this.started)
|
|
58
|
+
throw new Error("L2PSChannelTransport: already started");
|
|
59
|
+
this.started = true;
|
|
60
|
+
this.peer.onMessage(payload => {
|
|
61
|
+
// Chain onto `draining` so frames are processed one at a time
|
|
62
|
+
// in arrival order; each appends to the buffer then drains.
|
|
63
|
+
this.draining = this.draining
|
|
64
|
+
.then(() => this.ingest(payload))
|
|
65
|
+
.catch(err => this.onError?.(err));
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Build + sign the next outgoing envelope via the session, encrypt
|
|
70
|
+
* it under the subnet key, and deliver to every recipient.
|
|
71
|
+
*/
|
|
72
|
+
async send(opts) {
|
|
73
|
+
const signed = await this.session.sendOutgoing(opts);
|
|
74
|
+
const encrypted = await this.encrypt(JSON.stringify(signed));
|
|
75
|
+
const messageHash = signed.signature.signature; // unique per signed envelope
|
|
76
|
+
// Deliver to every recipient BEFORE committing the sequence locally.
|
|
77
|
+
// If any send rejects, the throw propagates here and appliedSeq is
|
|
78
|
+
// left untouched, so a retry re-emits the same sequence rather than
|
|
79
|
+
// skipping ahead and stranding peers behind a reorder gap. (Recipients
|
|
80
|
+
// that did receive it will drop the duplicate on resend — seq <=
|
|
81
|
+
// appliedSeq — so at-least-once delivery is safe.)
|
|
82
|
+
for (const to of this.recipients) {
|
|
83
|
+
await this.peer.send(to, encrypted, messageHash);
|
|
84
|
+
}
|
|
85
|
+
// Our own send advances the shared per-channel counter; record it
|
|
86
|
+
// so we expect the peer's reply at appliedSeq + 1.
|
|
87
|
+
if (signed.sequence > this.appliedSeq)
|
|
88
|
+
this.appliedSeq = signed.sequence;
|
|
89
|
+
return signed;
|
|
90
|
+
}
|
|
91
|
+
async ingest(payload) {
|
|
92
|
+
let msg;
|
|
93
|
+
try {
|
|
94
|
+
const json = await this.decrypt(payload.encrypted);
|
|
95
|
+
msg = JSON.parse(json);
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
throw new Error(`L2PSChannelTransport: failed to decrypt/parse inbound frame from ${payload.from}: ${e.message}`);
|
|
99
|
+
}
|
|
100
|
+
// Ignore traffic for other channels sharing the same subnet.
|
|
101
|
+
if (msg.channelId !== this.session.channelId)
|
|
102
|
+
return;
|
|
103
|
+
// Duplicate / already-applied (or a colliding concurrent send): drop.
|
|
104
|
+
if (msg.sequence <= this.appliedSeq)
|
|
105
|
+
return;
|
|
106
|
+
// Bound the reorder window: a member could otherwise stream many
|
|
107
|
+
// validly-encrypted frames at far-future sequences without ever
|
|
108
|
+
// filling the gap, growing `buffer` without limit. Drop anything
|
|
109
|
+
// beyond MAX_REORDER_AHEAD of the current contiguous point — a
|
|
110
|
+
// legitimate turn-based negotiation never runs that far ahead, and
|
|
111
|
+
// a dropped frame is re-deliverable (the offline queue replays it
|
|
112
|
+
// once the gap closes and appliedSeq advances).
|
|
113
|
+
if (msg.sequence > this.appliedSeq + MAX_REORDER_AHEAD) {
|
|
114
|
+
this.onError?.(new Error(`L2PSChannelTransport: dropping seq ${msg.sequence} — ` +
|
|
115
|
+
`more than ${MAX_REORDER_AHEAD} ahead of applied ${this.appliedSeq}`));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// Buffer; a later sequence with the same value would be a protocol
|
|
119
|
+
// error — keep the first seen.
|
|
120
|
+
if (!this.buffer.has(msg.sequence))
|
|
121
|
+
this.buffer.set(msg.sequence, msg);
|
|
122
|
+
await this.drain();
|
|
123
|
+
}
|
|
124
|
+
/** Apply every buffered message that is now contiguous with appliedSeq. */
|
|
125
|
+
async drain() {
|
|
126
|
+
// Sequence counter is shared across both directions, so the next
|
|
127
|
+
// expected inbound is appliedSeq + 1.
|
|
128
|
+
let next = this.buffer.get(this.appliedSeq + 1);
|
|
129
|
+
while (next) {
|
|
130
|
+
this.buffer.delete(next.sequence);
|
|
131
|
+
// Throws on tamper (bad signature, wrong sender, channelId
|
|
132
|
+
// mismatch) — propagate as channel-fatal per §8.12.
|
|
133
|
+
await this.session.receiveIncoming(next);
|
|
134
|
+
this.appliedSeq = next.sequence;
|
|
135
|
+
this.onMessage?.(next);
|
|
136
|
+
next = this.buffer.get(this.appliedSeq + 1);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/** Count of out-of-order messages currently held awaiting the gap. */
|
|
140
|
+
get bufferedCount() {
|
|
141
|
+
return this.buffer.size;
|
|
142
|
+
}
|
|
143
|
+
// ── AES-256-GCM (Web Crypto) — matches the messaging wire format:
|
|
144
|
+
// ciphertext (with auth tag) + 12-byte nonce, both base64. ──
|
|
145
|
+
async encrypt(plaintext) {
|
|
146
|
+
const nonce = crypto.getRandomValues(new Uint8Array(12));
|
|
147
|
+
const key = await crypto.subtle.importKey("raw", keyBytes(this.sharedKey), "AES-GCM", false, ["encrypt"]);
|
|
148
|
+
const cipher = await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce }, key, new TextEncoder().encode(plaintext));
|
|
149
|
+
return {
|
|
150
|
+
ciphertext: bytesToBase64(new Uint8Array(cipher)),
|
|
151
|
+
nonce: bytesToBase64(nonce),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
async decrypt(enc) {
|
|
155
|
+
const key = await crypto.subtle.importKey("raw", keyBytes(this.sharedKey), "AES-GCM", false, ["decrypt"]);
|
|
156
|
+
const plain = await crypto.subtle.decrypt({ name: "AES-GCM", iv: base64ToBytes(enc.nonce) }, key, base64ToBytes(enc.ciphertext));
|
|
157
|
+
return new TextDecoder().decode(plain);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Return a standalone `ArrayBuffer` holding exactly the bytes of `view`.
|
|
162
|
+
* `view.buffer` exposes the whole backing buffer, which for a `subarray`
|
|
163
|
+
* (e.g. a 32-byte key sliced out of a larger buffer) is longer than the
|
|
164
|
+
* view — Web Crypto would then see the wrong length / wrong bytes and
|
|
165
|
+
* reject or mis-key the AES import. Copying the exact `[byteOffset,
|
|
166
|
+
* byteOffset+byteLength)` window guarantees the key import sees only the
|
|
167
|
+
* intended bytes.
|
|
168
|
+
*/
|
|
169
|
+
function keyBytes(view) {
|
|
170
|
+
return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);
|
|
171
|
+
}
|
|
172
|
+
function bytesToBase64(bytes) {
|
|
173
|
+
return Buffer.from(bytes).toString("base64");
|
|
174
|
+
}
|
|
175
|
+
function base64ToBytes(b64) {
|
|
176
|
+
return new Uint8Array(Buffer.from(b64, "base64"));
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../src/l2ps/channel/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAIH;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,GAAG,CAAA;AA6D7B,MAAM,OAAO,oBAAoB;IAgB7B,YAAY,IAA8B;QAR1C,wEAAwE;QACvD,WAAM,GAAG,IAAI,GAAG,EAA0B,CAAA;QAC3D,sEAAsE;QAC9D,eAAU,GAAG,CAAC,CAAA;QACtB,wEAAwE;QAChE,aAAQ,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAA;QAC3C,YAAO,GAAG,KAAK,CAAA;QAGnB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACrB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;QAC/B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAA;QACjC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;QAC/B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;IAC/B,CAAC;IAED,kDAAkD;IAClD,KAAK;QACD,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;QAC1E,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;YAC1B,8DAA8D;YAC9D,4DAA4D;YAC5D,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ;iBACxB,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;iBAChC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAY,CAAC,CAAC,CAAA;QACnD,CAAC,CAAC,CAAA;IACN,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI,CAAC,IAIV;QACG,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;QAEpD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAA;QAC5D,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,SAAS,CAAA,CAAC,6BAA6B;QAC5E,qEAAqE;QACrE,mEAAmE;QACnE,oEAAoE;QACpE,uEAAuE;QACvE,iEAAiE;QACjE,mDAAmD;QACnD,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC/B,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,WAAW,CAAC,CAAA;QACpD,CAAC;QAED,kEAAkE;QAClE,mDAAmD;QACnD,IAAI,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU;YAAE,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAA;QACxE,OAAO,MAAM,CAAA;IACjB,CAAC;IAEO,KAAK,CAAC,MAAM,CAAC,OAA+B;QAChD,IAAI,GAAmB,CAAA;QACvB,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;YAClD,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAmB,CAAA;QAC5C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACX,oEAAoE,OAAO,CAAC,IAAI,KAC3E,CAAW,CAAC,OACjB,EAAE,CACL,CAAA;QACL,CAAC;QAED,6DAA6D;QAC7D,IAAI,GAAG,CAAC,SAAS,KAAK,IAAI,CAAC,OAAO,CAAC,SAAS;YAAE,OAAM;QACpD,sEAAsE;QACtE,IAAI,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,UAAU;YAAE,OAAM;QAC3C,iEAAiE;QACjE,gEAAgE;QAChE,iEAAiE;QACjE,+DAA+D;QAC/D,mEAAmE;QACnE,kEAAkE;QAClE,gDAAgD;QAChD,IAAI,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,GAAG,iBAAiB,EAAE,CAAC;YACrD,IAAI,CAAC,OAAO,EAAE,CACV,IAAI,KAAK,CACL,sCAAsC,GAAG,CAAC,QAAQ,KAAK;gBACnD,aAAa,iBAAiB,qBAAqB,IAAI,CAAC,UAAU,EAAE,CAC3E,CACJ,CAAA;YACD,OAAM;QACV,CAAC;QACD,mEAAmE;QACnE,+BAA+B;QAC/B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;QAEtE,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;IACtB,CAAC;IAED,2EAA2E;IACnE,KAAK,CAAC,KAAK;QACf,iEAAiE;QACjE,sCAAsC;QACtC,IAAI,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAA;QAC/C,OAAO,IAAI,EAAE,CAAC;YACV,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACjC,2DAA2D;YAC3D,oDAAoD;YACpD,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;YACxC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAA;YAC/B,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,CAAA;YACtB,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAA;QAC/C,CAAC;IACL,CAAC;IAED,sEAAsE;IACtE,IAAI,aAAa;QACb,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAA;IAC3B,CAAC;IAED,mEAAmE;IACnE,iEAAiE;IAEzD,KAAK,CAAC,OAAO,CAAC,SAAiB;QACnC,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAA;QACxD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CACrC,KAAK,EACL,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EACxB,SAAS,EACT,KAAK,EACL,CAAC,SAAS,CAAC,CACd,CAAA;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CACtC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,EAC9B,GAAG,EACH,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CACtC,CAAA;QACD,OAAO;YACH,UAAU,EAAE,aAAa,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;YACjD,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC;SAC9B,CAAA;IACL,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,GAA+B;QACjD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CACrC,KAAK,EACL,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EACxB,SAAS,EACT,KAAK,EACL,CAAC,SAAS,CAAC,CACd,CAAA;QACD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CACrC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,aAAa,CAAC,GAAG,CAAC,KAAK,CAAiB,EAAE,EACjE,GAAG,EACH,aAAa,CAAC,GAAG,CAAC,UAAU,CAAiB,CAChD,CAAA;QACD,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC1C,CAAC;CACJ;AAED;;;;;;;;GAQG;AACH,SAAS,QAAQ,CAAC,IAAgB;IAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CACpB,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CACrB,CAAA;AACpB,CAAC;AAED,SAAS,aAAa,CAAC,KAAiB;IACpC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;AAChD,CAAC;AAED,SAAS,aAAa,CAAC,GAAW;IAC9B,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAA;AACrD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BroadcastFailedError.js","sourceRoot":"","sources":["../../../src/websdk/BroadcastFailedError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;
|
|
1
|
+
{"version":3,"file":"BroadcastFailedError.js","sourceRoot":"","sources":["../../../src/websdk/BroadcastFailedError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAM3C,YAAY,IAA0D;QAClE,MAAM,YAAY,GACb,IAAI,CAAC,KAAa,EAAE,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,CAAA;QACnE,KAAK,CACD,IAAI,CAAC,OAAO;YACR,iEAAiE,IAAI,CAAC,MAAM,MAAM,YAAY,EAAE,CACvG,CAAA;QACD,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAA;QAClC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;IAC3B,CAAC;CACJ"}
|
|
@@ -98,7 +98,7 @@ export declare const DemosTransactions: {
|
|
|
98
98
|
* Broadcast a confirmed transaction and wait for inclusion.
|
|
99
99
|
*
|
|
100
100
|
* Polls the node's `getTransactionStatus` RPC until the tx is observed
|
|
101
|
-
* `included` or `failed`, or until `opts.timeoutMs` elapses (default
|
|
101
|
+
* `included` or `failed`, or until `opts.timeoutMs` elapses (default 60s).
|
|
102
102
|
*
|
|
103
103
|
* Use this when you want a single call with a deterministic outcome.
|
|
104
104
|
* Use plain `broadcast()` when you want to handle async confirmation
|
|
@@ -117,7 +117,7 @@ export declare const DemosTransactions: {
|
|
|
117
117
|
*
|
|
118
118
|
* @param validationData - The validity data of the transaction (from `confirm`)
|
|
119
119
|
* @param demos - The demos instance
|
|
120
|
-
* @param opts.timeoutMs - Total time to wait for inclusion. Defaults to
|
|
120
|
+
* @param opts.timeoutMs - Total time to wait for inclusion. Defaults to 60_000.
|
|
121
121
|
* @param opts.pollIntervalMs - Delay between status polls. Defaults to 500.
|
|
122
122
|
* @param opts.failFastOnBroadcastError - If true, throw `BroadcastFailedError`
|
|
123
123
|
* immediately when the broadcast can't contact the node. Defaults to false.
|
|
@@ -271,7 +271,7 @@ export const DemosTransactions = {
|
|
|
271
271
|
* Broadcast a confirmed transaction and wait for inclusion.
|
|
272
272
|
*
|
|
273
273
|
* Polls the node's `getTransactionStatus` RPC until the tx is observed
|
|
274
|
-
* `included` or `failed`, or until `opts.timeoutMs` elapses (default
|
|
274
|
+
* `included` or `failed`, or until `opts.timeoutMs` elapses (default 60s).
|
|
275
275
|
*
|
|
276
276
|
* Use this when you want a single call with a deterministic outcome.
|
|
277
277
|
* Use plain `broadcast()` when you want to handle async confirmation
|
|
@@ -290,7 +290,7 @@ export const DemosTransactions = {
|
|
|
290
290
|
*
|
|
291
291
|
* @param validationData - The validity data of the transaction (from `confirm`)
|
|
292
292
|
* @param demos - The demos instance
|
|
293
|
-
* @param opts.timeoutMs - Total time to wait for inclusion. Defaults to
|
|
293
|
+
* @param opts.timeoutMs - Total time to wait for inclusion. Defaults to 60_000.
|
|
294
294
|
* @param opts.pollIntervalMs - Delay between status polls. Defaults to 500.
|
|
295
295
|
* @param opts.failFastOnBroadcastError - If true, throw `BroadcastFailedError`
|
|
296
296
|
* immediately when the broadcast can't contact the node. Defaults to false.
|
|
@@ -298,7 +298,7 @@ export const DemosTransactions = {
|
|
|
298
298
|
* @returns The original broadcast response and the terminal status.
|
|
299
299
|
*/
|
|
300
300
|
broadcastAndWait: async function (validationData, demos, opts) {
|
|
301
|
-
const timeout = opts?.timeoutMs ??
|
|
301
|
+
const timeout = opts?.timeoutMs ?? 60000;
|
|
302
302
|
const pollInterval = opts?.pollIntervalMs ?? 500;
|
|
303
303
|
const failFast = opts?.failFastOnBroadcastError ?? false;
|
|
304
304
|
// Extract the tx hash from the validity data before broadcasting so
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransportError.js","sourceRoot":"","sources":["../../../src/websdk/TransportError.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,OAAO,cAAe,SAAQ,KAAK;
|
|
1
|
+
{"version":3,"file":"TransportError.js","sourceRoot":"","sources":["../../../src/websdk/TransportError.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,OAAO,cAAe,SAAQ,KAAK;IAMrC,YAAY,OAAe,EAAE,IAA0C;QACnE,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAA;QAC5B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAA;QAC7B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;IAC3B,CAAC;CACJ"}
|
|
@@ -7,6 +7,7 @@ import type { ValidatorInfo } from "../types/validator/ValidatorTypes";
|
|
|
7
7
|
import type { NetworkParameters, NetworkUpgradeProposal, ProposalVoteInfo } from "../types/blockchain/NetworkParameters";
|
|
8
8
|
import { RPCRequest, RPCResponse, RPCResponseWithValidityData } from "../types/communication/rpc";
|
|
9
9
|
import { IKeyPair } from "./types/KeyPair";
|
|
10
|
+
import { type ProgrammaticTx } from "./programmatic";
|
|
10
11
|
import { UnifiedCrypto } from "../encryption/unifiedCrypto";
|
|
11
12
|
import { type NetworkInfo } from "../denomination/networkInfo";
|
|
12
13
|
import { TweetSimplified } from "../types";
|
|
@@ -67,6 +68,50 @@ export declare class Demos {
|
|
|
67
68
|
* @returns Whether the connection was successful
|
|
68
69
|
*/
|
|
69
70
|
connect(rpc_url: string): Promise<boolean>;
|
|
71
|
+
/**
|
|
72
|
+
* One-call bootstrap: connect to a node and (optionally) a wallet, then
|
|
73
|
+
* return the ready instance for immediate use with `demos.run.*`.
|
|
74
|
+
*
|
|
75
|
+
* Convenience wrapper over {@link connect} + {@link connectWallet} — no
|
|
76
|
+
* new behaviour, just the two-step setup collapsed into one. Omit
|
|
77
|
+
* `wallet` to connect read-only.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* import { Demos } from "@kynesyslabs/demosdk/websdk"
|
|
82
|
+
* const demos = await Demos.start("https://node2.demos.sh", mnemonic)
|
|
83
|
+
* await demos.run.pay("0x...", 100n)
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @param rpc_url - The URL of the demos node.
|
|
87
|
+
* @param wallet - Master seed / mnemonic (string) or raw seed bytes.
|
|
88
|
+
* Omit to connect without a wallet.
|
|
89
|
+
* @param walletOptions - Forwarded to {@link connectWallet}.
|
|
90
|
+
* @returns This connected Demos instance.
|
|
91
|
+
*/
|
|
92
|
+
start(rpc_url: string, wallet?: string | Uint8Array, walletOptions?: {
|
|
93
|
+
algorithm?: SigningAlgorithm;
|
|
94
|
+
dual_sign?: boolean;
|
|
95
|
+
}): Promise<this>;
|
|
96
|
+
/**
|
|
97
|
+
* Static one-call bootstrap over the shared singleton — starts
|
|
98
|
+
* {@link Demos.instance} and returns it ready for `demos.run.*`.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* const demos = await Demos.start("https://node2.demos.sh", mnemonic)
|
|
103
|
+
* await demos.run.pay("0x...", 100n)
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @param rpc_url - The URL of the demos node.
|
|
107
|
+
* @param wallet - Master seed / mnemonic (string) or raw seed bytes.
|
|
108
|
+
* @param walletOptions - Forwarded to {@link connectWallet}.
|
|
109
|
+
* @returns The started shared Demos instance.
|
|
110
|
+
*/
|
|
111
|
+
static start(rpc_url: string, wallet?: string | Uint8Array, walletOptions?: {
|
|
112
|
+
algorithm?: SigningAlgorithm;
|
|
113
|
+
dual_sign?: boolean;
|
|
114
|
+
}): Promise<Demos>;
|
|
70
115
|
/**
|
|
71
116
|
* Connects to a Demos wallet using the provided master seed.
|
|
72
117
|
*
|
|
@@ -202,7 +247,7 @@ export declare class Demos {
|
|
|
202
247
|
* handle async confirmation yourself.
|
|
203
248
|
*
|
|
204
249
|
* @param validationData - The validity data of the transaction
|
|
205
|
-
* @param opts.timeoutMs - Total time to wait. Defaults to
|
|
250
|
+
* @param opts.timeoutMs - Total time to wait. Defaults to 60_000.
|
|
206
251
|
* @param opts.pollIntervalMs - Delay between polls. Defaults to 500.
|
|
207
252
|
*/
|
|
208
253
|
broadcastAndWait(validationData: RPCResponseWithValidityData, opts?: {
|
|
@@ -654,6 +699,41 @@ export declare class Demos {
|
|
|
654
699
|
}, demos: Demos): Promise<Transaction>;
|
|
655
700
|
voteOnUpgrade(proposalId: string, approve: boolean, demos: Demos): Promise<Transaction>;
|
|
656
701
|
};
|
|
702
|
+
private _run?;
|
|
703
|
+
/**
|
|
704
|
+
* Programmatic transaction facade — one call per transaction type.
|
|
705
|
+
*
|
|
706
|
+
* Collapses the classic `build → sign → confirm → broadcast` flow into a
|
|
707
|
+
* single method per operation (`run.pay`, `run.attest.*`, `run.tokens.*`,
|
|
708
|
+
* …) that auto-broadcasts within a configurable fee ceiling (default
|
|
709
|
+
* 5 DEM). Additive: the classic `pay`/`confirm`/`broadcast` methods are
|
|
710
|
+
* unchanged.
|
|
711
|
+
*
|
|
712
|
+
* Built lazily on first access (and memoised) rather than in the
|
|
713
|
+
* constructor. Two reasons: (1) the singleton `demos = Demos.instance` is
|
|
714
|
+
* created at import time, so eagerly *constructing* the namespaces during
|
|
715
|
+
* `new Demos()` — which reach into `@/abstraction`, tokens, contracts — is
|
|
716
|
+
* the part that risked tripping the websdk↔abstraction import cycle;
|
|
717
|
+
* deferring construction removes that crash vector. (2) it avoids building
|
|
718
|
+
* ~6 objects on every `new Demos()` that many callers never touch.
|
|
719
|
+
*
|
|
720
|
+
* Note: the programmatic module graph is still *loaded* when this file is
|
|
721
|
+
* imported (a static `import` cannot be deferred in ESM). That residual
|
|
722
|
+
* cycle is benign — no module reads a cross-cycle binding at evaluation
|
|
723
|
+
* time, only inside functions — and has been narrowed by importing
|
|
724
|
+
* `Identities` directly from `@/abstraction/Identities` rather than via the
|
|
725
|
+
* `@/abstraction` barrel.
|
|
726
|
+
*
|
|
727
|
+
* @example
|
|
728
|
+
* ```ts
|
|
729
|
+
* // one-call payment, auto-broadcast within the 5 DEM fee cap
|
|
730
|
+
* await demos.run.pay("0x...", 100n)
|
|
731
|
+
* // build + confirm only, broadcast yourself later
|
|
732
|
+
* const r = await demos.run.pay("0x...", 100n, { confirm: "manual" })
|
|
733
|
+
* await demos.broadcast(r.validityData)
|
|
734
|
+
* ```
|
|
735
|
+
*/
|
|
736
|
+
get run(): ProgrammaticTx;
|
|
657
737
|
DemosTransactions: {
|
|
658
738
|
empty: () => Transaction;
|
|
659
739
|
prepare: (data?: any) => Promise<Transaction>;
|
|
@@ -12,6 +12,7 @@ import { DemosWebAuth } from "./DemosWebAuth.js";
|
|
|
12
12
|
import { prepareXMPayload } from "./XMTransactions.js";
|
|
13
13
|
import { _required as required } from "./utils/required.js";
|
|
14
14
|
import { web2Calls } from "./Web2Calls.js";
|
|
15
|
+
import { createProgrammaticTx, } from "./programmatic/index.js";
|
|
15
16
|
import { hexToUint8Array, uint8ArrayToHex, UnifiedCrypto, } from "../encryption/unifiedCrypto.js";
|
|
16
17
|
import { GCRGeneration } from "./GCRGeneration.js";
|
|
17
18
|
import { Hashing } from "../encryption/Hashing.js";
|
|
@@ -276,6 +277,52 @@ export class Demos {
|
|
|
276
277
|
this.connected = true;
|
|
277
278
|
return this.connected;
|
|
278
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* One-call bootstrap: connect to a node and (optionally) a wallet, then
|
|
282
|
+
* return the ready instance for immediate use with `demos.run.*`.
|
|
283
|
+
*
|
|
284
|
+
* Convenience wrapper over {@link connect} + {@link connectWallet} — no
|
|
285
|
+
* new behaviour, just the two-step setup collapsed into one. Omit
|
|
286
|
+
* `wallet` to connect read-only.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```ts
|
|
290
|
+
* import { Demos } from "@kynesyslabs/demosdk/websdk"
|
|
291
|
+
* const demos = await Demos.start("https://node2.demos.sh", mnemonic)
|
|
292
|
+
* await demos.run.pay("0x...", 100n)
|
|
293
|
+
* ```
|
|
294
|
+
*
|
|
295
|
+
* @param rpc_url - The URL of the demos node.
|
|
296
|
+
* @param wallet - Master seed / mnemonic (string) or raw seed bytes.
|
|
297
|
+
* Omit to connect without a wallet.
|
|
298
|
+
* @param walletOptions - Forwarded to {@link connectWallet}.
|
|
299
|
+
* @returns This connected Demos instance.
|
|
300
|
+
*/
|
|
301
|
+
async start(rpc_url, wallet, walletOptions) {
|
|
302
|
+
await this.connect(rpc_url);
|
|
303
|
+
if (wallet !== undefined) {
|
|
304
|
+
await this.connectWallet(wallet, walletOptions);
|
|
305
|
+
}
|
|
306
|
+
return this;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Static one-call bootstrap over the shared singleton — starts
|
|
310
|
+
* {@link Demos.instance} and returns it ready for `demos.run.*`.
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```ts
|
|
314
|
+
* const demos = await Demos.start("https://node2.demos.sh", mnemonic)
|
|
315
|
+
* await demos.run.pay("0x...", 100n)
|
|
316
|
+
* ```
|
|
317
|
+
*
|
|
318
|
+
* @param rpc_url - The URL of the demos node.
|
|
319
|
+
* @param wallet - Master seed / mnemonic (string) or raw seed bytes.
|
|
320
|
+
* @param walletOptions - Forwarded to {@link connectWallet}.
|
|
321
|
+
* @returns The started shared Demos instance.
|
|
322
|
+
*/
|
|
323
|
+
static async start(rpc_url, wallet, walletOptions) {
|
|
324
|
+
return Demos.instance.start(rpc_url, wallet, walletOptions);
|
|
325
|
+
}
|
|
279
326
|
/**
|
|
280
327
|
* Connects to a Demos wallet using the provided master seed.
|
|
281
328
|
*
|
|
@@ -454,7 +501,7 @@ export class Demos {
|
|
|
454
501
|
* handle async confirmation yourself.
|
|
455
502
|
*
|
|
456
503
|
* @param validationData - The validity data of the transaction
|
|
457
|
-
* @param opts.timeoutMs - Total time to wait. Defaults to
|
|
504
|
+
* @param opts.timeoutMs - Total time to wait. Defaults to 60_000.
|
|
458
505
|
* @param opts.pollIntervalMs - Delay between polls. Defaults to 500.
|
|
459
506
|
*/
|
|
460
507
|
broadcastAndWait(validationData, opts) {
|
|
@@ -1417,6 +1464,42 @@ export class Demos {
|
|
|
1417
1464
|
}
|
|
1418
1465
|
return tlsn;
|
|
1419
1466
|
}
|
|
1467
|
+
/**
|
|
1468
|
+
* Programmatic transaction facade — one call per transaction type.
|
|
1469
|
+
*
|
|
1470
|
+
* Collapses the classic `build → sign → confirm → broadcast` flow into a
|
|
1471
|
+
* single method per operation (`run.pay`, `run.attest.*`, `run.tokens.*`,
|
|
1472
|
+
* …) that auto-broadcasts within a configurable fee ceiling (default
|
|
1473
|
+
* 5 DEM). Additive: the classic `pay`/`confirm`/`broadcast` methods are
|
|
1474
|
+
* unchanged.
|
|
1475
|
+
*
|
|
1476
|
+
* Built lazily on first access (and memoised) rather than in the
|
|
1477
|
+
* constructor. Two reasons: (1) the singleton `demos = Demos.instance` is
|
|
1478
|
+
* created at import time, so eagerly *constructing* the namespaces during
|
|
1479
|
+
* `new Demos()` — which reach into `@/abstraction`, tokens, contracts — is
|
|
1480
|
+
* the part that risked tripping the websdk↔abstraction import cycle;
|
|
1481
|
+
* deferring construction removes that crash vector. (2) it avoids building
|
|
1482
|
+
* ~6 objects on every `new Demos()` that many callers never touch.
|
|
1483
|
+
*
|
|
1484
|
+
* Note: the programmatic module graph is still *loaded* when this file is
|
|
1485
|
+
* imported (a static `import` cannot be deferred in ESM). That residual
|
|
1486
|
+
* cycle is benign — no module reads a cross-cycle binding at evaluation
|
|
1487
|
+
* time, only inside functions — and has been narrowed by importing
|
|
1488
|
+
* `Identities` directly from `@/abstraction/Identities` rather than via the
|
|
1489
|
+
* `@/abstraction` barrel.
|
|
1490
|
+
*
|
|
1491
|
+
* @example
|
|
1492
|
+
* ```ts
|
|
1493
|
+
* // one-call payment, auto-broadcast within the 5 DEM fee cap
|
|
1494
|
+
* await demos.run.pay("0x...", 100n)
|
|
1495
|
+
* // build + confirm only, broadcast yourself later
|
|
1496
|
+
* const r = await demos.run.pay("0x...", 100n, { confirm: "manual" })
|
|
1497
|
+
* await demos.broadcast(r.validityData)
|
|
1498
|
+
* ```
|
|
1499
|
+
*/
|
|
1500
|
+
get run() {
|
|
1501
|
+
return (this._run ?? (this._run = createProgrammaticTx(this)));
|
|
1502
|
+
}
|
|
1420
1503
|
}
|
|
1421
1504
|
Demos._instance = null;
|
|
1422
1505
|
/**
|