@arkade-os/sdk 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +156 -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 +41 -17
  8. package/dist/cjs/providers/ark.js +253 -317
  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 +46 -14
  15. package/dist/cjs/script/vhtlc.js +27 -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 +58 -34
  32. package/dist/cjs/wallet/serviceWorker/worker.js +117 -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 +30 -12
  41. package/dist/esm/providers/ark.js +252 -317
  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 +46 -14
  48. package/dist/esm/script/vhtlc.js +27 -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 +59 -35
  65. package/dist/esm/wallet/serviceWorker/worker.js +117 -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 +23 -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 +14 -15
  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,8 @@
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
+
4
6
  ## Installation
5
7
 
6
8
  ```bash
@@ -12,40 +14,84 @@ npm install @arkade-os/sdk
12
14
  ### Creating a Wallet
13
15
 
14
16
  ```typescript
15
- import { InMemoryKey, Wallet } from '@arkade-os/sdk'
17
+ import { SingleKey, Wallet } from '@arkade-os/sdk'
16
18
 
17
19
  // Create a new in-memory key (or use an external signer)
18
- const identity = InMemoryKey.fromHex('your_private_key_hex')
20
+ const identity = SingleKey.fromHex('your_private_key_hex')
19
21
 
20
22
  // Create a wallet with Ark support
21
23
  const wallet = await Wallet.create({
22
- network: 'mutinynet', // 'bitcoin', 'testnet', 'regtest', 'signet' or 'mutinynet'
23
24
  identity: identity,
24
25
  // Esplora API, can be left empty mempool.space API will be used
25
26
  esploraUrl: 'https://mutinynet.com/api',
26
- // OPTIONAL Ark Server connection information
27
27
  arkServerUrl: 'https://mutinynet.arkade.sh',
28
- arkServerPublicKey: 'fa73c6e4876ffb2dfc961d763cca9abc73d4b88efcb8f5e7ff92dc55e9aa553d'
29
28
  })
29
+ ```
30
+
31
+ ### Receiving Bitcoin
30
32
 
33
+ ```typescript
31
34
  // 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)
35
+ const arkAddress = await wallet.getAddress()
36
+ const boardingAddress = await wallet.getBoardingAddress()
37
+ console.log('Ark Address:', arkAddress)
38
+ console.log('Boarding Address:', boardingAddress)
39
+
40
+ const incomingFunds = await waitForIncomingFunds(wallet)
41
+ if (incomingFunds.type === "vtxo") {
42
+ // virtual coins received
43
+ console.log("VTXOs: ", incomingFunds.vtxos)
44
+ } else if (incomingFunds.type === "utxo") {
45
+ // boarding coins received
46
+ console.log("UTXOs: ", incomingFunds.coins)
47
+ }
48
+ ```
49
+
50
+ ### Onboarding
51
+
52
+ Onboarding allows you to swap onchain funds into VTXOs
53
+
54
+ ```typescript
55
+ import { Ramps } from '@arkade-os/sdk'
56
+
57
+ const onboardTxid = await new Ramps(wallet).onboard();
58
+ ```
59
+
60
+ ### Checking Balance
61
+
62
+ ```typescript
63
+ // Get detailed balance information
64
+ const balance = await wallet.getBalance()
65
+ console.log('Total Balance:', balance.total)
66
+ console.log('Boarding Total:', balance.boarding.total)
67
+ console.log('Offchain Available:', balance.available)
68
+ console.log('Offchain Settled:', balance.settled)
69
+ console.log('Offchain Preconfirmed:', balance.preconfirmed)
70
+ console.log('Recoverable:', balance.recoverable)
71
+
72
+ // Get virtual UTXOs (off-chain)
73
+ const virtualCoins = await wallet.getVtxos()
74
+
75
+ // Get boarding UTXOs
76
+ const boardingUtxos = await wallet.getBoardingUtxos()
37
77
  ```
38
78
 
39
79
  ### Sending Bitcoin
40
80
 
41
81
  ```typescript
42
- // Send bitcoin (automatically chooses on-chain or off-chain based on the address)
82
+ // Send bitcoin via Ark
43
83
  const txid = await wallet.sendBitcoin({
44
84
  address: 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx',
45
85
  amount: 50000, // in satoshis
46
86
  feeRate: 1 // optional, in sats/vbyte
47
87
  })
