@airgap/bitcoin 0.13.45-beta.1 → 0.13.45-beta.3
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/package.json +5 -5
- package/v0/index.js +10 -10
- package/v0/index.js.map +1 -1
- package/v0/protocol/BitcoinAddress.js +8 -9
- package/v0/protocol/BitcoinAddress.js.map +1 -1
- package/v0/protocol/BitcoinCryptoClient.js +16 -85
- package/v0/protocol/BitcoinCryptoClient.js.map +1 -1
- package/v0/protocol/BitcoinProtocol.js +590 -987
- package/v0/protocol/BitcoinProtocol.js.map +1 -1
- package/v0/protocol/BitcoinProtocolOptions.js +45 -111
- package/v0/protocol/BitcoinProtocolOptions.js.map +1 -1
- package/v0/protocol/BitcoinSegwitAddress.js +12 -29
- package/v0/protocol/BitcoinSegwitAddress.js.map +1 -1
- package/v0/protocol/BitcoinSegwitProtocol.js +348 -483
- package/v0/protocol/BitcoinSegwitProtocol.js.map +1 -1
- package/v0/protocol/BitcoinTestnetProtocol.js +28 -36
- package/v0/protocol/BitcoinTestnetProtocol.js.map +1 -1
- package/v0/serializer/validators/transaction-validator.js +22 -30
- package/v0/serializer/validators/transaction-validator.js.map +1 -1
- package/v0/serializer/validators/validators.js +23 -23
- package/v0/serializer/validators/validators.js.map +1 -1
- package/v1/block-explorer/BlockCypherBlockExplorer.js +12 -61
- package/v1/block-explorer/BlockCypherBlockExplorer.js.map +1 -1
- package/v1/data/BitcoinAddress.js +9 -10
- package/v1/data/BitcoinAddress.js.map +1 -1
- package/v1/data/BitcoinLegacyAddress.js +11 -12
- package/v1/data/BitcoinLegacyAddress.js.map +1 -1
- package/v1/data/BitcoinSegwitAddress.js +11 -12
- package/v1/data/BitcoinSegwitAddress.js.map +1 -1
- package/v1/data/BitcoinTaprootAddress.js +31 -22
- package/v1/data/BitcoinTaprootAddress.js.map +1 -1
- package/v1/index.js +11 -11
- package/v1/index.js.map +1 -1
- package/v1/module/BitcoinModule.d.ts +1 -1
- package/v1/module/BitcoinModule.js +44 -102
- package/v1/module/BitcoinModule.js.map +1 -1
- package/v1/module.js +2 -3
- package/v1/module.js.map +1 -1
- package/v1/protocol/BitcoinCryptoClient.js +22 -90
- package/v1/protocol/BitcoinCryptoClient.js.map +1 -1
- package/v1/protocol/BitcoinLegacyProtocol.js +520 -796
- package/v1/protocol/BitcoinLegacyProtocol.js.map +1 -1
- package/v1/protocol/BitcoinProtocol.js +735 -1169
- package/v1/protocol/BitcoinProtocol.js.map +1 -1
- package/v1/protocol/BitcoinSegwitProtocol.js +542 -796
- package/v1/protocol/BitcoinSegwitProtocol.js.map +1 -1
- package/v1/protocol/BitcoinTaprootProtocol.js +688 -1000
- package/v1/protocol/BitcoinTaprootProtocol.js.map +1 -1
- package/v1/protocol/BitcoinTestnetProtocol.js +14 -33
- package/v1/protocol/BitcoinTestnetProtocol.js.map +1 -1
- package/v1/serializer/v3/schemas/converter/transaction-converter.js +29 -52
- package/v1/serializer/v3/schemas/converter/transaction-converter.js.map +1 -1
- package/v1/serializer/v3/serializer-companion.js +98 -165
- package/v1/serializer/v3/serializer-companion.js.map +1 -1
- package/v1/serializer/v3/validators/transaction-validator.js +13 -16
- package/v1/serializer/v3/validators/transaction-validator.js.map +1 -1
- package/v1/serializer/v3/validators/validators.js +122 -213
- package/v1/serializer/v3/validators/validators.js.map +1 -1
- package/v1/types/crypto.d.ts +1 -1
- package/v1/types/key.d.ts +6 -6
- package/v1/types/protocol.d.ts +2 -2
- package/v1/types/transaction.d.ts +3 -3
- package/v1/utils/common.js +4 -6
- package/v1/utils/common.js.map +1 -1
- package/v1/utils/key.d.ts +5 -6
- package/v1/utils/key.js +38 -39
- package/v1/utils/key.js.map +1 -1
- package/v1/utils/network.js +3 -4
- package/v1/utils/network.js.map +1 -1
- package/v1/utils/protocol.js +25 -19
- package/v1/utils/protocol.js.map +1 -1
- package/v1/utils/signature.js +4 -5
- package/v1/utils/signature.js.map +1 -1
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __assign = (this && this.__assign) || function () {
|
|
3
|
-
__assign = Object.assign || function(t) {
|
|
4
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
-
s = arguments[i];
|
|
6
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
-
t[p] = s[p];
|
|
8
|
-
}
|
|
9
|
-
return t;
|
|
10
|
-
};
|
|
11
|
-
return __assign.apply(this, arguments);
|
|
12
|
-
};
|
|
13
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
3
|
if (k2 === undefined) k2 = k;
|
|
15
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -26,85 +15,48 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
26
15
|
}) : function(o, v) {
|
|
27
16
|
o["default"] = v;
|
|
28
17
|
});
|
|
29
|
-
var __importStar = (this && this.__importStar) || function (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
47
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
48
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
49
|
-
function step(op) {
|
|
50
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
51
|
-
while (_) try {
|
|
52
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
53
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
54
|
-
switch (op[0]) {
|
|
55
|
-
case 0: case 1: t = op; break;
|
|
56
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
57
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
58
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
59
|
-
default:
|
|
60
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
61
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
62
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
63
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
64
|
-
if (t[2]) _.ops.pop();
|
|
65
|
-
_.trys.pop(); continue;
|
|
66
|
-
}
|
|
67
|
-
op = body.call(thisArg, _);
|
|
68
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
69
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
73
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
74
|
-
if (ar || !(i in from)) {
|
|
75
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
76
|
-
ar[i] = from[i];
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
80
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
81
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
82
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
83
37
|
};
|
|
84
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
85
|
-
exports.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
39
|
+
exports.BitcoinTaprootProtocolImpl = void 0;
|
|
40
|
+
exports.createBitcoinTaprootProtocol = createBitcoinTaprootProtocol;
|
|
41
|
+
const coinlib_core_1 = require("@airgap/coinlib-core");
|
|
42
|
+
const index_1 = __importDefault(require("@airgap/coinlib-core/dependencies/src/axios-0.19.0/index"));
|
|
43
|
+
const bignumber_1 = __importDefault(require("@airgap/coinlib-core/dependencies/src/bignumber.js-9.0.0/bignumber"));
|
|
44
|
+
const errors_1 = require("@airgap/coinlib-core/errors");
|
|
45
|
+
const module_kit_1 = require("@airgap/module-kit");
|
|
46
|
+
const bitcoin = __importStar(require("bitcoinjs-lib"));
|
|
47
|
+
const BitcoinTaprootAddress_1 = require("../data/BitcoinTaprootAddress");
|
|
48
|
+
const common_1 = require("../utils/common");
|
|
49
|
+
const key_1 = require("../utils/key");
|
|
50
|
+
const network_1 = require("../utils/network");
|
|
51
|
+
const BitcoinProtocol_1 = require("./BitcoinProtocol");
|
|
52
|
+
const bip32_1 = require("bip32");
|
|
53
|
+
const BitcoinSegwitProtocol_1 = require("./BitcoinSegwitProtocol");
|
|
54
|
+
const crypto_1 = require("@airgap/crypto");
|
|
55
|
+
const secp256k1_1 = __importDefault(require("@bitcoinerlab/secp256k1"));
|
|
101
56
|
// Implementation
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (options === void 0) { options = {}; }
|
|
106
|
-
if (bitcoinJS === void 0) { bitcoinJS = bitcoin; }
|
|
107
|
-
var _a, _b, _c;
|
|
57
|
+
const DUST_AMOUNT = 50;
|
|
58
|
+
class BitcoinTaprootProtocolImpl {
|
|
59
|
+
constructor(options = {}, bitcoinJS = bitcoin) {
|
|
108
60
|
this._isBitcoinProtocol = true;
|
|
109
61
|
this._isBitcoinTaprootProtocol = true;
|
|
110
62
|
this.bip32 = (0, bip32_1.BIP32Factory)(secp256k1_1.default);
|
|
@@ -117,107 +69,82 @@ var BitcoinTaprootProtocolImpl = /** @class */ (function () {
|
|
|
117
69
|
};
|
|
118
70
|
this.bitcoinJS.lib.initEccLib(secp256k1_1.default);
|
|
119
71
|
this.segwit = new BitcoinSegwitProtocol_1.BitcoinSegwitProtocolImpl(options);
|
|
120
|
-
this.metadata =
|
|
72
|
+
this.metadata = {
|
|
73
|
+
...this.segwit.legacy.metadata,
|
|
74
|
+
identifier: coinlib_core_1.MainProtocolSymbols.BTC_TAPROOT,
|
|
75
|
+
name: 'Bitcoin (Taproot)',
|
|
76
|
+
account: {
|
|
77
|
+
...(this.segwit.legacy.metadata.account ?? {}),
|
|
78
|
+
standardDerivationPath: `m/86'/0'/0'`,
|
|
79
|
+
address: {
|
|
80
|
+
...(this.segwit.legacy.metadata.account?.address ?? {}),
|
|
81
|
+
regex: '^(?:[13]{1}[a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-z0-9]{39,59})$'
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async prepareTransactionWithPublicKey(publicKey, details, configuration) {
|
|
87
|
+
switch (publicKey.type) {
|
|
88
|
+
case 'pub':
|
|
89
|
+
return this.prepareTransactionWithNonExtendedPublicKey(publicKey, details, configuration);
|
|
90
|
+
case 'xpub':
|
|
91
|
+
return this.prepareTransactionWithExtendedPublicKey(publicKey, details, configuration);
|
|
92
|
+
default:
|
|
93
|
+
(0, coinlib_core_1.assertNever)(publicKey);
|
|
94
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Unsupported public key type.');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async prepareTransactionWithNonExtendedPublicKey(publicKey, details, configuration) {
|
|
98
|
+
throw new Error('Method not implemented.');
|
|
99
|
+
}
|
|
100
|
+
async getCryptoConfiguration() {
|
|
101
|
+
return this.segwit.getCryptoConfiguration();
|
|
102
|
+
}
|
|
103
|
+
async getKeyPairFromDerivative(derivative) {
|
|
104
|
+
return this.segwit.getKeyPairFromDerivative(derivative);
|
|
121
105
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
106
|
+
async signTransactionWithSecretKey(transaction, secretKey) {
|
|
107
|
+
switch (secretKey.type) {
|
|
108
|
+
case 'priv':
|
|
109
|
+
return this.signTransactionWithNonExtendedSecretKey(transaction, secretKey);
|
|
110
|
+
case 'xpriv':
|
|
111
|
+
return this.signTransactionWithExtendedSecretKey(transaction, secretKey);
|
|
112
|
+
default:
|
|
113
|
+
(0, coinlib_core_1.assertNever)(secretKey);
|
|
114
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Secret key type not supported.');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async signTransactionWithExtendedSecretKey(transaction, secretKey) {
|
|
118
|
+
const encodedExtendedSecretKey = (0, key_1.convertExtendedSecretKey)(secretKey, { format: 'encoded', type: 'xprv' });
|
|
119
|
+
const bip32 = this.bip32.fromBase58(encodedExtendedSecretKey.value);
|
|
120
|
+
const decodedPSBT = this.bitcoinJS.lib.Psbt.fromHex(transaction.psbt);
|
|
121
|
+
decodedPSBT.data.inputs.forEach((input, index) => {
|
|
122
|
+
input.tapBip32Derivation?.forEach((deriv) => {
|
|
123
|
+
try {
|
|
124
|
+
const cutoffFrom = deriv.path.lastIndexOf("'") || deriv.path.lastIndexOf('h');
|
|
125
|
+
const childPath = deriv.path.substr(cutoffFrom + 2);
|
|
126
|
+
const childNode = bip32.derivePath(childPath);
|
|
127
|
+
const tweakedChildNode = childNode.tweak(this.bitcoinJS.lib.crypto.taggedHash('TapTweak', Buffer.from(childNode.publicKey.subarray(1, 33))));
|
|
128
|
+
decodedPSBT.signInput(index, {
|
|
129
|
+
publicKey: Buffer.from(tweakedChildNode.publicKey),
|
|
130
|
+
sign: (hash, lowR) => Buffer.from(tweakedChildNode.sign(hash, lowR)),
|
|
131
|
+
signSchnorr: (hash) => Buffer.from(tweakedChildNode.signSchnorr(hash))
|
|
132
|
+
});
|
|
133
133
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
});
|
|
137
|
-
};
|
|
138
|
-
BitcoinTaprootProtocolImpl.prototype.prepareTransactionWithNonExtendedPublicKey = function (publicKey, details, configuration) {
|
|
139
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
140
|
-
return __generator(this, function (_a) {
|
|
141
|
-
throw new Error('Method not implemented.');
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
};
|
|
145
|
-
BitcoinTaprootProtocolImpl.prototype.getCryptoConfiguration = function () {
|
|
146
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
147
|
-
return __generator(this, function (_a) {
|
|
148
|
-
return [2 /*return*/, this.segwit.getCryptoConfiguration()];
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
};
|
|
152
|
-
BitcoinTaprootProtocolImpl.prototype.getKeyPairFromDerivative = function (derivative) {
|
|
153
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
154
|
-
return __generator(this, function (_a) {
|
|
155
|
-
return [2 /*return*/, this.segwit.getKeyPairFromDerivative(derivative)];
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
};
|
|
159
|
-
BitcoinTaprootProtocolImpl.prototype.signTransactionWithSecretKey = function (transaction, secretKey) {
|
|
160
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
161
|
-
return __generator(this, function (_a) {
|
|
162
|
-
switch (secretKey.type) {
|
|
163
|
-
case 'priv':
|
|
164
|
-
return [2 /*return*/, this.signTransactionWithNonExtendedSecretKey(transaction, secretKey)];
|
|
165
|
-
case 'xpriv':
|
|
166
|
-
return [2 /*return*/, this.signTransactionWithExtendedSecretKey(transaction, secretKey)];
|
|
167
|
-
default:
|
|
168
|
-
(0, coinlib_core_1.assertNever)(secretKey);
|
|
169
|
-
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Secret key type not supported.');
|
|
134
|
+
catch (e) {
|
|
135
|
+
throw new Error(`Error signing index #${index}`);
|
|
170
136
|
}
|
|
171
|
-
return [2 /*return*/];
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
};
|
|
175
|
-
BitcoinTaprootProtocolImpl.prototype.signTransactionWithExtendedSecretKey = function (transaction, secretKey) {
|
|
176
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
177
|
-
var encodedExtendedSecretKey, bip32, decodedPSBT;
|
|
178
|
-
var _this = this;
|
|
179
|
-
return __generator(this, function (_a) {
|
|
180
|
-
encodedExtendedSecretKey = (0, key_1.convertExtendedSecretKey)(secretKey, { format: 'encoded', type: 'xprv' });
|
|
181
|
-
bip32 = this.bip32.fromBase58(encodedExtendedSecretKey.value);
|
|
182
|
-
decodedPSBT = this.bitcoinJS.lib.Psbt.fromHex(transaction.psbt);
|
|
183
|
-
decodedPSBT.data.inputs.forEach(function (input, index) {
|
|
184
|
-
var _a;
|
|
185
|
-
(_a = input.tapBip32Derivation) === null || _a === void 0 ? void 0 : _a.forEach(function (deriv) {
|
|
186
|
-
try {
|
|
187
|
-
var cutoffFrom = deriv.path.lastIndexOf("'") || deriv.path.lastIndexOf('h');
|
|
188
|
-
var childPath = deriv.path.substr(cutoffFrom + 2);
|
|
189
|
-
var childNode = bip32.derivePath(childPath);
|
|
190
|
-
var tweakedChildNode_1 = childNode.tweak(_this.bitcoinJS.lib.crypto.taggedHash('TapTweak', Buffer.from(childNode.publicKey.subarray(1, 33))));
|
|
191
|
-
decodedPSBT.signInput(index, {
|
|
192
|
-
publicKey: Buffer.from(tweakedChildNode_1.publicKey),
|
|
193
|
-
sign: function (hash, lowR) { return Buffer.from(tweakedChildNode_1.sign(hash, lowR)); },
|
|
194
|
-
signSchnorr: function (hash) { return Buffer.from(tweakedChildNode_1.signSchnorr(hash)); }
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
catch (e) {
|
|
198
|
-
throw new Error("Error signing index #".concat(index));
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
return [2 /*return*/, (0, module_kit_1.newSignedTransaction)({ psbt: decodedPSBT.toHex() })];
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
};
|
|
206
|
-
BitcoinTaprootProtocolImpl.prototype.signTransactionWithNonExtendedSecretKey = function (transaction, secretKey) {
|
|
207
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
208
|
-
return __generator(this, function (_a) {
|
|
209
|
-
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Sign with non extended secret key not supported (Taproot).');
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
};
|
|
213
|
-
BitcoinTaprootProtocolImpl.prototype.getMetadata = function () {
|
|
214
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
215
|
-
return __generator(this, function (_a) {
|
|
216
|
-
return [2 /*return*/, this.metadata];
|
|
217
137
|
});
|
|
218
138
|
});
|
|
219
|
-
|
|
220
|
-
|
|
139
|
+
return (0, module_kit_1.newSignedTransaction)({ psbt: decodedPSBT.toHex() });
|
|
140
|
+
}
|
|
141
|
+
async signTransactionWithNonExtendedSecretKey(transaction, secretKey) {
|
|
142
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Sign with non extended secret key not supported (Taproot).');
|
|
143
|
+
}
|
|
144
|
+
async getMetadata() {
|
|
145
|
+
return this.metadata;
|
|
146
|
+
}
|
|
147
|
+
getAddressFromPublicKey(publicKey) {
|
|
221
148
|
switch (publicKey.type) {
|
|
222
149
|
case 'pub':
|
|
223
150
|
return this.getAddressFromNonExtendedPublicKey(publicKey);
|
|
@@ -227,853 +154,614 @@ var BitcoinTaprootProtocolImpl = /** @class */ (function () {
|
|
|
227
154
|
(0, coinlib_core_1.assertNever)(publicKey);
|
|
228
155
|
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Public key type is not supported.');
|
|
229
156
|
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
payment = this.bitcoinJS.lib.payments.p2tr({
|
|
237
|
-
internalPubkey: Buffer.from(encodedExtendedPublicKey.value, 'hex').subarray(1, 33),
|
|
238
|
-
network: this.bitcoinJS.config.network
|
|
239
|
-
});
|
|
240
|
-
return [2 /*return*/, BitcoinTaprootAddress_1.BitcoinTaprootAddress.fromPayment(payment).asString()];
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
};
|
|
244
|
-
BitcoinTaprootProtocolImpl.prototype.getDetailsFromTransaction = function (transaction, _publicKey) {
|
|
245
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
246
|
-
return __generator(this, function (_a) {
|
|
247
|
-
return [2 /*return*/, this.getDetailsFromPSBT(transaction.psbt, _publicKey)];
|
|
248
|
-
});
|
|
157
|
+
}
|
|
158
|
+
async getAddressFromExtendedPublicKey(extendedPublicKey) {
|
|
159
|
+
const encodedExtendedPublicKey = (0, key_1.convertExtendedPublicKey)(extendedPublicKey, { format: 'encoded', type: 'xpub' });
|
|
160
|
+
const payment = this.bitcoinJS.lib.payments.p2tr({
|
|
161
|
+
internalPubkey: Buffer.from(encodedExtendedPublicKey.value, 'hex').subarray(1, 33),
|
|
162
|
+
network: this.bitcoinJS.config.network
|
|
249
163
|
});
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
return
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
var unknownKeyVals = decodedPSBT.data.globalMap.unknownKeyVals;
|
|
277
|
-
if (unknownKeyVals) {
|
|
278
|
-
var amountArray = unknownKeyVals.filter(function (kv) { return kv.key.equals(Buffer.from('amount')); });
|
|
279
|
-
if (amountArray.length > 0) {
|
|
280
|
-
return new bignumber_1.default(amountArray[0].value.toString());
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
var accumulated = new bignumber_1.default(0);
|
|
284
|
-
var useAccumulated = false;
|
|
285
|
-
decodedPSBT.data.outputs.forEach(function (outputKeyValues, index) {
|
|
286
|
-
if (outputKeyValues.unknownKeyVals) {
|
|
287
|
-
var derivationPaths = outputKeyValues.unknownKeyVals
|
|
288
|
-
.filter(function (kv) { return kv.key.equals(Buffer.from('dp')); })
|
|
289
|
-
.map(function (kv) { return kv.value.toString(); });
|
|
290
|
-
if (derivationPaths.length > 0) {
|
|
291
|
-
useAccumulated = true;
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
var output = decodedPSBT.txOutputs[index];
|
|
296
|
-
accumulated = accumulated.plus(output.value);
|
|
297
|
-
});
|
|
298
|
-
if (useAccumulated) {
|
|
299
|
-
return accumulated;
|
|
300
|
-
}
|
|
301
|
-
return decodedPSBT.txOutputs
|
|
302
|
-
.map(function (obj) { return new bignumber_1.default(obj.value); })
|
|
303
|
-
.reduce(function (accumulator, currentValue) { return accumulator.plus(currentValue); });
|
|
304
|
-
})();
|
|
305
|
-
return [4 /*yield*/, Promise.all(decodedPSBT.data.outputs.map(function (obj, index) { return __awaiter(_this, void 0, void 0, function () {
|
|
306
|
-
var isChangeAddress, isOwned, addressIndex, address, amount, ourGeneratedAddress, getIndexes, ourPublickey, x, ourPublickey, getIndexes, ourPublickey, x, ourPublickey, x, ourPublickey;
|
|
307
|
-
return __generator(this, function (_a) {
|
|
308
|
-
switch (_a.label) {
|
|
309
|
-
case 0:
|
|
310
|
-
isChangeAddress = false;
|
|
311
|
-
isOwned = false;
|
|
312
|
-
addressIndex = 0;
|
|
313
|
-
address = decodedPSBT.txOutputs[index].address;
|
|
314
|
-
amount = decodedPSBT.txOutputs[index].value;
|
|
315
|
-
if (!obj.bip32Derivation) return [3 /*break*/, 11];
|
|
316
|
-
isChangeAddress = true;
|
|
317
|
-
getIndexes = obj.bip32Derivation[0].path.split('/');
|
|
318
|
-
if (!(publicKey.type === 'xpub')) return [3 /*break*/, 3];
|
|
319
|
-
return [4 /*yield*/, this.deriveFromExtendedPublicKey(publicKey, 1, +getIndexes[getIndexes.length - 1])];
|
|
320
|
-
case 1:
|
|
321
|
-
ourPublickey = _a.sent();
|
|
322
|
-
return [4 /*yield*/, this.getAddressFromPublicKey(ourPublickey)];
|
|
323
|
-
case 2:
|
|
324
|
-
ourGeneratedAddress = _a.sent();
|
|
325
|
-
return [3 /*break*/, 5];
|
|
326
|
-
case 3: return [4 /*yield*/, this.getAddressFromNonExtendedPublicKey(publicKey)];
|
|
327
|
-
case 4:
|
|
328
|
-
ourGeneratedAddress = _a.sent();
|
|
329
|
-
_a.label = 5;
|
|
330
|
-
case 5:
|
|
331
|
-
if (ourGeneratedAddress === address) {
|
|
332
|
-
isOwned = true;
|
|
333
|
-
addressIndex = +getIndexes[getIndexes.length - 1];
|
|
334
|
-
}
|
|
335
|
-
x = 0;
|
|
336
|
-
_a.label = 6;
|
|
337
|
-
case 6:
|
|
338
|
-
if (!(x < 1000)) return [3 /*break*/, 10];
|
|
339
|
-
return [4 /*yield*/, this.deriveFromExtendedPublicKey(publicKey, 1, x)];
|
|
340
|
-
case 7:
|
|
341
|
-
ourPublickey = _a.sent();
|
|
342
|
-
return [4 /*yield*/, this.getAddressFromPublicKey(ourPublickey)];
|
|
343
|
-
case 8:
|
|
344
|
-
ourGeneratedAddress = _a.sent();
|
|
345
|
-
if (ourGeneratedAddress === address) {
|
|
346
|
-
isOwned = true;
|
|
347
|
-
addressIndex = x;
|
|
348
|
-
return [3 /*break*/, 10];
|
|
349
|
-
}
|
|
350
|
-
_a.label = 9;
|
|
351
|
-
case 9:
|
|
352
|
-
x++;
|
|
353
|
-
return [3 /*break*/, 6];
|
|
354
|
-
case 10: return [3 /*break*/, 27];
|
|
355
|
-
case 11:
|
|
356
|
-
if (!obj.tapBip32Derivation) return [3 /*break*/, 22];
|
|
357
|
-
isChangeAddress = true;
|
|
358
|
-
getIndexes = obj.tapBip32Derivation[0].path.split('/');
|
|
359
|
-
if (!(publicKey.type === 'xpub')) return [3 /*break*/, 14];
|
|
360
|
-
return [4 /*yield*/, this.deriveFromExtendedPublicKey(publicKey, 1, +getIndexes[getIndexes.length - 1])];
|
|
361
|
-
case 12:
|
|
362
|
-
ourPublickey = _a.sent();
|
|
363
|
-
return [4 /*yield*/, this.getAddressFromPublicKey(ourPublickey)];
|
|
364
|
-
case 13:
|
|
365
|
-
ourGeneratedAddress = _a.sent();
|
|
366
|
-
return [3 /*break*/, 16];
|
|
367
|
-
case 14: return [4 /*yield*/, this.getAddressFromNonExtendedPublicKey(publicKey)];
|
|
368
|
-
case 15:
|
|
369
|
-
ourGeneratedAddress = _a.sent();
|
|
370
|
-
_a.label = 16;
|
|
371
|
-
case 16:
|
|
372
|
-
if (ourGeneratedAddress === address) {
|
|
373
|
-
isOwned = true;
|
|
374
|
-
addressIndex = +getIndexes[getIndexes.length - 1];
|
|
375
|
-
}
|
|
376
|
-
x = 0;
|
|
377
|
-
_a.label = 17;
|
|
378
|
-
case 17:
|
|
379
|
-
if (!(x < 1000)) return [3 /*break*/, 21];
|
|
380
|
-
return [4 /*yield*/, this.deriveFromExtendedPublicKey(publicKey, 1, x)];
|
|
381
|
-
case 18:
|
|
382
|
-
ourPublickey = _a.sent();
|
|
383
|
-
return [4 /*yield*/, this.getAddressFromPublicKey(ourPublickey)];
|
|
384
|
-
case 19:
|
|
385
|
-
ourGeneratedAddress = _a.sent();
|
|
386
|
-
if (ourGeneratedAddress === address) {
|
|
387
|
-
isOwned = true;
|
|
388
|
-
addressIndex = x;
|
|
389
|
-
return [3 /*break*/, 21];
|
|
390
|
-
}
|
|
391
|
-
_a.label = 20;
|
|
392
|
-
case 20:
|
|
393
|
-
x++;
|
|
394
|
-
return [3 /*break*/, 17];
|
|
395
|
-
case 21: return [3 /*break*/, 27];
|
|
396
|
-
case 22:
|
|
397
|
-
if (!obj.unknownKeyVals) return [3 /*break*/, 27];
|
|
398
|
-
x = 0;
|
|
399
|
-
_a.label = 23;
|
|
400
|
-
case 23:
|
|
401
|
-
if (!(x < 1000)) return [3 /*break*/, 27];
|
|
402
|
-
isChangeAddress = true;
|
|
403
|
-
return [4 /*yield*/, this.deriveFromExtendedPublicKey(publicKey, 1, x)];
|
|
404
|
-
case 24:
|
|
405
|
-
ourPublickey = _a.sent();
|
|
406
|
-
return [4 /*yield*/, this.getAddressFromPublicKey(ourPublickey)];
|
|
407
|
-
case 25:
|
|
408
|
-
ourGeneratedAddress = _a.sent();
|
|
409
|
-
if (ourGeneratedAddress === address) {
|
|
410
|
-
isOwned = true;
|
|
411
|
-
addressIndex = x;
|
|
412
|
-
return [3 /*break*/, 27];
|
|
413
|
-
}
|
|
414
|
-
_a.label = 26;
|
|
415
|
-
case 26:
|
|
416
|
-
x++;
|
|
417
|
-
return [3 /*break*/, 23];
|
|
418
|
-
case 27:
|
|
419
|
-
if (isChangeAddress && isOwned) {
|
|
420
|
-
alerts.push({
|
|
421
|
-
type: 'success',
|
|
422
|
-
title: { type: 'plain', value: '' },
|
|
423
|
-
description: { type: 'plain', value: 'Note: your change address has been verified' },
|
|
424
|
-
icon: undefined,
|
|
425
|
-
actions: undefined
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
else if (isChangeAddress && !isOwned) {
|
|
429
|
-
alerts.push({
|
|
430
|
-
type: 'warning',
|
|
431
|
-
title: { type: 'plain', value: '' },
|
|
432
|
-
description: { type: 'plain', value: 'Note: your change address has not been verified' },
|
|
433
|
-
icon: undefined,
|
|
434
|
-
actions: undefined
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
return [2 /*return*/, [
|
|
438
|
-
address,
|
|
439
|
-
{
|
|
440
|
-
isChangeAddress: isChangeAddress,
|
|
441
|
-
isOwned: isOwned,
|
|
442
|
-
path: addressIndex === 0 ? '' : "m/86'/0'/0'/1/".concat(addressIndex),
|
|
443
|
-
amount: amount
|
|
444
|
-
}
|
|
445
|
-
]];
|
|
446
|
-
}
|
|
447
|
-
});
|
|
448
|
-
}); }))];
|
|
449
|
-
case 1:
|
|
450
|
-
changeAddressDatas = _f.sent();
|
|
451
|
-
changeAddressInfo = {};
|
|
452
|
-
changeAddressDatas.forEach(function (changeAddressData) {
|
|
453
|
-
changeAddressInfo[changeAddressData[0]] = changeAddressData[1];
|
|
454
|
-
});
|
|
455
|
-
return [2 /*return*/, [
|
|
456
|
-
{
|
|
457
|
-
from: decodedPSBT.data.inputs.map(function (obj) {
|
|
458
|
-
var _a, _b;
|
|
459
|
-
return (_b = (_a = obj.tapBip32Derivation) === null || _a === void 0 ? void 0 : _a.map(function (el) {
|
|
460
|
-
return _this.bitcoinJS.lib.payments.p2tr({
|
|
461
|
-
internalPubkey: el.pubkey,
|
|
462
|
-
network: _this.bitcoinJS.lib.networks.bitcoin
|
|
463
|
-
}).address;
|
|
464
|
-
}).join(' ')) !== null && _b !== void 0 ? _b : 'INVALID';
|
|
465
|
-
}),
|
|
466
|
-
to: decodedPSBT.txOutputs.map(function (obj) {
|
|
467
|
-
return obj.address || "Script: ".concat(obj.script.toString('hex')) || 'unknown';
|
|
468
|
-
}),
|
|
469
|
-
isInbound: false,
|
|
470
|
-
amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
|
|
471
|
-
fee: (0, module_kit_1.newAmount)(fee, 'blockchain'),
|
|
472
|
-
network: this.options.network,
|
|
473
|
-
changeAddressInfo: changeAddressInfo,
|
|
474
|
-
uiAlerts: alerts,
|
|
475
|
-
json: {
|
|
476
|
-
inputTx: (0, common_1.eachRecursive)(clonedPSBT.txInputs),
|
|
477
|
-
outputTx: (0, common_1.eachRecursive)(clonedPSBT.txOutputs),
|
|
478
|
-
inputData: clonedPSBT.data.inputs,
|
|
479
|
-
outputData: clonedPSBT.data.outputs,
|
|
480
|
-
PSBTVersion: clonedPSBT.version,
|
|
481
|
-
PSBTLocktime: clonedPSBT.locktime,
|
|
482
|
-
PSBTGlobalMap: clonedPSBT.data.globalMap,
|
|
483
|
-
rawPSBT: psbt
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
]];
|
|
164
|
+
return BitcoinTaprootAddress_1.BitcoinTaprootAddress.fromPayment(payment).asString();
|
|
165
|
+
}
|
|
166
|
+
async getDetailsFromTransaction(transaction, _publicKey) {
|
|
167
|
+
return this.getDetailsFromPSBT(transaction.psbt, _publicKey);
|
|
168
|
+
}
|
|
169
|
+
async getDetailsFromPSBT(psbt, publicKey) {
|
|
170
|
+
const decodedPSBT = this.bitcoinJS.lib.Psbt.fromHex(psbt);
|
|
171
|
+
let fee = new bignumber_1.default(0);
|
|
172
|
+
for (const txIn of decodedPSBT.data.inputs) {
|
|
173
|
+
fee = fee.plus(new bignumber_1.default(txIn.witnessUtxo?.value ?? 0));
|
|
174
|
+
}
|
|
175
|
+
for (const txOut of decodedPSBT.txOutputs) {
|
|
176
|
+
fee = fee.minus(new bignumber_1.default(txOut.value));
|
|
177
|
+
}
|
|
178
|
+
const alerts = [];
|
|
179
|
+
const clonedPSBT = decodedPSBT.clone();
|
|
180
|
+
(0, common_1.eachRecursive)(clonedPSBT); // Convert all buffers to hex strings
|
|
181
|
+
const amount = (() => {
|
|
182
|
+
if (decodedPSBT.txOutputs.length === 1) {
|
|
183
|
+
return new bignumber_1.default(decodedPSBT.txOutputs[0].value);
|
|
184
|
+
}
|
|
185
|
+
const unknownKeyVals = decodedPSBT.data.globalMap.unknownKeyVals;
|
|
186
|
+
if (unknownKeyVals) {
|
|
187
|
+
const amountArray = unknownKeyVals.filter((kv) => kv.key.equals(Buffer.from('amount')));
|
|
188
|
+
if (amountArray.length > 0) {
|
|
189
|
+
return new bignumber_1.default(amountArray[0].value.toString());
|
|
487
190
|
}
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
return __generator(this, function (_a) {
|
|
501
|
-
switch (publicKey.type) {
|
|
502
|
-
case 'pub':
|
|
503
|
-
return [2 /*return*/, this.getTransactionsForNonExtendedPublicKey(publicKey, limit, cursor)];
|
|
504
|
-
case 'xpub':
|
|
505
|
-
return [2 /*return*/, this.getTransactionsForExtendedPublicKey(publicKey, limit, cursor)];
|
|
506
|
-
default:
|
|
507
|
-
(0, coinlib_core_1.assertNever)(publicKey);
|
|
508
|
-
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Public key type not supported');
|
|
191
|
+
}
|
|
192
|
+
let accumulated = new bignumber_1.default(0);
|
|
193
|
+
let useAccumulated = false;
|
|
194
|
+
decodedPSBT.data.outputs.forEach((outputKeyValues, index) => {
|
|
195
|
+
if (outputKeyValues.unknownKeyVals) {
|
|
196
|
+
const derivationPaths = outputKeyValues.unknownKeyVals
|
|
197
|
+
.filter((kv) => kv.key.equals(Buffer.from('dp')))
|
|
198
|
+
.map((kv) => kv.value.toString());
|
|
199
|
+
if (derivationPaths.length > 0) {
|
|
200
|
+
useAccumulated = true;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
509
203
|
}
|
|
510
|
-
|
|
204
|
+
const output = decodedPSBT.txOutputs[index];
|
|
205
|
+
accumulated = accumulated.plus(output.value);
|
|
511
206
|
});
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
207
|
+
if (useAccumulated) {
|
|
208
|
+
return accumulated;
|
|
209
|
+
}
|
|
210
|
+
return decodedPSBT.txOutputs
|
|
211
|
+
.map((obj) => new bignumber_1.default(obj.value))
|
|
212
|
+
.reduce((accumulator, currentValue) => accumulator.plus(currentValue));
|
|
213
|
+
})();
|
|
214
|
+
const changeAddressDatas = await Promise.all(decodedPSBT.data.outputs.map(async (obj, index) => {
|
|
215
|
+
let isChangeAddress = false;
|
|
216
|
+
let isOwned = false;
|
|
217
|
+
let addressIndex = 0;
|
|
218
|
+
const address = decodedPSBT.txOutputs[index].address;
|
|
219
|
+
const amount = decodedPSBT.txOutputs[index].value;
|
|
220
|
+
let ourGeneratedAddress;
|
|
221
|
+
if (obj.bip32Derivation) {
|
|
222
|
+
isChangeAddress = true;
|
|
223
|
+
const getIndexes = obj.bip32Derivation[0].path.split('/');
|
|
224
|
+
if (publicKey.type === 'xpub') {
|
|
225
|
+
const ourPublickey = await this.deriveFromExtendedPublicKey(publicKey, 1, +getIndexes[getIndexes.length - 1]);
|
|
226
|
+
ourGeneratedAddress = await this.getAddressFromPublicKey(ourPublickey);
|
|
523
227
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
};
|
|
527
|
-
BitcoinTaprootProtocolImpl.prototype.getTransactionsForExtendedPublicKey = function (extendedPublicKey, limit, cursor) {
|
|
528
|
-
var _a;
|
|
529
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
530
|
-
var encodedExtendedPublicKey, page, url, data, ourAddresses, airGapTransactions, _i, _b, transaction, tempAirGapTransactionFrom, tempAirGapTransactionTo, tempAirGapTransactionIsInbound, amountNotAdded, amount, _c, _d, vin, _e, _f, vout, airGapTransaction, hasNext;
|
|
531
|
-
return __generator(this, function (_g) {
|
|
532
|
-
switch (_g.label) {
|
|
533
|
-
case 0:
|
|
534
|
-
encodedExtendedPublicKey = (0, key_1.convertExtendedPublicKey)(extendedPublicKey, { format: 'encoded', type: 'xpub' });
|
|
535
|
-
page = (_a = cursor === null || cursor === void 0 ? void 0 : cursor.page) !== null && _a !== void 0 ? _a : 1;
|
|
536
|
-
url = "".concat(this.options.network.indexerApi, "/api/v2/xpub/tr(").concat(encodedExtendedPublicKey.value, ")?details=txs&tokens=used&pageSize=").concat(limit, "&page=").concat(page);
|
|
537
|
-
return [4 /*yield*/, index_1.default.get(url, {
|
|
538
|
-
responseType: 'json'
|
|
539
|
-
})];
|
|
540
|
-
case 1:
|
|
541
|
-
data = (_g.sent()).data;
|
|
542
|
-
ourAddresses = (data.tokens || []).filter(function (token) { return token.type === 'XPUBAddress'; }).map(function (token) { return token.name; });
|
|
543
|
-
airGapTransactions = [];
|
|
544
|
-
if (data.page === page) {
|
|
545
|
-
for (_i = 0, _b = data.transactions || []; _i < _b.length; _i++) {
|
|
546
|
-
transaction = _b[_i];
|
|
547
|
-
tempAirGapTransactionFrom = [];
|
|
548
|
-
tempAirGapTransactionTo = [];
|
|
549
|
-
tempAirGapTransactionIsInbound = true;
|
|
550
|
-
amountNotAdded = true;
|
|
551
|
-
amount = new bignumber_1.default(0);
|
|
552
|
-
for (_c = 0, _d = transaction.vin; _c < _d.length; _c++) {
|
|
553
|
-
vin = _d[_c];
|
|
554
|
-
if ((0, common_1.containsSome)(vin.addresses, ourAddresses)) {
|
|
555
|
-
tempAirGapTransactionIsInbound = false;
|
|
556
|
-
}
|
|
557
|
-
tempAirGapTransactionFrom.push.apply(tempAirGapTransactionFrom, vin.addresses);
|
|
558
|
-
}
|
|
559
|
-
for (_e = 0, _f = transaction.vout; _e < _f.length; _e++) {
|
|
560
|
-
vout = _f[_e];
|
|
561
|
-
if (vout.addresses) {
|
|
562
|
-
tempAirGapTransactionTo.push.apply(tempAirGapTransactionTo, vout.addresses);
|
|
563
|
-
}
|
|
564
|
-
if ((0, common_1.containsSome)(vout.addresses, ourAddresses) && transaction.vout.length > 2) {
|
|
565
|
-
amount = amount.plus(vout.value);
|
|
566
|
-
amountNotAdded = false;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
// deduct fee from amount
|
|
570
|
-
//amount = amount.minus(transaction.fees)
|
|
571
|
-
if (amountNotAdded) {
|
|
572
|
-
amount = amount.plus(transaction.vout[0].value);
|
|
573
|
-
}
|
|
574
|
-
airGapTransaction = {
|
|
575
|
-
from: tempAirGapTransactionFrom,
|
|
576
|
-
to: tempAirGapTransactionTo,
|
|
577
|
-
isInbound: tempAirGapTransactionIsInbound,
|
|
578
|
-
amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
|
|
579
|
-
fee: (0, module_kit_1.newAmount)(transaction.fees, 'blockchain'),
|
|
580
|
-
status: {
|
|
581
|
-
type: 'applied',
|
|
582
|
-
hash: transaction.txid,
|
|
583
|
-
block: transaction.blockHeight.toString()
|
|
584
|
-
},
|
|
585
|
-
network: this.options.network,
|
|
586
|
-
timestamp: transaction.blockTime
|
|
587
|
-
};
|
|
588
|
-
airGapTransactions.push(airGapTransaction);
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
hasNext = page < data.totalPages;
|
|
592
|
-
return [2 /*return*/, {
|
|
593
|
-
transactions: airGapTransactions,
|
|
594
|
-
cursor: {
|
|
595
|
-
hasNext: hasNext,
|
|
596
|
-
page: hasNext ? page + 1 : undefined
|
|
597
|
-
}
|
|
598
|
-
}];
|
|
228
|
+
else {
|
|
229
|
+
ourGeneratedAddress = await this.getAddressFromNonExtendedPublicKey(publicKey);
|
|
599
230
|
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
BitcoinTaprootProtocolImpl.prototype.getTransactionsForAddress = function (address, limit, cursor) {
|
|
604
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
605
|
-
return __generator(this, function (_a) {
|
|
606
|
-
return [2 /*return*/, this.getTransactionsForAddresses([address], limit, cursor)];
|
|
607
|
-
});
|
|
608
|
-
});
|
|
609
|
-
};
|
|
610
|
-
BitcoinTaprootProtocolImpl.prototype.getTransactionsForAddresses = function (addresses, limit, cursor) {
|
|
611
|
-
var _a;
|
|
612
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
613
|
-
var airGapTransactions, page, url, data, _i, _b, transaction, tempAirGapTransactionFrom, tempAirGapTransactionTo, tempAirGapTransactionIsInbound, amount, _c, _d, vin, _e, _f, vout, airGapTransaction, hasNext;
|
|
614
|
-
return __generator(this, function (_g) {
|
|
615
|
-
switch (_g.label) {
|
|
616
|
-
case 0:
|
|
617
|
-
airGapTransactions = [];
|
|
618
|
-
page = (_a = cursor === null || cursor === void 0 ? void 0 : cursor.page) !== null && _a !== void 0 ? _a : 1;
|
|
619
|
-
url = "".concat(this.options.network.indexerApi, "/api/v2/address/").concat(addresses[0], "?page=").concat(page, "&pageSize=").concat(limit, "&details=txs");
|
|
620
|
-
return [4 /*yield*/, index_1.default.get(url, {
|
|
621
|
-
responseType: 'json'
|
|
622
|
-
})];
|
|
623
|
-
case 1:
|
|
624
|
-
data = (_g.sent()).data;
|
|
625
|
-
if (data.page == page) {
|
|
626
|
-
for (_i = 0, _b = data.transactions || []; _i < _b.length; _i++) {
|
|
627
|
-
transaction = _b[_i];
|
|
628
|
-
tempAirGapTransactionFrom = [];
|
|
629
|
-
tempAirGapTransactionTo = [];
|
|
630
|
-
tempAirGapTransactionIsInbound = true;
|
|
631
|
-
amount = new bignumber_1.default(0);
|
|
632
|
-
for (_c = 0, _d = transaction.vin; _c < _d.length; _c++) {
|
|
633
|
-
vin = _d[_c];
|
|
634
|
-
if (vin.addresses && (0, common_1.containsSome)(vin.addresses, addresses)) {
|
|
635
|
-
tempAirGapTransactionIsInbound = false;
|
|
636
|
-
}
|
|
637
|
-
tempAirGapTransactionFrom.push.apply(tempAirGapTransactionFrom, vin.addresses);
|
|
638
|
-
amount = vin.value ? amount.plus(vin.value) : amount;
|
|
639
|
-
}
|
|
640
|
-
for (_e = 0, _f = transaction.vout; _e < _f.length; _e++) {
|
|
641
|
-
vout = _f[_e];
|
|
642
|
-
if (vout.addresses) {
|
|
643
|
-
tempAirGapTransactionTo.push.apply(tempAirGapTransactionTo, vout.addresses);
|
|
644
|
-
// If receiving address is our address, and transaction is outbound => our change
|
|
645
|
-
if ((0, common_1.containsSome)(vout.addresses, addresses) && !tempAirGapTransactionIsInbound) {
|
|
646
|
-
// remove only if related to this address
|
|
647
|
-
amount = amount.minus(new bignumber_1.default(vout.value));
|
|
648
|
-
}
|
|
649
|
-
// If receiving address is not ours, and transaction isbound => senders change
|
|
650
|
-
if (!(0, common_1.containsSome)(vout.addresses, addresses) && tempAirGapTransactionIsInbound) {
|
|
651
|
-
amount = amount.minus(new bignumber_1.default(vout.value));
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
// deduct fee from amount
|
|
656
|
-
amount = amount.minus(new bignumber_1.default(transaction.fees));
|
|
657
|
-
airGapTransaction = {
|
|
658
|
-
from: tempAirGapTransactionFrom,
|
|
659
|
-
to: tempAirGapTransactionTo,
|
|
660
|
-
isInbound: tempAirGapTransactionIsInbound,
|
|
661
|
-
amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
|
|
662
|
-
fee: (0, module_kit_1.newAmount)(transaction.fees, 'blockchain'),
|
|
663
|
-
status: {
|
|
664
|
-
type: 'applied',
|
|
665
|
-
hash: transaction.txid,
|
|
666
|
-
block: transaction.blockHeight.toString()
|
|
667
|
-
},
|
|
668
|
-
network: this.options.network,
|
|
669
|
-
timestamp: transaction.blockTime
|
|
670
|
-
};
|
|
671
|
-
airGapTransactions.push(airGapTransaction);
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
hasNext = page < data.totalPages;
|
|
675
|
-
return [2 /*return*/, {
|
|
676
|
-
transactions: airGapTransactions,
|
|
677
|
-
cursor: {
|
|
678
|
-
hasNext: hasNext,
|
|
679
|
-
page: hasNext ? page + 1 : undefined
|
|
680
|
-
}
|
|
681
|
-
}];
|
|
231
|
+
if (ourGeneratedAddress === address) {
|
|
232
|
+
isOwned = true;
|
|
233
|
+
addressIndex = +getIndexes[getIndexes.length - 1];
|
|
682
234
|
}
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
return [2 /*return*/, this.getBalanceOfNonExtendedPublicKey(publicKey)];
|
|
692
|
-
case 'xpub':
|
|
693
|
-
return [2 /*return*/, this.getBalanceOfExtendedPublicKey(publicKey)];
|
|
694
|
-
default:
|
|
695
|
-
(0, coinlib_core_1.assertNever)(publicKey);
|
|
696
|
-
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Unsupported public key type.');
|
|
235
|
+
for (let x = 0; x < 1000; x++) {
|
|
236
|
+
const ourPublickey = await this.deriveFromExtendedPublicKey(publicKey, 1, x);
|
|
237
|
+
ourGeneratedAddress = await this.getAddressFromPublicKey(ourPublickey);
|
|
238
|
+
if (ourGeneratedAddress === address) {
|
|
239
|
+
isOwned = true;
|
|
240
|
+
addressIndex = x;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
697
243
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
return __generator(this, function (_a) {
|
|
706
|
-
switch (_a.label) {
|
|
707
|
-
case 0: return [4 /*yield*/, this.getAddressFromPublicKey(publicKey)];
|
|
708
|
-
case 1:
|
|
709
|
-
address = _a.sent();
|
|
710
|
-
return [2 /*return*/, this.getBalanceOfAddresses([address])];
|
|
244
|
+
}
|
|
245
|
+
else if (obj.tapBip32Derivation) {
|
|
246
|
+
isChangeAddress = true;
|
|
247
|
+
const getIndexes = obj.tapBip32Derivation[0].path.split('/');
|
|
248
|
+
if (publicKey.type === 'xpub') {
|
|
249
|
+
const ourPublickey = await this.deriveFromExtendedPublicKey(publicKey, 1, +getIndexes[getIndexes.length - 1]);
|
|
250
|
+
ourGeneratedAddress = await this.getAddressFromPublicKey(ourPublickey);
|
|
711
251
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
};
|
|
715
|
-
BitcoinTaprootProtocolImpl.prototype.getBalanceOfExtendedPublicKey = function (extendedPublicKey) {
|
|
716
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
717
|
-
var encodedExtendedPublicKey, data;
|
|
718
|
-
return __generator(this, function (_a) {
|
|
719
|
-
switch (_a.label) {
|
|
720
|
-
case 0:
|
|
721
|
-
encodedExtendedPublicKey = (0, key_1.convertExtendedPublicKey)(extendedPublicKey, { format: 'encoded', type: 'xpub' });
|
|
722
|
-
return [4 /*yield*/, index_1.default.get("".concat(this.options.network.indexerApi, "/api/v2/xpub/tr(").concat(encodedExtendedPublicKey.value, ")?pageSize=1"), {
|
|
723
|
-
responseType: 'json'
|
|
724
|
-
})];
|
|
725
|
-
case 1:
|
|
726
|
-
data = (_a.sent()).data;
|
|
727
|
-
return [2 /*return*/, {
|
|
728
|
-
total: (0, module_kit_1.newAmount)(data.balance, 'blockchain')
|
|
729
|
-
}];
|
|
252
|
+
else {
|
|
253
|
+
ourGeneratedAddress = await this.getAddressFromNonExtendedPublicKey(publicKey);
|
|
730
254
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
BitcoinTaprootProtocolImpl.prototype.getTransactionMaxAmountWithPublicKey = function (publicKey, to, configuration) {
|
|
735
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
736
|
-
return __generator(this, function (_a) {
|
|
737
|
-
return [2 /*return*/, this.segwit.getTransactionMaxAmountWithPublicKey(publicKey, to, configuration)];
|
|
738
|
-
});
|
|
739
|
-
});
|
|
740
|
-
};
|
|
741
|
-
BitcoinTaprootProtocolImpl.prototype.getTransactionFeeWithPublicKey = function (publicKey, details, configuration) {
|
|
742
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
743
|
-
return __generator(this, function (_a) {
|
|
744
|
-
return [2 /*return*/, this.segwit.getTransactionFeeWithPublicKey(publicKey, details, configuration)];
|
|
745
|
-
});
|
|
746
|
-
});
|
|
747
|
-
};
|
|
748
|
-
BitcoinTaprootProtocolImpl.prototype.broadcastTransaction = function (transaction) {
|
|
749
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
750
|
-
var psbt, hexTransaction, data;
|
|
751
|
-
return __generator(this, function (_a) {
|
|
752
|
-
switch (_a.label) {
|
|
753
|
-
case 0:
|
|
754
|
-
psbt = this.bitcoinJS.lib.Psbt.fromHex(transaction.psbt);
|
|
755
|
-
// Verify and finalize each Taproot input
|
|
756
|
-
psbt.data.inputs.forEach(function (input, index) {
|
|
757
|
-
if (input.tapInternalKey) {
|
|
758
|
-
try {
|
|
759
|
-
var finalized = psbt.finalizeTaprootInput(index);
|
|
760
|
-
if (!finalized) {
|
|
761
|
-
throw new Error("Failed to finalize Taproot input #".concat(index));
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
catch (error) {
|
|
765
|
-
throw new Error("Error finalizing Taproot input #".concat(index, ": ").concat(error));
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
});
|
|
769
|
-
hexTransaction = psbt.extractTransaction().toHex();
|
|
770
|
-
return [4 /*yield*/, index_1.default.post("".concat(this.options.network.indexerApi, "/api/v2/sendtx/"), hexTransaction)];
|
|
771
|
-
case 1:
|
|
772
|
-
data = (_a.sent()).data;
|
|
773
|
-
return [2 /*return*/, data.result
|
|
774
|
-
// return ''
|
|
775
|
-
];
|
|
255
|
+
if (ourGeneratedAddress === address) {
|
|
256
|
+
isOwned = true;
|
|
257
|
+
addressIndex = +getIndexes[getIndexes.length - 1];
|
|
776
258
|
}
|
|
777
|
-
|
|
259
|
+
for (let x = 0; x < 1000; x++) {
|
|
260
|
+
const ourPublickey = await this.deriveFromExtendedPublicKey(publicKey, 1, x);
|
|
261
|
+
ourGeneratedAddress = await this.getAddressFromPublicKey(ourPublickey);
|
|
262
|
+
if (ourGeneratedAddress === address) {
|
|
263
|
+
isOwned = true;
|
|
264
|
+
addressIndex = x;
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else if (obj.unknownKeyVals) {
|
|
270
|
+
for (let x = 0; x < 1000; x++) {
|
|
271
|
+
isChangeAddress = true;
|
|
272
|
+
const ourPublickey = await this.deriveFromExtendedPublicKey(publicKey, 1, x);
|
|
273
|
+
ourGeneratedAddress = await this.getAddressFromPublicKey(ourPublickey);
|
|
274
|
+
if (ourGeneratedAddress === address) {
|
|
275
|
+
isOwned = true;
|
|
276
|
+
addressIndex = x;
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (isChangeAddress && isOwned) {
|
|
282
|
+
alerts.push({
|
|
283
|
+
type: 'success',
|
|
284
|
+
title: { type: 'plain', value: '' },
|
|
285
|
+
description: { type: 'plain', value: 'Note: your change address has been verified' },
|
|
286
|
+
icon: undefined,
|
|
287
|
+
actions: undefined
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
else if (isChangeAddress && !isOwned) {
|
|
291
|
+
alerts.push({
|
|
292
|
+
type: 'warning',
|
|
293
|
+
title: { type: 'plain', value: '' },
|
|
294
|
+
description: { type: 'plain', value: 'Note: your change address has not been verified' },
|
|
295
|
+
icon: undefined,
|
|
296
|
+
actions: undefined
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
return [
|
|
300
|
+
address,
|
|
301
|
+
{
|
|
302
|
+
isChangeAddress,
|
|
303
|
+
isOwned,
|
|
304
|
+
path: addressIndex === 0 ? '' : `m/86'/0'/0'/1/${addressIndex}`,
|
|
305
|
+
amount
|
|
306
|
+
}
|
|
307
|
+
];
|
|
308
|
+
}));
|
|
309
|
+
const changeAddressInfo = {};
|
|
310
|
+
changeAddressDatas.forEach((changeAddressData) => {
|
|
311
|
+
changeAddressInfo[changeAddressData[0]] = changeAddressData[1];
|
|
312
|
+
});
|
|
313
|
+
return [
|
|
314
|
+
{
|
|
315
|
+
from: decodedPSBT.data.inputs.map((obj) => obj.tapBip32Derivation
|
|
316
|
+
?.map((el) => this.bitcoinJS.lib.payments.p2tr({
|
|
317
|
+
internalPubkey: el.pubkey,
|
|
318
|
+
network: this.bitcoinJS.lib.networks.bitcoin
|
|
319
|
+
}).address)
|
|
320
|
+
.join(' ') ?? 'INVALID'),
|
|
321
|
+
to: decodedPSBT.txOutputs.map((obj) => {
|
|
322
|
+
return obj.address || `Script: ${obj.script.toString('hex')}` || 'unknown';
|
|
323
|
+
}),
|
|
324
|
+
isInbound: false,
|
|
325
|
+
amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
|
|
326
|
+
fee: (0, module_kit_1.newAmount)(fee, 'blockchain'),
|
|
327
|
+
network: this.options.network,
|
|
328
|
+
changeAddressInfo,
|
|
329
|
+
uiAlerts: alerts,
|
|
330
|
+
json: {
|
|
331
|
+
inputTx: (0, common_1.eachRecursive)(clonedPSBT.txInputs),
|
|
332
|
+
outputTx: (0, common_1.eachRecursive)(clonedPSBT.txOutputs),
|
|
333
|
+
inputData: clonedPSBT.data.inputs,
|
|
334
|
+
outputData: clonedPSBT.data.outputs,
|
|
335
|
+
PSBTVersion: clonedPSBT.version,
|
|
336
|
+
PSBTLocktime: clonedPSBT.locktime,
|
|
337
|
+
PSBTGlobalMap: clonedPSBT.data.globalMap,
|
|
338
|
+
rawPSBT: psbt
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
];
|
|
342
|
+
}
|
|
343
|
+
async getNetwork() {
|
|
344
|
+
return this.options.network;
|
|
345
|
+
}
|
|
346
|
+
async getTransactionsForPublicKey(publicKey, limit, cursor) {
|
|
347
|
+
switch (publicKey.type) {
|
|
348
|
+
case 'pub':
|
|
349
|
+
return this.getTransactionsForNonExtendedPublicKey(publicKey, limit, cursor);
|
|
350
|
+
case 'xpub':
|
|
351
|
+
return this.getTransactionsForExtendedPublicKey(publicKey, limit, cursor);
|
|
352
|
+
default:
|
|
353
|
+
(0, coinlib_core_1.assertNever)(publicKey);
|
|
354
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Public key type not supported');
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
async getTransactionsForNonExtendedPublicKey(publicKey, limit, cursor) {
|
|
358
|
+
const address = await this.getAddressFromPublicKey(publicKey);
|
|
359
|
+
return this.getTransactionsForAddresses([address], limit, cursor);
|
|
360
|
+
}
|
|
361
|
+
async getTransactionsForExtendedPublicKey(extendedPublicKey, limit, cursor) {
|
|
362
|
+
const encodedExtendedPublicKey = (0, key_1.convertExtendedPublicKey)(extendedPublicKey, { format: 'encoded', type: 'xpub' });
|
|
363
|
+
const page = cursor?.page ?? 1;
|
|
364
|
+
const url = `${this.options.network.indexerApi}/api/v2/xpub/tr(${encodedExtendedPublicKey.value})?details=txs&tokens=used&pageSize=${limit}&page=${page}`;
|
|
365
|
+
const { data } = await index_1.default.get(url, {
|
|
366
|
+
responseType: 'json'
|
|
367
|
+
});
|
|
368
|
+
const ourAddresses = (data.tokens || []).filter((token) => token.type === 'XPUBAddress').map((token) => token.name);
|
|
369
|
+
const airGapTransactions = [];
|
|
370
|
+
if (data.page === page) {
|
|
371
|
+
for (const transaction of data.transactions || []) {
|
|
372
|
+
const tempAirGapTransactionFrom = [];
|
|
373
|
+
const tempAirGapTransactionTo = [];
|
|
374
|
+
let tempAirGapTransactionIsInbound = true;
|
|
375
|
+
let amountNotAdded = true;
|
|
376
|
+
let amount = new bignumber_1.default(0);
|
|
377
|
+
for (const vin of transaction.vin) {
|
|
378
|
+
if ((0, common_1.containsSome)(vin.addresses, ourAddresses)) {
|
|
379
|
+
tempAirGapTransactionIsInbound = false;
|
|
380
|
+
}
|
|
381
|
+
tempAirGapTransactionFrom.push(...vin.addresses);
|
|
382
|
+
}
|
|
383
|
+
for (const vout of transaction.vout) {
|
|
384
|
+
if (vout.addresses) {
|
|
385
|
+
tempAirGapTransactionTo.push(...vout.addresses);
|
|
386
|
+
}
|
|
387
|
+
if ((0, common_1.containsSome)(vout.addresses, ourAddresses) && transaction.vout.length > 2) {
|
|
388
|
+
amount = amount.plus(vout.value);
|
|
389
|
+
amountNotAdded = false;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// deduct fee from amount
|
|
393
|
+
//amount = amount.minus(transaction.fees)
|
|
394
|
+
if (amountNotAdded) {
|
|
395
|
+
amount = amount.plus(transaction.vout[0].value);
|
|
396
|
+
}
|
|
397
|
+
const airGapTransaction = {
|
|
398
|
+
from: tempAirGapTransactionFrom,
|
|
399
|
+
to: tempAirGapTransactionTo,
|
|
400
|
+
isInbound: tempAirGapTransactionIsInbound,
|
|
401
|
+
amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
|
|
402
|
+
fee: (0, module_kit_1.newAmount)(transaction.fees, 'blockchain'),
|
|
403
|
+
status: {
|
|
404
|
+
type: 'applied',
|
|
405
|
+
hash: transaction.txid,
|
|
406
|
+
block: transaction.blockHeight.toString()
|
|
407
|
+
},
|
|
408
|
+
network: this.options.network,
|
|
409
|
+
timestamp: transaction.blockTime
|
|
410
|
+
};
|
|
411
|
+
airGapTransactions.push(airGapTransaction);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
const hasNext = page < data.totalPages;
|
|
415
|
+
return {
|
|
416
|
+
transactions: airGapTransactions,
|
|
417
|
+
cursor: {
|
|
418
|
+
hasNext,
|
|
419
|
+
page: hasNext ? page + 1 : undefined
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
async getTransactionsForAddress(address, limit, cursor) {
|
|
424
|
+
return this.getTransactionsForAddresses([address], limit, cursor);
|
|
425
|
+
}
|
|
426
|
+
async getTransactionsForAddresses(addresses, limit, cursor) {
|
|
427
|
+
const airGapTransactions = [];
|
|
428
|
+
const page = cursor?.page ?? 1;
|
|
429
|
+
const url = `${this.options.network.indexerApi}/api/v2/address/${addresses[0]}?page=${page}&pageSize=${limit}&details=txs`;
|
|
430
|
+
const { data } = await index_1.default.get(url, {
|
|
431
|
+
responseType: 'json'
|
|
432
|
+
});
|
|
433
|
+
if (data.page == page) {
|
|
434
|
+
for (const transaction of data.transactions || []) {
|
|
435
|
+
const tempAirGapTransactionFrom = [];
|
|
436
|
+
const tempAirGapTransactionTo = [];
|
|
437
|
+
let tempAirGapTransactionIsInbound = true;
|
|
438
|
+
let amount = new bignumber_1.default(0);
|
|
439
|
+
for (const vin of transaction.vin) {
|
|
440
|
+
if (vin.addresses && (0, common_1.containsSome)(vin.addresses, addresses)) {
|
|
441
|
+
tempAirGapTransactionIsInbound = false;
|
|
442
|
+
}
|
|
443
|
+
tempAirGapTransactionFrom.push(...vin.addresses);
|
|
444
|
+
amount = vin.value ? amount.plus(vin.value) : amount;
|
|
445
|
+
}
|
|
446
|
+
for (const vout of transaction.vout) {
|
|
447
|
+
if (vout.addresses) {
|
|
448
|
+
tempAirGapTransactionTo.push(...vout.addresses);
|
|
449
|
+
// If receiving address is our address, and transaction is outbound => our change
|
|
450
|
+
if ((0, common_1.containsSome)(vout.addresses, addresses) && !tempAirGapTransactionIsInbound) {
|
|
451
|
+
// remove only if related to this address
|
|
452
|
+
amount = amount.minus(new bignumber_1.default(vout.value));
|
|
453
|
+
}
|
|
454
|
+
// If receiving address is not ours, and transaction isbound => senders change
|
|
455
|
+
if (!(0, common_1.containsSome)(vout.addresses, addresses) && tempAirGapTransactionIsInbound) {
|
|
456
|
+
amount = amount.minus(new bignumber_1.default(vout.value));
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
// deduct fee from amount
|
|
461
|
+
amount = amount.minus(new bignumber_1.default(transaction.fees));
|
|
462
|
+
const airGapTransaction = {
|
|
463
|
+
from: tempAirGapTransactionFrom,
|
|
464
|
+
to: tempAirGapTransactionTo,
|
|
465
|
+
isInbound: tempAirGapTransactionIsInbound,
|
|
466
|
+
amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
|
|
467
|
+
fee: (0, module_kit_1.newAmount)(transaction.fees, 'blockchain'),
|
|
468
|
+
status: {
|
|
469
|
+
type: 'applied',
|
|
470
|
+
hash: transaction.txid,
|
|
471
|
+
block: transaction.blockHeight.toString()
|
|
472
|
+
},
|
|
473
|
+
network: this.options.network,
|
|
474
|
+
timestamp: transaction.blockTime
|
|
475
|
+
};
|
|
476
|
+
airGapTransactions.push(airGapTransaction);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const hasNext = page < data.totalPages;
|
|
480
|
+
return {
|
|
481
|
+
transactions: airGapTransactions,
|
|
482
|
+
cursor: {
|
|
483
|
+
hasNext,
|
|
484
|
+
page: hasNext ? page + 1 : undefined
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
async getBalanceOfPublicKey(publicKey) {
|
|
489
|
+
switch (publicKey.type) {
|
|
490
|
+
case 'pub':
|
|
491
|
+
return this.getBalanceOfNonExtendedPublicKey(publicKey);
|
|
492
|
+
case 'xpub':
|
|
493
|
+
return this.getBalanceOfExtendedPublicKey(publicKey);
|
|
494
|
+
default:
|
|
495
|
+
(0, coinlib_core_1.assertNever)(publicKey);
|
|
496
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Unsupported public key type.');
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
async getBalanceOfNonExtendedPublicKey(publicKey) {
|
|
500
|
+
const address = await this.getAddressFromPublicKey(publicKey);
|
|
501
|
+
return this.getBalanceOfAddresses([address]);
|
|
502
|
+
}
|
|
503
|
+
async getBalanceOfExtendedPublicKey(extendedPublicKey) {
|
|
504
|
+
const encodedExtendedPublicKey = (0, key_1.convertExtendedPublicKey)(extendedPublicKey, { format: 'encoded', type: 'xpub' });
|
|
505
|
+
const { data } = await index_1.default.get(`${this.options.network.indexerApi}/api/v2/xpub/tr(${encodedExtendedPublicKey.value})?pageSize=1`, {
|
|
506
|
+
responseType: 'json'
|
|
778
507
|
});
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
508
|
+
return {
|
|
509
|
+
total: (0, module_kit_1.newAmount)(data.balance, 'blockchain')
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
async getTransactionMaxAmountWithPublicKey(publicKey, to, configuration) {
|
|
513
|
+
return this.segwit.getTransactionMaxAmountWithPublicKey(publicKey, to, configuration);
|
|
514
|
+
}
|
|
515
|
+
async getTransactionFeeWithPublicKey(publicKey, details, configuration) {
|
|
516
|
+
return this.segwit.getTransactionFeeWithPublicKey(publicKey, details, configuration);
|
|
517
|
+
}
|
|
518
|
+
async broadcastTransaction(transaction) {
|
|
519
|
+
const psbt = this.bitcoinJS.lib.Psbt.fromHex(transaction.psbt);
|
|
520
|
+
// Verify and finalize each Taproot input
|
|
521
|
+
psbt.data.inputs.forEach((input, index) => {
|
|
522
|
+
if (input.tapInternalKey) {
|
|
523
|
+
try {
|
|
524
|
+
const finalized = psbt.finalizeTaprootInput(index);
|
|
525
|
+
if (!finalized) {
|
|
526
|
+
throw new Error(`Failed to finalize Taproot input #${index}`);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
catch (error) {
|
|
530
|
+
throw new Error(`Error finalizing Taproot input #${index}: ${error}`);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
793
533
|
});
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
534
|
+
// Extract and broadcast the finalized transaction
|
|
535
|
+
const hexTransaction = psbt.extractTransaction().toHex();
|
|
536
|
+
const { data } = await index_1.default.post(`${this.options.network.indexerApi}/api/v2/sendtx/`, hexTransaction);
|
|
537
|
+
return data.result;
|
|
538
|
+
// return ''
|
|
539
|
+
}
|
|
540
|
+
async getExtendedKeyPairFromDerivative(derivative) {
|
|
541
|
+
const bip32 = this.derivativeToBip32Node(derivative);
|
|
542
|
+
return {
|
|
543
|
+
secretKey: (0, module_kit_1.newExtendedSecretKey)(bip32.toBase58(), 'encoded'),
|
|
544
|
+
publicKey: (0, key_1.convertExtendedPublicKey)((0, module_kit_1.newExtendedPublicKey)(bip32.neutered().toBase58(), 'encoded'), {
|
|
545
|
+
format: 'encoded',
|
|
546
|
+
type: 'xpub'
|
|
547
|
+
})
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
derivativeToBip32Node(derivative) {
|
|
551
|
+
const extendedSecretKey = this.convertCryptoDerivative(derivative);
|
|
797
552
|
return this.bip32.fromBase58(extendedSecretKey.value, this.bitcoinJS.config.network);
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
553
|
+
}
|
|
554
|
+
convertCryptoDerivative(derivative) {
|
|
555
|
+
const hexNode = (0, crypto_1.encodeDerivative)('hex', {
|
|
556
|
+
...derivative,
|
|
557
|
+
secretKey: `00${derivative.secretKey}`
|
|
558
|
+
});
|
|
559
|
+
const extendedSecretKey = {
|
|
802
560
|
type: 'xpriv',
|
|
803
561
|
format: 'hex',
|
|
804
562
|
value: hexNode.secretKey
|
|
805
563
|
};
|
|
806
564
|
return (0, key_1.convertExtendedSecretKey)(extendedSecretKey, { format: 'encoded', type: 'xprv' });
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
return
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
return
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
BitcoinTaprootProtocolImpl.prototype.verifyMessageWithPublicKey = function (message, signature, publicKey) {
|
|
836
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
837
|
-
return __generator(this, function (_a) {
|
|
838
|
-
return [2 /*return*/, this.segwit.verifyMessageWithPublicKey(message, signature, publicKey)];
|
|
839
|
-
});
|
|
840
|
-
});
|
|
841
|
-
};
|
|
842
|
-
BitcoinTaprootProtocolImpl.prototype.decryptAsymmetricWithKeyPair = function (payload, keyPair) {
|
|
843
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
844
|
-
return __generator(this, function (_a) {
|
|
845
|
-
return [2 /*return*/, this.segwit.decryptAsymmetricWithKeyPair(payload, keyPair)];
|
|
846
|
-
});
|
|
847
|
-
});
|
|
848
|
-
};
|
|
849
|
-
BitcoinTaprootProtocolImpl.prototype.encryptAsymmetricWithPublicKey = function (payload, publicKey) {
|
|
850
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
851
|
-
return __generator(this, function (_a) {
|
|
852
|
-
return [2 /*return*/, this.segwit.encryptAsymmetricWithPublicKey(payload, publicKey)];
|
|
853
|
-
});
|
|
854
|
-
});
|
|
855
|
-
};
|
|
856
|
-
BitcoinTaprootProtocolImpl.prototype.encryptAESWithSecretKey = function (payload, secretKey) {
|
|
857
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
858
|
-
return __generator(this, function (_a) {
|
|
859
|
-
return [2 /*return*/, this.segwit.encryptAESWithSecretKey(payload, secretKey)];
|
|
860
|
-
});
|
|
861
|
-
});
|
|
862
|
-
};
|
|
863
|
-
BitcoinTaprootProtocolImpl.prototype.decryptAESWithSecretKey = function (payload, secretKey) {
|
|
565
|
+
}
|
|
566
|
+
async deriveFromExtendedSecretKey(extendedSecretKey, visibilityIndex, addressIndex) {
|
|
567
|
+
return this.segwit.deriveFromExtendedSecretKey(extendedSecretKey, visibilityIndex, addressIndex);
|
|
568
|
+
}
|
|
569
|
+
async deriveFromExtendedPublicKey(extendedPublicKey, visibilityIndex, addressIndex) {
|
|
570
|
+
const encodedPublicKey = (0, key_1.convertExtendedPublicKey)(extendedPublicKey, { format: 'encoded', type: 'xpub' });
|
|
571
|
+
const derivedBip32 = this.bip32
|
|
572
|
+
.fromBase58(encodedPublicKey.value, this.bitcoinJS.config.network)
|
|
573
|
+
.derive(visibilityIndex)
|
|
574
|
+
.derive(addressIndex);
|
|
575
|
+
return (0, module_kit_1.newPublicKey)(Buffer.from(derivedBip32.publicKey).toString('hex'), 'hex');
|
|
576
|
+
}
|
|
577
|
+
async signMessageWithKeyPair(message, keyPair) {
|
|
578
|
+
return this.segwit.signMessageWithKeyPair(message, keyPair);
|
|
579
|
+
}
|
|
580
|
+
async verifyMessageWithPublicKey(message, signature, publicKey) {
|
|
581
|
+
return this.segwit.verifyMessageWithPublicKey(message, signature, publicKey);
|
|
582
|
+
}
|
|
583
|
+
async decryptAsymmetricWithKeyPair(payload, keyPair) {
|
|
584
|
+
return this.segwit.decryptAsymmetricWithKeyPair(payload, keyPair);
|
|
585
|
+
}
|
|
586
|
+
async encryptAsymmetricWithPublicKey(payload, publicKey) {
|
|
587
|
+
return this.segwit.encryptAsymmetricWithPublicKey(payload, publicKey);
|
|
588
|
+
}
|
|
589
|
+
async encryptAESWithSecretKey(payload, secretKey) {
|
|
590
|
+
return this.segwit.encryptAESWithSecretKey(payload, secretKey);
|
|
591
|
+
}
|
|
592
|
+
decryptAESWithSecretKey(payload, secretKey) {
|
|
864
593
|
return this.segwit.decryptAESWithSecretKey(payload, secretKey);
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
return
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
};
|
|
873
|
-
BitcoinTaprootProtocolImpl.prototype.getBalanceOfAddresses = function (addresses, configuration) {
|
|
874
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
875
|
-
return __generator(this, function (_a) {
|
|
876
|
-
return [2 /*return*/, this.segwit.getBalanceOfAddresses(addresses)];
|
|
877
|
-
});
|
|
878
|
-
});
|
|
879
|
-
};
|
|
594
|
+
}
|
|
595
|
+
async getBalanceOfAddress(address, configuration) {
|
|
596
|
+
return this.segwit.getBalanceOfAddress(address);
|
|
597
|
+
}
|
|
598
|
+
async getBalanceOfAddresses(addresses, configuration) {
|
|
599
|
+
return this.segwit.getBalanceOfAddresses(addresses);
|
|
600
|
+
}
|
|
880
601
|
// Common methods similar to Segwit implementation
|
|
881
602
|
// ... [Include all the common methods from Segwit implementation but modify for Taproot]
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
603
|
+
async getAddressFromNonExtendedPublicKey(publicKey) {
|
|
604
|
+
const hexPublicKey = (0, key_1.convertPublicKey)(publicKey, 'hex');
|
|
605
|
+
const payment = this.bitcoinJS.lib.payments.p2tr({
|
|
606
|
+
internalPubkey: Buffer.from(hexPublicKey.value, 'hex').subarray(1, 33),
|
|
607
|
+
network: this.bitcoinJS.config.network
|
|
608
|
+
});
|
|
609
|
+
return BitcoinTaprootAddress_1.BitcoinTaprootAddress.fromPayment(payment).asString();
|
|
610
|
+
}
|
|
611
|
+
async prepareTransactionWithExtendedPublicKey(extendedPublicKey, details, configuration) {
|
|
612
|
+
if (configuration?.masterFingerprint === undefined) {
|
|
613
|
+
throw new errors_1.ConditionViolationError(coinlib_core_1.Domain.BITCOIN, 'Master fingerprint not set.');
|
|
614
|
+
}
|
|
615
|
+
let fee;
|
|
616
|
+
if (configuration?.fee !== undefined) {
|
|
617
|
+
fee = configuration.fee;
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
const estimatedFee = await this.getTransactionFeeWithPublicKey(extendedPublicKey, details);
|
|
621
|
+
fee = estimatedFee.medium;
|
|
622
|
+
}
|
|
623
|
+
const wrappedFee = new bignumber_1.default((0, module_kit_1.newAmount)(fee).blockchain(this.segwit.legacy.units).value);
|
|
624
|
+
const transaction = (0, module_kit_1.newUnsignedTransaction)({
|
|
625
|
+
ins: [],
|
|
626
|
+
outs: []
|
|
627
|
+
});
|
|
628
|
+
const { data: utxos } = await index_1.default.get(`${this.options.network.indexerApi}/api/v2/utxo/tr(${extendedPublicKey.value})?confirmed=true`, {
|
|
629
|
+
responseType: 'json'
|
|
630
|
+
});
|
|
631
|
+
if (utxos.length <= 0) {
|
|
632
|
+
throw new errors_1.BalanceError(coinlib_core_1.Domain.BITCOIN, 'Not enough balance.'); // no transactions found on those addresses, probably won't find anything in the next ones
|
|
633
|
+
}
|
|
634
|
+
const totalRequiredBalance = details
|
|
635
|
+
.map(({ amount }) => new bignumber_1.default((0, module_kit_1.newAmount)(amount).blockchain(this.segwit.legacy.units).value))
|
|
636
|
+
.reduce((accumulator, currentValue) => accumulator.plus(currentValue))
|
|
637
|
+
.plus(wrappedFee);
|
|
638
|
+
let valueAccumulator = new bignumber_1.default(0);
|
|
639
|
+
const getPathIndexes = (path) => {
|
|
640
|
+
const result = path
|
|
641
|
+
.split('/')
|
|
642
|
+
.slice(-2)
|
|
643
|
+
.map((item) => parseInt(item))
|
|
644
|
+
.filter((item) => !isNaN(item));
|
|
645
|
+
if (result.length !== 2) {
|
|
646
|
+
throw new Error('Unexpected path format');
|
|
647
|
+
}
|
|
648
|
+
return [result[0], result[1]];
|
|
649
|
+
};
|
|
650
|
+
for (const utxo of utxos) {
|
|
651
|
+
valueAccumulator = valueAccumulator.plus(utxo.value);
|
|
652
|
+
const indexes = getPathIndexes(utxo.path);
|
|
653
|
+
const derivedPublicKey = await this.deriveFromExtendedPublicKey(extendedPublicKey, indexes[0], indexes[1]);
|
|
654
|
+
const derivedAddress = await this.getAddressFromPublicKey(derivedPublicKey);
|
|
655
|
+
if (derivedAddress === utxo.address) {
|
|
656
|
+
transaction.ins.push({
|
|
657
|
+
txId: utxo.txid,
|
|
658
|
+
value: new bignumber_1.default(utxo.value).toString(10),
|
|
659
|
+
vout: utxo.vout,
|
|
660
|
+
address: utxo.address,
|
|
661
|
+
derivationPath: utxo.path
|
|
890
662
|
});
|
|
891
|
-
|
|
663
|
+
}
|
|
664
|
+
else {
|
|
665
|
+
throw new Error('Invalid address returned from API');
|
|
666
|
+
}
|
|
667
|
+
if (valueAccumulator.isGreaterThanOrEqualTo(totalRequiredBalance)) {
|
|
668
|
+
break;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
if (valueAccumulator.isLessThan(totalRequiredBalance)) {
|
|
672
|
+
throw new Error('not enough balance 2');
|
|
673
|
+
}
|
|
674
|
+
for (let i = 0; i < details.length; i++) {
|
|
675
|
+
const value = (0, module_kit_1.newAmount)(details[i].amount).blockchain(this.segwit.legacy.units).value;
|
|
676
|
+
transaction.outs.push({
|
|
677
|
+
recipient: details[i].to,
|
|
678
|
+
isChange: false,
|
|
679
|
+
value
|
|
680
|
+
});
|
|
681
|
+
valueAccumulator = valueAccumulator.minus(value);
|
|
682
|
+
}
|
|
683
|
+
const lastUsedInternalAddress = Math.max(-1, ...utxos
|
|
684
|
+
.map((utxo) => getPathIndexes(utxo.path))
|
|
685
|
+
.filter((indexes) => indexes[0] === 1)
|
|
686
|
+
.map((indexes) => indexes[1]));
|
|
687
|
+
// If the change is considered dust, the transaction will fail.
|
|
688
|
+
// Dust is a variable value around 300-600 satoshis, depending on the configuration.
|
|
689
|
+
// We set a low fee here to not block any transactions, but it might still fail due to "dust".
|
|
690
|
+
const changeValue = valueAccumulator.minus(wrappedFee);
|
|
691
|
+
if (changeValue.isGreaterThan(new bignumber_1.default(DUST_AMOUNT))) {
|
|
692
|
+
const changeAddressIndex = lastUsedInternalAddress + 1;
|
|
693
|
+
const derivedPublicKey = await this.deriveFromExtendedPublicKey(extendedPublicKey, 1, changeAddressIndex);
|
|
694
|
+
const derivedAddress = await this.getAddressFromPublicKey(derivedPublicKey);
|
|
695
|
+
transaction.outs.push({
|
|
696
|
+
recipient: derivedAddress,
|
|
697
|
+
isChange: true,
|
|
698
|
+
value: changeValue.toString(10),
|
|
699
|
+
derivationPath: `1/${changeAddressIndex}`
|
|
892
700
|
});
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
case 4:
|
|
923
|
-
utxos = (_a.sent()).data;
|
|
924
|
-
if (utxos.length <= 0) {
|
|
925
|
-
throw new errors_1.BalanceError(coinlib_core_1.Domain.BITCOIN, 'Not enough balance.'); // no transactions found on those addresses, probably won't find anything in the next ones
|
|
926
|
-
}
|
|
927
|
-
totalRequiredBalance = details
|
|
928
|
-
.map(function (_a) {
|
|
929
|
-
var amount = _a.amount;
|
|
930
|
-
return new bignumber_1.default((0, module_kit_1.newAmount)(amount).blockchain(_this.segwit.legacy.units).value);
|
|
931
|
-
})
|
|
932
|
-
.reduce(function (accumulator, currentValue) { return accumulator.plus(currentValue); })
|
|
933
|
-
.plus(wrappedFee);
|
|
934
|
-
valueAccumulator = new bignumber_1.default(0);
|
|
935
|
-
getPathIndexes = function (path) {
|
|
936
|
-
var result = path
|
|
937
|
-
.split('/')
|
|
938
|
-
.slice(-2)
|
|
939
|
-
.map(function (item) { return parseInt(item); })
|
|
940
|
-
.filter(function (item) { return !isNaN(item); });
|
|
941
|
-
if (result.length !== 2) {
|
|
942
|
-
throw new Error('Unexpected path format');
|
|
943
|
-
}
|
|
944
|
-
return [result[0], result[1]];
|
|
945
|
-
};
|
|
946
|
-
_i = 0, utxos_1 = utxos;
|
|
947
|
-
_a.label = 5;
|
|
948
|
-
case 5:
|
|
949
|
-
if (!(_i < utxos_1.length)) return [3 /*break*/, 9];
|
|
950
|
-
utxo = utxos_1[_i];
|
|
951
|
-
valueAccumulator = valueAccumulator.plus(utxo.value);
|
|
952
|
-
indexes = getPathIndexes(utxo.path);
|
|
953
|
-
return [4 /*yield*/, this.deriveFromExtendedPublicKey(extendedPublicKey, indexes[0], indexes[1])];
|
|
954
|
-
case 6:
|
|
955
|
-
derivedPublicKey = _a.sent();
|
|
956
|
-
return [4 /*yield*/, this.getAddressFromPublicKey(derivedPublicKey)];
|
|
957
|
-
case 7:
|
|
958
|
-
derivedAddress = _a.sent();
|
|
959
|
-
if (derivedAddress === utxo.address) {
|
|
960
|
-
transaction.ins.push({
|
|
961
|
-
txId: utxo.txid,
|
|
962
|
-
value: new bignumber_1.default(utxo.value).toString(10),
|
|
963
|
-
vout: utxo.vout,
|
|
964
|
-
address: utxo.address,
|
|
965
|
-
derivationPath: utxo.path
|
|
966
|
-
});
|
|
967
|
-
}
|
|
968
|
-
else {
|
|
969
|
-
throw new Error('Invalid address returned from API');
|
|
970
|
-
}
|
|
971
|
-
if (valueAccumulator.isGreaterThanOrEqualTo(totalRequiredBalance)) {
|
|
972
|
-
return [3 /*break*/, 9];
|
|
973
|
-
}
|
|
974
|
-
_a.label = 8;
|
|
975
|
-
case 8:
|
|
976
|
-
_i++;
|
|
977
|
-
return [3 /*break*/, 5];
|
|
978
|
-
case 9:
|
|
979
|
-
if (valueAccumulator.isLessThan(totalRequiredBalance)) {
|
|
980
|
-
throw new Error('not enough balance 2');
|
|
981
|
-
}
|
|
982
|
-
for (i = 0; i < details.length; i++) {
|
|
983
|
-
value = (0, module_kit_1.newAmount)(details[i].amount).blockchain(this.segwit.legacy.units).value;
|
|
984
|
-
transaction.outs.push({
|
|
985
|
-
recipient: details[i].to,
|
|
986
|
-
isChange: false,
|
|
987
|
-
value: value
|
|
988
|
-
});
|
|
989
|
-
valueAccumulator = valueAccumulator.minus(value);
|
|
990
|
-
}
|
|
991
|
-
lastUsedInternalAddress = Math.max.apply(Math, __spreadArray([-1], utxos
|
|
992
|
-
.map(function (utxo) { return getPathIndexes(utxo.path); })
|
|
993
|
-
.filter(function (indexes) { return indexes[0] === 1; })
|
|
994
|
-
.map(function (indexes) { return indexes[1]; }), false));
|
|
995
|
-
changeValue = valueAccumulator.minus(wrappedFee);
|
|
996
|
-
if (!changeValue.isGreaterThan(new bignumber_1.default(DUST_AMOUNT))) return [3 /*break*/, 12];
|
|
997
|
-
changeAddressIndex = lastUsedInternalAddress + 1;
|
|
998
|
-
return [4 /*yield*/, this.deriveFromExtendedPublicKey(extendedPublicKey, 1, changeAddressIndex)];
|
|
999
|
-
case 10:
|
|
1000
|
-
derivedPublicKey = _a.sent();
|
|
1001
|
-
return [4 /*yield*/, this.getAddressFromPublicKey(derivedPublicKey)];
|
|
1002
|
-
case 11:
|
|
1003
|
-
derivedAddress = _a.sent();
|
|
1004
|
-
transaction.outs.push({
|
|
1005
|
-
recipient: derivedAddress,
|
|
1006
|
-
isChange: true,
|
|
1007
|
-
value: changeValue.toString(10),
|
|
1008
|
-
derivationPath: "1/".concat(changeAddressIndex)
|
|
1009
|
-
});
|
|
1010
|
-
_a.label = 12;
|
|
1011
|
-
case 12:
|
|
1012
|
-
psbt = new this.bitcoinJS.lib.Psbt();
|
|
1013
|
-
// We add the total amount of the transaction to the global map. This can be used to show the info in the "from-to" component after the transaction was signed.
|
|
1014
|
-
psbt.addUnknownKeyValToGlobal({
|
|
1015
|
-
key: Buffer.from('amount'),
|
|
1016
|
-
value: Buffer.from(details
|
|
1017
|
-
.reduce(function (accumulator, next) {
|
|
1018
|
-
return accumulator.plus((0, module_kit_1.newAmount)(next.amount).blockchain(_this.segwit.legacy.units).value);
|
|
1019
|
-
}, new bignumber_1.default(0))
|
|
1020
|
-
.toString())
|
|
1021
|
-
});
|
|
1022
|
-
xpubExtendedPublicKey = (0, key_1.convertExtendedPublicKey)(extendedPublicKey, { format: 'encoded', type: 'xpub' });
|
|
1023
|
-
keyPair = this.bip32.fromBase58(xpubExtendedPublicKey.value);
|
|
1024
|
-
replaceByFee = (configuration === null || configuration === void 0 ? void 0 : configuration.replaceByFee) ? true : false;
|
|
1025
|
-
transaction.ins.forEach(function (tx) {
|
|
1026
|
-
var indexes = getPathIndexes(tx.derivationPath);
|
|
1027
|
-
var childNode = keyPair.derivePath(indexes.join('/'));
|
|
1028
|
-
var xOnlyPubkey = childNode.publicKey.length === 33 ? childNode.publicKey.slice(1, 33) : childNode.publicKey;
|
|
1029
|
-
var payment = _this.bitcoinJS.lib.payments.p2tr({
|
|
1030
|
-
internalPubkey: Buffer.from(xOnlyPubkey),
|
|
1031
|
-
network: _this.bitcoinJS.config.network
|
|
1032
|
-
});
|
|
1033
|
-
var inputCommon = {
|
|
1034
|
-
hash: tx.txId,
|
|
1035
|
-
index: tx.vout,
|
|
1036
|
-
sequence: replaceByFee ? 0xfffffffd : undefined,
|
|
1037
|
-
witnessUtxo: {
|
|
1038
|
-
script: payment.output,
|
|
1039
|
-
value: parseInt(tx.value, 10)
|
|
1040
|
-
}
|
|
1041
|
-
};
|
|
1042
|
-
var p2shOutput = payment.output;
|
|
1043
|
-
if (!p2shOutput) {
|
|
1044
|
-
throw new Error('no p2shOutput');
|
|
1045
|
-
}
|
|
1046
|
-
var fingerprintBuffer = Buffer.from(configuration.masterFingerprint.value, 'hex');
|
|
1047
|
-
psbt.addInput(__assign(__assign({}, inputCommon), { tapInternalKey: Buffer.from(xOnlyPubkey), tapBip32Derivation: [
|
|
1048
|
-
{
|
|
1049
|
-
leafHashes: [],
|
|
1050
|
-
path: tx.derivationPath,
|
|
1051
|
-
pubkey: Buffer.from(xOnlyPubkey),
|
|
1052
|
-
masterFingerprint: fingerprintBuffer
|
|
1053
|
-
}
|
|
1054
|
-
] }));
|
|
1055
|
-
});
|
|
1056
|
-
transaction.outs.forEach(function (out, index) {
|
|
1057
|
-
psbt.addOutput({ address: out.recipient, value: parseInt(out.value, 10) });
|
|
1058
|
-
if (out.derivationPath) {
|
|
1059
|
-
psbt.addUnknownKeyValToOutput(index, {
|
|
1060
|
-
key: Buffer.from('dp'),
|
|
1061
|
-
value: Buffer.from(out.derivationPath, 'utf8')
|
|
1062
|
-
});
|
|
1063
|
-
}
|
|
1064
|
-
});
|
|
1065
|
-
return [2 /*return*/, (0, module_kit_1.newUnsignedTransaction)({ psbt: psbt.toHex() })];
|
|
701
|
+
}
|
|
702
|
+
const psbt = new this.bitcoinJS.lib.Psbt();
|
|
703
|
+
// We add the total amount of the transaction to the global map. This can be used to show the info in the "from-to" component after the transaction was signed.
|
|
704
|
+
psbt.addUnknownKeyValToGlobal({
|
|
705
|
+
key: Buffer.from('amount'),
|
|
706
|
+
value: Buffer.from(details
|
|
707
|
+
.reduce((accumulator, next) => {
|
|
708
|
+
return accumulator.plus((0, module_kit_1.newAmount)(next.amount).blockchain(this.segwit.legacy.units).value);
|
|
709
|
+
}, new bignumber_1.default(0))
|
|
710
|
+
.toString())
|
|
711
|
+
});
|
|
712
|
+
const xpubExtendedPublicKey = (0, key_1.convertExtendedPublicKey)(extendedPublicKey, { format: 'encoded', type: 'xpub' });
|
|
713
|
+
const keyPair = this.bip32.fromBase58(xpubExtendedPublicKey.value);
|
|
714
|
+
const replaceByFee = configuration?.replaceByFee ? true : false;
|
|
715
|
+
transaction.ins.forEach((tx) => {
|
|
716
|
+
const indexes = getPathIndexes(tx.derivationPath);
|
|
717
|
+
const childNode = keyPair.derivePath(indexes.join('/'));
|
|
718
|
+
const xOnlyPubkey = childNode.publicKey.length === 33 ? childNode.publicKey.slice(1, 33) : childNode.publicKey;
|
|
719
|
+
const payment = this.bitcoinJS.lib.payments.p2tr({
|
|
720
|
+
internalPubkey: Buffer.from(xOnlyPubkey),
|
|
721
|
+
network: this.bitcoinJS.config.network
|
|
722
|
+
});
|
|
723
|
+
const inputCommon = {
|
|
724
|
+
hash: tx.txId,
|
|
725
|
+
index: tx.vout,
|
|
726
|
+
sequence: replaceByFee ? 0xfffffffd : undefined,
|
|
727
|
+
witnessUtxo: {
|
|
728
|
+
script: payment.output,
|
|
729
|
+
value: parseInt(tx.value, 10)
|
|
1066
730
|
}
|
|
1067
|
-
}
|
|
731
|
+
};
|
|
732
|
+
const p2shOutput = payment.output;
|
|
733
|
+
if (!p2shOutput) {
|
|
734
|
+
throw new Error('no p2shOutput');
|
|
735
|
+
}
|
|
736
|
+
const fingerprintBuffer = Buffer.from(configuration.masterFingerprint.value, 'hex');
|
|
737
|
+
psbt.addInput({
|
|
738
|
+
...inputCommon,
|
|
739
|
+
tapInternalKey: Buffer.from(xOnlyPubkey),
|
|
740
|
+
tapBip32Derivation: [
|
|
741
|
+
{
|
|
742
|
+
leafHashes: [],
|
|
743
|
+
path: tx.derivationPath,
|
|
744
|
+
pubkey: Buffer.from(xOnlyPubkey),
|
|
745
|
+
masterFingerprint: fingerprintBuffer
|
|
746
|
+
}
|
|
747
|
+
]
|
|
748
|
+
});
|
|
749
|
+
});
|
|
750
|
+
transaction.outs.forEach((out, index) => {
|
|
751
|
+
psbt.addOutput({ address: out.recipient, value: parseInt(out.value, 10) });
|
|
752
|
+
if (out.derivationPath) {
|
|
753
|
+
psbt.addUnknownKeyValToOutput(index, {
|
|
754
|
+
key: Buffer.from('dp'),
|
|
755
|
+
value: Buffer.from(out.derivationPath, 'utf8')
|
|
756
|
+
});
|
|
757
|
+
}
|
|
1068
758
|
});
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
}
|
|
759
|
+
return (0, module_kit_1.newUnsignedTransaction)({ psbt: psbt.toHex() });
|
|
760
|
+
}
|
|
761
|
+
}
|
|
1072
762
|
exports.BitcoinTaprootProtocolImpl = BitcoinTaprootProtocolImpl;
|
|
1073
763
|
// Factory
|
|
1074
|
-
function createBitcoinTaprootProtocol(options) {
|
|
1075
|
-
if (options === void 0) { options = {}; }
|
|
764
|
+
function createBitcoinTaprootProtocol(options = {}) {
|
|
1076
765
|
return new BitcoinTaprootProtocolImpl(options);
|
|
1077
766
|
}
|
|
1078
|
-
exports.createBitcoinTaprootProtocol = createBitcoinTaprootProtocol;
|
|
1079
767
|
//# sourceMappingURL=BitcoinTaprootProtocol.js.map
|