@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.
- package/README.md +156 -174
- package/dist/cjs/arknote/index.js +61 -58
- package/dist/cjs/bip322/errors.js +13 -0
- package/dist/cjs/bip322/index.js +178 -0
- package/dist/cjs/forfeit.js +14 -25
- package/dist/cjs/identity/singleKey.js +68 -0
- package/dist/cjs/index.js +41 -17
- package/dist/cjs/providers/ark.js +253 -317
- package/dist/cjs/providers/indexer.js +525 -0
- package/dist/cjs/providers/onchain.js +193 -15
- package/dist/cjs/script/address.js +48 -17
- package/dist/cjs/script/base.js +120 -3
- package/dist/cjs/script/default.js +18 -4
- package/dist/cjs/script/tapscript.js +46 -14
- package/dist/cjs/script/vhtlc.js +27 -7
- package/dist/cjs/tree/signingSession.js +63 -106
- package/dist/cjs/tree/txTree.js +193 -0
- package/dist/cjs/tree/validation.js +79 -155
- package/dist/cjs/utils/anchor.js +35 -0
- package/dist/cjs/utils/arkTransaction.js +108 -0
- package/dist/cjs/utils/transactionHistory.js +84 -72
- package/dist/cjs/utils/txSizeEstimator.js +12 -0
- package/dist/cjs/utils/unknownFields.js +211 -0
- package/dist/cjs/wallet/index.js +12 -0
- package/dist/cjs/wallet/onchain.js +201 -0
- package/dist/cjs/wallet/ramps.js +95 -0
- package/dist/cjs/wallet/serviceWorker/db/vtxo/idb.js +32 -0
- package/dist/cjs/wallet/serviceWorker/request.js +15 -12
- package/dist/cjs/wallet/serviceWorker/response.js +22 -27
- package/dist/cjs/wallet/serviceWorker/utils.js +8 -0
- package/dist/cjs/wallet/serviceWorker/wallet.js +58 -34
- package/dist/cjs/wallet/serviceWorker/worker.js +117 -108
- package/dist/cjs/wallet/unroll.js +270 -0
- package/dist/cjs/wallet/wallet.js +701 -454
- package/dist/esm/arknote/index.js +61 -57
- package/dist/esm/bip322/errors.js +9 -0
- package/dist/esm/bip322/index.js +174 -0
- package/dist/esm/forfeit.js +15 -26
- package/dist/esm/identity/singleKey.js +64 -0
- package/dist/esm/index.js +30 -12
- package/dist/esm/providers/ark.js +252 -317
- package/dist/esm/providers/indexer.js +521 -0
- package/dist/esm/providers/onchain.js +193 -15
- package/dist/esm/script/address.js +48 -17
- package/dist/esm/script/base.js +120 -3
- package/dist/esm/script/default.js +18 -4
- package/dist/esm/script/tapscript.js +46 -14
- package/dist/esm/script/vhtlc.js +27 -7
- package/dist/esm/tree/signingSession.js +65 -108
- package/dist/esm/tree/txTree.js +189 -0
- package/dist/esm/tree/validation.js +75 -152
- package/dist/esm/utils/anchor.js +31 -0
- package/dist/esm/utils/arkTransaction.js +105 -0
- package/dist/esm/utils/transactionHistory.js +84 -72
- package/dist/esm/utils/txSizeEstimator.js +12 -0
- package/dist/esm/utils/unknownFields.js +173 -0
- package/dist/esm/wallet/index.js +9 -0
- package/dist/esm/wallet/onchain.js +196 -0
- package/dist/esm/wallet/ramps.js +91 -0
- package/dist/esm/wallet/serviceWorker/db/vtxo/idb.js +32 -0
- package/dist/esm/wallet/serviceWorker/request.js +15 -12
- package/dist/esm/wallet/serviceWorker/response.js +22 -27
- package/dist/esm/wallet/serviceWorker/utils.js +8 -0
- package/dist/esm/wallet/serviceWorker/wallet.js +59 -35
- package/dist/esm/wallet/serviceWorker/worker.js +117 -108
- package/dist/esm/wallet/unroll.js +267 -0
- package/dist/esm/wallet/wallet.js +674 -461
- package/dist/types/arknote/index.d.ts +40 -13
- package/dist/types/bip322/errors.d.ts +6 -0
- package/dist/types/bip322/index.d.ts +57 -0
- package/dist/types/forfeit.d.ts +2 -14
- package/dist/types/identity/singleKey.d.ts +27 -0
- package/dist/types/index.d.ts +23 -12
- package/dist/types/providers/ark.d.ts +114 -95
- package/dist/types/providers/indexer.d.ts +186 -0
- package/dist/types/providers/onchain.d.ts +41 -11
- package/dist/types/script/address.d.ts +26 -2
- package/dist/types/script/base.d.ts +13 -3
- package/dist/types/script/default.d.ts +22 -0
- package/dist/types/script/tapscript.d.ts +61 -5
- package/dist/types/script/vhtlc.d.ts +27 -0
- package/dist/types/tree/signingSession.d.ts +5 -5
- package/dist/types/tree/txTree.d.ts +28 -0
- package/dist/types/tree/validation.d.ts +15 -22
- package/dist/types/utils/anchor.d.ts +19 -0
- package/dist/types/utils/arkTransaction.d.ts +27 -0
- package/dist/types/utils/transactionHistory.d.ts +7 -1
- package/dist/types/utils/txSizeEstimator.d.ts +3 -0
- package/dist/types/utils/unknownFields.d.ts +83 -0
- package/dist/types/wallet/index.d.ts +51 -50
- package/dist/types/wallet/onchain.d.ts +49 -0
- package/dist/types/wallet/ramps.d.ts +32 -0
- package/dist/types/wallet/serviceWorker/db/vtxo/idb.d.ts +2 -0
- package/dist/types/wallet/serviceWorker/db/vtxo/index.d.ts +2 -0
- package/dist/types/wallet/serviceWorker/request.d.ts +14 -16
- package/dist/types/wallet/serviceWorker/response.d.ts +17 -19
- package/dist/types/wallet/serviceWorker/utils.d.ts +8 -0
- package/dist/types/wallet/serviceWorker/wallet.d.ts +36 -8
- package/dist/types/wallet/serviceWorker/worker.d.ts +7 -3
- package/dist/types/wallet/unroll.d.ts +102 -0
- package/dist/types/wallet/wallet.d.ts +71 -25
- package/package.json +14 -15
- package/dist/cjs/identity/inMemoryKey.js +0 -40
- package/dist/cjs/tree/vtxoTree.js +0 -231
- package/dist/cjs/utils/coinselect.js +0 -73
- package/dist/cjs/utils/psbt.js +0 -137
- package/dist/esm/identity/inMemoryKey.js +0 -36
- package/dist/esm/tree/vtxoTree.js +0 -191
- package/dist/esm/utils/coinselect.js +0 -69
- package/dist/esm/utils/psbt.js +0 -131
- package/dist/types/identity/inMemoryKey.d.ts +0 -12
- package/dist/types/tree/vtxoTree.d.ts +0 -33
- package/dist/types/utils/coinselect.d.ts +0 -21
- package/dist/types/utils/psbt.d.ts +0 -11
|
@@ -1,76 +1,77 @@
|
|
|
1
|
-
import { base58 } from "@scure/base";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// ArkNote is a note with the issuer's signature
|
|
1
|
+
import { base58, hex } from "@scure/base";
|
|
2
|
+
import { VtxoScript } from '../script/base.js';
|
|
3
|
+
import { sha256 } from "@scure/btc-signer/utils";
|
|
4
|
+
import { Script } from "@scure/btc-signer";
|
|
5
|
+
/**
|
|
6
|
+
* ArkNotes are special virtual coins in the Ark protocol that can be created
|
|
7
|
+
* and spent without requiring any transactions. The server mints them, and they
|
|
8
|
+
* are encoded as base58 strings with a human-readable prefix. It contains a
|
|
9
|
+
* preimage and value.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // Create an ArkNote
|
|
14
|
+
* const note = new ArkNote(preimage, 50000);
|
|
15
|
+
*
|
|
16
|
+
* // Encode to string
|
|
17
|
+
* const noteString = note.toString();
|
|
18
|
+
*
|
|
19
|
+
* // Decode from string
|
|
20
|
+
* const decodedNote = ArkNote.fromString(noteString);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
24
23
|
export class ArkNote {
|
|
25
|
-
constructor(
|
|
26
|
-
this.
|
|
27
|
-
this.
|
|
24
|
+
constructor(preimage, value, HRP = ArkNote.DefaultHRP) {
|
|
25
|
+
this.preimage = preimage;
|
|
26
|
+
this.value = value;
|
|
27
|
+
this.HRP = HRP;
|
|
28
|
+
this.vout = 0;
|
|
29
|
+
const preimageHash = sha256(this.preimage);
|
|
30
|
+
this.vtxoScript = new VtxoScript([noteTapscript(preimageHash)]);
|
|
31
|
+
const leaf = this.vtxoScript.leaves[0];
|
|
32
|
+
this.txid = hex.encode(new Uint8Array(preimageHash).reverse());
|
|
33
|
+
this.tapTree = this.vtxoScript.encode();
|
|
34
|
+
this.forfeitTapLeafScript = leaf;
|
|
35
|
+
this.intentTapLeafScript = leaf;
|
|
36
|
+
this.value = value;
|
|
37
|
+
this.status = { confirmed: true };
|
|
38
|
+
this.extraWitness = [this.preimage];
|
|
28
39
|
}
|
|
29
40
|
encode() {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
result.
|
|
33
|
-
result.set(this.signature, detailsBytes.length);
|
|
41
|
+
const result = new Uint8Array(ArkNote.Length);
|
|
42
|
+
result.set(this.preimage, 0);
|
|
43
|
+
writeUInt32BE(result, this.value, this.preimage.length);
|
|
34
44
|
return result;
|
|
35
45
|
}
|
|
36
|
-
static decode(data) {
|
|
37
|
-
if (data.length
|
|
38
|
-
throw new Error(`invalid data length: expected
|
|
46
|
+
static decode(data, hrp = ArkNote.DefaultHRP) {
|
|
47
|
+
if (data.length !== ArkNote.Length) {
|
|
48
|
+
throw new Error(`invalid data length: expected ${ArkNote.Length} bytes, got ${data.length}`);
|
|
39
49
|
}
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
throw new Error(`invalid signature length: expected 64 bytes, got ${signature.length}`);
|
|
44
|
-
}
|
|
45
|
-
return new ArkNote(noteData, signature);
|
|
50
|
+
const preimage = data.subarray(0, ArkNote.PreimageLength);
|
|
51
|
+
const value = readUInt32BE(data, ArkNote.PreimageLength);
|
|
52
|
+
return new ArkNote(preimage, value, hrp);
|
|
46
53
|
}
|
|
47
|
-
static fromString(noteStr) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const encoded = noteStr.slice(ArkNote.HRP.length);
|
|
52
|
-
if (encoded.length < 103 || encoded.length > 104) {
|
|
53
|
-
throw new Error(`invalid note length: expected 103 or 104 chars, got ${encoded.length}`);
|
|
54
|
+
static fromString(noteStr, hrp = ArkNote.DefaultHRP) {
|
|
55
|
+
noteStr = noteStr.trim();
|
|
56
|
+
if (!noteStr.startsWith(hrp)) {
|
|
57
|
+
throw new Error(`invalid human-readable part: expected ${hrp} prefix (note '${noteStr}')`);
|
|
54
58
|
}
|
|
59
|
+
const encoded = noteStr.slice(hrp.length);
|
|
55
60
|
const decoded = base58.decode(encoded);
|
|
56
61
|
if (decoded.length === 0) {
|
|
57
62
|
throw new Error("failed to decode base58 string");
|
|
58
63
|
}
|
|
59
|
-
return ArkNote.decode(
|
|
64
|
+
return ArkNote.decode(decoded, hrp);
|
|
60
65
|
}
|
|
61
66
|
toString() {
|
|
62
|
-
return
|
|
67
|
+
return this.HRP + base58.encode(this.encode());
|
|
63
68
|
}
|
|
64
69
|
}
|
|
65
|
-
ArkNote.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
function readBigUInt64BE(array, offset) {
|
|
71
|
-
const view = new DataView(array.buffer, array.byteOffset + offset, 8);
|
|
72
|
-
return view.getBigUint64(0, false);
|
|
73
|
-
}
|
|
70
|
+
ArkNote.DefaultHRP = "arknote";
|
|
71
|
+
ArkNote.PreimageLength = 32; // 32 bytes for the preimage
|
|
72
|
+
ArkNote.ValueLength = 4; // 4 bytes for the value
|
|
73
|
+
ArkNote.Length = ArkNote.PreimageLength + ArkNote.ValueLength;
|
|
74
|
+
ArkNote.FakeOutpointIndex = 0;
|
|
74
75
|
function writeUInt32BE(array, value, offset) {
|
|
75
76
|
const view = new DataView(array.buffer, array.byteOffset + offset, 4);
|
|
76
77
|
view.setUint32(0, value, false);
|
|
@@ -79,3 +80,6 @@ function readUInt32BE(array, offset) {
|
|
|
79
80
|
const view = new DataView(array.buffer, array.byteOffset + offset, 4);
|
|
80
81
|
return view.getUint32(0, false);
|
|
81
82
|
}
|
|
83
|
+
function noteTapscript(preimageHash) {
|
|
84
|
+
return Script.encode(["SHA256", preimageHash, "EQUAL"]);
|
|
85
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export class BIP322Error extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = "BIP322Error";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export const ErrMissingInputs = new BIP322Error("missing inputs");
|
|
8
|
+
export const ErrMissingData = new BIP322Error("missing data");
|
|
9
|
+
export const ErrMissingWitnessUtxo = new BIP322Error("missing witness utxo");
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { OP, Transaction, Script, SigHash } from "@scure/btc-signer";
|
|
2
|
+
import { ErrMissingData, ErrMissingInputs, ErrMissingWitnessUtxo, } from './errors.js';
|
|
3
|
+
import { schnorr } from "@noble/curves/secp256k1";
|
|
4
|
+
import { base64 } from "@scure/base";
|
|
5
|
+
/**
|
|
6
|
+
* BIP-322 signature implementation for Bitcoin message signing.
|
|
7
|
+
*
|
|
8
|
+
* BIP-322 defines a standard for signing Bitcoin messages as well as proving
|
|
9
|
+
* ownership of coins. This namespace provides utilities for creating and
|
|
10
|
+
* validating BIP-322.
|
|
11
|
+
*
|
|
12
|
+
* @see https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // Create a BIP-322 proof
|
|
17
|
+
* const proof = BIP322.create(
|
|
18
|
+
* "Hello Bitcoin!",
|
|
19
|
+
* [input],
|
|
20
|
+
* [output]
|
|
21
|
+
* );
|
|
22
|
+
*
|
|
23
|
+
* // Sign the proof
|
|
24
|
+
* const signedProof = await identity.sign(proof);
|
|
25
|
+
*
|
|
26
|
+
* // Extract the signature
|
|
27
|
+
* const signature = BIP322.signature(signedProof);
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export var BIP322;
|
|
31
|
+
(function (BIP322) {
|
|
32
|
+
/**
|
|
33
|
+
* Creates a new BIP-322 "full" proof of funds unsigned transaction.
|
|
34
|
+
*
|
|
35
|
+
* This function constructs a special transaction that can be signed to prove
|
|
36
|
+
* ownership of VTXOs and UTXOs. The proof includes the message to be
|
|
37
|
+
* signed and the inputs/outputs that demonstrate ownership.
|
|
38
|
+
*
|
|
39
|
+
* @param message - The BIP-322 message to be signed
|
|
40
|
+
* @param inputs - Array of transaction inputs to prove ownership of
|
|
41
|
+
* @param outputs - Optional array of transaction outputs
|
|
42
|
+
* @returns An unsigned BIP-322 proof transaction
|
|
43
|
+
*/
|
|
44
|
+
function create(message, inputs, outputs = []) {
|
|
45
|
+
if (inputs.length == 0)
|
|
46
|
+
throw ErrMissingInputs;
|
|
47
|
+
if (!validateInputs(inputs))
|
|
48
|
+
throw ErrMissingData;
|
|
49
|
+
if (!validateOutputs(outputs))
|
|
50
|
+
throw ErrMissingData;
|
|
51
|
+
// create the initial transaction to spend
|
|
52
|
+
const toSpend = craftToSpendTx(message, inputs[0].witnessUtxo.script);
|
|
53
|
+
// create the transaction to sign
|
|
54
|
+
return craftToSignTx(toSpend, inputs, outputs);
|
|
55
|
+
}
|
|
56
|
+
BIP322.create = create;
|
|
57
|
+
/**
|
|
58
|
+
* Finalizes and extracts the FullProof transaction into a BIP-322 signature.
|
|
59
|
+
*
|
|
60
|
+
* This function takes a signed proof transaction and converts it into a
|
|
61
|
+
* base64-encoded signature string. If the proof's inputs have special
|
|
62
|
+
* spending conditions, a custom finalizer can be provided.
|
|
63
|
+
*
|
|
64
|
+
* @param signedProof - The signed BIP-322 proof transaction
|
|
65
|
+
* @param finalizer - Optional custom finalizer function
|
|
66
|
+
* @returns Base64-encoded BIP-322 signature
|
|
67
|
+
*/
|
|
68
|
+
function signature(signedProof, finalizer = (tx) => tx.finalize()) {
|
|
69
|
+
finalizer(signedProof);
|
|
70
|
+
return base64.encode(signedProof.extract());
|
|
71
|
+
}
|
|
72
|
+
BIP322.signature = signature;
|
|
73
|
+
})(BIP322 || (BIP322 = {}));
|
|
74
|
+
const OP_RETURN_EMPTY_PKSCRIPT = new Uint8Array([OP.RETURN]);
|
|
75
|
+
const ZERO_32 = new Uint8Array(32).fill(0);
|
|
76
|
+
const MAX_INDEX = 0xffffffff;
|
|
77
|
+
const TAG_BIP322 = "BIP0322-signed-message";
|
|
78
|
+
function validateInput(input) {
|
|
79
|
+
if (input.index === undefined)
|
|
80
|
+
throw ErrMissingData;
|
|
81
|
+
if (input.txid === undefined)
|
|
82
|
+
throw ErrMissingData;
|
|
83
|
+
if (input.witnessUtxo === undefined)
|
|
84
|
+
throw ErrMissingWitnessUtxo;
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
function validateInputs(inputs) {
|
|
88
|
+
inputs.forEach(validateInput);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
function validateOutput(output) {
|
|
92
|
+
if (output.amount === undefined)
|
|
93
|
+
throw ErrMissingData;
|
|
94
|
+
if (output.script === undefined)
|
|
95
|
+
throw ErrMissingData;
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
function validateOutputs(outputs) {
|
|
99
|
+
outputs.forEach(validateOutput);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
// craftToSpendTx creates the initial transaction that will be spent in the proof
|
|
103
|
+
export function craftToSpendTx(message, pkScript) {
|
|
104
|
+
const messageHash = hashMessage(message);
|
|
105
|
+
const tx = new Transaction({
|
|
106
|
+
version: 0,
|
|
107
|
+
allowUnknownOutputs: true,
|
|
108
|
+
allowUnknown: true,
|
|
109
|
+
allowUnknownInputs: true,
|
|
110
|
+
});
|
|
111
|
+
// add input with zero hash and max index
|
|
112
|
+
tx.addInput({
|
|
113
|
+
txid: ZERO_32, // zero hash
|
|
114
|
+
index: MAX_INDEX,
|
|
115
|
+
sequence: 0,
|
|
116
|
+
});
|
|
117
|
+
// add output with zero value and provided pkScript
|
|
118
|
+
tx.addOutput({
|
|
119
|
+
amount: 0n,
|
|
120
|
+
script: pkScript,
|
|
121
|
+
});
|
|
122
|
+
tx.updateInput(0, {
|
|
123
|
+
finalScriptSig: Script.encode(["OP_0", messageHash]),
|
|
124
|
+
});
|
|
125
|
+
return tx;
|
|
126
|
+
}
|
|
127
|
+
// craftToSignTx creates the transaction that will be signed for the proof
|
|
128
|
+
function craftToSignTx(toSpend, inputs, outputs) {
|
|
129
|
+
const firstInput = inputs[0];
|
|
130
|
+
const tx = new Transaction({
|
|
131
|
+
version: 2,
|
|
132
|
+
allowUnknownOutputs: outputs.length === 0,
|
|
133
|
+
allowUnknown: true,
|
|
134
|
+
allowUnknownInputs: true,
|
|
135
|
+
lockTime: 0,
|
|
136
|
+
});
|
|
137
|
+
// add the first "toSpend" input
|
|
138
|
+
tx.addInput({
|
|
139
|
+
...firstInput,
|
|
140
|
+
txid: toSpend.id,
|
|
141
|
+
index: 0,
|
|
142
|
+
witnessUtxo: {
|
|
143
|
+
script: firstInput.witnessUtxo.script,
|
|
144
|
+
amount: 0n,
|
|
145
|
+
},
|
|
146
|
+
sighashType: SigHash.ALL,
|
|
147
|
+
});
|
|
148
|
+
// add other inputs
|
|
149
|
+
for (const input of inputs) {
|
|
150
|
+
tx.addInput({
|
|
151
|
+
...input,
|
|
152
|
+
sighashType: SigHash.ALL,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
// add the special OP_RETURN output if no outputs are provided
|
|
156
|
+
if (outputs.length === 0) {
|
|
157
|
+
outputs = [
|
|
158
|
+
{
|
|
159
|
+
amount: 0n,
|
|
160
|
+
script: OP_RETURN_EMPTY_PKSCRIPT,
|
|
161
|
+
},
|
|
162
|
+
];
|
|
163
|
+
}
|
|
164
|
+
for (const output of outputs) {
|
|
165
|
+
tx.addOutput({
|
|
166
|
+
amount: output.amount,
|
|
167
|
+
script: output.script,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return tx;
|
|
171
|
+
}
|
|
172
|
+
function hashMessage(message) {
|
|
173
|
+
return schnorr.utils.taggedHash(TAG_BIP322, new TextEncoder().encode(message));
|
|
174
|
+
}
|
package/dist/esm/forfeit.js
CHANGED
|
@@ -1,35 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { Transaction } from "@scure/btc-signer";
|
|
2
|
+
import { P2A } from './utils/anchor.js';
|
|
3
|
+
export function buildForfeitTx(inputs, forfeitPkScript, txLocktime) {
|
|
3
4
|
const tx = new Transaction({
|
|
4
|
-
version:
|
|
5
|
+
version: 3,
|
|
5
6
|
lockTime: txLocktime,
|
|
6
7
|
});
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
sequence: 0xffffffff,
|
|
16
|
-
});
|
|
17
|
-
// Add VTXO input
|
|
18
|
-
tx.addInput({
|
|
19
|
-
txid: vtxoInput.txid,
|
|
20
|
-
index: vtxoInput.vout,
|
|
21
|
-
witnessUtxo: {
|
|
22
|
-
script: vtxoPkScript,
|
|
23
|
-
amount: vtxoAmount,
|
|
24
|
-
},
|
|
25
|
-
sequence: txLocktime ? 0xfffffffe : 0xffffffff, // MAX_SEQUENCE - 1 if locktime is set
|
|
26
|
-
sighashType: SigHash.DEFAULT,
|
|
27
|
-
});
|
|
28
|
-
const amount = BigInt(vtxoAmount) + BigInt(connectorAmount) - BigInt(feeAmount);
|
|
8
|
+
let amount = 0n;
|
|
9
|
+
for (const input of inputs) {
|
|
10
|
+
if (!input.witnessUtxo) {
|
|
11
|
+
throw new Error("input needs witness utxo");
|
|
12
|
+
}
|
|
13
|
+
amount += input.witnessUtxo.amount;
|
|
14
|
+
tx.addInput(input);
|
|
15
|
+
}
|
|
29
16
|
// Add main output to server
|
|
30
17
|
tx.addOutput({
|
|
31
|
-
script:
|
|
18
|
+
script: forfeitPkScript,
|
|
32
19
|
amount,
|
|
33
20
|
});
|
|
21
|
+
// Add P2A output
|
|
22
|
+
tx.addOutput(P2A);
|
|
34
23
|
return tx;
|
|
35
24
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { pubSchnorr, randomPrivateKeyBytes } from "@scure/btc-signer/utils";
|
|
2
|
+
import { hex } from "@scure/base";
|
|
3
|
+
import { SigHash } from "@scure/btc-signer";
|
|
4
|
+
import { TreeSignerSession } from '../tree/signingSession.js';
|
|
5
|
+
const ZERO_32 = new Uint8Array(32).fill(0);
|
|
6
|
+
const ALL_SIGHASH = Object.values(SigHash).filter((x) => typeof x === "number");
|
|
7
|
+
/**
|
|
8
|
+
* In-memory single key implementation for Bitcoin transaction signing.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // Create from hex string
|
|
13
|
+
* const key = SingleKey.fromHex('your_private_key_hex');
|
|
14
|
+
*
|
|
15
|
+
* // Create from raw bytes
|
|
16
|
+
* const key = SingleKey.fromPrivateKey(privateKeyBytes);
|
|
17
|
+
*
|
|
18
|
+
* // Sign a transaction
|
|
19
|
+
* const signedTx = await key.sign(transaction);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export class SingleKey {
|
|
23
|
+
constructor(key) {
|
|
24
|
+
this.key = key || randomPrivateKeyBytes();
|
|
25
|
+
}
|
|
26
|
+
static fromPrivateKey(privateKey) {
|
|
27
|
+
return new SingleKey(privateKey);
|
|
28
|
+
}
|
|
29
|
+
static fromHex(privateKeyHex) {
|
|
30
|
+
return new SingleKey(hex.decode(privateKeyHex));
|
|
31
|
+
}
|
|
32
|
+
async sign(tx, inputIndexes) {
|
|
33
|
+
const txCpy = tx.clone();
|
|
34
|
+
if (!inputIndexes) {
|
|
35
|
+
try {
|
|
36
|
+
if (!txCpy.sign(this.key, ALL_SIGHASH, ZERO_32)) {
|
|
37
|
+
throw new Error("Failed to sign transaction");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
if (e instanceof Error &&
|
|
42
|
+
e.message.includes("No inputs signed")) {
|
|
43
|
+
// ignore
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
throw e;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return txCpy;
|
|
50
|
+
}
|
|
51
|
+
for (const inputIndex of inputIndexes) {
|
|
52
|
+
if (!txCpy.signIdx(this.key, inputIndex, ALL_SIGHASH, ZERO_32)) {
|
|
53
|
+
throw new Error(`Failed to sign input #${inputIndex}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return txCpy;
|
|
57
|
+
}
|
|
58
|
+
xOnlyPublicKey() {
|
|
59
|
+
return pubSchnorr(this.key);
|
|
60
|
+
}
|
|
61
|
+
signerSession() {
|
|
62
|
+
return TreeSignerSession.random();
|
|
63
|
+
}
|
|
64
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,38 +1,56 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SingleKey } from './identity/singleKey.js';
|
|
2
2
|
import { ArkAddress } from './script/address.js';
|
|
3
3
|
import { VHTLC } from './script/vhtlc.js';
|
|
4
4
|
import { DefaultVtxo } from './script/default.js';
|
|
5
5
|
import { VtxoScript } from './script/base.js';
|
|
6
6
|
import { TxType, } from './wallet/index.js';
|
|
7
|
-
import { Wallet } from './wallet/wallet.js';
|
|
7
|
+
import { Wallet, waitForIncomingFunds } from './wallet/wallet.js';
|
|
8
|
+
import { TxTree } from './tree/txTree.js';
|
|
9
|
+
import { Ramps } from './wallet/ramps.js';
|
|
8
10
|
import { ServiceWorkerWallet } from './wallet/serviceWorker/wallet.js';
|
|
11
|
+
import { OnchainWallet } from './wallet/onchain.js';
|
|
9
12
|
import { setupServiceWorker } from './wallet/serviceWorker/utils.js';
|
|
10
13
|
import { Worker } from './wallet/serviceWorker/worker.js';
|
|
11
14
|
import { Request } from './wallet/serviceWorker/request.js';
|
|
12
15
|
import { Response } from './wallet/serviceWorker/response.js';
|
|
13
|
-
import { ESPLORA_URL, EsploraProvider } from './providers/onchain.js';
|
|
14
|
-
import { RestArkProvider } from './providers/ark.js';
|
|
16
|
+
import { ESPLORA_URL, EsploraProvider, } from './providers/onchain.js';
|
|
17
|
+
import { RestArkProvider, SettlementEventType, } from './providers/ark.js';
|
|
15
18
|
import { CLTVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CSVMultisigTapscript, decodeTapscript, MultisigTapscript, } from './script/tapscript.js';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
19
|
+
import { buildOffchainTx, } from './utils/arkTransaction.js';
|
|
20
|
+
import { VtxoTaprootTree, ConditionWitness, getArkPsbtFields, setArkPsbtField, ArkPsbtFieldKey, ArkPsbtFieldKeyType, CosignerPublicKey, VtxoTreeExpiry, } from './utils/unknownFields.js';
|
|
21
|
+
import { BIP322 } from './bip322/index.js';
|
|
22
|
+
import { ArkNote } from './arknote/index.js';
|
|
18
23
|
import { IndexedDBVtxoRepository } from './wallet/serviceWorker/db/vtxo/idb.js';
|
|
19
24
|
import { networks } from './networks.js';
|
|
20
|
-
|
|
25
|
+
import { RestIndexerProvider, IndexerTxType, ChainTxType, } from './providers/indexer.js';
|
|
26
|
+
import { P2A } from './utils/anchor.js';
|
|
27
|
+
import { Unroll } from './wallet/unroll.js';
|
|
28
|
+
export {
|
|
29
|
+
// Wallets
|
|
30
|
+
Wallet, SingleKey, OnchainWallet, Ramps,
|
|
21
31
|
// Providers
|
|
22
|
-
ESPLORA_URL, EsploraProvider, RestArkProvider,
|
|
32
|
+
ESPLORA_URL, EsploraProvider, RestArkProvider, RestIndexerProvider,
|
|
23
33
|
// Script-related
|
|
24
34
|
ArkAddress, DefaultVtxo, VtxoScript, VHTLC,
|
|
25
35
|
// Enums
|
|
26
|
-
TxType,
|
|
36
|
+
TxType, IndexerTxType, ChainTxType, SettlementEventType,
|
|
27
37
|
// Service Worker
|
|
28
38
|
setupServiceWorker, Worker, ServiceWorkerWallet, Request, Response,
|
|
29
39
|
// Tapscript
|
|
30
40
|
decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript,
|
|
41
|
+
// Ark PSBT fields
|
|
42
|
+
ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness,
|
|
31
43
|
// Utils
|
|
32
|
-
|
|
44
|
+
buildOffchainTx, waitForIncomingFunds,
|
|
33
45
|
// Arknote
|
|
34
|
-
ArkNote,
|
|
46
|
+
ArkNote,
|
|
35
47
|
// Network
|
|
36
48
|
networks,
|
|
37
49
|
// Database
|
|
38
|
-
IndexedDBVtxoRepository,
|
|
50
|
+
IndexedDBVtxoRepository,
|
|
51
|
+
// BIP322
|
|
52
|
+
BIP322,
|
|
53
|
+
// TxTree
|
|
54
|
+
TxTree,
|
|
55
|
+
// Anchor
|
|
56
|
+
P2A, Unroll, };
|