88
+ ```
48
89
 
90
+ ### Batch Settlements
91
+
92
+ This can be used to move preconfirmed balances into finalized balances, to convert manually UTXOs and VTXOs.
93
+
94
+ ```typescript
49
95
  // For settling transactions
50
96
  const settleTxid = await wallet.settle({
51
97
  inputs, // from getVtxos() or getBoardingUtxos()
@@ -56,20 +102,6 @@ const settleTxid = await wallet.settle({
56
102
  })
57
103
  ```
58
104
 
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
105
 
74
106
  ### Transaction History
75
107
 
@@ -80,26 +112,94 @@ console.log('History:', history)
80
112
 
81
113
  // Example history entry:
82
114
  {
83
- type: TxType.TxReceived, // or TxType.TxSent
84
- amount: 50000,
85
- settled: true,
86
115
  key: {
87
116
  boardingTxid: '...', // for boarding transactions
117
+ commitmentTxid: '...', // for commitment transactions
88
118
  redeemTxid: '...' // for regular transactions
89
- }
119
+ },
120
+ type: TxType.TxReceived, // or TxType.TxSent
121
+ amount: 50000,
122
+ settled: true,
123
+ createdAt: 1234567890
90
124
  }
91
125
  ```
92
126
 
127
+ ### Offboarding
128
+
129
+ Collaborative exit or "offboarding" allows you to withdraw your virtual funds to an onchain address.
130
+
131
+ ```typescript
132
+ import { Ramps } from '@arkade-os/sdk'
133
+
134
+ const exitTxid = await new Ramps(wallet).offboard(onchainAddress);
135
+ ```
136
+
93
137
  ### Unilateral Exit
94
138
 
139
+ 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:
140
+
141
+ 1. **Unrolling**: Broadcasting the transaction chain from off-chain back to on-chain
142
+ 2. **Completing the exit**: Spending the unrolled VTXOs after the timelock expires
143
+
144
+ #### Step 1: Unrolling VTXOs
145
+
95
146
  ```typescript
96
- // Unilateral exit all vtxos
97
- await wallet.exit();
147
+ import { Unroll, OnchainWallet } from '@arkade-os/sdk'
148
+
149
+ // Create an onchain wallet to pay for P2A outputs in VTXO branches
150
+ // OnchainWallet implements the AnchorBumper interface
151
+ const onchainWallet = new OnchainWallet(wallet.identity, 'regtest');
152
+
153
+ // Unroll a specific VTXO
154
+ const vtxo = { txid: 'your_vtxo_txid', vout: 0 };
155
+ const session = await Unroll.Session.create(
156
+ vtxo,
157
+ onchainWallet,
158
+ onchainWallet.provider,
159
+ wallet.indexerProvider
160
+ );
161
+
162
+ // Iterate through the unrolling steps
163
+ for await (const step of session) {
164
+ switch (step.type) {
165
+ case Unroll.StepType.WAIT:
166
+ console.log(`Waiting for transaction ${step.txid} to be confirmed`);
167
+ break;
168
+ case Unroll.StepType.UNROLL:
169
+ console.log(`Broadcasting transaction ${step.tx.id}`);
170
+ break;
171
+ case Unroll.StepType.DONE:
172
+ console.log(`Unrolling complete for VTXO ${step.vtxoTxid}`);
173
+ break;
174
+ }
175
+ }
176
+ ```
177
+
178
+ The unrolling process works by:
179
+ - Traversing the transaction chain from the root (most recent) to the leaf (oldest)
180
+ - Broadcasting each transaction that isn't already on-chain
181
+ - Waiting for confirmations between steps
182
+ - Using P2A (Pay-to-Anchor) transactions to pay for fees
98
183
 
99
- // Unilateral exit a specific vtxo
100
- await wallet.exit([{ txid: vtxo.txid, vout: vtxo.vout }]);
184
+ #### Step 2: Completing the Exit
185
+
186
+ Once VTXOs are fully unrolled and the unilateral exit timelock has expired, you can complete the exit:
187
+
188
+ ```typescript
189
+ // Complete the exit for specific VTXOs
190
+ await Unroll.completeUnroll(
191
+ wallet,
192
+ [vtxo.txid], // Array of VTXO transaction IDs to complete
193
+ onchainWallet.address // Address to receive the exit amount
194
+ );
101
195
  ```
102
196
 
197
+ **Important Notes:**
198
+ - Each VTXO may require multiple unroll steps depending on the transaction chain length
199
+ - Each unroll step must be confirmed before proceeding to the next
200
+ - The `completeUnroll` method can only be called after VTXOs are fully unrolled and the timelock has expired
201
+ - You need sufficient on-chain funds in the `OnchainWallet` to pay for P2A transaction fees
202
+
103
203
  ### Running the wallet in a service worker
104
204
 
105
205
  1. Create a service worker file
@@ -108,7 +208,7 @@ await wallet.exit([{ txid: vtxo.txid, vout: vtxo.vout }]);
108
208
  // service-worker.ts
109
209
  import { Worker } from '@arkade-os/sdk'
110
210
 
111
- // Worker is a class handling the communication between the main thread and the service worker
211
+ // Worker handles communication between the main thread and service worker
112
212
  new Worker().start()
113
213
  ```
114
214
 
@@ -120,15 +220,13 @@ new Worker().start()
120
220
  const serviceWorker = await setupServiceWorker('/service-worker.js')
121
221
  const wallet = new ServiceWorkerWallet(serviceWorker)
122
222
 
123
- // initialize the wallet
223
+ // Initialize the wallet
124
224
  await wallet.init({
125
- network: 'mutinynet', // 'bitcoin', 'testnet', 'regtest', 'signet' or 'mutinynet'
126
225
  privateKey: 'your_private_key_hex',
127
226
  // Esplora API, can be left empty mempool.space API will be used
128
227
  esploraUrl: 'https://mutinynet.com/api',
129
228
  // OPTIONAL Ark Server connection information
130
229
  arkServerUrl: 'https://mutinynet.arkade.sh',
131
- arkServerPublicKey: 'fa73c6e4876ffb2dfc961d763cca9abc73d4b88efcb8f5e7ff92dc55e9aa553d'
132
230
  })
133
231
 
134
232
  // check service worker status
@@ -139,140 +237,7 @@ console.log('Service worker status:', status.walletInitialized)
139
237
  await wallet.clear()
140
238
  ```
141
239
 
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
- ```
240
+ _For complete API documentation, visit our [TypeScript documentation](https://arkade-os.github.io/ts-sdk/)._
276
241
 
277
242
  ## Development
278
243
 
@@ -291,7 +256,7 @@ pnpm format
291
256
  pnpm lint
292
257
  ```
293
258
 
294
- 2.Install nigiri for integration tests:
259
+ 2. Install nigiri for integration tests:
295
260
 
296
261
  ```bash
297
262
  curl https://getnigiri.vulpem.com | bash
@@ -306,12 +271,20 @@ pnpm test
306
271
  # Run unit tests only
307
272
  pnpm test:unit
308
273
 
309
- # Run integration tests (requires nigiri)
274
+ # Run integration tests with ark provided by nigiri
310
275
  nigiri start --ark
311
- pnpm test:setup # Run setup script for integration tests
276
+ pnpm test:setup # Run setup script for integration tests
312
277
  pnpm test:integration
313
278
  nigiri stop --delete
314
279
 
280
+ # Run integration tests with ark provided by docker (requires nigiri)
281
+ nigiri start
282
+ pnpm test:up-docker
283
+ pnpm test:setup-docker # Run setup script for integration tests
284
+ pnpm test:integration-docker
285
+ pnpm test:down-docker
286
+ nigiri stop --delete
287
+
315
288
  # Watch mode for development
316
289
  pnpm test:watch
317
290
 
@@ -319,6 +292,15 @@ pnpm test:watch
319
292
  pnpm test:coverage
320
293
  ```
321
294
 
295
+ ### Building the documentation
296
+
297
+ ```bash
298
+ # Build the TS doc
299
+ pnpm docs:build
300
+ # open the docs in the browser
301
+ pnpm docs:open
302
+ ```
303
+
322
304
  ### Releasing
323
305
 
324
306
  ```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");