suprafx-agent-sdk 0.3.1
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/LICENSE +21 -0
- package/README.md +452 -0
- package/dist/bin/suprafx-mcp.d.ts +15 -0
- package/dist/bin/suprafx-mcp.js +238 -0
- package/dist/bin/suprafx-mcp.js.map +1 -0
- package/dist/src/asset-registry.d.ts +61 -0
- package/dist/src/asset-registry.js +118 -0
- package/dist/src/asset-registry.js.map +1 -0
- package/dist/src/client.d.ts +227 -0
- package/dist/src/client.js +282 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/derive-ids.d.ts +112 -0
- package/dist/src/derive-ids.js +361 -0
- package/dist/src/derive-ids.js.map +1 -0
- package/dist/src/event-bcs.d.ts +341 -0
- package/dist/src/event-bcs.js +767 -0
- package/dist/src/event-bcs.js.map +1 -0
- package/dist/src/index.d.ts +26 -0
- package/dist/src/index.js +26 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/mcp/config.d.ts +32 -0
- package/dist/src/mcp/config.js +101 -0
- package/dist/src/mcp/config.js.map +1 -0
- package/dist/src/mcp/lifecycle.d.ts +109 -0
- package/dist/src/mcp/lifecycle.js +170 -0
- package/dist/src/mcp/lifecycle.js.map +1 -0
- package/dist/src/mcp/preflight.d.ts +36 -0
- package/dist/src/mcp/preflight.js +291 -0
- package/dist/src/mcp/preflight.js.map +1 -0
- package/dist/src/mcp/server.d.ts +20 -0
- package/dist/src/mcp/server.js +235 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools.d.ts +51 -0
- package/dist/src/mcp/tools.js +1022 -0
- package/dist/src/mcp/tools.js.map +1 -0
- package/dist/src/sign-event.d.ts +185 -0
- package/dist/src/sign-event.js +331 -0
- package/dist/src/sign-event.js.map +1 -0
- package/dist/src/signer.d.ts +89 -0
- package/dist/src/signer.js +226 -0
- package/dist/src/signer.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BCS encoders for user-originated `Event` variants.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the Rust struct schemas in
|
|
5
|
+
* `council-rust/crates/protocol/src/events.rs` byte-for-byte.
|
|
6
|
+
* Cross-language fixture
|
|
7
|
+
* (`lib/council/__fixtures__/user-event-envelope-fixtures.json`)
|
|
8
|
+
* proves equivalence; any drift is caught by
|
|
9
|
+
* `tests/unit/council-event-bcs.test.ts`.
|
|
10
|
+
*
|
|
11
|
+
* ## Why we encode client-side (not server-side)
|
|
12
|
+
*
|
|
13
|
+
* The user signs `event_bcs` directly. If the server encoded those
|
|
14
|
+
* bytes, a malicious or compromised server could mutate the event
|
|
15
|
+
* (UI shows "Withdraw 100 USDC", server encodes "Withdraw 1M USDC")
|
|
16
|
+
* and the user's wallet would sign the malicious bytes without the
|
|
17
|
+
* user knowing — chain accepts the sig as valid because the math
|
|
18
|
+
* works. Client-side encoding makes the bytes-the-user-signs equal
|
|
19
|
+
* the bytes-the-UI-rendered, since both come from the same auditable
|
|
20
|
+
* open-source TS code.
|
|
21
|
+
*
|
|
22
|
+
* Standard practice — Aptos, Sui, Solana, Ethereum all encode user
|
|
23
|
+
* transactions client-side for the same reason.
|
|
24
|
+
*
|
|
25
|
+
* ## Variant index (must match Rust `Event` enum order)
|
|
26
|
+
*
|
|
27
|
+
* BCS encodes a Rust enum as `ULEB128(discriminant) + fields`. The
|
|
28
|
+
* discriminant is the variant's declaration order in the enum:
|
|
29
|
+
*
|
|
30
|
+
* 0 DepositCredited (validator-attested; not signed by user)
|
|
31
|
+
* 1 WithdrawRequested ← user
|
|
32
|
+
* 2 WithdrawFinalized (validator-attested)
|
|
33
|
+
* 3 WithdrawCancelled (lifecycle)
|
|
34
|
+
* 4 SubmitRfq ← user
|
|
35
|
+
* 5 CancelRfq ← user
|
|
36
|
+
* 6 PlaceQuote ← user (maker)
|
|
37
|
+
* 7 AcceptQuote ← user (taker)
|
|
38
|
+
* 8 WithdrawQuote ← user (maker)
|
|
39
|
+
* 9 SlashMaker (lifecycle)
|
|
40
|
+
* 10..19 validator/governance
|
|
41
|
+
* 20 DelegatePolicyCreated ← user (master)
|
|
42
|
+
* 21 DelegatePolicyUpdated ← user (master)
|
|
43
|
+
* 22 DelegatePolicyRevoked ← user (master)
|
|
44
|
+
* 23..30 other (not user-signed)
|
|
45
|
+
*
|
|
46
|
+
* If any of these indices change in Rust, the cross-language fixture
|
|
47
|
+
* will fail at the next `cargo run --example
|
|
48
|
+
* gen_user_event_envelope_fixture` and the TS test will catch it.
|
|
49
|
+
*
|
|
50
|
+
* ## Type sizes (locked at the protocol level)
|
|
51
|
+
*
|
|
52
|
+
* AccountId [u8; 32]
|
|
53
|
+
* AssetId [u8; 32]
|
|
54
|
+
* PairId [u8; 32]
|
|
55
|
+
* RfqId [u8; 16]
|
|
56
|
+
* QuoteId [u8; 16]
|
|
57
|
+
* TradeId [u8; 16]
|
|
58
|
+
* Hash [u8; 32]
|
|
59
|
+
* Amount u128 (16 LE bytes; BCS does NOT use ULEB128 for u128)
|
|
60
|
+
* SequenceNumber u64 (8 LE bytes)
|
|
61
|
+
*/
|
|
62
|
+
/** Settlement mode: Platform=0, OnChain=1. Matches Rust `SettlementMode`. */
|
|
63
|
+
export type SettlementMode = "Platform" | "OnChain";
|
|
64
|
+
/** Delegate role: Maker=0, Taker=1, Agent=2. Matches Rust `DelegateRole`. */
|
|
65
|
+
export type DelegateRole = "Maker" | "Taker" | "Agent";
|
|
66
|
+
/**
|
|
67
|
+
* `SubmitRfq` payload. Field order MUST match
|
|
68
|
+
* `council_protocol::events::SubmitRfq` struct declaration.
|
|
69
|
+
*/
|
|
70
|
+
/**
|
|
71
|
+
* `DepositCredited` payload — validator-attested L1-deposit credit.
|
|
72
|
+
* Layout matches Rust `council_protocol::events::DepositCredited`
|
|
73
|
+
* field order; BCS is positional so any reorder there must mirror
|
|
74
|
+
* here or the cross-language fixture round-trip breaks.
|
|
75
|
+
*/
|
|
76
|
+
export interface DepositCreditedEvent {
|
|
77
|
+
user: Uint8Array;
|
|
78
|
+
asset: Uint8Array;
|
|
79
|
+
amount: bigint;
|
|
80
|
+
source_chain: string;
|
|
81
|
+
source_tx: Uint8Array;
|
|
82
|
+
deposit_id: bigint;
|
|
83
|
+
source_block: bigint;
|
|
84
|
+
attesting_validators: Uint8Array[];
|
|
85
|
+
attestations: Uint8Array[];
|
|
86
|
+
}
|
|
87
|
+
export interface SubmitRfqEvent {
|
|
88
|
+
user: Uint8Array;
|
|
89
|
+
pair: Uint8Array;
|
|
90
|
+
base_asset: Uint8Array;
|
|
91
|
+
quote_asset: Uint8Array;
|
|
92
|
+
size: bigint;
|
|
93
|
+
reference_price: bigint;
|
|
94
|
+
auto_accept: boolean;
|
|
95
|
+
auto_accept_target_rate: bigint;
|
|
96
|
+
allow_partial_fills: boolean;
|
|
97
|
+
min_fill_size: bigint;
|
|
98
|
+
expires_at_ms: bigint;
|
|
99
|
+
rfq_id: Uint8Array;
|
|
100
|
+
user_sequence_number: bigint;
|
|
101
|
+
settlement_mode: SettlementMode;
|
|
102
|
+
}
|
|
103
|
+
/** `CancelRfq` payload. */
|
|
104
|
+
export interface CancelRfqEvent {
|
|
105
|
+
user: Uint8Array;
|
|
106
|
+
rfq_id: Uint8Array;
|
|
107
|
+
reason: string;
|
|
108
|
+
}
|
|
109
|
+
/** `PlaceQuote` payload. Note: `maker`, NOT `user`. */
|
|
110
|
+
export interface PlaceQuoteEvent {
|
|
111
|
+
maker: Uint8Array;
|
|
112
|
+
rfq_id: Uint8Array;
|
|
113
|
+
quote_id: Uint8Array;
|
|
114
|
+
rate: bigint;
|
|
115
|
+
fill_size: bigint;
|
|
116
|
+
user_sequence_number: bigint;
|
|
117
|
+
}
|
|
118
|
+
/** `AcceptQuote` payload. Note: `taker` field, plus `trade_id` (NOT `rfq_id`). */
|
|
119
|
+
export interface AcceptQuoteEvent {
|
|
120
|
+
taker: Uint8Array;
|
|
121
|
+
quote_id: Uint8Array;
|
|
122
|
+
trade_id: Uint8Array;
|
|
123
|
+
user_sequence_number: bigint;
|
|
124
|
+
}
|
|
125
|
+
/** `WithdrawQuote` payload. */
|
|
126
|
+
export interface WithdrawQuoteEvent {
|
|
127
|
+
maker: Uint8Array;
|
|
128
|
+
quote_id: Uint8Array;
|
|
129
|
+
}
|
|
130
|
+
/** `WithdrawRequested` payload. */
|
|
131
|
+
export interface WithdrawRequestedEvent {
|
|
132
|
+
user: Uint8Array;
|
|
133
|
+
asset: Uint8Array;
|
|
134
|
+
amount: bigint;
|
|
135
|
+
/**
|
|
136
|
+
* AssetId the protocol withdrawal fee is paid in. v1: always SUPRA
|
|
137
|
+
* (matches the Rust constant in `protocol/src/fees.rs`). Future
|
|
138
|
+
* USD-pegged variants may switch per chain config.
|
|
139
|
+
*
|
|
140
|
+
* Wire position: AFTER `amount`, BEFORE `withdrawal_id` — must
|
|
141
|
+
* match Rust `events::WithdrawRequested` exactly. Existing BCS
|
|
142
|
+
* fixtures from before this field was added will fail to decode
|
|
143
|
+
* (the explorer reader returns null for them, which the renderer
|
|
144
|
+
* already handles as "unknown event").
|
|
145
|
+
*/
|
|
146
|
+
fee_asset: Uint8Array;
|
|
147
|
+
/**
|
|
148
|
+
* Fee amount in `fee_asset` micro-units. dApp computes via
|
|
149
|
+
* `computeWithdrawalFee(amount, asset)`; validator re-computes
|
|
150
|
+
* and rejects on mismatch.
|
|
151
|
+
*/
|
|
152
|
+
fee_amount: bigint;
|
|
153
|
+
withdrawal_id: bigint;
|
|
154
|
+
dest_chain: string;
|
|
155
|
+
dest_address: Uint8Array;
|
|
156
|
+
deadline_ms: bigint;
|
|
157
|
+
user_sequence_number: bigint;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* One entry of a delegate's per-asset cap map (Option B). Mirrors the
|
|
161
|
+
* Rust `policy::AssetCap` keyed by its `AssetId`.
|
|
162
|
+
*
|
|
163
|
+
* ═══ ZERO SEMANTICS — VERIFIED AGAINST THE CONTRACT, 2026-09-15 ═══
|
|
164
|
+
*
|
|
165
|
+
* `0n` means **NO TRADES ALLOWED** for this asset (fail-closed).
|
|
166
|
+
* It does NOT mean "unlimited".
|
|
167
|
+
* An asset with NO ENTRY is also not tradeable (deny-by-absence),
|
|
168
|
+
* and an empty map authorizes nothing.
|
|
169
|
+
* For "effectively unlimited", use `MAX_CAP` (u64::MAX) below.
|
|
170
|
+
*
|
|
171
|
+
* The validator ORIGINALLY treated `0` as unlimited — fail-OPEN, a
|
|
172
|
+
* whitehat confirmed it exploitable, and it was fixed in
|
|
173
|
+
* `council-rust/crates/protocol/src/policy.rs` on 2026-06-07. This
|
|
174
|
+
* comment kept saying "0n = authorized, unlimited" long after the
|
|
175
|
+
* contract stopped behaving that way, and an onboarding review read it
|
|
176
|
+
* and concluded a zero cap grants unlimited authority. It does the
|
|
177
|
+
* opposite. Keep this comment in step with the contract.
|
|
178
|
+
*/
|
|
179
|
+
export interface AssetCapEntry {
|
|
180
|
+
/** 32-byte AssetId. */
|
|
181
|
+
asset: Uint8Array;
|
|
182
|
+
/**
|
|
183
|
+
* Per-trade cap (Amount, micro-units). `0n` = NO TRADES for this
|
|
184
|
+
* asset. Use `MAX_CAP` for effectively unlimited.
|
|
185
|
+
*/
|
|
186
|
+
maxTradeSize: bigint;
|
|
187
|
+
/** Cumulative open-earmark cap. Same zero semantics. */
|
|
188
|
+
maxEarmarkTotal: bigint;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* The canonical "effectively unlimited" cap sentinel: `u64::MAX`.
|
|
192
|
+
*
|
|
193
|
+
* NOT `u128::MAX` — the validator's `checked_add(earmarks, size)`
|
|
194
|
+
* overflows there. NOT `0n`, which is fail-closed (see above).
|
|
195
|
+
*/
|
|
196
|
+
export declare const MAX_CAP: bigint;
|
|
197
|
+
/** `DelegatePolicyCreated` payload. Used for session bootstrap. */
|
|
198
|
+
export interface DelegatePolicyCreatedEvent {
|
|
199
|
+
master: Uint8Array;
|
|
200
|
+
delegate: Uint8Array;
|
|
201
|
+
label: string;
|
|
202
|
+
allowed_roles: DelegateRole[];
|
|
203
|
+
allowed_pairs: Uint8Array[];
|
|
204
|
+
/**
|
|
205
|
+
* Per-asset caps — a BCS `BTreeMap<AssetId, AssetCap>`. DENY
|
|
206
|
+
* semantics: an asset absent from this list is not tradeable.
|
|
207
|
+
* See `docs/handoffs/option-b-per-asset-caps-design.md`.
|
|
208
|
+
*/
|
|
209
|
+
asset_caps: AssetCapEntry[];
|
|
210
|
+
/**
|
|
211
|
+
* Batch number at which this delegation EXPIRES — the on-chain
|
|
212
|
+
* session bound (#25 H10). `0n` = never expires. Once consensus
|
|
213
|
+
* reaches this batch, `check_delegate_policy` rejects every
|
|
214
|
+
* delegated action, so a leaked delegate key is time-bounded even
|
|
215
|
+
* if the master never submits a revoke. Carried in the signed
|
|
216
|
+
* envelope so the master cryptographically commits to the lifetime.
|
|
217
|
+
* Wire position: AFTER `asset_caps`, BEFORE `user_sequence_number`
|
|
218
|
+
* — must match Rust `events::DelegatePolicyCreated` exactly.
|
|
219
|
+
*/
|
|
220
|
+
expires_at_batch: bigint;
|
|
221
|
+
user_sequence_number: bigint;
|
|
222
|
+
}
|
|
223
|
+
/** Taker on-chain settlement claim. Bumps taker's sequence number;
|
|
224
|
+
* no balance change (claim only — bridge attesters verify later). */
|
|
225
|
+
export interface TakerTxPendingEvent {
|
|
226
|
+
trade_id: Uint8Array;
|
|
227
|
+
taker: Uint8Array;
|
|
228
|
+
source_chain: string;
|
|
229
|
+
source_tx: Uint8Array;
|
|
230
|
+
user_sequence_number: bigint;
|
|
231
|
+
}
|
|
232
|
+
/** Maker on-chain settlement claim. Bumps maker's sequence number. */
|
|
233
|
+
export interface MakerTxPendingEvent {
|
|
234
|
+
trade_id: Uint8Array;
|
|
235
|
+
maker: Uint8Array;
|
|
236
|
+
source_chain: string;
|
|
237
|
+
source_tx: Uint8Array;
|
|
238
|
+
user_sequence_number: bigint;
|
|
239
|
+
}
|
|
240
|
+
/** Master-signed delegate-policy update. Same shape as Created plus
|
|
241
|
+
* an `active` flag inserted between max_earmark_total + sequence. */
|
|
242
|
+
export interface DelegatePolicyUpdatedEvent {
|
|
243
|
+
master: Uint8Array;
|
|
244
|
+
delegate: Uint8Array;
|
|
245
|
+
label: string;
|
|
246
|
+
allowed_roles: DelegateRole[];
|
|
247
|
+
allowed_pairs: Uint8Array[];
|
|
248
|
+
/** Per-asset caps — see `AssetCapEntry`. BCS `BTreeMap<AssetId, AssetCap>`. */
|
|
249
|
+
asset_caps: AssetCapEntry[];
|
|
250
|
+
active: boolean;
|
|
251
|
+
user_sequence_number: bigint;
|
|
252
|
+
}
|
|
253
|
+
/** Master-signed delegate-policy revocation. Removes the policy
|
|
254
|
+
* entirely; in-flight earmarks are NOT auto-cleared. */
|
|
255
|
+
export interface DelegatePolicyRevokedEvent {
|
|
256
|
+
master: Uint8Array;
|
|
257
|
+
delegate: Uint8Array;
|
|
258
|
+
user_sequence_number: bigint;
|
|
259
|
+
}
|
|
260
|
+
/** Master-signed link revocation. Removes (chain, address) from the
|
|
261
|
+
* user's linked_addresses + clears the address_to_master reverse index. */
|
|
262
|
+
export interface LinkedAddressRevokedEvent {
|
|
263
|
+
/** Master account (32 bytes). */
|
|
264
|
+
user: Uint8Array;
|
|
265
|
+
/** Foreign chain id ("eth-sepolia", "supra-testnet", ...). */
|
|
266
|
+
chain: string;
|
|
267
|
+
/** Foreign address bytes (variable length per chain). */
|
|
268
|
+
address: Uint8Array;
|
|
269
|
+
/** Strict-next sequence number for the master. */
|
|
270
|
+
user_sequence_number: bigint;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Tagged-union shape for the user-event encoder. Each `kind` maps
|
|
274
|
+
* 1-1 to a Rust `Event` variant we support; the discriminator
|
|
275
|
+
* determines the BCS variant tag and which struct schema is used
|
|
276
|
+
* for the body.
|
|
277
|
+
*/
|
|
278
|
+
export type UserEvent = {
|
|
279
|
+
kind: "DepositCredited";
|
|
280
|
+
payload: DepositCreditedEvent;
|
|
281
|
+
} | {
|
|
282
|
+
kind: "SubmitRfq";
|
|
283
|
+
payload: SubmitRfqEvent;
|
|
284
|
+
} | {
|
|
285
|
+
kind: "CancelRfq";
|
|
286
|
+
payload: CancelRfqEvent;
|
|
287
|
+
} | {
|
|
288
|
+
kind: "PlaceQuote";
|
|
289
|
+
payload: PlaceQuoteEvent;
|
|
290
|
+
} | {
|
|
291
|
+
kind: "AcceptQuote";
|
|
292
|
+
payload: AcceptQuoteEvent;
|
|
293
|
+
} | {
|
|
294
|
+
kind: "WithdrawQuote";
|
|
295
|
+
payload: WithdrawQuoteEvent;
|
|
296
|
+
} | {
|
|
297
|
+
kind: "WithdrawRequested";
|
|
298
|
+
payload: WithdrawRequestedEvent;
|
|
299
|
+
} | {
|
|
300
|
+
kind: "TakerTxPending";
|
|
301
|
+
payload: TakerTxPendingEvent;
|
|
302
|
+
} | {
|
|
303
|
+
kind: "MakerTxPending";
|
|
304
|
+
payload: MakerTxPendingEvent;
|
|
305
|
+
} | {
|
|
306
|
+
kind: "DelegatePolicyCreated";
|
|
307
|
+
payload: DelegatePolicyCreatedEvent;
|
|
308
|
+
} | {
|
|
309
|
+
kind: "DelegatePolicyUpdated";
|
|
310
|
+
payload: DelegatePolicyUpdatedEvent;
|
|
311
|
+
} | {
|
|
312
|
+
kind: "DelegatePolicyRevoked";
|
|
313
|
+
payload: DelegatePolicyRevokedEvent;
|
|
314
|
+
} | {
|
|
315
|
+
kind: "LinkedAddressRevoked";
|
|
316
|
+
payload: LinkedAddressRevokedEvent;
|
|
317
|
+
};
|
|
318
|
+
/**
|
|
319
|
+
* BCS-encode a user-originated `Event`. Returns the bytes the user
|
|
320
|
+
* signs (becomes `event_bcs` in the `SignedEventEnvelope`).
|
|
321
|
+
*
|
|
322
|
+
* Pure function. Same input → same bytes, every time.
|
|
323
|
+
*/
|
|
324
|
+
export declare function encodeUserEvent(ev: UserEvent): Uint8Array;
|
|
325
|
+
/**
|
|
326
|
+
* Decode a BCS-encoded `Event` into the corresponding `UserEvent`
|
|
327
|
+
* variant. Reads the variant tag (ULEB128) from the front of the
|
|
328
|
+
* buffer + dispatches.
|
|
329
|
+
*
|
|
330
|
+
* Returns `null` for variants this module doesn't know about
|
|
331
|
+
* (validator-attested events like `DepositCredited`, governance, etc.) —
|
|
332
|
+
* callers should treat that as "decoding deferred to a future
|
|
333
|
+
* version" rather than an error.
|
|
334
|
+
*
|
|
335
|
+
* Throws on truly malformed BCS bytes (truncated, invalid bools, etc).
|
|
336
|
+
*
|
|
337
|
+
* After decoding, `reader.remaining()` should be 0; if not, the
|
|
338
|
+
* payload had trailing bytes (caller-supplied buffer too long, or
|
|
339
|
+
* a struct-field-mismatch bug).
|
|
340
|
+
*/
|
|
341
|
+
export declare function decodeUserEvent(bcs: Uint8Array): UserEvent | null;
|