@arkade-os/sdk 0.1.4 → 0.2.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.
Files changed (114) hide show
  1. package/README.md +157 -174
  2. package/dist/cjs/arknote/index.js +61 -58
  3. package/dist/cjs/bip322/errors.js +13 -0
  4. package/dist/cjs/bip322/index.js +178 -0
  5. package/dist/cjs/forfeit.js +14 -25
  6. package/dist/cjs/identity/singleKey.js +68 -0
  7. package/dist/cjs/index.js +43 -17
  8. package/dist/cjs/providers/ark.js +261 -321
  9. package/dist/cjs/providers/indexer.js +525 -0
  10. package/dist/cjs/providers/onchain.js +193 -15
  11. package/dist/cjs/script/address.js +48 -17
  12. package/dist/cjs/script/base.js +120 -3
  13. package/dist/cjs/script/default.js +18 -4
  14. package/dist/cjs/script/tapscript.js +61 -20
  15. package/dist/cjs/script/vhtlc.js +85 -7
  16. package/dist/cjs/tree/signingSession.js +63 -106
  17. package/dist/cjs/tree/txTree.js +193 -0
  18. package/dist/cjs/tree/validation.js +79 -155
  19. package/dist/cjs/utils/anchor.js +35 -0
  20. package/dist/cjs/utils/arkTransaction.js +108 -0
  21. package/dist/cjs/utils/transactionHistory.js +84 -72
  22. package/dist/cjs/utils/txSizeEstimator.js +12 -0
  23. package/dist/cjs/utils/unknownFields.js +211 -0
  24. package/dist/cjs/wallet/index.js +12 -0
  25. package/dist/cjs/wallet/onchain.js +201 -0
  26. package/dist/cjs/wallet/ramps.js +95 -0
  27. package/dist/cjs/wallet/serviceWorker/db/vtxo/idb.js +32 -0
  28. package/dist/cjs/wallet/serviceWorker/request.js +15 -12
  29. package/dist/cjs/wallet/serviceWorker/response.js +22 -27
  30. package/dist/cjs/wallet/serviceWorker/utils.js +8 -0
  31. package/dist/cjs/wallet/serviceWorker/wallet.js +61 -34
  32. package/dist/cjs/wallet/serviceWorker/worker.js +120 -108
  33. package/dist/cjs/wallet/unroll.js +270 -0
  34. package/dist/cjs/wallet/wallet.js +701 -454
  35. package/dist/esm/arknote/index.js +61 -57
  36. package/dist/esm/bip322/errors.js +9 -0
  37. package/dist/esm/bip322/index.js +174 -0
  38. package/dist/esm/forfeit.js +15 -26
  39. package/dist/esm/identity/singleKey.js +64 -0
  40. package/dist/esm/index.js +31 -12
  41. package/dist/esm/providers/ark.js +259 -320
  42. package/dist/esm/providers/indexer.js +521 -0
  43. package/dist/esm/providers/onchain.js +193 -15
  44. package/dist/esm/script/address.js +48 -17
  45. package/dist/esm/script/base.js +120 -3
  46. package/dist/esm/script/default.js +18 -4
  47. package/dist/esm/script/tapscript.js +61 -20
  48. package/dist/esm/script/vhtlc.js +85 -7
  49. package/dist/esm/tree/signingSession.js +65 -108
  50. package/dist/esm/tree/txTree.js +189 -0
  51. package/dist/esm/tree/validation.js +75 -152
  52. package/dist/esm/utils/anchor.js +31 -0
  53. package/dist/esm/utils/arkTransaction.js +105 -0
  54. package/dist/esm/utils/transactionHistory.js +84 -72
  55. package/dist/esm/utils/txSizeEstimator.js +12 -0
  56. package/dist/esm/utils/unknownFields.js +173 -0
  57. package/dist/esm/wallet/index.js +9 -0
  58. package/dist/esm/wallet/onchain.js +196 -0
  59. package/dist/esm/wallet/ramps.js +91 -0
  60. package/dist/esm/wallet/serviceWorker/db/vtxo/idb.js +32 -0
  61. package/dist/esm/wallet/serviceWorker/request.js +15 -12
  62. package/dist/esm/wallet/serviceWorker/response.js +22 -27
  63. package/dist/esm/wallet/serviceWorker/utils.js +8 -0
  64. package/dist/esm/wallet/serviceWorker/wallet.js +62 -35
  65. package/dist/esm/wallet/serviceWorker/worker.js +120 -108
  66. package/dist/esm/wallet/unroll.js +267 -0
  67. package/dist/esm/wallet/wallet.js +674 -461
  68. package/dist/types/arknote/index.d.ts +40 -13
  69. package/dist/types/bip322/errors.d.ts +6 -0
  70. package/dist/types/bip322/index.d.ts +57 -0
  71. package/dist/types/forfeit.d.ts +2 -14
  72. package/dist/types/identity/singleKey.d.ts +27 -0
  73. package/dist/types/index.d.ts +24 -12
  74. package/dist/types/providers/ark.d.ts +114 -95
  75. package/dist/types/providers/indexer.d.ts +186 -0
  76. package/dist/types/providers/onchain.d.ts +41 -11
  77. package/dist/types/script/address.d.ts +26 -2
  78. package/dist/types/script/base.d.ts +13 -3
  79. package/dist/types/script/default.d.ts +22 -0
  80. package/dist/types/script/tapscript.d.ts +61 -5
  81. package/dist/types/script/vhtlc.d.ts +27 -0
  82. package/dist/types/tree/signingSession.d.ts +5 -5
  83. package/dist/types/tree/txTree.d.ts +28 -0
  84. package/dist/types/tree/validation.d.ts +15 -22
  85. package/dist/types/utils/anchor.d.ts +19 -0
  86. package/dist/types/utils/arkTransaction.d.ts +27 -0
  87. package/dist/types/utils/transactionHistory.d.ts +7 -1
  88. package/dist/types/utils/txSizeEstimator.d.ts +3 -0
  89. package/dist/types/utils/unknownFields.d.ts +83 -0
  90. package/dist/types/wallet/index.d.ts +51 -50
  91. package/dist/types/wallet/onchain.d.ts +49 -0
  92. package/dist/types/wallet/ramps.d.ts +32 -0
  93. package/dist/types/wallet/serviceWorker/db/vtxo/idb.d.ts +2 -0
  94. package/dist/types/wallet/serviceWorker/db/vtxo/index.d.ts +2 -0
  95. package/dist/types/wallet/serviceWorker/request.d.ts +14 -16
  96. package/dist/types/wallet/serviceWorker/response.d.ts +17 -19
  97. package/dist/types/wallet/serviceWorker/utils.d.ts +8 -0
  98. package/dist/types/wallet/serviceWorker/wallet.d.ts +36 -8
  99. package/dist/types/wallet/serviceWorker/worker.d.ts +7 -3
  100. package/dist/types/wallet/unroll.d.ts +102 -0
  101. package/dist/types/wallet/wallet.d.ts +71 -25
  102. package/package.json +37 -35
  103. package/dist/cjs/identity/inMemoryKey.js +0 -40
  104. package/dist/cjs/tree/vtxoTree.js +0 -231
  105. package/dist/cjs/utils/coinselect.js +0 -73
  106. package/dist/cjs/utils/psbt.js +0 -137
  107. package/dist/esm/identity/inMemoryKey.js +0 -36
  108. package/dist/esm/tree/vtxoTree.js +0 -191
  109. package/dist/esm/utils/coinselect.js +0 -69
  110. package/dist/esm/utils/psbt.js +0 -131
  111. package/dist/types/identity/inMemoryKey.d.ts +0 -12
  112. package/dist/types/tree/vtxoTree.d.ts +0 -33
  113. package/dist/types/utils/coinselect.d.ts +0 -21
  114. package/dist/types/utils/psbt.d.ts +0 -11
