@secondlayer/stacks 2.0.1 → 2.1.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/dist/shared/stacks-9z833ww5.js +409 -0
- package/dist/shared/stacks-9z833ww5.js.map +10 -0
- package/dist/shared/stacks-mnnhpex3.cjs +407 -0
- package/dist/shared/stacks-mnnhpex3.cjs.map +10 -0
- package/dist/src/pox/index.cjs +3 -408
- package/dist/src/pox/index.cjs.map +3 -4
- package/dist/src/pox/index.js +7 -408
- package/dist/src/pox/index.js.map +3 -4
- package/dist/src/sbtc/index.cjs +270 -0
- package/dist/src/sbtc/index.cjs.map +14 -0
- package/dist/src/sbtc/index.d.cts +399 -0
- package/dist/src/sbtc/index.d.ts +399 -0
- package/dist/src/sbtc/index.js +286 -0
- package/dist/src/sbtc/index.js.map +14 -0
- package/package.json +6 -1
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
/** Account derived from a local private key (mnemonic or raw key). */
|
|
2
|
+
type LocalAccount = {
|
|
3
|
+
type: "local"
|
|
4
|
+
address: string
|
|
5
|
+
/** Compressed public key (hex) */
|
|
6
|
+
publicKey: string
|
|
7
|
+
/** Raw ECDSA sign over a hash */
|
|
8
|
+
sign(hash: Uint8Array): Uint8Array
|
|
9
|
+
/** Sign a structured message (SIP-018) */
|
|
10
|
+
signMessage(message: string | Uint8Array): string
|
|
11
|
+
};
|
|
12
|
+
/** Account with a user-provided signing function (sync or async). */
|
|
13
|
+
type CustomAccount = {
|
|
14
|
+
type: "custom"
|
|
15
|
+
address: string
|
|
16
|
+
publicKey: string
|
|
17
|
+
sign(hash: Uint8Array): Promise<Uint8Array> | Uint8Array
|
|
18
|
+
};
|
|
19
|
+
/** Browser wallet provider interface (e.g. Leather, Xverse). */
|
|
20
|
+
type StacksProvider = {
|
|
21
|
+
request(method: string, params?: any): Promise<any>
|
|
22
|
+
};
|
|
23
|
+
/** Account backed by a browser wallet {@link StacksProvider}. */
|
|
24
|
+
type ProviderAccount = {
|
|
25
|
+
type: "provider"
|
|
26
|
+
address: string
|
|
27
|
+
publicKey: string
|
|
28
|
+
provider: StacksProvider
|
|
29
|
+
};
|
|
30
|
+
/** Full chain descriptor used by clients and transports for network-aware operations. */
|
|
31
|
+
type StacksChain = {
|
|
32
|
+
/** Chain ID (e.g. 0x00000001 for mainnet) */
|
|
33
|
+
id: number
|
|
34
|
+
/** Human-readable name */
|
|
35
|
+
name: string
|
|
36
|
+
/** Network type */
|
|
37
|
+
network: "mainnet" | "testnet"
|
|
38
|
+
/** Transaction version byte for serialization */
|
|
39
|
+
transactionVersion: number
|
|
40
|
+
/** Peer network ID for P2P broadcasting */
|
|
41
|
+
peerNetworkId: number
|
|
42
|
+
/** Address version bytes */
|
|
43
|
+
addressVersion: {
|
|
44
|
+
singleSig: number
|
|
45
|
+
multiSig: number
|
|
46
|
+
}
|
|
47
|
+
/** Magic bytes for network identification */
|
|
48
|
+
magicBytes: string
|
|
49
|
+
/** Boot address (system contracts deployer) */
|
|
50
|
+
bootAddress: string
|
|
51
|
+
/** Native currency info */
|
|
52
|
+
nativeCurrency: {
|
|
53
|
+
name: string
|
|
54
|
+
symbol: string
|
|
55
|
+
decimals: number
|
|
56
|
+
}
|
|
57
|
+
/** Default RPC URLs */
|
|
58
|
+
rpcUrls: {
|
|
59
|
+
default: {
|
|
60
|
+
http: string[]
|
|
61
|
+
ws?: string[]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Block explorer URLs */
|
|
65
|
+
blockExplorers?: {
|
|
66
|
+
default: {
|
|
67
|
+
name: string
|
|
68
|
+
url: string
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
/** Function that sends an HTTP request to a Stacks node API path. */
|
|
73
|
+
type RequestFn = (path: string, options?: RequestOptions) => Promise<any>;
|
|
74
|
+
/** Options for a transport-level HTTP request. */
|
|
75
|
+
type RequestOptions = {
|
|
76
|
+
method?: "GET" | "POST" | "PUT" | "DELETE"
|
|
77
|
+
body?: unknown
|
|
78
|
+
headers?: Record<string, string>
|
|
79
|
+
};
|
|
80
|
+
/** Shared configuration for all transport types. */
|
|
81
|
+
type TransportConfig = {
|
|
82
|
+
url?: string
|
|
83
|
+
timeout?: number
|
|
84
|
+
retryCount?: number
|
|
85
|
+
retryDelay?: number
|
|
86
|
+
fetchOptions?: RequestInit
|
|
87
|
+
apiKey?: string
|
|
88
|
+
};
|
|
89
|
+
/** A resolved transport instance with a bound request function. */
|
|
90
|
+
type Transport = {
|
|
91
|
+
type: string
|
|
92
|
+
request: RequestFn
|
|
93
|
+
config: TransportConfig
|
|
94
|
+
destroy?: () => void
|
|
95
|
+
};
|
|
96
|
+
/** Union of all supported account types (local key, custom signer, or browser provider). */
|
|
97
|
+
type Account = LocalAccount | CustomAccount | ProviderAccount;
|
|
98
|
+
/**
|
|
99
|
+
* Core client instance that holds chain context, transport, and extensible actions.
|
|
100
|
+
* Created via {@link createClient}, {@link createPublicClient}, or {@link createWalletClient}.
|
|
101
|
+
*/
|
|
102
|
+
type Client<TExtended extends Record<string, unknown> = Record<string, unknown>> = {
|
|
103
|
+
chain?: StacksChain
|
|
104
|
+
account?: Account
|
|
105
|
+
transport: Transport
|
|
106
|
+
request: RequestFn
|
|
107
|
+
extend: <const TNew extends Record<string, unknown>>(fn: (client: Client<TExtended>) => TNew) => Client<TExtended & TNew> & TNew
|
|
108
|
+
} & TExtended;
|
|
109
|
+
/**
|
|
110
|
+
* sBTC mainnet contract identifiers.
|
|
111
|
+
*
|
|
112
|
+
* The protocol uses three contracts:
|
|
113
|
+
* - `sbtc-token` — SIP-010 fungible token with mint/burn/transfer SIP-005 events.
|
|
114
|
+
* - `sbtc-deposit` — entry point for deposit completion calls (no print events).
|
|
115
|
+
* - `sbtc-registry` — emits all protocol-state print events (deposits, withdrawals,
|
|
116
|
+
* signer-set rotations, governance).
|
|
117
|
+
*
|
|
118
|
+
* Verified against the deployed mainnet contracts via Hiro's
|
|
119
|
+
* `/v2/contracts/source/...` endpoint.
|
|
120
|
+
*/
|
|
121
|
+
declare const SBTC_CONTRACTS: {
|
|
122
|
+
readonly mainnet: {
|
|
123
|
+
readonly address: "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4"
|
|
124
|
+
readonly token: "sbtc-token"
|
|
125
|
+
readonly deposit: "sbtc-deposit"
|
|
126
|
+
readonly registry: "sbtc-registry"
|
|
127
|
+
}
|
|
128
|
+
readonly testnet: {
|
|
129
|
+
readonly address: "SN3R84XZYA63QS28932XQF3G1J8R9PC3W76P9CSQS"
|
|
130
|
+
readonly token: "sbtc-token"
|
|
131
|
+
readonly deposit: "sbtc-deposit"
|
|
132
|
+
readonly registry: "sbtc-registry"
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
type SbtcNetwork = keyof typeof SBTC_CONTRACTS;
|
|
136
|
+
/** Asset identifier for `sbtc-token` (mainnet). */
|
|
137
|
+
declare const SBTC_ASSET_IDENTIFIER_MAINNET: string;
|
|
138
|
+
/** Asset identifier for `sbtc-token` (testnet). */
|
|
139
|
+
declare const SBTC_ASSET_IDENTIFIER_TESTNET: string;
|
|
140
|
+
/** All print-event topic strings emitted by `sbtc-registry`. */
|
|
141
|
+
declare const SBTC_EVENT_TOPICS: readonly ["completed-deposit", "withdrawal-create", "withdrawal-accept", "withdrawal-reject", "key-rotation", "update-protocol-contract"];
|
|
142
|
+
type SbtcEventTopic = (typeof SBTC_EVENT_TOPICS)[number];
|
|
143
|
+
/** Bitcoin address version bytes used in BTC recipient tuples. Same byte map as PoX. */
|
|
144
|
+
declare const SBTC_BTC_ADDRESS_VERSION: {
|
|
145
|
+
readonly p2pkh: 0x00
|
|
146
|
+
readonly p2sh: 0x01
|
|
147
|
+
readonly p2sh_p2wpkh: 0x02
|
|
148
|
+
readonly p2sh_p2wsh: 0x03
|
|
149
|
+
readonly p2wpkh: 0x04
|
|
150
|
+
readonly p2wsh: 0x05
|
|
151
|
+
readonly p2tr: 0x06
|
|
152
|
+
};
|
|
153
|
+
/** Number of decimal places in the sBTC fungible token (matches BTC). */
|
|
154
|
+
declare const SBTC_DECIMALS = 8;
|
|
155
|
+
/** Smallest unit of sBTC, denominated in satoshis. */
|
|
156
|
+
declare const SBTC_UNIT_NAME: "satoshis";
|
|
157
|
+
/**
|
|
158
|
+
* Resolve the qualified contract identifier for a given protocol contract.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* sbtcContractId("mainnet", "registry")
|
|
162
|
+
* // => "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-registry"
|
|
163
|
+
*/
|
|
164
|
+
declare function sbtcContractId(network: SbtcNetwork, contract: "token" | "deposit" | "registry"): string;
|
|
165
|
+
/**
|
|
166
|
+
* Bitcoin recipient address as encoded in `withdrawal-create` events.
|
|
167
|
+
* `version` is a single byte mapping to {@link SBTC_BTC_ADDRESS_VERSION};
|
|
168
|
+
* `hashbytes` is the 20- or 32-byte hash payload.
|
|
169
|
+
*/
|
|
170
|
+
type SbtcBtcRecipient = {
|
|
171
|
+
version: number
|
|
172
|
+
hashbytes: Uint8Array
|
|
173
|
+
};
|
|
174
|
+
/** `(print { topic: "completed-deposit", ... })` from `sbtc-registry`. */
|
|
175
|
+
type CompletedDepositEvent = {
|
|
176
|
+
topic: "completed-deposit"
|
|
177
|
+
bitcoinTxid: Uint8Array
|
|
178
|
+
outputIndex: bigint
|
|
179
|
+
amount: bigint
|
|
180
|
+
burnHash: Uint8Array
|
|
181
|
+
burnHeight: bigint
|
|
182
|
+
sweepTxid: Uint8Array
|
|
183
|
+
};
|
|
184
|
+
/** `(print { topic: "withdrawal-create", ... })`. */
|
|
185
|
+
type WithdrawalCreateEvent = {
|
|
186
|
+
topic: "withdrawal-create"
|
|
187
|
+
requestId: bigint
|
|
188
|
+
amount: bigint
|
|
189
|
+
sender: string
|
|
190
|
+
recipient: SbtcBtcRecipient
|
|
191
|
+
blockHeight: bigint
|
|
192
|
+
maxFee: bigint
|
|
193
|
+
};
|
|
194
|
+
/** `(print { topic: "withdrawal-accept", ... })`. */
|
|
195
|
+
type WithdrawalAcceptEvent = {
|
|
196
|
+
topic: "withdrawal-accept"
|
|
197
|
+
requestId: bigint
|
|
198
|
+
bitcoinTxid: Uint8Array
|
|
199
|
+
signerBitmap: bigint
|
|
200
|
+
outputIndex: bigint
|
|
201
|
+
fee: bigint
|
|
202
|
+
burnHash: Uint8Array
|
|
203
|
+
burnHeight: bigint
|
|
204
|
+
sweepTxid: Uint8Array
|
|
205
|
+
};
|
|
206
|
+
/** `(print { topic: "withdrawal-reject", ... })`. */
|
|
207
|
+
type WithdrawalRejectEvent = {
|
|
208
|
+
topic: "withdrawal-reject"
|
|
209
|
+
requestId: bigint
|
|
210
|
+
signerBitmap: bigint
|
|
211
|
+
};
|
|
212
|
+
/** `(print { topic: "key-rotation", ... })` — signer-set rotation. */
|
|
213
|
+
type KeyRotationEvent = {
|
|
214
|
+
topic: "key-rotation"
|
|
215
|
+
newKeys: Uint8Array[]
|
|
216
|
+
newAddress: string
|
|
217
|
+
newAggregatePubkey: Uint8Array
|
|
218
|
+
newSignatureThreshold: bigint
|
|
219
|
+
};
|
|
220
|
+
/** `(print { topic: "update-protocol-contract", ... })` — governance hook. */
|
|
221
|
+
type UpdateProtocolContractEvent = {
|
|
222
|
+
topic: "update-protocol-contract"
|
|
223
|
+
contractType: Uint8Array
|
|
224
|
+
newContract: string
|
|
225
|
+
};
|
|
226
|
+
/** Discriminated union of every protocol-state event from `sbtc-registry`. */
|
|
227
|
+
type SbtcRegistryEvent = CompletedDepositEvent | WithdrawalCreateEvent | WithdrawalAcceptEvent | WithdrawalRejectEvent | KeyRotationEvent | UpdateProtocolContractEvent;
|
|
228
|
+
type SbtcTokenTransferEvent = {
|
|
229
|
+
type: "transfer"
|
|
230
|
+
sender: string
|
|
231
|
+
recipient: string
|
|
232
|
+
amount: bigint
|
|
233
|
+
memo: Uint8Array | null
|
|
234
|
+
};
|
|
235
|
+
type SbtcTokenMintEvent = {
|
|
236
|
+
type: "mint"
|
|
237
|
+
recipient: string
|
|
238
|
+
amount: bigint
|
|
239
|
+
};
|
|
240
|
+
type SbtcTokenBurnEvent = {
|
|
241
|
+
type: "burn"
|
|
242
|
+
sender: string
|
|
243
|
+
amount: bigint
|
|
244
|
+
};
|
|
245
|
+
type SbtcTokenEvent = SbtcTokenTransferEvent | SbtcTokenMintEvent | SbtcTokenBurnEvent;
|
|
246
|
+
/** Helper for narrowing on `topic`. */
|
|
247
|
+
type SbtcEventByTopic<T extends SbtcEventTopic> = Extract<SbtcRegistryEvent, {
|
|
248
|
+
topic: T
|
|
249
|
+
}>;
|
|
250
|
+
/**
|
|
251
|
+
* Format a `(buff 1) + (buff 32)` BTC recipient tuple into a canonical
|
|
252
|
+
* mainnet Bitcoin address string.
|
|
253
|
+
*
|
|
254
|
+
* Used to decode the `recipient` field of `withdrawal-create` events
|
|
255
|
+
* into a human-readable address. Mirrors the reverse direction of the
|
|
256
|
+
* `parseBtcAddress` helper in `pox/utils.ts`.
|
|
257
|
+
*/
|
|
258
|
+
declare function formatBtcAddress(recipient: SbtcBtcRecipient): string;
|
|
259
|
+
/**
|
|
260
|
+
* Validate that a buffer is a 32-byte Bitcoin transaction id.
|
|
261
|
+
* Throws if the buffer is the wrong length.
|
|
262
|
+
*/
|
|
263
|
+
declare function validateBitcoinTxid(buf: Uint8Array): void;
|
|
264
|
+
/**
|
|
265
|
+
* Hex-encode a Bitcoin txid for storage / display. Throws if the input is
|
|
266
|
+
* not 32 bytes.
|
|
267
|
+
*/
|
|
268
|
+
declare function bitcoinTxidToHex(buf: Uint8Array): string;
|
|
269
|
+
/**
|
|
270
|
+
* Parse a hex string back into a 32-byte txid. Mirrors `bitcoinTxidToHex`.
|
|
271
|
+
*/
|
|
272
|
+
declare function bitcoinTxidFromHex(hex: string): Uint8Array;
|
|
273
|
+
/**
|
|
274
|
+
* Convert satoshis (BigInt) to a decimal-string sBTC amount.
|
|
275
|
+
*
|
|
276
|
+
* sBTC has 8 decimals (matching BTC). 100_000_000 sats = 1 sBTC.
|
|
277
|
+
*/
|
|
278
|
+
declare function satsToSbtc(sats: bigint): string;
|
|
279
|
+
/**
|
|
280
|
+
* Parse a decimal-string sBTC amount into satoshis. Inverse of
|
|
281
|
+
* {@link satsToSbtc}.
|
|
282
|
+
*/
|
|
283
|
+
declare function sbtcToSats(amount: string): bigint;
|
|
284
|
+
/**
|
|
285
|
+
* Minimal read-only ABI for `sbtc-token`.
|
|
286
|
+
*
|
|
287
|
+
* Only covers the SIP-010 fungible-token getters needed for supply / balance
|
|
288
|
+
* queries. Public mutating functions are intentionally omitted; the data plane
|
|
289
|
+
* doesn't sign sBTC token transfers itself, and the dataset captures
|
|
290
|
+
* mutation effects through SIP-005 token events on the indexer side.
|
|
291
|
+
*/
|
|
292
|
+
declare const SBTC_TOKEN_ABI: {
|
|
293
|
+
readonly functions: readonly [{
|
|
294
|
+
readonly name: "get-name"
|
|
295
|
+
readonly access: "read-only"
|
|
296
|
+
readonly args: readonly []
|
|
297
|
+
readonly outputs: {
|
|
298
|
+
readonly response: {
|
|
299
|
+
readonly ok: {
|
|
300
|
+
readonly "string-ascii": {
|
|
301
|
+
readonly length: 32
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
readonly error: "none"
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}, {
|
|
308
|
+
readonly name: "get-symbol"
|
|
309
|
+
readonly access: "read-only"
|
|
310
|
+
readonly args: readonly []
|
|
311
|
+
readonly outputs: {
|
|
312
|
+
readonly response: {
|
|
313
|
+
readonly ok: {
|
|
314
|
+
readonly "string-ascii": {
|
|
315
|
+
readonly length: 10
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
readonly error: "none"
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}, {
|
|
322
|
+
readonly name: "get-decimals"
|
|
323
|
+
readonly access: "read-only"
|
|
324
|
+
readonly args: readonly []
|
|
325
|
+
readonly outputs: {
|
|
326
|
+
readonly response: {
|
|
327
|
+
readonly ok: "uint128"
|
|
328
|
+
readonly error: "none"
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}, {
|
|
332
|
+
readonly name: "get-total-supply"
|
|
333
|
+
readonly access: "read-only"
|
|
334
|
+
readonly args: readonly []
|
|
335
|
+
readonly outputs: {
|
|
336
|
+
readonly response: {
|
|
337
|
+
readonly ok: "uint128"
|
|
338
|
+
readonly error: "none"
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}, {
|
|
342
|
+
readonly name: "get-balance"
|
|
343
|
+
readonly access: "read-only"
|
|
344
|
+
readonly args: readonly [{
|
|
345
|
+
readonly name: "owner"
|
|
346
|
+
readonly type: "principal"
|
|
347
|
+
}]
|
|
348
|
+
readonly outputs: {
|
|
349
|
+
readonly response: {
|
|
350
|
+
readonly ok: "uint128"
|
|
351
|
+
readonly error: "none"
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}, {
|
|
355
|
+
readonly name: "get-token-uri"
|
|
356
|
+
readonly access: "read-only"
|
|
357
|
+
readonly args: readonly []
|
|
358
|
+
readonly outputs: {
|
|
359
|
+
readonly response: {
|
|
360
|
+
readonly ok: {
|
|
361
|
+
readonly optional: {
|
|
362
|
+
readonly "string-utf8": {
|
|
363
|
+
readonly length: 256
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
readonly error: "none"
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}]
|
|
371
|
+
};
|
|
372
|
+
/** Actions provided by the sBTC extension. */
|
|
373
|
+
type SbtcActions = {
|
|
374
|
+
sbtc: {
|
|
375
|
+
getTotalSupply: () => Promise<bigint>
|
|
376
|
+
getBalance: (owner: string) => Promise<bigint>
|
|
377
|
+
getName: () => Promise<string>
|
|
378
|
+
getSymbol: () => Promise<string>
|
|
379
|
+
getDecimals: () => Promise<bigint>
|
|
380
|
+
getTokenUri: () => Promise<string | null>
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
/**
|
|
384
|
+
* sBTC extension for the Stacks client.
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* import { createWalletClient, http, mainnet } from "stacks";
|
|
388
|
+
* import { sbtc } from "stacks/sbtc";
|
|
389
|
+
*
|
|
390
|
+
* const client = createWalletClient({
|
|
391
|
+
* chain: mainnet,
|
|
392
|
+
* transport: http(),
|
|
393
|
+
* }).extend(sbtc());
|
|
394
|
+
*
|
|
395
|
+
* const supply = await client.sbtc.getTotalSupply();
|
|
396
|
+
* const balance = await client.sbtc.getBalance("SP1...");
|
|
397
|
+
*/
|
|
398
|
+
declare function sbtc(): (client: Client) => SbtcActions;
|
|
399
|
+
export { validateBitcoinTxid, sbtcToSats, sbtcContractId, sbtc, satsToSbtc, formatBtcAddress, bitcoinTxidToHex, bitcoinTxidFromHex, WithdrawalRejectEvent, WithdrawalCreateEvent, WithdrawalAcceptEvent, UpdateProtocolContractEvent, SbtcTokenTransferEvent, SbtcTokenMintEvent, SbtcTokenEvent, SbtcTokenBurnEvent, SbtcRegistryEvent, SbtcNetwork, SbtcEventTopic, SbtcEventByTopic, SbtcBtcRecipient, SbtcActions, SBTC_UNIT_NAME, SBTC_TOKEN_ABI, SBTC_EVENT_TOPICS, SBTC_DECIMALS, SBTC_CONTRACTS, SBTC_BTC_ADDRESS_VERSION, SBTC_ASSET_IDENTIFIER_TESTNET, SBTC_ASSET_IDENTIFIER_MAINNET, KeyRotationEvent, CompletedDepositEvent };
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bech32,
|
|
3
|
+
bech32m
|
|
4
|
+
} from "../../shared/stacks-9z833ww5.js";
|
|
5
|
+
import {
|
|
6
|
+
getContract
|
|
7
|
+
} from "../../shared/stacks-7tn3zsbe.js";
|
|
8
|
+
import"../../shared/stacks-g7ys594x.js";
|
|
9
|
+
import"../../shared/stacks-709tra19.js";
|
|
10
|
+
import"../../shared/stacks-g7ffp8aj.js";
|
|
11
|
+
import"../../shared/stacks-kmnthgj7.js";
|
|
12
|
+
import"../../shared/stacks-0zysn74p.js";
|
|
13
|
+
import"../../shared/stacks-v9jqcpd4.js";
|
|
14
|
+
import"../../shared/stacks-xxn5ma6g.js";
|
|
15
|
+
import"../../shared/stacks-6xmk24yw.js";
|
|
16
|
+
import {
|
|
17
|
+
bytesToHex,
|
|
18
|
+
hexToBytes
|
|
19
|
+
} from "../../shared/stacks-2h8d2y27.js";
|
|
20
|
+
|
|
21
|
+
// src/sbtc/abi.ts
|
|
22
|
+
var SBTC_TOKEN_ABI = {
|
|
23
|
+
functions: [
|
|
24
|
+
{
|
|
25
|
+
name: "get-name",
|
|
26
|
+
access: "read-only",
|
|
27
|
+
args: [],
|
|
28
|
+
outputs: {
|
|
29
|
+
response: { ok: { "string-ascii": { length: 32 } }, error: "none" }
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "get-symbol",
|
|
34
|
+
access: "read-only",
|
|
35
|
+
args: [],
|
|
36
|
+
outputs: {
|
|
37
|
+
response: { ok: { "string-ascii": { length: 10 } }, error: "none" }
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "get-decimals",
|
|
42
|
+
access: "read-only",
|
|
43
|
+
args: [],
|
|
44
|
+
outputs: { response: { ok: "uint128", error: "none" } }
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "get-total-supply",
|
|
48
|
+
access: "read-only",
|
|
49
|
+
args: [],
|
|
50
|
+
outputs: { response: { ok: "uint128", error: "none" } }
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "get-balance",
|
|
54
|
+
access: "read-only",
|
|
55
|
+
args: [{ name: "owner", type: "principal" }],
|
|
56
|
+
outputs: { response: { ok: "uint128", error: "none" } }
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "get-token-uri",
|
|
60
|
+
access: "read-only",
|
|
61
|
+
args: [],
|
|
62
|
+
outputs: {
|
|
63
|
+
response: {
|
|
64
|
+
ok: { optional: { "string-utf8": { length: 256 } } },
|
|
65
|
+
error: "none"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// src/sbtc/constants.ts
|
|
73
|
+
var SBTC_CONTRACTS = {
|
|
74
|
+
mainnet: {
|
|
75
|
+
address: "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4",
|
|
76
|
+
token: "sbtc-token",
|
|
77
|
+
deposit: "sbtc-deposit",
|
|
78
|
+
registry: "sbtc-registry"
|
|
79
|
+
},
|
|
80
|
+
testnet: {
|
|
81
|
+
address: "SN3R84XZYA63QS28932XQF3G1J8R9PC3W76P9CSQS",
|
|
82
|
+
token: "sbtc-token",
|
|
83
|
+
deposit: "sbtc-deposit",
|
|
84
|
+
registry: "sbtc-registry"
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var SBTC_ASSET_IDENTIFIER_MAINNET = `${SBTC_CONTRACTS.mainnet.address}.${SBTC_CONTRACTS.mainnet.token}::sbtc-token`;
|
|
88
|
+
var SBTC_ASSET_IDENTIFIER_TESTNET = `${SBTC_CONTRACTS.testnet.address}.${SBTC_CONTRACTS.testnet.token}::sbtc-token`;
|
|
89
|
+
var SBTC_EVENT_TOPICS = [
|
|
90
|
+
"completed-deposit",
|
|
91
|
+
"withdrawal-create",
|
|
92
|
+
"withdrawal-accept",
|
|
93
|
+
"withdrawal-reject",
|
|
94
|
+
"key-rotation",
|
|
95
|
+
"update-protocol-contract"
|
|
96
|
+
];
|
|
97
|
+
var SBTC_BTC_ADDRESS_VERSION = {
|
|
98
|
+
p2pkh: 0,
|
|
99
|
+
p2sh: 1,
|
|
100
|
+
p2sh_p2wpkh: 2,
|
|
101
|
+
p2sh_p2wsh: 3,
|
|
102
|
+
p2wpkh: 4,
|
|
103
|
+
p2wsh: 5,
|
|
104
|
+
p2tr: 6
|
|
105
|
+
};
|
|
106
|
+
var SBTC_DECIMALS = 8;
|
|
107
|
+
var SBTC_UNIT_NAME = "satoshis";
|
|
108
|
+
function sbtcContractId(network, contract) {
|
|
109
|
+
const cfg = SBTC_CONTRACTS[network];
|
|
110
|
+
return `${cfg.address}.${cfg[contract]}`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/sbtc/actions.ts
|
|
114
|
+
function getTokenContract(client) {
|
|
115
|
+
if (!client.chain) {
|
|
116
|
+
throw new Error("Client must have a chain configured");
|
|
117
|
+
}
|
|
118
|
+
const network = client.chain.network;
|
|
119
|
+
const contract = network === "mainnet" ? SBTC_CONTRACTS.mainnet : SBTC_CONTRACTS.testnet;
|
|
120
|
+
return getContract({
|
|
121
|
+
client,
|
|
122
|
+
address: contract.address,
|
|
123
|
+
name: contract.token,
|
|
124
|
+
abi: SBTC_TOKEN_ABI
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
async function getTotalSupply(client) {
|
|
128
|
+
const token = getTokenContract(client);
|
|
129
|
+
return await token.read.getTotalSupply({});
|
|
130
|
+
}
|
|
131
|
+
async function getBalance(client, owner) {
|
|
132
|
+
const token = getTokenContract(client);
|
|
133
|
+
return await token.read.getBalance({ owner });
|
|
134
|
+
}
|
|
135
|
+
async function getName(client) {
|
|
136
|
+
const token = getTokenContract(client);
|
|
137
|
+
return await token.read.getName({});
|
|
138
|
+
}
|
|
139
|
+
async function getSymbol(client) {
|
|
140
|
+
const token = getTokenContract(client);
|
|
141
|
+
return await token.read.getSymbol({});
|
|
142
|
+
}
|
|
143
|
+
async function getDecimals(client) {
|
|
144
|
+
const token = getTokenContract(client);
|
|
145
|
+
return await token.read.getDecimals({});
|
|
146
|
+
}
|
|
147
|
+
async function getTokenUri(client) {
|
|
148
|
+
const token = getTokenContract(client);
|
|
149
|
+
return await token.read.getTokenUri({});
|
|
150
|
+
}
|
|
151
|
+
// src/sbtc/utils.ts
|
|
152
|
+
var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
153
|
+
function base58Encode(bytes) {
|
|
154
|
+
let num = 0n;
|
|
155
|
+
for (const byte of bytes)
|
|
156
|
+
num = num * 256n + BigInt(byte);
|
|
157
|
+
let str = "";
|
|
158
|
+
while (num > 0n) {
|
|
159
|
+
const r = num % 58n;
|
|
160
|
+
str = BASE58_ALPHABET[Number(r)] + str;
|
|
161
|
+
num /= 58n;
|
|
162
|
+
}
|
|
163
|
+
for (const byte of bytes) {
|
|
164
|
+
if (byte === 0)
|
|
165
|
+
str = `1${str}`;
|
|
166
|
+
else
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
return str;
|
|
170
|
+
}
|
|
171
|
+
function sha256(bytes) {
|
|
172
|
+
const hasher = new Bun.CryptoHasher("sha256");
|
|
173
|
+
hasher.update(bytes);
|
|
174
|
+
return hasher.digest();
|
|
175
|
+
}
|
|
176
|
+
function doubleSha256(bytes) {
|
|
177
|
+
return sha256(sha256(bytes));
|
|
178
|
+
}
|
|
179
|
+
function base58CheckEncode(version, hashbytes) {
|
|
180
|
+
const payload = new Uint8Array(1 + hashbytes.length);
|
|
181
|
+
payload[0] = version;
|
|
182
|
+
payload.set(hashbytes, 1);
|
|
183
|
+
const checksum = doubleSha256(payload).slice(0, 4);
|
|
184
|
+
const full = new Uint8Array(payload.length + 4);
|
|
185
|
+
full.set(payload, 0);
|
|
186
|
+
full.set(checksum, payload.length);
|
|
187
|
+
return base58Encode(full);
|
|
188
|
+
}
|
|
189
|
+
function formatBtcAddress(recipient) {
|
|
190
|
+
const { version, hashbytes } = recipient;
|
|
191
|
+
switch (version) {
|
|
192
|
+
case SBTC_BTC_ADDRESS_VERSION.p2pkh:
|
|
193
|
+
return base58CheckEncode(0, hashbytes);
|
|
194
|
+
case SBTC_BTC_ADDRESS_VERSION.p2sh:
|
|
195
|
+
case SBTC_BTC_ADDRESS_VERSION.p2sh_p2wpkh:
|
|
196
|
+
case SBTC_BTC_ADDRESS_VERSION.p2sh_p2wsh:
|
|
197
|
+
return base58CheckEncode(5, hashbytes);
|
|
198
|
+
case SBTC_BTC_ADDRESS_VERSION.p2wpkh:
|
|
199
|
+
case SBTC_BTC_ADDRESS_VERSION.p2wsh: {
|
|
200
|
+
const words = bech32.toWords(hashbytes);
|
|
201
|
+
return bech32.encode("bc", [0, ...words]);
|
|
202
|
+
}
|
|
203
|
+
case SBTC_BTC_ADDRESS_VERSION.p2tr: {
|
|
204
|
+
const words = bech32m.toWords(hashbytes);
|
|
205
|
+
return bech32m.encode("bc", [1, ...words]);
|
|
206
|
+
}
|
|
207
|
+
default:
|
|
208
|
+
throw new Error(`Unknown BTC address version: ${version}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function validateBitcoinTxid(buf) {
|
|
212
|
+
if (buf.length !== 32) {
|
|
213
|
+
throw new Error(`Bitcoin txid must be 32 bytes, got ${buf.length}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function bitcoinTxidToHex(buf) {
|
|
217
|
+
validateBitcoinTxid(buf);
|
|
218
|
+
return bytesToHex(buf);
|
|
219
|
+
}
|
|
220
|
+
function bitcoinTxidFromHex(hex) {
|
|
221
|
+
const buf = hexToBytes(hex);
|
|
222
|
+
validateBitcoinTxid(buf);
|
|
223
|
+
return buf;
|
|
224
|
+
}
|
|
225
|
+
function satsToSbtc(sats) {
|
|
226
|
+
const sign = sats < 0n ? "-" : "";
|
|
227
|
+
const abs = sats < 0n ? -sats : sats;
|
|
228
|
+
const whole = abs / 100000000n;
|
|
229
|
+
const frac = abs % 100000000n;
|
|
230
|
+
if (frac === 0n)
|
|
231
|
+
return `${sign}${whole}`;
|
|
232
|
+
const fracStr = frac.toString().padStart(8, "0").replace(/0+$/, "");
|
|
233
|
+
return `${sign}${whole}.${fracStr}`;
|
|
234
|
+
}
|
|
235
|
+
function sbtcToSats(amount) {
|
|
236
|
+
const trimmed = amount.trim();
|
|
237
|
+
if (!/^-?\d+(?:\.\d+)?$/.test(trimmed)) {
|
|
238
|
+
throw new Error(`Invalid sBTC amount: ${amount}`);
|
|
239
|
+
}
|
|
240
|
+
const negative = trimmed.startsWith("-");
|
|
241
|
+
const body = negative ? trimmed.slice(1) : trimmed;
|
|
242
|
+
const dotIndex = body.indexOf(".");
|
|
243
|
+
const whole = dotIndex < 0 ? body : body.slice(0, dotIndex);
|
|
244
|
+
const frac = dotIndex < 0 ? "" : body.slice(dotIndex + 1);
|
|
245
|
+
if (frac.length > 8) {
|
|
246
|
+
throw new Error(`sBTC amount has more than 8 decimal places: ${amount}`);
|
|
247
|
+
}
|
|
248
|
+
const padded = frac.padEnd(8, "0");
|
|
249
|
+
const sats = BigInt(whole) * 100000000n + BigInt(padded);
|
|
250
|
+
return negative ? -sats : sats;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// src/sbtc/index.ts
|
|
254
|
+
function sbtc() {
|
|
255
|
+
return (client) => ({
|
|
256
|
+
sbtc: {
|
|
257
|
+
getTotalSupply: () => getTotalSupply(client),
|
|
258
|
+
getBalance: (owner) => getBalance(client, owner),
|
|
259
|
+
getName: () => getName(client),
|
|
260
|
+
getSymbol: () => getSymbol(client),
|
|
261
|
+
getDecimals: () => getDecimals(client),
|
|
262
|
+
getTokenUri: () => getTokenUri(client)
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
export {
|
|
267
|
+
validateBitcoinTxid,
|
|
268
|
+
sbtcToSats,
|
|
269
|
+
sbtcContractId,
|
|
270
|
+
sbtc,
|
|
271
|
+
satsToSbtc,
|
|
272
|
+
formatBtcAddress,
|
|
273
|
+
bitcoinTxidToHex,
|
|
274
|
+
bitcoinTxidFromHex,
|
|
275
|
+
SBTC_UNIT_NAME,
|
|
276
|
+
SBTC_TOKEN_ABI,
|
|
277
|
+
SBTC_EVENT_TOPICS,
|
|
278
|
+
SBTC_DECIMALS,
|
|
279
|
+
SBTC_CONTRACTS,
|
|
280
|
+
SBTC_BTC_ADDRESS_VERSION,
|
|
281
|
+
SBTC_ASSET_IDENTIFIER_TESTNET,
|
|
282
|
+
SBTC_ASSET_IDENTIFIER_MAINNET
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
//# debugId=ABC665DEBE54FC7C64756E2164756E21
|
|
286
|
+
//# sourceMappingURL=index.js.map
|