@arkade-os/sdk 0.4.15 → 0.4.16
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/README.md +102 -96
- package/dist/cjs/arkfee/estimator.js +1 -1
- package/dist/cjs/arkfee/types.js +2 -1
- package/dist/cjs/arknote/index.js +43 -4
- package/dist/cjs/bip322/index.js +1 -1
- package/dist/cjs/contracts/arkcontract.js +1 -1
- package/dist/cjs/contracts/contractManager.js +40 -24
- package/dist/cjs/contracts/contractWatcher.js +29 -22
- package/dist/cjs/contracts/handlers/default.js +1 -1
- package/dist/cjs/contracts/handlers/delegate.js +1 -1
- package/dist/cjs/contracts/handlers/helpers.js +1 -1
- package/dist/cjs/extension/asset/assetGroup.js +92 -5
- package/dist/cjs/extension/asset/assetId.js +67 -3
- package/dist/cjs/extension/asset/assetInput.js +18 -0
- package/dist/cjs/extension/asset/assetOutput.js +15 -0
- package/dist/cjs/extension/asset/assetRef.js +66 -0
- package/dist/cjs/extension/asset/metadata.js +15 -0
- package/dist/cjs/extension/asset/packet.js +4 -1
- package/dist/cjs/extension/index.js +1 -1
- package/dist/cjs/forfeit.js +14 -0
- package/dist/cjs/identity/seedIdentity.js +2 -2
- package/dist/cjs/identity/singleKey.js +4 -0
- package/dist/cjs/intent/index.js +28 -12
- package/dist/cjs/providers/ark.js +3 -2
- package/dist/cjs/providers/delegator.js +20 -1
- package/dist/cjs/providers/expoArk.js +2 -2
- package/dist/cjs/providers/indexer.js +2 -2
- package/dist/cjs/providers/onchain.js +2 -1
- package/dist/cjs/repositories/realm/schemas.js +2 -2
- package/dist/cjs/repositories/realm/types.js +1 -1
- package/dist/cjs/script/address.js +37 -6
- package/dist/cjs/script/base.js +70 -1
- package/dist/cjs/script/default.js +3 -0
- package/dist/cjs/script/delegate.js +4 -0
- package/dist/cjs/script/tapscript.js +17 -2
- package/dist/cjs/script/vhtlc.js +35 -27
- package/dist/cjs/storage/fileSystem.js +1 -1
- package/dist/cjs/storage/inMemory.js +1 -1
- package/dist/cjs/storage/indexedDB.js +1 -1
- package/dist/cjs/storage/localStorage.js +1 -1
- package/dist/cjs/tree/validation.js +1 -1
- package/dist/cjs/utils/arkTransaction.js +5 -5
- package/dist/cjs/utils/bip21.js +16 -3
- package/dist/cjs/utils/syncCursors.js +4 -4
- package/dist/cjs/utils/transaction.js +1 -1
- package/dist/cjs/utils/transactionHistory.js +11 -11
- package/dist/cjs/utils/unknownFields.js +3 -3
- package/dist/cjs/wallet/asset-manager.js +4 -4
- package/dist/cjs/wallet/batch.js +5 -5
- package/dist/cjs/wallet/delegator.js +9 -8
- package/dist/cjs/wallet/expo/background.js +3 -3
- package/dist/cjs/wallet/expo/wallet.js +7 -7
- package/dist/cjs/wallet/index.js +43 -0
- package/dist/cjs/wallet/onchain.js +43 -5
- package/dist/cjs/wallet/ramps.js +44 -14
- package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +22 -22
- package/dist/cjs/wallet/serviceWorker/wallet.js +28 -24
- package/dist/cjs/wallet/unroll.js +12 -8
- package/dist/cjs/wallet/utils.js +1 -1
- package/dist/cjs/wallet/vtxo-manager.js +122 -82
- package/dist/cjs/wallet/wallet.js +125 -67
- package/dist/cjs/worker/expo/asyncStorageTaskQueue.js +1 -1
- package/dist/cjs/worker/expo/processors/contractPollProcessor.js +2 -2
- package/dist/cjs/worker/expo/taskRunner.js +3 -3
- package/dist/cjs/worker/messageBus.js +3 -0
- package/dist/esm/arkfee/estimator.js +1 -1
- package/dist/esm/arkfee/types.js +2 -1
- package/dist/esm/arknote/index.js +43 -4
- package/dist/esm/bip322/index.js +1 -1
- package/dist/esm/contracts/arkcontract.js +1 -1
- package/dist/esm/contracts/contractManager.js +40 -24
- package/dist/esm/contracts/contractWatcher.js +29 -22
- package/dist/esm/contracts/handlers/default.js +1 -1
- package/dist/esm/contracts/handlers/delegate.js +1 -1
- package/dist/esm/contracts/handlers/helpers.js +1 -1
- package/dist/esm/extension/asset/assetGroup.js +92 -5
- package/dist/esm/extension/asset/assetId.js +67 -3
- package/dist/esm/extension/asset/assetInput.js +18 -0
- package/dist/esm/extension/asset/assetOutput.js +15 -0
- package/dist/esm/extension/asset/assetRef.js +66 -0
- package/dist/esm/extension/asset/metadata.js +15 -0
- package/dist/esm/extension/asset/packet.js +4 -1
- package/dist/esm/extension/index.js +1 -1
- package/dist/esm/forfeit.js +14 -0
- package/dist/esm/identity/seedIdentity.js +2 -2
- package/dist/esm/identity/singleKey.js +4 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/intent/index.js +28 -12
- package/dist/esm/providers/ark.js +3 -2
- package/dist/esm/providers/delegator.js +20 -1
- package/dist/esm/providers/expoArk.js +2 -2
- package/dist/esm/providers/indexer.js +2 -2
- package/dist/esm/providers/onchain.js +2 -1
- package/dist/esm/repositories/realm/schemas.js +2 -2
- package/dist/esm/repositories/realm/types.js +1 -1
- package/dist/esm/script/address.js +37 -6
- package/dist/esm/script/base.js +70 -1
- package/dist/esm/script/default.js +3 -0
- package/dist/esm/script/delegate.js +4 -0
- package/dist/esm/script/tapscript.js +17 -2
- package/dist/esm/script/vhtlc.js +35 -27
- package/dist/esm/storage/fileSystem.js +1 -1
- package/dist/esm/storage/inMemory.js +1 -1
- package/dist/esm/storage/indexedDB.js +1 -1
- package/dist/esm/storage/localStorage.js +1 -1
- package/dist/esm/tree/validation.js +1 -1
- package/dist/esm/utils/arkTransaction.js +5 -5
- package/dist/esm/utils/bip21.js +16 -3
- package/dist/esm/utils/syncCursors.js +4 -4
- package/dist/esm/utils/transaction.js +1 -1
- package/dist/esm/utils/transactionHistory.js +11 -11
- package/dist/esm/utils/unknownFields.js +3 -3
- package/dist/esm/wallet/asset-manager.js +4 -4
- package/dist/esm/wallet/batch.js +5 -5
- package/dist/esm/wallet/delegator.js +9 -8
- package/dist/esm/wallet/expo/background.js +3 -3
- package/dist/esm/wallet/expo/wallet.js +7 -7
- package/dist/esm/wallet/index.js +43 -0
- package/dist/esm/wallet/onchain.js +43 -5
- package/dist/esm/wallet/ramps.js +44 -14
- package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +22 -22
- package/dist/esm/wallet/serviceWorker/wallet.js +28 -24
- package/dist/esm/wallet/unroll.js +12 -8
- package/dist/esm/wallet/utils.js +1 -1
- package/dist/esm/wallet/vtxo-manager.js +121 -81
- package/dist/esm/wallet/wallet.js +125 -67
- package/dist/esm/worker/expo/asyncStorageTaskQueue.js +1 -1
- package/dist/esm/worker/expo/processors/contractPollProcessor.js +2 -2
- package/dist/esm/worker/expo/taskRunner.js +3 -3
- package/dist/esm/worker/messageBus.js +3 -0
- package/dist/types/arkfee/estimator.d.ts +1 -1
- package/dist/types/arkfee/types.d.ts +2 -1
- package/dist/types/arknote/index.d.ts +44 -4
- package/dist/types/bip322/index.d.ts +1 -1
- package/dist/types/contracts/arkcontract.d.ts +1 -1
- package/dist/types/contracts/contractManager.d.ts +40 -63
- package/dist/types/contracts/contractWatcher.d.ts +39 -18
- package/dist/types/contracts/handlers/default.d.ts +1 -1
- package/dist/types/contracts/handlers/delegate.d.ts +1 -1
- package/dist/types/contracts/handlers/helpers.d.ts +1 -1
- package/dist/types/contracts/types.d.ts +36 -26
- package/dist/types/extension/asset/assetGroup.d.ts +92 -1
- package/dist/types/extension/asset/assetId.d.ts +67 -3
- package/dist/types/extension/asset/assetInput.d.ts +18 -0
- package/dist/types/extension/asset/assetOutput.d.ts +15 -0
- package/dist/types/extension/asset/assetRef.d.ts +66 -0
- package/dist/types/extension/asset/metadata.d.ts +15 -0
- package/dist/types/extension/asset/packet.d.ts +4 -1
- package/dist/types/extension/index.d.ts +1 -1
- package/dist/types/forfeit.d.ts +14 -0
- package/dist/types/identity/index.d.ts +16 -0
- package/dist/types/identity/seedIdentity.d.ts +8 -6
- package/dist/types/identity/singleKey.d.ts +4 -0
- package/dist/types/intent/index.d.ts +19 -6
- package/dist/types/providers/ark.d.ts +40 -2
- package/dist/types/providers/delegator.d.ts +54 -1
- package/dist/types/providers/expoArk.d.ts +2 -2
- package/dist/types/providers/indexer.d.ts +105 -2
- package/dist/types/providers/onchain.d.ts +62 -1
- package/dist/types/repositories/realm/schemas.d.ts +2 -2
- package/dist/types/repositories/realm/types.d.ts +2 -2
- package/dist/types/repositories/walletRepository.d.ts +16 -0
- package/dist/types/script/address.d.ts +35 -2
- package/dist/types/script/base.d.ts +66 -1
- package/dist/types/script/default.d.ts +3 -0
- package/dist/types/script/delegate.d.ts +4 -0
- package/dist/types/script/tapscript.d.ts +17 -2
- package/dist/types/script/vhtlc.d.ts +35 -27
- package/dist/types/storage/fileSystem.d.ts +1 -1
- package/dist/types/storage/inMemory.d.ts +1 -1
- package/dist/types/storage/index.d.ts +1 -1
- package/dist/types/storage/indexedDB.d.ts +1 -1
- package/dist/types/storage/localStorage.d.ts +1 -1
- package/dist/types/utils/arkTransaction.d.ts +3 -3
- package/dist/types/utils/bip21.d.ts +17 -0
- package/dist/types/utils/syncCursors.d.ts +4 -4
- package/dist/types/utils/transaction.d.ts +1 -1
- package/dist/types/utils/transactionHistory.d.ts +3 -3
- package/dist/types/utils/unknownFields.d.ts +5 -5
- package/dist/types/wallet/asset-manager.d.ts +3 -3
- package/dist/types/wallet/batch.d.ts +27 -7
- package/dist/types/wallet/delegator.d.ts +10 -0
- package/dist/types/wallet/expo/background.d.ts +4 -4
- package/dist/types/wallet/expo/wallet.d.ts +10 -10
- package/dist/types/wallet/index.d.ts +457 -25
- package/dist/types/wallet/onchain.d.ts +42 -4
- package/dist/types/wallet/ramps.d.ts +40 -10
- package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +4 -4
- package/dist/types/wallet/serviceWorker/wallet.d.ts +71 -33
- package/dist/types/wallet/unroll.d.ts +8 -6
- package/dist/types/wallet/vtxo-manager.d.ts +146 -93
- package/dist/types/wallet/wallet.d.ts +91 -33
- package/dist/types/worker/expo/asyncStorageTaskQueue.d.ts +1 -1
- package/dist/types/worker/expo/processors/contractPollProcessor.d.ts +1 -1
- package/dist/types/worker/expo/taskRunner.d.ts +6 -6
- package/dist/types/worker/messageBus.d.ts +5 -3
- package/package.json +1 -1
package/dist/esm/intent/index.js
CHANGED
|
@@ -8,10 +8,11 @@ import { getSequence, VtxoScript } from '../script/base.js';
|
|
|
8
8
|
* Intent proof implementation for Bitcoin message signing.
|
|
9
9
|
*
|
|
10
10
|
* Intent proof defines a standard for signing Bitcoin messages as well as proving
|
|
11
|
-
* ownership of
|
|
12
|
-
* validating Intent proof.
|
|
11
|
+
* ownership of outputs.
|
|
13
12
|
*
|
|
14
|
-
*
|
|
13
|
+
* This namespace provides utilities for creating and validating Intent proof.
|
|
14
|
+
*
|
|
15
|
+
* It is greatly inspired by BIP322.
|
|
15
16
|
* @see https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki
|
|
16
17
|
*
|
|
17
18
|
* @example
|
|
@@ -33,11 +34,11 @@ export var Intent;
|
|
|
33
34
|
* Creates a new Intent proof unsigned transaction.
|
|
34
35
|
*
|
|
35
36
|
* This function constructs a special transaction that can be signed to prove
|
|
36
|
-
* ownership of
|
|
37
|
+
* ownership of onchain and virtual outputs. The proof includes the message to be
|
|
37
38
|
* signed and the inputs/outputs that demonstrate ownership.
|
|
38
39
|
*
|
|
39
40
|
* @param message - The Intent message to be signed, either raw string of Message object
|
|
40
|
-
* @param
|
|
41
|
+
* @param ins - Array of transaction inputs to prove ownership of
|
|
41
42
|
* @param outputs - Optional array of transaction outputs
|
|
42
43
|
* @returns An unsigned Intent proof transaction
|
|
43
44
|
*/
|
|
@@ -52,12 +53,18 @@ export var Intent;
|
|
|
52
53
|
throw new Error("invalid inputs");
|
|
53
54
|
if (!validateOutputs(outputs))
|
|
54
55
|
throw new Error("invalid outputs");
|
|
55
|
-
//
|
|
56
|
+
// Create the initial transaction to spend.
|
|
56
57
|
const toSpend = craftToSpendTx(message, inputs[0].witnessUtxo.script);
|
|
57
|
-
//
|
|
58
|
+
// Create the transaction to sign.
|
|
58
59
|
return craftToSignTx(toSpend, inputs, outputs);
|
|
59
60
|
}
|
|
60
61
|
Intent.create = create;
|
|
62
|
+
/**
|
|
63
|
+
* Compute the fee paid by an intent proof transaction.
|
|
64
|
+
*
|
|
65
|
+
* @param proof - Intent proof transaction
|
|
66
|
+
* @returns The fee in satoshis
|
|
67
|
+
*/
|
|
61
68
|
function fee(proof) {
|
|
62
69
|
let sumOfInputs = 0n;
|
|
63
70
|
for (let i = 0; i < proof.inputsLength; i++) {
|
|
@@ -79,6 +86,12 @@ export var Intent;
|
|
|
79
86
|
return Number(sumOfInputs - sumOfOutputs);
|
|
80
87
|
}
|
|
81
88
|
Intent.fee = fee;
|
|
89
|
+
/**
|
|
90
|
+
* Serialize an intent message to the canonical JSON string used for signing.
|
|
91
|
+
*
|
|
92
|
+
* @param message - Intent message payload
|
|
93
|
+
* @returns Canonical string form of the message
|
|
94
|
+
*/
|
|
82
95
|
function encodeMessage(message) {
|
|
83
96
|
switch (message.type) {
|
|
84
97
|
case "register":
|
|
@@ -139,7 +152,7 @@ function validateOutputs(outputs) {
|
|
|
139
152
|
*
|
|
140
153
|
* @param message - The message to embed
|
|
141
154
|
* @param pkScript - The scriptPubKey of the signer's address
|
|
142
|
-
* @param tag - Tagged-hash tag (defaults to the
|
|
155
|
+
* @param tag - Tagged-hash tag (defaults to the Arkade intent proof tag)
|
|
143
156
|
*/
|
|
144
157
|
export function craftToSpendTx(message, pkScript, tag = TAG_INTENT_PROOF) {
|
|
145
158
|
const messageHash = hashMessage(message, tag);
|
|
@@ -165,12 +178,15 @@ export function craftToSpendTx(message, pkScript, tag = TAG_INTENT_PROOF) {
|
|
|
165
178
|
// craftToSignTx creates the transaction that will be signed for the proof
|
|
166
179
|
function craftToSignTx(toSpend, inputs, outputs) {
|
|
167
180
|
const firstInput = inputs[0];
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
181
|
+
// Proof tx is never broadcast onchain — toSpend references a zero-hash
|
|
182
|
+
// outpoint (see BIP-322). The tx exists only as a sighash commitment
|
|
183
|
+
// the server verifies signatures against; nLockTime and nSequence carry
|
|
184
|
+
// no consensus meaning here, they only need to match between signer and
|
|
185
|
+
// verifier. Use lockTime = 0 (BIP-322 convention) and leave each input's
|
|
186
|
+
// nSequence untouched.
|
|
171
187
|
const tx = new Transaction({
|
|
172
188
|
version: 2,
|
|
173
|
-
lockTime,
|
|
189
|
+
lockTime: 0,
|
|
174
190
|
});
|
|
175
191
|
// add the first "toSpend" input
|
|
176
192
|
tx.addInput({
|
|
@@ -15,11 +15,12 @@ export var SettlementEventType;
|
|
|
15
15
|
SettlementEventType["StreamStarted"] = "stream_started";
|
|
16
16
|
})(SettlementEventType || (SettlementEventType = {}));
|
|
17
17
|
/**
|
|
18
|
-
* REST-based
|
|
18
|
+
* REST-based Arkade provider implementation.
|
|
19
|
+
*
|
|
19
20
|
* @see https://buf.build/arkade-os/arkd/docs/main:ark.v1#ark.v1.ArkService
|
|
20
21
|
* @example
|
|
21
22
|
* ```typescript
|
|
22
|
-
* const provider = new RestArkProvider('https://
|
|
23
|
+
* const provider = new RestArkProvider('https://arkade.computer');
|
|
23
24
|
* const info = await provider.getInfo();
|
|
24
25
|
* ```
|
|
25
26
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Intent } from '../intent/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* REST-based
|
|
3
|
+
* REST-based delegation provider implementation.
|
|
4
4
|
* @example
|
|
5
5
|
* ```typescript
|
|
6
6
|
* const provider = new RestDelegatorProvider('https://delegator.example.com');
|
|
@@ -9,9 +9,22 @@ import { Intent } from '../intent/index.js';
|
|
|
9
9
|
* ```
|
|
10
10
|
*/
|
|
11
11
|
export class RestDelegatorProvider {
|
|
12
|
+
/**
|
|
13
|
+
* Create a REST delegation provider targeting the given base URL.
|
|
14
|
+
*
|
|
15
|
+
* @param url - Base URL of the delegation service
|
|
16
|
+
*/
|
|
12
17
|
constructor(url) {
|
|
13
18
|
this.url = url;
|
|
14
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Submit a delegation request to the remote delegation service.
|
|
22
|
+
*
|
|
23
|
+
* @param intent - Signed register intent to delegate
|
|
24
|
+
* @param forfeitTxs - Forfeit transactions associated with the delegation request
|
|
25
|
+
* @param options - Optional delegate behavior flags
|
|
26
|
+
* @throws Error if the remote service rejects the request
|
|
27
|
+
*/
|
|
15
28
|
async delegate(intent, forfeitTxs, options) {
|
|
16
29
|
const url = `${this.url}/v1/delegate`;
|
|
17
30
|
const response = await fetch(url, {
|
|
@@ -33,6 +46,12 @@ export class RestDelegatorProvider {
|
|
|
33
46
|
throw new Error(`Failed to delegate: ${errorText}`);
|
|
34
47
|
}
|
|
35
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Fetch delegate metadata exposed by the remote delegation service.
|
|
51
|
+
*
|
|
52
|
+
* @returns Delegate identity and fee information
|
|
53
|
+
* @throws Error if the remote service returns invalid data
|
|
54
|
+
*/
|
|
36
55
|
async getDelegateInfo() {
|
|
37
56
|
const url = `${this.url}/v1/delegator/info`;
|
|
38
57
|
const response = await fetch(url);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RestArkProvider, isFetchTimeoutError, } from './ark.js';
|
|
2
2
|
import { getExpoFetch, sseStreamIterator } from './expoUtils.js';
|
|
3
3
|
/**
|
|
4
|
-
* Expo-compatible
|
|
4
|
+
* Expo-compatible Arkade provider implementation using expo/fetch for SSE support.
|
|
5
5
|
* This provider works specifically in React Native/Expo environments where
|
|
6
6
|
* standard EventSource is not available but expo/fetch provides SSE capabilities.
|
|
7
7
|
*
|
|
@@ -9,7 +9,7 @@ import { getExpoFetch, sseStreamIterator } from './expoUtils.js';
|
|
|
9
9
|
* ```typescript
|
|
10
10
|
* import { ExpoArkProvider } from '@arkade-os/sdk/providers/expo';
|
|
11
11
|
*
|
|
12
|
-
* const provider = new ExpoArkProvider('https://
|
|
12
|
+
* const provider = new ExpoArkProvider('https://arkade.computer');
|
|
13
13
|
* const info = await provider.getInfo();
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
@@ -17,11 +17,11 @@ export var ChainTxType;
|
|
|
17
17
|
ChainTxType["CHECKPOINT"] = "INDEXER_CHAINED_TX_TYPE_CHECKPOINT";
|
|
18
18
|
})(ChainTxType || (ChainTxType = {}));
|
|
19
19
|
/**
|
|
20
|
-
* REST-based
|
|
20
|
+
* REST-based indexer provider implementation.
|
|
21
21
|
* @see https://buf.build/arkade-os/arkd/docs/main:ark.v1#ark.v1.IndexerService
|
|
22
22
|
* @example
|
|
23
23
|
* ```typescript
|
|
24
|
-
* const provider = new RestIndexerProvider('https://
|
|
24
|
+
* const provider = new RestIndexerProvider('https://arkade.computer');
|
|
25
25
|
* const commitmentTx = await provider.getCommitmentTx("6686af8f3be3517880821f62e6c3d749b9d6713736a1d8e229a55daa659446b2");
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
@@ -10,11 +10,12 @@ export const ESPLORA_URL = {
|
|
|
10
10
|
};
|
|
11
11
|
/**
|
|
12
12
|
* Implementation of the onchain provider interface for esplora REST API.
|
|
13
|
+
*
|
|
13
14
|
* @see https://mempool.space/docs/api/rest
|
|
14
15
|
* @example
|
|
15
16
|
* ```typescript
|
|
16
17
|
* const provider = new EsploraProvider("https://mempool.space/api");
|
|
17
|
-
* const
|
|
18
|
+
* const outputs = await provider.getCoins("bcrt1q679zsd45msawvr7782r0twvmukns3drlstjt77");
|
|
18
19
|
* ```
|
|
19
20
|
*/
|
|
20
21
|
export class EsploraProvider {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Realm object schemas for the
|
|
2
|
+
* Realm object schemas for the Arkade wallet.
|
|
3
3
|
*
|
|
4
4
|
* All schema names are prefixed with "Ark" to avoid collisions with
|
|
5
5
|
* other Realm schemas in the consuming application.
|
|
@@ -93,7 +93,7 @@ export const ArkContractSchema = {
|
|
|
93
93
|
},
|
|
94
94
|
};
|
|
95
95
|
/**
|
|
96
|
-
* All Realm schemas needed by the
|
|
96
|
+
* All Realm schemas needed by the Arkade wallet repositories.
|
|
97
97
|
* Pass this array to your Realm configuration's `schema` property.
|
|
98
98
|
*/
|
|
99
99
|
export const ArkRealmSchemas = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Minimal interface for the subset of the Realm API used by the
|
|
3
|
-
*
|
|
3
|
+
* Arkade repositories. Consumers pass their real Realm instance and
|
|
4
4
|
* the compiler validates it satisfies this shape.
|
|
5
5
|
*/
|
|
6
6
|
export {};
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { bech32m } from "@scure/base";
|
|
2
2
|
import { Script } from "@scure/btc-signer/script.js";
|
|
3
3
|
/**
|
|
4
|
-
* ArkAddress allows
|
|
5
|
-
*
|
|
4
|
+
* ArkAddress allows creating and decoding bech32m-encoded Arkade addresses.
|
|
5
|
+
*
|
|
6
|
+
* An Arkade address is composed of:
|
|
6
7
|
* - a human readable prefix (hrp)
|
|
7
8
|
* - a version byte (1 byte)
|
|
8
9
|
* - a server public key (32 bytes)
|
|
9
10
|
* - a vtxo taproot public key (32 bytes)
|
|
10
11
|
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* This is an Arkade-specific address format.
|
|
14
|
+
* It is distinct from the Taproot onchain address returned by `VtxoScript.onchainAddress`.
|
|
15
|
+
*
|
|
16
|
+
* @see VtxoScript
|
|
17
|
+
*
|
|
11
18
|
* @example
|
|
12
19
|
* ```typescript
|
|
13
20
|
* const address = new ArkAddress(
|
|
@@ -23,6 +30,16 @@ import { Script } from "@scure/btc-signer/script.js";
|
|
|
23
30
|
* ```
|
|
24
31
|
*/
|
|
25
32
|
export class ArkAddress {
|
|
33
|
+
/**
|
|
34
|
+
* Create an Arkade address from its server key, vtxo taproot public key, and prefix.
|
|
35
|
+
*
|
|
36
|
+
* @param serverPubKey - 32-byte Arkade server public key
|
|
37
|
+
* @param vtxoTaprootKey - 32-byte tweaked vtxo taproot public key
|
|
38
|
+
* @param hrp - Bech32 human-readable prefix
|
|
39
|
+
* @param version - Address version byte
|
|
40
|
+
* @defaultValue `version = 0`
|
|
41
|
+
* @throws Error if either public key is not 32 bytes long
|
|
42
|
+
*/
|
|
26
43
|
constructor(serverPubKey, vtxoTaprootKey, hrp, version = 0) {
|
|
27
44
|
this.serverPubKey = serverPubKey;
|
|
28
45
|
this.vtxoTaprootKey = vtxoTaprootKey;
|
|
@@ -37,13 +54,21 @@ export class ArkAddress {
|
|
|
37
54
|
vtxoTaprootKey.length);
|
|
38
55
|
}
|
|
39
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Decode an Arkade address from its bech32m string form.
|
|
59
|
+
*
|
|
60
|
+
* @param address - Bech32m-encoded Arkade address
|
|
61
|
+
* @returns Decoded Arkade address
|
|
62
|
+
* @throws Error if the address is malformed or has an invalid payload length
|
|
63
|
+
* @see encode
|
|
64
|
+
*/
|
|
40
65
|
static decode(address) {
|
|
41
66
|
const decoded = bech32m.decodeUnsafe(address, 1023);
|
|
42
67
|
if (!decoded) {
|
|
43
68
|
throw new Error("Invalid address");
|
|
44
69
|
}
|
|
45
70
|
const data = new Uint8Array(bech32m.fromWords(decoded.words));
|
|
46
|
-
// First the version byte, then 32 bytes server pubkey, then 32 bytes vtxo taproot
|
|
71
|
+
// First the version byte, then 32 bytes server pubkey, then 32 bytes vtxo taproot public key.
|
|
47
72
|
if (data.length !== 1 + 32 + 32) {
|
|
48
73
|
throw new Error("Invalid data length, expected 65 bytes, got " + data.length);
|
|
49
74
|
}
|
|
@@ -52,8 +77,14 @@ export class ArkAddress {
|
|
|
52
77
|
const vtxoTaprootPubKey = data.slice(33, 65);
|
|
53
78
|
return new ArkAddress(serverPubKey, vtxoTaprootPubKey, decoded.prefix, version);
|
|
54
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Encode the address to its bech32m string form.
|
|
82
|
+
*
|
|
83
|
+
* @returns Bech32m-encoded Arkade address
|
|
84
|
+
* @see decode
|
|
85
|
+
*/
|
|
55
86
|
encode() {
|
|
56
|
-
// Combine version byte, server pubkey, and vtxo taproot
|
|
87
|
+
// Combine version byte, server pubkey, and vtxo taproot public key.
|
|
57
88
|
const data = new Uint8Array(1 + 32 + 32);
|
|
58
89
|
data[0] = this.version;
|
|
59
90
|
data.set(this.serverPubKey, 1);
|
|
@@ -61,11 +92,11 @@ export class ArkAddress {
|
|
|
61
92
|
const words = bech32m.toWords(data);
|
|
62
93
|
return bech32m.encode(this.hrp, words, 1023);
|
|
63
94
|
}
|
|
64
|
-
|
|
95
|
+
/** ScriptPubKey used to send non-dust funds to the address. */
|
|
65
96
|
get pkScript() {
|
|
66
97
|
return Script.encode(["OP_1", this.vtxoTaprootKey]);
|
|
67
98
|
}
|
|
68
|
-
|
|
99
|
+
/** ScriptPubKey used to send sub-dust funds to the address. */
|
|
69
100
|
get subdustPkScript() {
|
|
70
101
|
return Script.encode(["RETURN", this.vtxoTaprootKey]);
|
|
71
102
|
}
|
package/dist/esm/script/base.js
CHANGED
|
@@ -11,18 +11,35 @@ export function scriptFromTapLeafScript(leaf) {
|
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* VtxoScript is a script that contains a list of tapleaf scripts.
|
|
14
|
-
* It is used to create
|
|
14
|
+
* It is used to create virtual output scripts.
|
|
15
|
+
*
|
|
16
|
+
* @see ArkAddress
|
|
15
17
|
*
|
|
16
18
|
* @example
|
|
17
19
|
* ```typescript
|
|
18
20
|
* const vtxoScript = new VtxoScript([new Uint8Array(32), new Uint8Array(32)]);
|
|
21
|
+
* ```
|
|
19
22
|
*/
|
|
20
23
|
export class VtxoScript {
|
|
24
|
+
/**
|
|
25
|
+
* Decode a virtual output script from an encoded TapTree.
|
|
26
|
+
*
|
|
27
|
+
* @param tapTree - Encoded TapTree bytes
|
|
28
|
+
* @returns Decoded virtual output script
|
|
29
|
+
* @throws Error if the TapTree cannot be decoded into a valid script set
|
|
30
|
+
* @see encode
|
|
31
|
+
*/
|
|
21
32
|
static decode(tapTree) {
|
|
22
33
|
const leaves = TapTreeCoder.decode(tapTree);
|
|
23
34
|
const scripts = leaves.map((leaf) => leaf.script);
|
|
24
35
|
return new VtxoScript(scripts);
|
|
25
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a virtual output script from its tapleaf scripts.
|
|
39
|
+
*
|
|
40
|
+
* @param scripts - Raw tapscript bytes for each leaf
|
|
41
|
+
* @throws Error if the provided leaves cannot produce a valid Taproot tree
|
|
42
|
+
*/
|
|
26
43
|
constructor(scripts) {
|
|
27
44
|
this.scripts = scripts;
|
|
28
45
|
// reverse the scripts if the number of scripts is odd
|
|
@@ -43,6 +60,12 @@ export class VtxoScript {
|
|
|
43
60
|
this.leaves = payment.tapLeafScript;
|
|
44
61
|
this.tweakedPublicKey = payment.tweakedPubkey;
|
|
45
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Encode the virtual output script to a TapTree byte representation.
|
|
65
|
+
*
|
|
66
|
+
* @returns Encoded TapTree bytes
|
|
67
|
+
* @see decode
|
|
68
|
+
*/
|
|
46
69
|
encode() {
|
|
47
70
|
const tapTree = TapTreeCoder.encode(this.scripts.map((script) => ({
|
|
48
71
|
depth: 1,
|
|
@@ -51,18 +74,40 @@ export class VtxoScript {
|
|
|
51
74
|
})));
|
|
52
75
|
return tapTree;
|
|
53
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Build the Arkade address corresponding to this virtual output script.
|
|
79
|
+
*
|
|
80
|
+
* @param prefix - Bech32 human-readable prefix
|
|
81
|
+
* @param serverPubKey - 32-byte Arkade server public key
|
|
82
|
+
* @returns Arkade address for this script
|
|
83
|
+
* @see ArkAddress
|
|
84
|
+
*/
|
|
54
85
|
address(prefix, serverPubKey) {
|
|
55
86
|
return new ArkAddress(serverPubKey, this.tweakedPublicKey, prefix);
|
|
56
87
|
}
|
|
57
88
|
get pkScript() {
|
|
58
89
|
return Script.encode(["OP_1", this.tweakedPublicKey]);
|
|
59
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Build the Taproot onchain address corresponding to this virtual output script.
|
|
93
|
+
*
|
|
94
|
+
* @param network - Bitcoin network descriptor
|
|
95
|
+
* @returns Taproot onchain address
|
|
96
|
+
* @see address
|
|
97
|
+
*/
|
|
60
98
|
onchainAddress(network) {
|
|
61
99
|
return Address(network).encode({
|
|
62
100
|
type: "tr",
|
|
63
101
|
pubkey: this.tweakedPublicKey,
|
|
64
102
|
});
|
|
65
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Look up a tapleaf script by its hex-encoded tapscript body.
|
|
106
|
+
*
|
|
107
|
+
* @param scriptHex - Hex-encoded tapscript body without the leaf version byte
|
|
108
|
+
* @returns Matching tapleaf script
|
|
109
|
+
* @throws Error if no matching leaf exists
|
|
110
|
+
*/
|
|
66
111
|
findLeaf(scriptHex) {
|
|
67
112
|
const leaf = this.leaves.find((leaf) => hex.encode(scriptFromTapLeafScript(leaf)) === scriptHex);
|
|
68
113
|
if (!leaf) {
|
|
@@ -70,6 +115,12 @@ export class VtxoScript {
|
|
|
70
115
|
}
|
|
71
116
|
return leaf;
|
|
72
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Return all unilateral exit paths embedded in the virtual output script.
|
|
120
|
+
*
|
|
121
|
+
* @returns CSV-based exit paths found in the leaves
|
|
122
|
+
* @see getSequence
|
|
123
|
+
*/
|
|
73
124
|
exitPaths() {
|
|
74
125
|
const paths = [];
|
|
75
126
|
for (const leaf of this.leaves) {
|
|
@@ -91,6 +142,24 @@ export class VtxoScript {
|
|
|
91
142
|
return paths;
|
|
92
143
|
}
|
|
93
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Extract the timelock value encoded in a timelocked tapleaf, if any.
|
|
147
|
+
*
|
|
148
|
+
* The return value is unit-ambiguous: for a CSV leaf it is a BIP-68
|
|
149
|
+
* nSequence (relative timelock); for a CLTV leaf it is an absolute
|
|
150
|
+
* nLockTime. Callers must know which leaf shape they are inspecting to
|
|
151
|
+
* interpret the number correctly, and must not copy a CSV result into
|
|
152
|
+
* `Transaction.lockTime` (or vice versa).
|
|
153
|
+
*
|
|
154
|
+
* @param tapLeafScript - Tapleaf script to inspect
|
|
155
|
+
* @returns The encoded timelock value, or `undefined` when neither a CSV
|
|
156
|
+
* nor CLTV path is present
|
|
157
|
+
* @see VtxoScript.exitPaths
|
|
158
|
+
*/
|
|
159
|
+
// TODO(next-major): return a discriminated union
|
|
160
|
+
// (`{ kind: "relative", nSequence } | { kind: "absolute", lockTime }`)
|
|
161
|
+
// so callers can't conflate the two. Deferred because changing the
|
|
162
|
+
// return type is a breaking change.
|
|
94
163
|
export function getSequence(tapLeafScript) {
|
|
95
164
|
let sequence = undefined;
|
|
96
165
|
try {
|
|
@@ -22,6 +22,7 @@ export var DefaultVtxo;
|
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
24
|
class Script extends VtxoScript {
|
|
25
|
+
/** Create the default virtual output script with one forfeit path and one exit path. */
|
|
25
26
|
constructor(options) {
|
|
26
27
|
const { pubKey, serverPubKey, csvTimelock = Script.DEFAULT_TIMELOCK, } = options;
|
|
27
28
|
const forfeitScript = MultisigTapscript.encode({
|
|
@@ -36,9 +37,11 @@ export var DefaultVtxo;
|
|
|
36
37
|
this.forfeitScript = hex.encode(forfeitScript);
|
|
37
38
|
this.exitScript = hex.encode(exitScript);
|
|
38
39
|
}
|
|
40
|
+
/** Return the forfeit tapleaf script. */
|
|
39
41
|
forfeit() {
|
|
40
42
|
return this.findLeaf(this.forfeitScript);
|
|
41
43
|
}
|
|
44
|
+
/** Return the unilateral exit tapleaf script. */
|
|
42
45
|
exit() {
|
|
43
46
|
return this.findLeaf(this.exitScript);
|
|
44
47
|
}
|
|
@@ -21,6 +21,7 @@ export var DelegateVtxo;
|
|
|
21
21
|
* ```
|
|
22
22
|
*/
|
|
23
23
|
class Script extends VtxoScript {
|
|
24
|
+
/** Create a delegated virtual output script with forfeit, exit, and delegate paths. */
|
|
24
25
|
constructor(options) {
|
|
25
26
|
const defaultVtxo = new DefaultVtxo.Script(options);
|
|
26
27
|
const { delegatePubKey, pubKey, serverPubKey } = options;
|
|
@@ -32,12 +33,15 @@ export var DelegateVtxo;
|
|
|
32
33
|
this.defaultVtxo = defaultVtxo;
|
|
33
34
|
this.delegateScript = hex.encode(delegateScript);
|
|
34
35
|
}
|
|
36
|
+
/** Return the forfeit tapleaf script. */
|
|
35
37
|
forfeit() {
|
|
36
38
|
return this.findLeaf(this.defaultVtxo.forfeitScript);
|
|
37
39
|
}
|
|
40
|
+
/** Return the unilateral exit tapleaf script. */
|
|
38
41
|
exit() {
|
|
39
42
|
return this.findLeaf(this.defaultVtxo.exitScript);
|
|
40
43
|
}
|
|
44
|
+
/** Return the delegate tapleaf script. */
|
|
41
45
|
delegate() {
|
|
42
46
|
return this.findLeaf(this.delegateScript);
|
|
43
47
|
}
|
|
@@ -11,9 +11,9 @@ export var TapscriptType;
|
|
|
11
11
|
TapscriptType["CLTVMultisig"] = "cltv-multisig";
|
|
12
12
|
})(TapscriptType || (TapscriptType = {}));
|
|
13
13
|
/**
|
|
14
|
-
* decodeTapscript is a function that decodes an
|
|
14
|
+
* decodeTapscript is a function that decodes an Arkade tapscript from a raw script.
|
|
15
15
|
*
|
|
16
|
-
* @throws {Error} if the script is not a valid
|
|
16
|
+
* @throws {Error} if the script is not a valid Arkade tapscript
|
|
17
17
|
* @example
|
|
18
18
|
* ```typescript
|
|
19
19
|
* const arkTapscript = decodeTapscript(new Uint8Array(32));
|
|
@@ -55,6 +55,7 @@ export var MultisigTapscript;
|
|
|
55
55
|
MultisigType[MultisigType["CHECKSIG"] = 0] = "CHECKSIG";
|
|
56
56
|
MultisigType[MultisigType["CHECKSIGADD"] = 1] = "CHECKSIGADD";
|
|
57
57
|
})(MultisigType = MultisigTapscript.MultisigType || (MultisigTapscript.MultisigType = {}));
|
|
58
|
+
/** Encode a plain multisig tapscript. */
|
|
58
59
|
function encode(params) {
|
|
59
60
|
if (params.pubkeys.length === 0) {
|
|
60
61
|
throw new Error("At least 1 pubkey is required");
|
|
@@ -92,6 +93,7 @@ export var MultisigTapscript;
|
|
|
92
93
|
};
|
|
93
94
|
}
|
|
94
95
|
MultisigTapscript.encode = encode;
|
|
96
|
+
/** Decode a plain multisig tapscript from raw script bytes. */
|
|
95
97
|
function decode(script) {
|
|
96
98
|
if (script.length === 0) {
|
|
97
99
|
throw new Error("Failed to decode: script is empty");
|
|
@@ -204,6 +206,7 @@ export var MultisigTapscript;
|
|
|
204
206
|
script,
|
|
205
207
|
};
|
|
206
208
|
}
|
|
209
|
+
/** Return true when the tapscript is a plain multisig tapscript. */
|
|
207
210
|
function is(tapscript) {
|
|
208
211
|
return tapscript.type === TapscriptType.Multisig;
|
|
209
212
|
}
|
|
@@ -224,6 +227,7 @@ export var MultisigTapscript;
|
|
|
224
227
|
*/
|
|
225
228
|
export var CSVMultisigTapscript;
|
|
226
229
|
(function (CSVMultisigTapscript) {
|
|
230
|
+
/** Encode a CSV multisig tapscript. */
|
|
227
231
|
function encode(params) {
|
|
228
232
|
for (const pubkey of params.pubkeys) {
|
|
229
233
|
if (pubkey.length !== 32) {
|
|
@@ -250,6 +254,7 @@ export var CSVMultisigTapscript;
|
|
|
250
254
|
};
|
|
251
255
|
}
|
|
252
256
|
CSVMultisigTapscript.encode = encode;
|
|
257
|
+
/** Decode a CSV multisig tapscript from raw script bytes. */
|
|
253
258
|
function decode(script) {
|
|
254
259
|
if (script.length === 0) {
|
|
255
260
|
throw new Error("Failed to decode: script is empty");
|
|
@@ -301,6 +306,7 @@ export var CSVMultisigTapscript;
|
|
|
301
306
|
};
|
|
302
307
|
}
|
|
303
308
|
CSVMultisigTapscript.decode = decode;
|
|
309
|
+
/** Return true when the tapscript is a CSV multisig tapscript. */
|
|
304
310
|
function is(tapscript) {
|
|
305
311
|
return tapscript.type === TapscriptType.CSVMultisig;
|
|
306
312
|
}
|
|
@@ -320,6 +326,7 @@ export var CSVMultisigTapscript;
|
|
|
320
326
|
*/
|
|
321
327
|
export var ConditionCSVMultisigTapscript;
|
|
322
328
|
(function (ConditionCSVMultisigTapscript) {
|
|
329
|
+
/** Encode a condition + CSV multisig tapscript. */
|
|
323
330
|
function encode(params) {
|
|
324
331
|
const script = new Uint8Array([
|
|
325
332
|
...params.conditionScript,
|
|
@@ -333,6 +340,7 @@ export var ConditionCSVMultisigTapscript;
|
|
|
333
340
|
};
|
|
334
341
|
}
|
|
335
342
|
ConditionCSVMultisigTapscript.encode = encode;
|
|
343
|
+
/** Decode a condition + CSV multisig tapscript from raw script bytes. */
|
|
336
344
|
function decode(script) {
|
|
337
345
|
if (script.length === 0) {
|
|
338
346
|
throw new Error("Failed to decode: script is empty");
|
|
@@ -376,6 +384,7 @@ export var ConditionCSVMultisigTapscript;
|
|
|
376
384
|
};
|
|
377
385
|
}
|
|
378
386
|
ConditionCSVMultisigTapscript.decode = decode;
|
|
387
|
+
/** Return true when the tapscript is a condition + CSV multisig tapscript. */
|
|
379
388
|
function is(tapscript) {
|
|
380
389
|
return tapscript.type === TapscriptType.ConditionCSVMultisig;
|
|
381
390
|
}
|
|
@@ -395,6 +404,7 @@ export var ConditionCSVMultisigTapscript;
|
|
|
395
404
|
*/
|
|
396
405
|
export var ConditionMultisigTapscript;
|
|
397
406
|
(function (ConditionMultisigTapscript) {
|
|
407
|
+
/** Encode a condition + multisig tapscript. */
|
|
398
408
|
function encode(params) {
|
|
399
409
|
const script = new Uint8Array([
|
|
400
410
|
...params.conditionScript,
|
|
@@ -408,6 +418,7 @@ export var ConditionMultisigTapscript;
|
|
|
408
418
|
};
|
|
409
419
|
}
|
|
410
420
|
ConditionMultisigTapscript.encode = encode;
|
|
421
|
+
/** Decode a condition + multisig tapscript from raw script bytes. */
|
|
411
422
|
function decode(script) {
|
|
412
423
|
if (script.length === 0) {
|
|
413
424
|
throw new Error("Failed to decode: script is empty");
|
|
@@ -451,6 +462,7 @@ export var ConditionMultisigTapscript;
|
|
|
451
462
|
};
|
|
452
463
|
}
|
|
453
464
|
ConditionMultisigTapscript.decode = decode;
|
|
465
|
+
/** Return true when the tapscript is a condition + multisig tapscript. */
|
|
454
466
|
function is(tapscript) {
|
|
455
467
|
return tapscript.type === TapscriptType.ConditionMultisig;
|
|
456
468
|
}
|
|
@@ -470,6 +482,7 @@ export var ConditionMultisigTapscript;
|
|
|
470
482
|
*/
|
|
471
483
|
export var CLTVMultisigTapscript;
|
|
472
484
|
(function (CLTVMultisigTapscript) {
|
|
485
|
+
/** Encode a CLTV multisig tapscript. */
|
|
473
486
|
function encode(params) {
|
|
474
487
|
const locktime = MinimalScriptNum.encode(params.absoluteTimelock);
|
|
475
488
|
const asm = [
|
|
@@ -489,6 +502,7 @@ export var CLTVMultisigTapscript;
|
|
|
489
502
|
};
|
|
490
503
|
}
|
|
491
504
|
CLTVMultisigTapscript.encode = encode;
|
|
505
|
+
/** Decode a CLTV multisig tapscript from raw script bytes. */
|
|
492
506
|
function decode(script) {
|
|
493
507
|
if (script.length === 0) {
|
|
494
508
|
throw new Error("Failed to decode: script is empty");
|
|
@@ -536,6 +550,7 @@ export var CLTVMultisigTapscript;
|
|
|
536
550
|
};
|
|
537
551
|
}
|
|
538
552
|
CLTVMultisigTapscript.decode = decode;
|
|
553
|
+
/** Return true when the tapscript is a CLTV multisig tapscript. */
|
|
539
554
|
function is(tapscript) {
|
|
540
555
|
return tapscript.type === TapscriptType.CLTVMultisig;
|
|
541
556
|
}
|