package/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # Arkade TypeScript SDK
2
2
  The Arkade SDK is a TypeScript library for building Bitcoin wallets with support for both on-chain and off-chain transactions via the Ark protocol.
3
3
 
4
+ [![TypeScript Documentation](https://img.shields.io/badge/TypeScript-Documentation-blue?style=flat-square)](https://arkade-os.github.io/ts-sdk/)
5
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/arkade-os/ts-sdk)
6
+
4
7
  ## Installation
5
8
 
6
9
  ```bash
@@ -12,40 +15,84 @@ npm install @arkade-os/sdk
12
15
  ### Creating a Wallet
13
16
 
14
17
  ```typescript
15
- import { InMemoryKey, Wallet } from '@arkade-os/sdk'
18
+ import { SingleKey, Wallet } from '@arkade-os/sdk'
16
19
 
17
20
  // Create a new in-memory key (or use an external signer)
18
- const identity = InMemoryKey.fromHex('your_private_key_hex')
21
+ const identity = SingleKey.fromHex('your_private_key_hex')
19
22
 
20
23
  // Create a wallet with Ark support
21
24
  const wallet = await Wallet.create({
22
- network: 'mutinynet', // 'bitcoin', 'testnet', 'regtest', 'signet' or 'mutinynet'
23
25
  identity: identity,
24
26
  // Esplora API, can be left empty mempool.space API will be used
25
27
  esploraUrl: 'https://mutinynet.com/api',
26
- // OPTIONAL Ark Server connection information
27
28
  arkServerUrl: 'https://mutinynet.arkade.sh',
28
- arkServerPublicKey: 'fa73c6e4876ffb2dfc961d763cca9abc73d4b88efcb8f5e7ff92dc55e9aa553d'
29
29
  })
30
+ ```
31
+
32
+ ### Receiving Bitcoin
30
33
 
34
+ ```typescript
31
35
  // Get wallet addresses
32
- const addresses = await wallet.getAddress()
33
- console.log('Bitcoin Address:', addresses.onchain)
34
- console.log('Ark Address:', addresses.offchain)
35
- console.log('Boarding Address:', addresses.boarding)
36
- console.log('BIP21 URI:', addresses.bip21)
36
+ const arkAddress = await wallet.getAddress()
37
+ const boardingAddress = await wallet.getBoardingAddress()
38
+ console.log('Ark Address:', arkAddress)
39
+ console.log('Boarding Address:', boardingAddress)
40
+
41
+ const incomingFunds = await waitForIncomingFunds(wallet)
42
+ if (incomingFunds.type === "vtxo") {
43
+ // virtual coins received
44
+ console.log("VTXOs: ", incomingFunds.vtxos)
45
+ } else if (incomingFunds.type === "utxo") {
46
+ // boarding coins received
47
+ console.log("UTXOs: ", incomingFunds.coins)
48
+ }
49
+ ```
50
+
51
+ ### Onboarding
52
+
53
+ Onboarding allows you to swap onchain funds into VTXOs
54
+
55
+ ```typescript
56
+ import { Ramps } from '@arkade-os/sdk'
57
+
58
+ const onboardTxid = await new Ramps(wallet).onboard();
59
+ ```
60
+
61
+ ### Checking Balance
62
+
63
+ ```typescript
64
+ // Get detailed balance information
65
+ const balance = await wallet.getBalance()
66
+ console.log('Total Balance:', balance.total)
67
+ console.log('Boarding Total:', balance.boarding.total)
68
+ console.log('Offchain Available:', balance.available)
69
+ console.log('Offchain Settled:', balance.settled)
70
+ console.log('Offchain Preconfirmed:', balance.preconfirmed)
71
+ console.log('Recoverable:', balance.recoverable)
72
+
73
+ // Get virtual UTXOs (off-chain)
74
+ const virtualCoins = await wallet.getVtxos()
75
+
76
+ // Get boarding UTXOs
77
+ const boardingUtxos = await wallet.getBoardingUtxos()
37
78
  ```
38
79
 
39
80
  ### Sending Bitcoin
40
81
 
41
82
  ```typescript
42
- // Send bitcoin (automatically chooses on-chain or off-chain based on the address)
83
+ // Send bitcoin via Ark
43
84
  const txid = await wallet.sendBitcoin({
44
85
  address: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx',
45
86
  amount: 50000, // in satoshis
46
87
  feeRate: 1 // optional, in sats/vbyte
47
88
  })
89
+ ```
48
90
 
91
+ ### Batch Settlements
92
+
93
+ This can be used to move preconfirmed balances into finalized balances, to convert manually UTXOs and VTXOs.
94
+
95
+ ```typescript
49
96
  // For settling transactions
50
97
  const settleTxid = await wallet.settle({
51
98
  inputs, // from getVtxos() or getBoardingUtxos()
@@ -56,20 +103,6 @@ const settleTxid = await wallet.settle({
56
103
  })
57
104
  ```
58
105
 
59
- ### Checking Balance
60
-
61
- ```typescript
62
- // Get detailed balance information
63
- const balance = await wallet.getBalance()
64
- console.log('Total Onchain:', balance.onchain.total)
65
- console.log('Total Offchain:', balance.offchain.total)
66
-
67
- // Get virtual UTXOs (off-chain)
68
- const virtualCoins = await wallet.getVtxos()
69
-
70
- // Get boarding UTXOs
71
- const boardingUtxos = await wallet.getBoardingUtxos()
72
- ```
73
106
 
74
107
  ### Transaction History
75
108
 
@@ -80,26 +113,94 @@ console.log('History:', history)
80
113
 
81
114
  // Example history entry:
82
115
  {
83
- type: TxType.TxReceived, // or TxType.TxSent
84
- amount: 50000,
85
- settled: true,
86
116
  key: {
87
117
  boardingTxid: '...', // for boarding transactions
118
+ commitmentTxid: '...', // for commitment transactions
88
119
  redeemTxid: '...' // for regular transactions
89
- }
120
+ },
121
+ type: TxType.TxReceived, // or TxType.TxSent
122
+ amount: 50000,
123
+ settled: true,
124
+ createdAt: 1234567890
90
125
  }
91
126
  ```
92
127
 
128
+ ### Offboarding
129
+
130
+ Collaborative exit or "offboarding" allows you to withdraw your virtual funds to an onchain address.
131
+
132
+ ```typescript
133
+ import { Ramps } from '@arkade-os/sdk'
134
+
135
+ const exitTxid = await new Ramps(wallet).offboard(onchainAddress);
136
+ ```
137
+
93
138
  ### Unilateral Exit
94
139
 
140
+ Unilateral exit allows you to withdraw your funds from the Ark protocol back to the Bitcoin blockchain without requiring cooperation from the Ark server. This process involves two main steps:
141
+
142
+ 1. **Unrolling**: Broadcasting the transaction chain from off-chain back to on-chain
143
+ 2. **Completing the exit**: Spending the unrolled VTXOs after the timelock expires
144
+
145
+ #### Step 1: Unrolling VTXOs
146
+
95
147
  ```typescript
96
- // Unilateral exit all vtxos
97
- await wallet.exit();
148
+ import { Unroll, OnchainWallet } from '@arkade-os/sdk'
149
+
150
+ // Create an onchain wallet to pay for P2A outputs in VTXO branches
151
+ // OnchainWallet implements the AnchorBumper interface
152
+ const onchainWallet = new OnchainWallet(wallet.identity, 'regtest');
153
+
154
+ // Unroll a specific VTXO
155
+ const vtxo = { txid: 'your_vtxo_txid', vout: 0 };
156
+ const session = await Unroll.Session.create(
157
+ vtxo,
158
+ onchainWallet,
159
+ onchainWallet.provider,
160
+ wallet.indexerProvider
161
+ );
162
+
163
+ // Iterate through the unrolling steps
164
+ for await (const step of session) {
165
+ switch (step.type) {
166
+ case Unroll.StepType.WAIT:
167
+ console.log(`Waiting for transaction ${step.txid} to be confirmed`);
168
+ break;
169
+ case Unroll.StepType.UNROLL:
170
+ console.log(`Broadcasting transaction ${step.tx.id}`);
171
+ break;
172
+ case Unroll.StepType.DONE:
173
+ console.log(`Unrolling complete for VTXO ${step.vtxoTxid}`);
174
+ break;
175
+ }
176
+ }
177
+ ```
178
+
179
+ The unrolling process works by:
180
+ - Traversing the transaction chain from the root (most recent) to the leaf (oldest)
181
+ - Broadcasting each transaction that isn't already on-chain
182
+ - Waiting for confirmations between steps
183
+ - Using P2A (Pay-to-Anchor) transactions to pay for fees
98
184
 
99
- // Unilateral exit a specific vtxo
100
- await wallet.exit([{ txid: vtxo.txid, vout: vtxo.vout }]);
185
+ #### Step 2: Completing the Exit
186
+
187
+ Once VTXOs are fully unrolled and the unilateral exit timelock has expired, you can complete the exit:
188
+
189
+ ```typescript
190
+ // Complete the exit for specific VTXOs
191
+ await Unroll.completeUnroll(
192
+ wallet,
193
+ [vtxo.txid], // Array of VTXO transaction IDs to complete
194
+ onchainWallet.address // Address to receive the exit amount
195
+ );
101
196
  ```
102
197
 
198
+ **Important Notes:**
199
+ - Each VTXO may require multiple unroll steps depending on the transaction chain length
200
+ - Each unroll step must be confirmed before proceeding to the next
201
+ - The `completeUnroll` method can only be called after VTXOs are fully unrolled and the timelock has expired
202
+ - You need sufficient on-chain funds in the `OnchainWallet` to pay for P2A transaction fees
203
+
103
204
  ### Running the wallet in a service worker
104
205
 
105
206
  1. Create a service worker file
@@ -108,7 +209,7 @@ await wallet.exit([{ txid: vtxo.txid, vout: vtxo.vout }]);
108
209
  // service-worker.ts
109
210
  import { Worker } from '@arkade-os/sdk'
110
211
 
111
- // Worker is a class handling the communication between the main thread and the service worker
212
+ // Worker handles communication between the main thread and service worker
112
213
  new Worker().start()
113
214
  ```
114
215
 
@@ -120,15 +221,13 @@ new Worker().start()
120
221
  const serviceWorker = await setupServiceWorker('/service-worker.js')
121
222
  const wallet = new ServiceWorkerWallet(serviceWorker)
122
223
 
123
- // initialize the wallet
224
+ // Initialize the wallet
124
225
  await wallet.init({
125
- network: 'mutinynet', // 'bitcoin', 'testnet', 'regtest', 'signet' or 'mutinynet'
126
226
  privateKey: 'your_private_key_hex',
127
227
  // Esplora API, can be left empty mempool.space API will be used
128
228
  esploraUrl: 'https://mutinynet.com/api',
129
229
  // OPTIONAL Ark Server connection information
130
230
  arkServerUrl: 'https://mutinynet.arkade.sh',
131
- arkServerPublicKey: 'fa73c6e4876ffb2dfc961d763cca9abc73d4b88efcb8f5e7ff92dc55e9aa553d'
132
231
  })
133
232
 
134
233
  // check service worker status
@@ -139,140 +238,7 @@ console.log('Service worker status:', status.walletInitialized)
139
238
  await wallet.clear()
140
239
  ```
141
240
 
142
- ## API Reference
143
-
144
- ### Wallet
145
-
146
- #### Constructor Options
147
-
148
- ```typescript
149
- interface WalletConfig {
150
- /** Network to use ('bitcoin', 'testnet', 'regtest', 'signet', or 'mutinynet') */
151
- network: NetworkName;
152
- /** Identity for signing transactions */
153
- identity: Identity;
154
- /** Optional Esplora API URL */
155
- esploraUrl?: string;
156
- /** Ark server URL (optional) */
157
- arkServerUrl?: string;
158
- /** Ark server public key (optional) */
159
- arkServerPublicKey?: string;
160
- /** Optional boarding timelock configuration */
161
- boardingTimelock?: RelativeTimelock;
162
- /** Optional exit timelock configuration */
163
- exitTimelock?: RelativeTimelock;
164
- }
165
- ```
166
-
167
- #### Methods
168
-
169
- ```typescript
170
- interface IWallet {
171
- /** Get wallet addresses */
172
- getAddress(): Promise<{
173
- onchain?: Address;
174
- offchain?: Address;
175
- boarding?: Address;
176
- bip21?: string;
177
- }>;
178
-
179
- /** Get wallet balance */
180
- getBalance(): Promise<{
181
- onchain: {
182
- total: number;
183
- confirmed: number;
184
- unconfirmed: number;
185
- };
186
- offchain: {
187
- total: number;
188
- settled: number;
189
- pending: number;
190
- swept: number;
191
- };
192
- total: number;
193
- }>;
194
-
195
- /** Send bitcoin (on-chain or off-chain) */
196
- sendBitcoin(params: {
197
- address: string;
198
- amount: number;
199
- feeRate?: number;
200
- memo?: string;
201
- }, zeroFee?: boolean): Promise<string>;
202
-
203
- /** Get virtual UTXOs */
204
- getVtxos(): Promise<VirtualCoin[]>;
205
-
206
- /** Get boarding UTXOs */
207
- getBoardingUtxos(): Promise<BoardingUtxo[]>;
208
-
209
- /** Settle transactions */
210
- settle(params: {
211
- inputs: (VirtualCoin | BoardingUtxo)[];
212
- outputs: {
213
- address: string;
214
- amount: bigint;
215
- }[];
216
- }): Promise<string>;
217
-
218
- /** Get transaction history */
219
- getTransactionHistory(): Promise<Transaction[]>;
220
- }
221
-
222
- /** Transaction types */
223
- enum TxType {
224
- TxSent = 'sent',
225
- TxReceived = 'received'
226
- }
227
-
228
- /** Transaction history entry */
229
- interface Transaction {
230
- type: TxType;
231
- amount: number;
232
- settled: boolean;
233
- key: {
234
- boardingTxid?: string;
235
- redeemTxid?: string;
236
- };
237
- }
238
-
239
- /** Virtual coin (off-chain UTXO) */
240
- interface VirtualCoin {
241
- txid: string;
242
- value: number;
243
- virtualStatus: {
244
- state: 'pending' | 'settled';
245
- };
246
- spentBy?: string;
247
- createdAt: Date;
248
- }
249
-
250
- /** Boarding UTXO */
251
- interface BoardingUtxo {
252
- txid: string;
253
- vout: number;
254
- value: number;
255
- }
256
- ```
257
-
258
- #### Identity
259
-
260
- ```typescript
261
- export interface Identity {
262
- sign(tx: Transaction, inputIndexes?: number[]): Promise<Transaction>;
263
- xOnlyPublicKey(): Uint8Array;
264
- signerSession(): SignerSession;
265
- }
266
- ```
267
-
268
- The SDK provides a default implementation of the `Identity` interface: `InMemoryKey` for managing private keys in memory:
269
-
270
- ```typescript
271
- class InMemoryKey {
272
- static fromPrivateKey(privateKey: Uint8Array): InMemoryKey;
273
- static fromHex(privateKeyHex: string): InMemoryKey;
274
- }
275
- ```
241
+ _For complete API documentation, visit our [TypeScript documentation](https://arkade-os.github.io/ts-sdk/)._
276
242
 
277
243
  ## Development
278
244
 
@@ -291,7 +257,7 @@ pnpm format
291
257
  pnpm lint
292
258
  ```
293
259
 
294
- 2.Install nigiri for integration tests:
260
+ 2. Install nigiri for integration tests:
295
261
 
296
262
  ```bash
297
263
  curl https://getnigiri.vulpem.com | bash
@@ -306,12 +272,20 @@ pnpm test
306
272
  # Run unit tests only
307
273
  pnpm test:unit
308
274
 
309
- # Run integration tests (requires nigiri)
275
+ # Run integration tests with ark provided by nigiri
310
276
  nigiri start --ark
311
- pnpm test:setup # Run setup script for integration tests
277
+ pnpm test:setup # Run setup script for integration tests
312
278
  pnpm test:integration
313
279
  nigiri stop --delete
314
280
 
281
+ # Run integration tests with ark provided by docker (requires nigiri)
282
+ nigiri start
283
+ pnpm test:up-docker
284
+ pnpm test:setup-docker # Run setup script for integration tests
285
+ pnpm test:integration-docker
286
+ pnpm test:down-docker
287
+ nigiri stop --delete
288
+
315
289
  # Watch mode for development
316
290
  pnpm test:watch
317
291
 
@@ -319,6 +293,15 @@ pnpm test:watch
319
293
  pnpm test:coverage
320
294
  ```
321
295
 
296
+ ### Building the documentation
297
+
298
+ ```bash
299
+ # Build the TS doc
300
+ pnpm docs:build
301
+ # open the docs in the browser
302
+ pnpm docs:open
303
+ ```
304
+
322
305
  ### Releasing
323
306
 
324
307
  ```bash
@@ -1,81 +1,81 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ArkNote = exports.ArkNoteData = void 0;
3
+ exports.ArkNote = void 0;
4
4
  const base_1 = require("@scure/base");
5
- // ArkNoteData is the unsigned data part of a note
6
- class ArkNoteData {
7
- constructor(id, value) {
8
- this.id = id;
9
- this.value = value;
10
- }
11
- encode() {
12
- const array = new Uint8Array(12);
13
- writeBigUInt64BE(array, this.id, 0);
14
- writeUInt32BE(array, this.value, 8);
15
- return array;
16
- }
17
- static decode(data) {
18
- if (data.length !== 12) {
19
- throw new Error(`invalid data length: expected 12 bytes, got ${data.length}`);
20
- }
21
- const id = readBigUInt64BE(data, 0);
22
- const value = readUInt32BE(data, 8);
23
- return new ArkNoteData(id, value);
24
- }
25
- }
26
- exports.ArkNoteData = ArkNoteData;
27
- // ArkNote is a note with the issuer's signature
5
+ const base_2 = require("../script/base");
6
+ const utils_1 = require("@scure/btc-signer/utils");
7
+ const btc_signer_1 = require("@scure/btc-signer");
8
+ /**
9
+ * ArkNotes are special virtual coins in the Ark protocol that can be created
10
+ * and spent without requiring any transactions. The server mints them, and they
11
+ * are encoded as base58 strings with a human-readable prefix. It contains a
12
+ * preimage and value.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * // Create an ArkNote
17
+ * const note = new ArkNote(preimage, 50000);
18
+ *
19
+ * // Encode to string
20
+ * const noteString = note.toString();
21
+ *
22
+ * // Decode from string
23
+ * const decodedNote = ArkNote.fromString(noteString);
24
+ * ```
25
+ */
28
26
  class ArkNote {
29
- constructor(data, signature) {
30
- this.data = data;
31
- this.signature = signature;
27
+ constructor(preimage, value, HRP = ArkNote.DefaultHRP) {
28
+ this.preimage = preimage;
29
+ this.value = value;
30
+ this.HRP = HRP;
31
+ this.vout = 0;
32
+ const preimageHash = (0, utils_1.sha256)(this.preimage);
33
+ this.vtxoScript = new base_2.VtxoScript([noteTapscript(preimageHash)]);
34
+ const leaf = this.vtxoScript.leaves[0];
35
+ this.txid = base_1.hex.encode(new Uint8Array(preimageHash).reverse());
36
+ this.tapTree = this.vtxoScript.encode();
37
+ this.forfeitTapLeafScript = leaf;
38
+ this.intentTapLeafScript = leaf;
39
+ this.value = value;
40
+ this.status = { confirmed: true };
41
+ this.extraWitness = [this.preimage];
32
42
  }
33
43
  encode() {
34
- const detailsBytes = this.data.encode();
35
- const result = new Uint8Array(detailsBytes.length + this.signature.length);
36
- result.set(detailsBytes);
37
- result.set(this.signature, detailsBytes.length);
44
+ const result = new Uint8Array(ArkNote.Length);
45
+ result.set(this.preimage, 0);
46
+ writeUInt32BE(result, this.value, this.preimage.length);
38
47
  return result;
39
48
  }
40
- static decode(data) {
41
- if (data.length < 12) {
42
- throw new Error(`invalid data length: expected at least 12 bytes, got ${data.length}`);
49
+ static decode(data, hrp = ArkNote.DefaultHRP) {
50
+ if (data.length !== ArkNote.Length) {
51
+ throw new Error(`invalid data length: expected ${ArkNote.Length} bytes, got ${data.length}`);
43
52
  }
44
- const noteData = ArkNoteData.decode(data.subarray(0, 12));
45
- const signature = data.subarray(12);
46
- if (signature.length !== 64) {
47
- throw new Error(`invalid signature length: expected 64 bytes, got ${signature.length}`);
48
- }
49
- return new ArkNote(noteData, signature);
53
+ const preimage = data.subarray(0, ArkNote.PreimageLength);
54
+ const value = readUInt32BE(data, ArkNote.PreimageLength);
55
+ return new ArkNote(preimage, value, hrp);
50
56
  }
51
- static fromString(noteStr) {
52
- if (!noteStr.startsWith(ArkNote.HRP)) {
53
- throw new Error(`invalid human-readable part: expected ${ArkNote.HRP} prefix (note '${noteStr}')`);
54
- }
55
- const encoded = noteStr.slice(ArkNote.HRP.length);
56
- if (encoded.length < 103 || encoded.length > 104) {
57
- throw new Error(`invalid note length: expected 103 or 104 chars, got ${encoded.length}`);
57
+ static fromString(noteStr, hrp = ArkNote.DefaultHRP) {
58
+ noteStr = noteStr.trim();
59
+ if (!noteStr.startsWith(hrp)) {
60
+ throw new Error(`invalid human-readable part: expected ${hrp} prefix (note '${noteStr}')`);
58
61
  }
62
+ const encoded = noteStr.slice(hrp.length);
59
63
  const decoded = base_1.base58.decode(encoded);
60
64
  if (decoded.length === 0) {
61
65
  throw new Error("failed to decode base58 string");
62
66
  }
63
- return ArkNote.decode(new Uint8Array(decoded));
67
+ return ArkNote.decode(decoded, hrp);
64
68
  }
65
69
  toString() {
66
- return ArkNote.HRP + base_1.base58.encode(this.encode());
70
+ return this.HRP + base_1.base58.encode(this.encode());
67
71
  }
68
72
  }
69
73
  exports.ArkNote = ArkNote;
70
- ArkNote.HRP = "arknote";
71
- function writeBigUInt64BE(array, value, offset) {
72
- const view = new DataView(array.buffer, array.byteOffset + offset, 8);
73
- view.setBigUint64(0, value, false);
74
- }
75
- function readBigUInt64BE(array, offset) {
76
- const view = new DataView(array.buffer, array.byteOffset + offset, 8);
77
- return view.getBigUint64(0, false);
78
- }
74
+ ArkNote.DefaultHRP = "arknote";
75
+ ArkNote.PreimageLength = 32; // 32 bytes for the preimage
76
+ ArkNote.ValueLength = 4; // 4 bytes for the value
77
+ ArkNote.Length = ArkNote.PreimageLength + ArkNote.ValueLength;
78
+ ArkNote.FakeOutpointIndex = 0;
79
79
  function writeUInt32BE(array, value, offset) {
80
80
  const view = new DataView(array.buffer, array.byteOffset + offset, 4);
81
81
  view.setUint32(0, value, false);
@@ -84,3 +84,6 @@ function readUInt32BE(array, offset) {
84
84
  const view = new DataView(array.buffer, array.byteOffset + offset, 4);
85
85
  return view.getUint32(0, false);
86
86
  }
87
+ function noteTapscript(preimageHash) {
88
+ return btc_signer_1.Script.encode(["SHA256", preimageHash, "EQUAL"]);
89
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ErrMissingWitnessUtxo = exports.ErrMissingData = exports.ErrMissingInputs = exports.BIP322Error = void 0;
4
+ class BIP322Error extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "BIP322Error";
8
+ }
9
+ }
10
+ exports.BIP322Error = BIP322Error;
11
+ exports.ErrMissingInputs = new BIP322Error("missing inputs");
12
+ exports.ErrMissingData = new BIP322Error("missing data");
13
+ exports.ErrMissingWitnessUtxo = new BIP322Error("missing witness utxo");