@airgap/bitcoin 0.13.45-beta.2 → 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,84 +15,47 @@ 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
|
-
|
|
39
|
+
exports.BitcoinSegwitProtocolImpl = void 0;
|
|
40
|
+
exports.createBitcoinSegwitProtocol = createBitcoinSegwitProtocol;
|
|
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 crypto_1 = require("@airgap/crypto");
|
|
46
|
+
const module_kit_1 = require("@airgap/module-kit");
|
|
47
|
+
const bitcoin = __importStar(require("bitcoinjs-lib"));
|
|
48
|
+
const BitcoinSegwitAddress_1 = require("../data/BitcoinSegwitAddress");
|
|
49
|
+
const common_1 = require("../utils/common");
|
|
50
|
+
const key_1 = require("../utils/key");
|
|
51
|
+
const network_1 = require("../utils/network");
|
|
52
|
+
const BitcoinProtocol_1 = require("./BitcoinProtocol");
|
|
53
|
+
const bip32_1 = require("bip32");
|
|
54
|
+
const secp256k1_1 = __importDefault(require("@bitcoinerlab/secp256k1"));
|
|
100
55
|
// Implementation
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (options === void 0) { options = {}; }
|
|
105
|
-
if (bitcoinJS === void 0) { bitcoinJS = bitcoin; }
|
|
106
|
-
var _a, _b, _c;
|
|
56
|
+
const DUST_AMOUNT = 50;
|
|
57
|
+
class BitcoinSegwitProtocolImpl {
|
|
58
|
+
constructor(options = {}, bitcoinJS = bitcoin) {
|
|
107
59
|
this._isBitcoinProtocol = true;
|
|
108
60
|
this._isBitcoinSegwitProtocol = true;
|
|
109
61
|
this.bip32 = (0, bip32_1.BIP32Factory)(secp256k1_1.default);
|
|
@@ -114,7 +66,7 @@ var BitcoinSegwitProtocolImpl = /** @class */ (function () {
|
|
|
114
66
|
network: (0, network_1.getBitcoinJSNetwork)(this.options.network, bitcoinJS)
|
|
115
67
|
}
|
|
116
68
|
};
|
|
117
|
-
|
|
69
|
+
const keyConfiguration = {
|
|
118
70
|
xpriv: {
|
|
119
71
|
type: 'zprv'
|
|
120
72
|
},
|
|
@@ -123,741 +75,535 @@ var BitcoinSegwitProtocolImpl = /** @class */ (function () {
|
|
|
123
75
|
}
|
|
124
76
|
};
|
|
125
77
|
this.legacy = new BitcoinProtocol_1.BitcoinProtocolImpl(options, keyConfiguration);
|
|
126
|
-
this.metadata =
|
|
78
|
+
this.metadata = {
|
|
79
|
+
...this.legacy.metadata,
|
|
80
|
+
identifier: coinlib_core_1.MainProtocolSymbols.BTC_SEGWIT,
|
|
81
|
+
name: 'Bitcoin (Segwit)',
|
|
82
|
+
account: {
|
|
83
|
+
...(this.legacy.metadata.account ?? {}),
|
|
84
|
+
standardDerivationPath: `m/84'/0'/0'`,
|
|
85
|
+
address: {
|
|
86
|
+
...(this.legacy.metadata.account?.address ?? {}),
|
|
87
|
+
regex: '^(?:[13]{1}[a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-z0-9]{39,59})$'
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
127
91
|
}
|
|
128
|
-
|
|
129
|
-
return
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
92
|
+
async getMetadata() {
|
|
93
|
+
return this.metadata;
|
|
94
|
+
}
|
|
95
|
+
async getAddressFromPublicKey(publicKey) {
|
|
96
|
+
switch (publicKey.type) {
|
|
97
|
+
case 'pub':
|
|
98
|
+
return this.getAddressFromNonExtendedPublicKey(publicKey);
|
|
99
|
+
case 'xpub':
|
|
100
|
+
return this.getAddressFromExtendedPublicKey(publicKey);
|
|
101
|
+
default:
|
|
102
|
+
(0, coinlib_core_1.assertNever)(publicKey);
|
|
103
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Public key type is not supported.');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async getAddressFromNonExtendedPublicKey(publicKey) {
|
|
107
|
+
const hexPublicKey = (0, key_1.convertPublicKey)(publicKey, 'hex');
|
|
108
|
+
const payment = this.bitcoinJS.lib.payments.p2wpkh({ pubkey: Buffer.from(hexPublicKey.value, 'hex') });
|
|
109
|
+
return BitcoinSegwitAddress_1.BitcoinSegwitAddress.fromPayment(payment).asString();
|
|
110
|
+
}
|
|
111
|
+
async getAddressFromExtendedPublicKey(extendedPublicKey) {
|
|
112
|
+
const encodedExtendedPublicKey = (0, key_1.convertExtendedPublicKey)(extendedPublicKey, { format: 'encoded', type: 'xpub' });
|
|
113
|
+
const bip32 = this.bip32.fromBase58(encodedExtendedPublicKey.value, this.bitcoinJS.config.network);
|
|
114
|
+
return BitcoinSegwitAddress_1.BitcoinSegwitAddress.fromBip32(bip32).asString();
|
|
115
|
+
}
|
|
116
|
+
async deriveFromExtendedPublicKey(publicKey, visibilityIndex, addressIndex) {
|
|
117
|
+
const encodedPublicKey = (0, key_1.convertExtendedPublicKey)(publicKey, { format: 'encoded', type: 'xpub' });
|
|
118
|
+
const derivedBip32 = this.bip32
|
|
119
|
+
.fromBase58(encodedPublicKey.value, this.bitcoinJS.config.network)
|
|
120
|
+
.derive(visibilityIndex)
|
|
121
|
+
.derive(addressIndex);
|
|
122
|
+
return (0, module_kit_1.newPublicKey)(Buffer.from(derivedBip32.publicKey).toString('hex'), 'hex');
|
|
123
|
+
}
|
|
124
|
+
async getDetailsFromTransaction(transaction, _publicKey) {
|
|
125
|
+
return this.getDetailsFromPSBT(transaction.psbt, _publicKey);
|
|
126
|
+
}
|
|
127
|
+
async getDetailsFromPSBT(psbt, publickey) {
|
|
128
|
+
const decodedPSBT = this.bitcoinJS.lib.Psbt.fromHex(psbt);
|
|
129
|
+
let fee = new bignumber_1.default(0);
|
|
130
|
+
for (const txIn of decodedPSBT.data.inputs) {
|
|
131
|
+
fee = fee.plus(new bignumber_1.default(txIn.witnessUtxo?.value ?? 0));
|
|
132
|
+
}
|
|
133
|
+
for (const txOut of decodedPSBT.txOutputs) {
|
|
134
|
+
fee = fee.minus(new bignumber_1.default(txOut.value));
|
|
135
|
+
}
|
|
136
|
+
const alerts = [];
|
|
137
|
+
const clonedPSBT = decodedPSBT.clone();
|
|
138
|
+
(0, common_1.eachRecursive)(clonedPSBT); // All buffers to hex string
|
|
139
|
+
// Amount is tricky for BTC. Full amount of inputs is always transferred, but usually a (big) part of the amount is sent back to the sender via change address. So it's not easy to determine what the amount is that the user intended to send.
|
|
140
|
+
const amount = (() => {
|
|
141
|
+
// If tx has only one output, this is the amount
|
|
142
|
+
if (decodedPSBT.txOutputs.length === 1) {
|
|
143
|
+
return new bignumber_1.default(decodedPSBT.txOutputs[0].value);
|
|
144
|
+
}
|
|
145
|
+
// If we can match one output to an exact amount that we add to the PSBT, this is our amount.
|
|
146
|
+
{
|
|
147
|
+
const unknownKeyVals = decodedPSBT.data.globalMap.unknownKeyVals;
|
|
148
|
+
if (unknownKeyVals) {
|
|
149
|
+
const amountArray = unknownKeyVals.filter((kv) => kv.key.equals(Buffer.from('amount')));
|
|
150
|
+
if (amountArray.length > 0) {
|
|
151
|
+
return new bignumber_1.default(amountArray[0].value.toString()); // Buffer to number
|
|
152
|
+
}
|
|
146
153
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
BitcoinSegwitProtocolImpl.prototype.getAddressFromExtendedPublicKey = function (extendedPublicKey) {
|
|
162
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
163
|
-
var encodedExtendedPublicKey, bip32;
|
|
164
|
-
return __generator(this, function (_a) {
|
|
165
|
-
encodedExtendedPublicKey = (0, key_1.convertExtendedPublicKey)(extendedPublicKey, { format: 'encoded', type: 'xpub' });
|
|
166
|
-
bip32 = this.bip32.fromBase58(encodedExtendedPublicKey.value, this.bitcoinJS.config.network);
|
|
167
|
-
return [2 /*return*/, BitcoinSegwitAddress_1.BitcoinSegwitAddress.fromBip32(bip32).asString()];
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
};
|
|
171
|
-
BitcoinSegwitProtocolImpl.prototype.deriveFromExtendedPublicKey = function (publicKey, visibilityIndex, addressIndex) {
|
|
172
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
173
|
-
var encodedPublicKey, derivedBip32;
|
|
174
|
-
return __generator(this, function (_a) {
|
|
175
|
-
encodedPublicKey = (0, key_1.convertExtendedPublicKey)(publicKey, { format: 'encoded', type: 'xpub' });
|
|
176
|
-
derivedBip32 = this.bip32
|
|
177
|
-
.fromBase58(encodedPublicKey.value, this.bitcoinJS.config.network)
|
|
178
|
-
.derive(visibilityIndex)
|
|
179
|
-
.derive(addressIndex);
|
|
180
|
-
return [2 /*return*/, (0, module_kit_1.newPublicKey)(Buffer.from(derivedBip32.publicKey).toString('hex'), 'hex')];
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
};
|
|
184
|
-
BitcoinSegwitProtocolImpl.prototype.getDetailsFromTransaction = function (transaction, _publicKey) {
|
|
185
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
186
|
-
return __generator(this, function (_a) {
|
|
187
|
-
return [2 /*return*/, this.getDetailsFromPSBT(transaction.psbt, _publicKey)];
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
};
|
|
191
|
-
BitcoinSegwitProtocolImpl.prototype.getDetailsFromPSBT = function (psbt, publickey) {
|
|
192
|
-
var _a, _b;
|
|
193
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
194
|
-
var decodedPSBT, fee, _i, _c, txIn, _d, _e, txOut, alerts, clonedPSBT, amount, changeAddressDatas, changeAddressInfo;
|
|
195
|
-
var _this = this;
|
|
196
|
-
return __generator(this, function (_f) {
|
|
197
|
-
switch (_f.label) {
|
|
198
|
-
case 0:
|
|
199
|
-
decodedPSBT = this.bitcoinJS.lib.Psbt.fromHex(psbt);
|
|
200
|
-
fee = new bignumber_1.default(0);
|
|
201
|
-
for (_i = 0, _c = decodedPSBT.data.inputs; _i < _c.length; _i++) {
|
|
202
|
-
txIn = _c[_i];
|
|
203
|
-
fee = fee.plus(new bignumber_1.default((_b = (_a = txIn.witnessUtxo) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : 0));
|
|
204
|
-
}
|
|
205
|
-
for (_d = 0, _e = decodedPSBT.txOutputs; _d < _e.length; _d++) {
|
|
206
|
-
txOut = _e[_d];
|
|
207
|
-
fee = fee.minus(new bignumber_1.default(txOut.value));
|
|
208
|
-
}
|
|
209
|
-
alerts = [];
|
|
210
|
-
clonedPSBT = decodedPSBT.clone();
|
|
211
|
-
(0, common_1.eachRecursive)(clonedPSBT); // All buffers to hex string
|
|
212
|
-
amount = (function () {
|
|
213
|
-
// If tx has only one output, this is the amount
|
|
214
|
-
if (decodedPSBT.txOutputs.length === 1) {
|
|
215
|
-
return new bignumber_1.default(decodedPSBT.txOutputs[0].value);
|
|
216
|
-
}
|
|
217
|
-
// If we can match one output to an exact amount that we add to the PSBT, this is our amount.
|
|
218
|
-
{
|
|
219
|
-
var unknownKeyVals = decodedPSBT.data.globalMap.unknownKeyVals;
|
|
220
|
-
if (unknownKeyVals) {
|
|
221
|
-
var amountArray = unknownKeyVals.filter(function (kv) { return kv.key.equals(Buffer.from('amount')); });
|
|
222
|
-
if (amountArray.length > 0) {
|
|
223
|
-
return new bignumber_1.default(amountArray[0].value.toString()); // Buffer to number
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
// If tx has an output and we added a derivation path in the PSBT (in the wallet, prepareTransaction), we know that it is a change address and we ignore it.
|
|
228
|
-
var accumulated = new bignumber_1.default(0);
|
|
229
|
-
var useAccumulated = false;
|
|
230
|
-
decodedPSBT.data.outputs.forEach(function (outputKeyValues, index) {
|
|
231
|
-
if (outputKeyValues.unknownKeyVals) {
|
|
232
|
-
var derivationPaths = outputKeyValues.unknownKeyVals
|
|
233
|
-
.filter(function (kv) { return kv.key.equals(Buffer.from('dp')); })
|
|
234
|
-
.map(function (kv) { return kv.value.toString(); });
|
|
235
|
-
if (derivationPaths.length > 0) {
|
|
236
|
-
// If one of the outputs has the derivation in the custom key/value map, we can use this to determine the amount.
|
|
237
|
-
useAccumulated = true;
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
var output = decodedPSBT.txOutputs[index];
|
|
242
|
-
accumulated = accumulated.plus(output.value);
|
|
243
|
-
});
|
|
244
|
-
if (useAccumulated) {
|
|
245
|
-
return accumulated;
|
|
246
|
-
}
|
|
247
|
-
// If we cannot match anything above, we need to assume that the whole amount is being sent and the user has to check the outputs.
|
|
248
|
-
return decodedPSBT.txOutputs
|
|
249
|
-
.map(function (obj) { return new bignumber_1.default(obj.value); })
|
|
250
|
-
.reduce(function (accumulator, currentValue) { return accumulator.plus(currentValue); });
|
|
251
|
-
})();
|
|
252
|
-
return [4 /*yield*/, Promise.all(decodedPSBT.data.outputs.map(function (obj, index) { return __awaiter(_this, void 0, void 0, function () {
|
|
253
|
-
var isChangeAddress, isOwned, addressIndex, address, amount, ourGeneratedAddress, getIndexes, ourPublickey, x, ourPublickey, x, ourPublickey;
|
|
254
|
-
return __generator(this, function (_a) {
|
|
255
|
-
switch (_a.label) {
|
|
256
|
-
case 0:
|
|
257
|
-
isChangeAddress = false;
|
|
258
|
-
isOwned = false;
|
|
259
|
-
addressIndex = 0;
|
|
260
|
-
address = decodedPSBT.txOutputs[index].address;
|
|
261
|
-
amount = decodedPSBT.txOutputs[index].value;
|
|
262
|
-
if (!obj.bip32Derivation) return [3 /*break*/, 11];
|
|
263
|
-
isChangeAddress = true;
|
|
264
|
-
getIndexes = obj.bip32Derivation[0].path.split('/');
|
|
265
|
-
if (!(publickey.type === 'xpub')) return [3 /*break*/, 3];
|
|
266
|
-
return [4 /*yield*/, this.deriveFromExtendedPublicKey(publickey, 1, +getIndexes[getIndexes.length - 1])];
|
|
267
|
-
case 1:
|
|
268
|
-
ourPublickey = _a.sent();
|
|
269
|
-
return [4 /*yield*/, this.getAddressFromPublicKey(ourPublickey)];
|
|
270
|
-
case 2:
|
|
271
|
-
ourGeneratedAddress = _a.sent();
|
|
272
|
-
return [3 /*break*/, 5];
|
|
273
|
-
case 3: return [4 /*yield*/, this.getAddressFromNonExtendedPublicKey(publickey)];
|
|
274
|
-
case 4:
|
|
275
|
-
ourGeneratedAddress = _a.sent();
|
|
276
|
-
_a.label = 5;
|
|
277
|
-
case 5:
|
|
278
|
-
if (ourGeneratedAddress === address) {
|
|
279
|
-
isOwned = true;
|
|
280
|
-
addressIndex = +getIndexes[getIndexes.length - 1];
|
|
281
|
-
}
|
|
282
|
-
x = 0;
|
|
283
|
-
_a.label = 6;
|
|
284
|
-
case 6:
|
|
285
|
-
if (!(x < 1000)) return [3 /*break*/, 10];
|
|
286
|
-
return [4 /*yield*/, this.deriveFromExtendedPublicKey(publickey, 1, x)];
|
|
287
|
-
case 7:
|
|
288
|
-
ourPublickey = _a.sent();
|
|
289
|
-
return [4 /*yield*/, this.getAddressFromPublicKey(ourPublickey)];
|
|
290
|
-
case 8:
|
|
291
|
-
ourGeneratedAddress = _a.sent();
|
|
292
|
-
if (ourGeneratedAddress === address) {
|
|
293
|
-
isOwned = true;
|
|
294
|
-
addressIndex = x;
|
|
295
|
-
return [3 /*break*/, 10];
|
|
296
|
-
}
|
|
297
|
-
_a.label = 9;
|
|
298
|
-
case 9:
|
|
299
|
-
x++;
|
|
300
|
-
return [3 /*break*/, 6];
|
|
301
|
-
case 10: return [3 /*break*/, 16];
|
|
302
|
-
case 11:
|
|
303
|
-
if (!obj.unknownKeyVals) return [3 /*break*/, 16];
|
|
304
|
-
x = 0;
|
|
305
|
-
_a.label = 12;
|
|
306
|
-
case 12:
|
|
307
|
-
if (!(x < 1000)) return [3 /*break*/, 16];
|
|
308
|
-
isChangeAddress = true;
|
|
309
|
-
return [4 /*yield*/, this.deriveFromExtendedPublicKey(publickey, 1, x)];
|
|
310
|
-
case 13:
|
|
311
|
-
ourPublickey = _a.sent();
|
|
312
|
-
return [4 /*yield*/, this.getAddressFromPublicKey(ourPublickey)];
|
|
313
|
-
case 14:
|
|
314
|
-
ourGeneratedAddress = _a.sent();
|
|
315
|
-
if (ourGeneratedAddress === address) {
|
|
316
|
-
isOwned = true;
|
|
317
|
-
addressIndex = x;
|
|
318
|
-
return [3 /*break*/, 16];
|
|
319
|
-
}
|
|
320
|
-
_a.label = 15;
|
|
321
|
-
case 15:
|
|
322
|
-
x++;
|
|
323
|
-
return [3 /*break*/, 12];
|
|
324
|
-
case 16:
|
|
325
|
-
if (isChangeAddress && isOwned) {
|
|
326
|
-
alerts.push({
|
|
327
|
-
type: 'success',
|
|
328
|
-
title: {
|
|
329
|
-
type: 'plain',
|
|
330
|
-
value: ''
|
|
331
|
-
},
|
|
332
|
-
description: {
|
|
333
|
-
type: 'plain',
|
|
334
|
-
value: 'Note: your change address has been verified'
|
|
335
|
-
},
|
|
336
|
-
icon: undefined,
|
|
337
|
-
actions: undefined
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
else if (isChangeAddress && !isOwned) {
|
|
341
|
-
alerts.push({
|
|
342
|
-
type: 'warning',
|
|
343
|
-
title: {
|
|
344
|
-
type: 'plain',
|
|
345
|
-
value: ''
|
|
346
|
-
},
|
|
347
|
-
description: {
|
|
348
|
-
type: 'plain',
|
|
349
|
-
value: 'Note: your change address has not been verified'
|
|
350
|
-
},
|
|
351
|
-
icon: undefined,
|
|
352
|
-
actions: undefined
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
return [2 /*return*/, [
|
|
356
|
-
address,
|
|
357
|
-
{
|
|
358
|
-
isChangeAddress: isChangeAddress,
|
|
359
|
-
isOwned: isOwned,
|
|
360
|
-
path: addressIndex === 0 ? '' : "m/84'/0'/0'/1/".concat(addressIndex),
|
|
361
|
-
amount: amount
|
|
362
|
-
}
|
|
363
|
-
]];
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
}); }))];
|
|
367
|
-
case 1:
|
|
368
|
-
changeAddressDatas = _f.sent();
|
|
369
|
-
changeAddressInfo = {};
|
|
370
|
-
changeAddressDatas.forEach(function (changeAddressData) {
|
|
371
|
-
changeAddressInfo[changeAddressData[0]] = changeAddressData[1];
|
|
372
|
-
});
|
|
373
|
-
return [2 /*return*/, [
|
|
374
|
-
{
|
|
375
|
-
from: decodedPSBT.data.inputs.map(function (obj) {
|
|
376
|
-
var _a, _b;
|
|
377
|
-
return (_b = (_a = obj.bip32Derivation) === null || _a === void 0 ? void 0 : _a.map(function (el) {
|
|
378
|
-
return _this.bitcoinJS.lib.payments.p2wpkh({
|
|
379
|
-
pubkey: el.pubkey,
|
|
380
|
-
network: _this.bitcoinJS.lib.networks.bitcoin
|
|
381
|
-
}).address;
|
|
382
|
-
}).join(' ')) !== null && _b !== void 0 ? _b : 'INVALID';
|
|
383
|
-
}),
|
|
384
|
-
to: decodedPSBT.txOutputs.map(function (obj) {
|
|
385
|
-
return obj.address || "Script: ".concat(obj.script.toString('hex')) || 'unknown';
|
|
386
|
-
}),
|
|
387
|
-
isInbound: false,
|
|
388
|
-
amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
|
|
389
|
-
fee: (0, module_kit_1.newAmount)(fee, 'blockchain'),
|
|
390
|
-
network: this.options.network,
|
|
391
|
-
changeAddressInfo: changeAddressInfo,
|
|
392
|
-
uiAlerts: alerts,
|
|
393
|
-
json: {
|
|
394
|
-
// This is some unstructured data about the PSBT. This is shown in the UI as a JSON for advanced users.
|
|
395
|
-
inputTx: (0, common_1.eachRecursive)(clonedPSBT.txInputs),
|
|
396
|
-
outputTx: (0, common_1.eachRecursive)(clonedPSBT.txOutputs),
|
|
397
|
-
inputData: clonedPSBT.data.inputs,
|
|
398
|
-
outputData: clonedPSBT.data.outputs,
|
|
399
|
-
PSBTVersion: clonedPSBT.version,
|
|
400
|
-
PSBTLocktime: clonedPSBT.locktime,
|
|
401
|
-
PSBTGlobalMap: clonedPSBT.data.globalMap,
|
|
402
|
-
rawPSBT: psbt
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
]];
|
|
154
|
+
}
|
|
155
|
+
// If tx has an output and we added a derivation path in the PSBT (in the wallet, prepareTransaction), we know that it is a change address and we ignore it.
|
|
156
|
+
let accumulated = new bignumber_1.default(0);
|
|
157
|
+
let useAccumulated = false;
|
|
158
|
+
decodedPSBT.data.outputs.forEach((outputKeyValues, index) => {
|
|
159
|
+
if (outputKeyValues.unknownKeyVals) {
|
|
160
|
+
const derivationPaths = outputKeyValues.unknownKeyVals
|
|
161
|
+
.filter((kv) => kv.key.equals(Buffer.from('dp')))
|
|
162
|
+
.map((kv) => kv.value.toString());
|
|
163
|
+
if (derivationPaths.length > 0) {
|
|
164
|
+
// If one of the outputs has the derivation in the custom key/value map, we can use this to determine the amount.
|
|
165
|
+
useAccumulated = true;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
406
168
|
}
|
|
169
|
+
const output = decodedPSBT.txOutputs[index];
|
|
170
|
+
accumulated = accumulated.plus(output.value);
|
|
407
171
|
});
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
return
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
});
|
|
430
|
-
});
|
|
431
|
-
};
|
|
432
|
-
BitcoinSegwitProtocolImpl.prototype.getKeyPairFromDerivative = function (derivative) {
|
|
433
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
434
|
-
var bip32, privateKeyUint8, privateKey, publicKeyUint8, publicKey;
|
|
435
|
-
return __generator(this, function (_a) {
|
|
436
|
-
bip32 = this.derivativeToBip32Node(derivative);
|
|
437
|
-
privateKeyUint8 = bip32.privateKey;
|
|
438
|
-
if (privateKeyUint8 === undefined) {
|
|
439
|
-
throw new Error('No private key!');
|
|
172
|
+
if (useAccumulated) {
|
|
173
|
+
return accumulated;
|
|
174
|
+
}
|
|
175
|
+
// If we cannot match anything above, we need to assume that the whole amount is being sent and the user has to check the outputs.
|
|
176
|
+
return decodedPSBT.txOutputs
|
|
177
|
+
.map((obj) => new bignumber_1.default(obj.value))
|
|
178
|
+
.reduce((accumulator, currentValue) => accumulator.plus(currentValue));
|
|
179
|
+
})();
|
|
180
|
+
const changeAddressDatas = await Promise.all(decodedPSBT.data.outputs.map(async (obj, index) => {
|
|
181
|
+
let isChangeAddress = false;
|
|
182
|
+
let isOwned = false;
|
|
183
|
+
let addressIndex = 0;
|
|
184
|
+
const address = decodedPSBT.txOutputs[index].address;
|
|
185
|
+
const amount = decodedPSBT.txOutputs[index].value;
|
|
186
|
+
let ourGeneratedAddress;
|
|
187
|
+
if (obj.bip32Derivation) {
|
|
188
|
+
isChangeAddress = true;
|
|
189
|
+
const getIndexes = obj.bip32Derivation[0].path.split('/');
|
|
190
|
+
if (publickey.type === 'xpub') {
|
|
191
|
+
const ourPublickey = await this.deriveFromExtendedPublicKey(publickey, 1, +getIndexes[getIndexes.length - 1]);
|
|
192
|
+
ourGeneratedAddress = await this.getAddressFromPublicKey(ourPublickey);
|
|
440
193
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
publicKey = Buffer.from(publicKeyUint8);
|
|
444
|
-
return [2 /*return*/, {
|
|
445
|
-
secretKey: (0, module_kit_1.newSecretKey)(privateKey.toString('hex'), 'hex'),
|
|
446
|
-
publicKey: (0, module_kit_1.newPublicKey)(publicKey.toString('hex'), 'hex')
|
|
447
|
-
}];
|
|
448
|
-
});
|
|
449
|
-
});
|
|
450
|
-
};
|
|
451
|
-
BitcoinSegwitProtocolImpl.prototype.getExtendedKeyPairFromDerivative = function (derivative) {
|
|
452
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
453
|
-
var bip32;
|
|
454
|
-
return __generator(this, function (_a) {
|
|
455
|
-
bip32 = this.derivativeToBip32Node(derivative);
|
|
456
|
-
return [2 /*return*/, {
|
|
457
|
-
secretKey: (0, module_kit_1.newExtendedSecretKey)(bip32.toBase58(), 'encoded'),
|
|
458
|
-
publicKey: (0, key_1.convertExtendedPublicKey)((0, module_kit_1.newExtendedPublicKey)(bip32.neutered().toBase58(), 'encoded'), {
|
|
459
|
-
format: 'encoded',
|
|
460
|
-
type: 'zpub'
|
|
461
|
-
})
|
|
462
|
-
}];
|
|
463
|
-
});
|
|
464
|
-
});
|
|
465
|
-
};
|
|
466
|
-
BitcoinSegwitProtocolImpl.prototype.deriveFromExtendedSecretKey = function (extendedSecretKey, visibilityIndex, addressIndex) {
|
|
467
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
468
|
-
var encodedSecretKey, derivedBip32, privateKeyUint8, privateKey;
|
|
469
|
-
return __generator(this, function (_a) {
|
|
470
|
-
encodedSecretKey = (0, key_1.convertExtendedSecretKey)(extendedSecretKey, { format: 'encoded', type: 'xprv' });
|
|
471
|
-
derivedBip32 = this.bip32
|
|
472
|
-
.fromBase58(encodedSecretKey.value, this.bitcoinJS.config.network)
|
|
473
|
-
.derive(visibilityIndex)
|
|
474
|
-
.derive(addressIndex);
|
|
475
|
-
privateKeyUint8 = derivedBip32.privateKey;
|
|
476
|
-
if (privateKeyUint8 === undefined) {
|
|
477
|
-
throw new Error('No private key!');
|
|
194
|
+
else {
|
|
195
|
+
ourGeneratedAddress = await this.getAddressFromNonExtendedPublicKey(publickey);
|
|
478
196
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
});
|
|
483
|
-
};
|
|
484
|
-
BitcoinSegwitProtocolImpl.prototype.signTransactionWithSecretKey = function (transaction, secretKey) {
|
|
485
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
486
|
-
return __generator(this, function (_a) {
|
|
487
|
-
switch (secretKey.type) {
|
|
488
|
-
case 'priv':
|
|
489
|
-
return [2 /*return*/, this.signTransactionWithNonExtendedSecretKey(transaction, secretKey)];
|
|
490
|
-
case 'xpriv':
|
|
491
|
-
return [2 /*return*/, this.signTransactionWithExtendedSecretKey(transaction, secretKey)];
|
|
492
|
-
default:
|
|
493
|
-
(0, coinlib_core_1.assertNever)(secretKey);
|
|
494
|
-
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Secret key type not supported.');
|
|
197
|
+
if (ourGeneratedAddress === address) {
|
|
198
|
+
isOwned = true;
|
|
199
|
+
addressIndex = +getIndexes[getIndexes.length - 1];
|
|
495
200
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
201
|
+
for (let x = 0; x < 1000; x++) {
|
|
202
|
+
const ourPublickey = await this.deriveFromExtendedPublicKey(publickey, 1, x);
|
|
203
|
+
ourGeneratedAddress = await this.getAddressFromPublicKey(ourPublickey);
|
|
204
|
+
if (ourGeneratedAddress === address) {
|
|
205
|
+
isOwned = true;
|
|
206
|
+
addressIndex = x;
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else if (obj.unknownKeyVals) {
|
|
212
|
+
for (let x = 0; x < 1000; x++) {
|
|
213
|
+
isChangeAddress = true;
|
|
214
|
+
const ourPublickey = await this.deriveFromExtendedPublicKey(publickey, 1, x);
|
|
215
|
+
ourGeneratedAddress = await this.getAddressFromPublicKey(ourPublickey);
|
|
216
|
+
if (ourGeneratedAddress === address) {
|
|
217
|
+
isOwned = true;
|
|
218
|
+
addressIndex = x;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (isChangeAddress && isOwned) {
|
|
224
|
+
alerts.push({
|
|
225
|
+
type: 'success',
|
|
226
|
+
title: {
|
|
227
|
+
type: 'plain',
|
|
228
|
+
value: ''
|
|
229
|
+
},
|
|
230
|
+
description: {
|
|
231
|
+
type: 'plain',
|
|
232
|
+
value: 'Note: your change address has been verified'
|
|
233
|
+
},
|
|
234
|
+
icon: undefined,
|
|
235
|
+
actions: undefined
|
|
531
236
|
});
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
});
|
|
556
|
-
};
|
|
557
|
-
BitcoinSegwitProtocolImpl.prototype.decryptAESWithSecretKey = function (payload, secretKey) {
|
|
558
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
559
|
-
return __generator(this, function (_a) {
|
|
560
|
-
return [2 /*return*/, this.legacy.decryptAESWithSecretKey(payload, secretKey)];
|
|
561
|
-
});
|
|
562
|
-
});
|
|
563
|
-
};
|
|
564
|
-
// Online
|
|
565
|
-
BitcoinSegwitProtocolImpl.prototype.getNetwork = function () {
|
|
566
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
567
|
-
return __generator(this, function (_a) {
|
|
568
|
-
return [2 /*return*/, this.options.network];
|
|
569
|
-
});
|
|
570
|
-
});
|
|
571
|
-
};
|
|
572
|
-
BitcoinSegwitProtocolImpl.prototype.getTransactionsForPublicKey = function (publicKey, limit, cursor) {
|
|
573
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
574
|
-
return __generator(this, function (_a) {
|
|
575
|
-
return [2 /*return*/, this.legacy.getTransactionsForPublicKey(publicKey, limit, cursor)];
|
|
576
|
-
});
|
|
577
|
-
});
|
|
578
|
-
};
|
|
579
|
-
BitcoinSegwitProtocolImpl.prototype.getTransactionsForAddress = function (address, limit, cursor) {
|
|
580
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
581
|
-
return __generator(this, function (_a) {
|
|
582
|
-
return [2 /*return*/, this.legacy.getTransactionsForAddress(address, limit, cursor)];
|
|
583
|
-
});
|
|
584
|
-
});
|
|
585
|
-
};
|
|
586
|
-
BitcoinSegwitProtocolImpl.prototype.getTransactionsForAddresses = function (addresses, limit, cursor) {
|
|
587
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
588
|
-
return __generator(this, function (_a) {
|
|
589
|
-
return [2 /*return*/, this.legacy.getTransactionsForAddresses(addresses, limit, cursor)];
|
|
590
|
-
});
|
|
591
|
-
});
|
|
592
|
-
};
|
|
593
|
-
BitcoinSegwitProtocolImpl.prototype.getBalanceOfPublicKey = function (publicKey) {
|
|
594
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
595
|
-
return __generator(this, function (_a) {
|
|
596
|
-
return [2 /*return*/, this.legacy.getBalanceOfPublicKey(publicKey)];
|
|
597
|
-
});
|
|
598
|
-
});
|
|
599
|
-
};
|
|
600
|
-
BitcoinSegwitProtocolImpl.prototype.getBalanceOfAddress = function (address) {
|
|
601
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
602
|
-
return __generator(this, function (_a) {
|
|
603
|
-
return [2 /*return*/, this.legacy.getBalanceOfAddress(address)];
|
|
604
|
-
});
|
|
605
|
-
});
|
|
606
|
-
};
|
|
607
|
-
BitcoinSegwitProtocolImpl.prototype.getBalanceOfAddresses = function (addresses) {
|
|
608
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
609
|
-
return __generator(this, function (_a) {
|
|
610
|
-
return [2 /*return*/, this.legacy.getBalanceOfAddresses(addresses)];
|
|
611
|
-
});
|
|
612
|
-
});
|
|
613
|
-
};
|
|
614
|
-
BitcoinSegwitProtocolImpl.prototype.getTransactionMaxAmountWithPublicKey = function (publicKey, to, configuration) {
|
|
615
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
616
|
-
return __generator(this, function (_a) {
|
|
617
|
-
return [2 /*return*/, this.legacy.getTransactionMaxAmountWithPublicKey(publicKey, to, configuration)];
|
|
618
|
-
});
|
|
619
|
-
});
|
|
620
|
-
};
|
|
621
|
-
BitcoinSegwitProtocolImpl.prototype.getTransactionFeeWithPublicKey = function (publicKey, details, configuration) {
|
|
622
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
623
|
-
return __generator(this, function (_a) {
|
|
624
|
-
return [2 /*return*/, this.legacy.getTransactionFeeWithPublicKey(publicKey, details, configuration)];
|
|
625
|
-
});
|
|
626
|
-
});
|
|
627
|
-
};
|
|
628
|
-
BitcoinSegwitProtocolImpl.prototype.prepareTransactionWithPublicKey = function (publicKey, details, configuration) {
|
|
629
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
630
|
-
return __generator(this, function (_a) {
|
|
631
|
-
switch (publicKey.type) {
|
|
632
|
-
case 'pub':
|
|
633
|
-
return [2 /*return*/, this.prepareTransactionWithNonExtendedPublicKey(publicKey, details, configuration)];
|
|
634
|
-
case 'xpub':
|
|
635
|
-
return [2 /*return*/, this.prepareTransactionWithExtendedPublicKey(publicKey, details, configuration)];
|
|
636
|
-
default:
|
|
637
|
-
(0, coinlib_core_1.assertNever)(publicKey);
|
|
638
|
-
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Unuspported public key type.');
|
|
237
|
+
}
|
|
238
|
+
else if (isChangeAddress && !isOwned) {
|
|
239
|
+
alerts.push({
|
|
240
|
+
type: 'warning',
|
|
241
|
+
title: {
|
|
242
|
+
type: 'plain',
|
|
243
|
+
value: ''
|
|
244
|
+
},
|
|
245
|
+
description: {
|
|
246
|
+
type: 'plain',
|
|
247
|
+
value: 'Note: your change address has not been verified'
|
|
248
|
+
},
|
|
249
|
+
icon: undefined,
|
|
250
|
+
actions: undefined
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
return [
|
|
254
|
+
address,
|
|
255
|
+
{
|
|
256
|
+
isChangeAddress: isChangeAddress,
|
|
257
|
+
isOwned: isOwned,
|
|
258
|
+
path: addressIndex === 0 ? '' : `m/84'/0'/0'/1/${addressIndex}`,
|
|
259
|
+
amount
|
|
639
260
|
}
|
|
640
|
-
|
|
261
|
+
];
|
|
262
|
+
}));
|
|
263
|
+
const changeAddressInfo = {};
|
|
264
|
+
changeAddressDatas.forEach((changeAddressData) => {
|
|
265
|
+
changeAddressInfo[changeAddressData[0]] = changeAddressData[1];
|
|
266
|
+
});
|
|
267
|
+
return [
|
|
268
|
+
{
|
|
269
|
+
from: decodedPSBT.data.inputs.map((obj) => obj.bip32Derivation
|
|
270
|
+
?.map((el) => this.bitcoinJS.lib.payments.p2wpkh({
|
|
271
|
+
pubkey: el.pubkey,
|
|
272
|
+
network: this.bitcoinJS.lib.networks.bitcoin
|
|
273
|
+
}).address)
|
|
274
|
+
.join(' ') ?? 'INVALID'),
|
|
275
|
+
to: decodedPSBT.txOutputs.map((obj) => {
|
|
276
|
+
return obj.address || `Script: ${obj.script.toString('hex')}` || 'unknown';
|
|
277
|
+
}),
|
|
278
|
+
isInbound: false,
|
|
279
|
+
amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
|
|
280
|
+
fee: (0, module_kit_1.newAmount)(fee, 'blockchain'),
|
|
281
|
+
network: this.options.network,
|
|
282
|
+
changeAddressInfo,
|
|
283
|
+
uiAlerts: alerts,
|
|
284
|
+
json: {
|
|
285
|
+
// This is some unstructured data about the PSBT. This is shown in the UI as a JSON for advanced users.
|
|
286
|
+
inputTx: (0, common_1.eachRecursive)(clonedPSBT.txInputs),
|
|
287
|
+
outputTx: (0, common_1.eachRecursive)(clonedPSBT.txOutputs),
|
|
288
|
+
inputData: clonedPSBT.data.inputs,
|
|
289
|
+
outputData: clonedPSBT.data.outputs,
|
|
290
|
+
PSBTVersion: clonedPSBT.version,
|
|
291
|
+
PSBTLocktime: clonedPSBT.locktime,
|
|
292
|
+
PSBTGlobalMap: clonedPSBT.data.globalMap,
|
|
293
|
+
rawPSBT: psbt
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
];
|
|
297
|
+
}
|
|
298
|
+
async verifyMessageWithPublicKey(message, signature, publicKey) {
|
|
299
|
+
return this.legacy.verifyMessageWithPublicKey(message, signature, publicKey);
|
|
300
|
+
}
|
|
301
|
+
async encryptAsymmetricWithPublicKey(payload, publicKey) {
|
|
302
|
+
return this.legacy.encryptAsymmetricWithPublicKey(payload, publicKey);
|
|
303
|
+
}
|
|
304
|
+
// Offline
|
|
305
|
+
async getCryptoConfiguration() {
|
|
306
|
+
return this.legacy.getCryptoConfiguration();
|
|
307
|
+
}
|
|
308
|
+
async getKeyPairFromDerivative(derivative) {
|
|
309
|
+
const bip32 = this.derivativeToBip32Node(derivative);
|
|
310
|
+
const privateKeyUint8 = bip32.privateKey;
|
|
311
|
+
if (privateKeyUint8 === undefined) {
|
|
312
|
+
throw new Error('No private key!');
|
|
313
|
+
}
|
|
314
|
+
const privateKey = Buffer.from(privateKeyUint8);
|
|
315
|
+
const publicKeyUint8 = bip32.publicKey;
|
|
316
|
+
const publicKey = Buffer.from(publicKeyUint8);
|
|
317
|
+
return {
|
|
318
|
+
secretKey: (0, module_kit_1.newSecretKey)(privateKey.toString('hex'), 'hex'),
|
|
319
|
+
publicKey: (0, module_kit_1.newPublicKey)(publicKey.toString('hex'), 'hex')
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
async getExtendedKeyPairFromDerivative(derivative) {
|
|
323
|
+
const bip32 = this.derivativeToBip32Node(derivative);
|
|
324
|
+
return {
|
|
325
|
+
secretKey: (0, module_kit_1.newExtendedSecretKey)(bip32.toBase58(), 'encoded'),
|
|
326
|
+
publicKey: (0, key_1.convertExtendedPublicKey)((0, module_kit_1.newExtendedPublicKey)(bip32.neutered().toBase58(), 'encoded'), {
|
|
327
|
+
format: 'encoded',
|
|
328
|
+
type: 'zpub'
|
|
329
|
+
})
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
async deriveFromExtendedSecretKey(extendedSecretKey, visibilityIndex, addressIndex) {
|
|
333
|
+
const encodedSecretKey = (0, key_1.convertExtendedSecretKey)(extendedSecretKey, { format: 'encoded', type: 'xprv' });
|
|
334
|
+
const derivedBip32 = this.bip32
|
|
335
|
+
.fromBase58(encodedSecretKey.value, this.bitcoinJS.config.network)
|
|
336
|
+
.derive(visibilityIndex)
|
|
337
|
+
.derive(addressIndex);
|
|
338
|
+
const privateKeyUint8 = derivedBip32.privateKey;
|
|
339
|
+
if (privateKeyUint8 === undefined) {
|
|
340
|
+
throw new Error('No private key!');
|
|
341
|
+
}
|
|
342
|
+
const privateKey = Buffer.from(privateKeyUint8);
|
|
343
|
+
return (0, module_kit_1.newSecretKey)(privateKey.toString('hex'), 'hex');
|
|
344
|
+
}
|
|
345
|
+
async signTransactionWithSecretKey(transaction, secretKey) {
|
|
346
|
+
switch (secretKey.type) {
|
|
347
|
+
case 'priv':
|
|
348
|
+
return this.signTransactionWithNonExtendedSecretKey(transaction, secretKey);
|
|
349
|
+
case 'xpriv':
|
|
350
|
+
return this.signTransactionWithExtendedSecretKey(transaction, secretKey);
|
|
351
|
+
default:
|
|
352
|
+
(0, coinlib_core_1.assertNever)(secretKey);
|
|
353
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Secret key type not supported.');
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
async signTransactionWithNonExtendedSecretKey(transaction, secretKey) {
|
|
357
|
+
// No reference implementation in v0
|
|
358
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Sign with non extended secret key not supported (Segwit).');
|
|
359
|
+
}
|
|
360
|
+
async signTransactionWithExtendedSecretKey(transaction, extendedSecretKey) {
|
|
361
|
+
const encodedExtendedSecretKey = (0, key_1.convertExtendedSecretKey)(extendedSecretKey, { format: 'encoded', type: 'xprv' });
|
|
362
|
+
const bip32 = this.bip32.fromBase58(encodedExtendedSecretKey.value);
|
|
363
|
+
const decodedPSBT = this.bitcoinJS.lib.Psbt.fromHex(transaction.psbt);
|
|
364
|
+
decodedPSBT.data.inputs.forEach((input, index) => {
|
|
365
|
+
input.bip32Derivation?.forEach((deriv) => {
|
|
366
|
+
try {
|
|
367
|
+
// This uses the same logic to find child key as the "findWalletByFingerprintDerivationPathAndProtocolIdentifier" method in the Vault
|
|
368
|
+
const cutoffFrom = deriv.path.lastIndexOf("'") || deriv.path.lastIndexOf('h');
|
|
369
|
+
const childPath = deriv.path.substr(cutoffFrom + 2);
|
|
370
|
+
const childNode = bip32.derivePath(childPath);
|
|
371
|
+
// Wrap publicKey as Buffer to match Signer interface
|
|
372
|
+
decodedPSBT.signInput(index, {
|
|
373
|
+
publicKey: Buffer.from(childNode.publicKey),
|
|
374
|
+
sign: (hash, lowR) => Buffer.from(childNode.sign(hash, lowR))
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
catch (e) { }
|
|
641
378
|
});
|
|
642
379
|
});
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
380
|
+
return (0, module_kit_1.newSignedTransaction)({ psbt: decodedPSBT.toHex() });
|
|
381
|
+
}
|
|
382
|
+
async signMessageWithKeyPair(message, keyPair) {
|
|
383
|
+
return this.legacy.signMessageWithKeyPair(message, keyPair);
|
|
384
|
+
}
|
|
385
|
+
async decryptAsymmetricWithKeyPair(payload, keyPair) {
|
|
386
|
+
return this.legacy.decryptAsymmetricWithKeyPair(payload, keyPair);
|
|
387
|
+
}
|
|
388
|
+
async encryptAESWithSecretKey(payload, secretKey) {
|
|
389
|
+
return this.legacy.encryptAESWithSecretKey(payload, secretKey);
|
|
390
|
+
}
|
|
391
|
+
async decryptAESWithSecretKey(payload, secretKey) {
|
|
392
|
+
return this.legacy.decryptAESWithSecretKey(payload, secretKey);
|
|
393
|
+
}
|
|
394
|
+
// Online
|
|
395
|
+
async getNetwork() {
|
|
396
|
+
return this.options.network;
|
|
397
|
+
}
|
|
398
|
+
async getTransactionsForPublicKey(publicKey, limit, cursor) {
|
|
399
|
+
return this.legacy.getTransactionsForPublicKey(publicKey, limit, cursor);
|
|
400
|
+
}
|
|
401
|
+
async getTransactionsForAddress(address, limit, cursor) {
|
|
402
|
+
return this.legacy.getTransactionsForAddress(address, limit, cursor);
|
|
403
|
+
}
|
|
404
|
+
async getTransactionsForAddresses(addresses, limit, cursor) {
|
|
405
|
+
return this.legacy.getTransactionsForAddresses(addresses, limit, cursor);
|
|
406
|
+
}
|
|
407
|
+
async getBalanceOfPublicKey(publicKey) {
|
|
408
|
+
return this.legacy.getBalanceOfPublicKey(publicKey);
|
|
409
|
+
}
|
|
410
|
+
async getBalanceOfAddress(address) {
|
|
411
|
+
return this.legacy.getBalanceOfAddress(address);
|
|
412
|
+
}
|
|
413
|
+
async getBalanceOfAddresses(addresses) {
|
|
414
|
+
return this.legacy.getBalanceOfAddresses(addresses);
|
|
415
|
+
}
|
|
416
|
+
async getTransactionMaxAmountWithPublicKey(publicKey, to, configuration) {
|
|
417
|
+
return this.legacy.getTransactionMaxAmountWithPublicKey(publicKey, to, configuration);
|
|
418
|
+
}
|
|
419
|
+
async getTransactionFeeWithPublicKey(publicKey, details, configuration) {
|
|
420
|
+
return this.legacy.getTransactionFeeWithPublicKey(publicKey, details, configuration);
|
|
421
|
+
}
|
|
422
|
+
async prepareTransactionWithPublicKey(publicKey, details, configuration) {
|
|
423
|
+
switch (publicKey.type) {
|
|
424
|
+
case 'pub':
|
|
425
|
+
return this.prepareTransactionWithNonExtendedPublicKey(publicKey, details, configuration);
|
|
426
|
+
case 'xpub':
|
|
427
|
+
return this.prepareTransactionWithExtendedPublicKey(publicKey, details, configuration);
|
|
428
|
+
default:
|
|
429
|
+
(0, coinlib_core_1.assertNever)(publicKey);
|
|
430
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Unuspported public key type.');
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
async prepareTransactionWithNonExtendedPublicKey(publicKey, details, configuration) {
|
|
434
|
+
// No reference implementation in v0
|
|
435
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Prepare transaction with non extended public key not supported (Segwit).');
|
|
436
|
+
}
|
|
437
|
+
async prepareTransactionWithExtendedPublicKey(extendedPublicKey, details, configuration) {
|
|
438
|
+
if (configuration?.masterFingerprint === undefined) {
|
|
439
|
+
throw new errors_1.ConditionViolationError(coinlib_core_1.Domain.BITCOIN, 'Master fingerprint not set.');
|
|
440
|
+
}
|
|
441
|
+
let fee;
|
|
442
|
+
if (configuration?.fee !== undefined) {
|
|
443
|
+
fee = configuration.fee;
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
const estimatedFee = await this.getTransactionFeeWithPublicKey(extendedPublicKey, details);
|
|
447
|
+
fee = estimatedFee.medium;
|
|
448
|
+
}
|
|
449
|
+
const wrappedFee = new bignumber_1.default((0, module_kit_1.newAmount)(fee).blockchain(this.legacy.units).value);
|
|
450
|
+
const transaction = (0, module_kit_1.newUnsignedTransaction)({
|
|
451
|
+
ins: [],
|
|
452
|
+
outs: []
|
|
650
453
|
});
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
654
|
-
var fee, estimatedFee, wrappedFee, transaction, utxos, totalRequiredBalance, valueAccumulator, getPathIndexes, _i, utxos_1, utxo, indexes, derivedPublicKey, derivedAddress, i, value, lastUsedInternalAddress, changeValue, changeAddressIndex, derivedPublicKey, derivedAddress, psbt, xpubExtendedPublicKey, keyPair, replaceByFee;
|
|
655
|
-
var _this = this;
|
|
656
|
-
return __generator(this, function (_a) {
|
|
657
|
-
switch (_a.label) {
|
|
658
|
-
case 0:
|
|
659
|
-
if ((configuration === null || configuration === void 0 ? void 0 : configuration.masterFingerprint) === undefined) {
|
|
660
|
-
throw new errors_1.ConditionViolationError(coinlib_core_1.Domain.BITCOIN, 'Master fingerprint not set.');
|
|
661
|
-
}
|
|
662
|
-
if (!((configuration === null || configuration === void 0 ? void 0 : configuration.fee) !== undefined)) return [3 /*break*/, 1];
|
|
663
|
-
fee = configuration.fee;
|
|
664
|
-
return [3 /*break*/, 3];
|
|
665
|
-
case 1: return [4 /*yield*/, this.getTransactionFeeWithPublicKey(extendedPublicKey, details)];
|
|
666
|
-
case 2:
|
|
667
|
-
estimatedFee = _a.sent();
|
|
668
|
-
fee = estimatedFee.medium;
|
|
669
|
-
_a.label = 3;
|
|
670
|
-
case 3:
|
|
671
|
-
wrappedFee = new bignumber_1.default((0, module_kit_1.newAmount)(fee).blockchain(this.legacy.units).value);
|
|
672
|
-
transaction = (0, module_kit_1.newUnsignedTransaction)({
|
|
673
|
-
ins: [],
|
|
674
|
-
outs: []
|
|
675
|
-
});
|
|
676
|
-
return [4 /*yield*/, index_1.default.get("".concat(this.options.network.indexerApi, "/api/v2/utxo/").concat(extendedPublicKey.value, "?confirmed=true"), {
|
|
677
|
-
responseType: 'json'
|
|
678
|
-
})];
|
|
679
|
-
case 4:
|
|
680
|
-
utxos = (_a.sent()).data;
|
|
681
|
-
if (utxos.length <= 0) {
|
|
682
|
-
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
|
|
683
|
-
}
|
|
684
|
-
totalRequiredBalance = details
|
|
685
|
-
.map(function (_a) {
|
|
686
|
-
var amount = _a.amount;
|
|
687
|
-
return new bignumber_1.default((0, module_kit_1.newAmount)(amount).blockchain(_this.legacy.units).value);
|
|
688
|
-
})
|
|
689
|
-
.reduce(function (accumulator, currentValue) { return accumulator.plus(currentValue); })
|
|
690
|
-
.plus(wrappedFee);
|
|
691
|
-
valueAccumulator = new bignumber_1.default(0);
|
|
692
|
-
getPathIndexes = function (path) {
|
|
693
|
-
var result = path
|
|
694
|
-
.split('/')
|
|
695
|
-
.slice(-2)
|
|
696
|
-
.map(function (item) { return parseInt(item); })
|
|
697
|
-
.filter(function (item) { return !isNaN(item); });
|
|
698
|
-
if (result.length !== 2) {
|
|
699
|
-
throw new Error('Unexpected path format');
|
|
700
|
-
}
|
|
701
|
-
return [result[0], result[1]];
|
|
702
|
-
};
|
|
703
|
-
_i = 0, utxos_1 = utxos;
|
|
704
|
-
_a.label = 5;
|
|
705
|
-
case 5:
|
|
706
|
-
if (!(_i < utxos_1.length)) return [3 /*break*/, 9];
|
|
707
|
-
utxo = utxos_1[_i];
|
|
708
|
-
valueAccumulator = valueAccumulator.plus(utxo.value);
|
|
709
|
-
indexes = getPathIndexes(utxo.path);
|
|
710
|
-
return [4 /*yield*/, this.deriveFromExtendedPublicKey(extendedPublicKey, indexes[0], indexes[1])];
|
|
711
|
-
case 6:
|
|
712
|
-
derivedPublicKey = _a.sent();
|
|
713
|
-
return [4 /*yield*/, this.getAddressFromPublicKey(derivedPublicKey)];
|
|
714
|
-
case 7:
|
|
715
|
-
derivedAddress = _a.sent();
|
|
716
|
-
if (derivedAddress === utxo.address) {
|
|
717
|
-
transaction.ins.push({
|
|
718
|
-
txId: utxo.txid,
|
|
719
|
-
value: new bignumber_1.default(utxo.value).toString(10),
|
|
720
|
-
vout: utxo.vout,
|
|
721
|
-
address: utxo.address,
|
|
722
|
-
derivationPath: utxo.path
|
|
723
|
-
});
|
|
724
|
-
}
|
|
725
|
-
else {
|
|
726
|
-
throw new Error('Invalid address returned from API');
|
|
727
|
-
}
|
|
728
|
-
if (valueAccumulator.isGreaterThanOrEqualTo(totalRequiredBalance)) {
|
|
729
|
-
return [3 /*break*/, 9];
|
|
730
|
-
}
|
|
731
|
-
_a.label = 8;
|
|
732
|
-
case 8:
|
|
733
|
-
_i++;
|
|
734
|
-
return [3 /*break*/, 5];
|
|
735
|
-
case 9:
|
|
736
|
-
if (valueAccumulator.isLessThan(totalRequiredBalance)) {
|
|
737
|
-
throw new Error('not enough balance 2');
|
|
738
|
-
}
|
|
739
|
-
for (i = 0; i < details.length; i++) {
|
|
740
|
-
value = (0, module_kit_1.newAmount)(details[i].amount).blockchain(this.legacy.units).value;
|
|
741
|
-
transaction.outs.push({
|
|
742
|
-
recipient: details[i].to,
|
|
743
|
-
isChange: false,
|
|
744
|
-
value: value
|
|
745
|
-
});
|
|
746
|
-
valueAccumulator = valueAccumulator.minus(value);
|
|
747
|
-
}
|
|
748
|
-
lastUsedInternalAddress = Math.max.apply(Math, __spreadArray([-1], utxos
|
|
749
|
-
.map(function (utxo) { return getPathIndexes(utxo.path); })
|
|
750
|
-
.filter(function (indexes) { return indexes[0] === 1; })
|
|
751
|
-
.map(function (indexes) { return indexes[1]; }), false));
|
|
752
|
-
changeValue = valueAccumulator.minus(wrappedFee);
|
|
753
|
-
if (!changeValue.isGreaterThan(new bignumber_1.default(DUST_AMOUNT))) return [3 /*break*/, 12];
|
|
754
|
-
changeAddressIndex = lastUsedInternalAddress + 1;
|
|
755
|
-
return [4 /*yield*/, this.deriveFromExtendedPublicKey(extendedPublicKey, 1, changeAddressIndex)];
|
|
756
|
-
case 10:
|
|
757
|
-
derivedPublicKey = _a.sent();
|
|
758
|
-
return [4 /*yield*/, this.getAddressFromPublicKey(derivedPublicKey)];
|
|
759
|
-
case 11:
|
|
760
|
-
derivedAddress = _a.sent();
|
|
761
|
-
transaction.outs.push({
|
|
762
|
-
recipient: derivedAddress,
|
|
763
|
-
isChange: true,
|
|
764
|
-
value: changeValue.toString(10),
|
|
765
|
-
derivationPath: "1/".concat(changeAddressIndex)
|
|
766
|
-
});
|
|
767
|
-
_a.label = 12;
|
|
768
|
-
case 12:
|
|
769
|
-
psbt = new this.bitcoinJS.lib.Psbt();
|
|
770
|
-
// 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.
|
|
771
|
-
psbt.addUnknownKeyValToGlobal({
|
|
772
|
-
key: Buffer.from('amount'),
|
|
773
|
-
value: Buffer.from(details
|
|
774
|
-
.reduce(function (accumulator, next) {
|
|
775
|
-
return accumulator.plus((0, module_kit_1.newAmount)(next.amount).blockchain(_this.legacy.units).value);
|
|
776
|
-
}, new bignumber_1.default(0))
|
|
777
|
-
.toString())
|
|
778
|
-
});
|
|
779
|
-
xpubExtendedPublicKey = (0, key_1.convertExtendedPublicKey)(extendedPublicKey, { format: 'encoded', type: 'xpub' });
|
|
780
|
-
keyPair = this.bip32.fromBase58(xpubExtendedPublicKey.value);
|
|
781
|
-
replaceByFee = (configuration === null || configuration === void 0 ? void 0 : configuration.replaceByFee) ? true : false;
|
|
782
|
-
transaction.ins.forEach(function (tx) {
|
|
783
|
-
var indexes = getPathIndexes(tx.derivationPath);
|
|
784
|
-
var childNode = keyPair.derivePath(indexes.join('/'));
|
|
785
|
-
var payment = _this.bitcoinJS.lib.payments.p2wpkh({
|
|
786
|
-
pubkey: Buffer.from(childNode.publicKey),
|
|
787
|
-
network: _this.bitcoinJS.config.network
|
|
788
|
-
});
|
|
789
|
-
var p2shOutput = payment.output;
|
|
790
|
-
if (!p2shOutput) {
|
|
791
|
-
throw new Error('no p2shOutput');
|
|
792
|
-
}
|
|
793
|
-
psbt.addInput({
|
|
794
|
-
hash: tx.txId,
|
|
795
|
-
index: tx.vout,
|
|
796
|
-
sequence: replaceByFee ? 0xfffffffd : undefined,
|
|
797
|
-
witnessUtxo: {
|
|
798
|
-
script: p2shOutput,
|
|
799
|
-
value: parseInt(tx.value, 10)
|
|
800
|
-
},
|
|
801
|
-
bip32Derivation: [
|
|
802
|
-
{
|
|
803
|
-
masterFingerprint: Buffer.from(configuration.masterFingerprint.value, 'hex'),
|
|
804
|
-
pubkey: Buffer.from(childNode.publicKey),
|
|
805
|
-
path: tx.derivationPath
|
|
806
|
-
}
|
|
807
|
-
]
|
|
808
|
-
});
|
|
809
|
-
});
|
|
810
|
-
transaction.outs.forEach(function (out, index) {
|
|
811
|
-
psbt.addOutput({ address: out.recipient, value: parseInt(out.value, 10) });
|
|
812
|
-
if (out.derivationPath) {
|
|
813
|
-
// We add the derivation path of our change address to the key value map of the PSBT. This will allow us to later "filter" out this address when displaying the transaction info.
|
|
814
|
-
psbt.addUnknownKeyValToOutput(index, {
|
|
815
|
-
key: Buffer.from('dp'),
|
|
816
|
-
value: Buffer.from(out.derivationPath, 'utf8')
|
|
817
|
-
});
|
|
818
|
-
}
|
|
819
|
-
});
|
|
820
|
-
return [2 /*return*/, (0, module_kit_1.newUnsignedTransaction)({ psbt: psbt.toHex() })];
|
|
821
|
-
}
|
|
822
|
-
});
|
|
454
|
+
const { data: utxos } = await index_1.default.get(`${this.options.network.indexerApi}/api/v2/utxo/${extendedPublicKey.value}?confirmed=true`, {
|
|
455
|
+
responseType: 'json'
|
|
823
456
|
});
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
457
|
+
if (utxos.length <= 0) {
|
|
458
|
+
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
|
|
459
|
+
}
|
|
460
|
+
const totalRequiredBalance = details
|
|
461
|
+
.map(({ amount }) => new bignumber_1.default((0, module_kit_1.newAmount)(amount).blockchain(this.legacy.units).value))
|
|
462
|
+
.reduce((accumulator, currentValue) => accumulator.plus(currentValue))
|
|
463
|
+
.plus(wrappedFee);
|
|
464
|
+
let valueAccumulator = new bignumber_1.default(0);
|
|
465
|
+
const getPathIndexes = (path) => {
|
|
466
|
+
const result = path
|
|
467
|
+
.split('/')
|
|
468
|
+
.slice(-2)
|
|
469
|
+
.map((item) => parseInt(item))
|
|
470
|
+
.filter((item) => !isNaN(item));
|
|
471
|
+
if (result.length !== 2) {
|
|
472
|
+
throw new Error('Unexpected path format');
|
|
473
|
+
}
|
|
474
|
+
return [result[0], result[1]];
|
|
475
|
+
};
|
|
476
|
+
for (const utxo of utxos) {
|
|
477
|
+
valueAccumulator = valueAccumulator.plus(utxo.value);
|
|
478
|
+
const indexes = getPathIndexes(utxo.path);
|
|
479
|
+
const derivedPublicKey = await this.deriveFromExtendedPublicKey(extendedPublicKey, indexes[0], indexes[1]);
|
|
480
|
+
const derivedAddress = await this.getAddressFromPublicKey(derivedPublicKey);
|
|
481
|
+
if (derivedAddress === utxo.address) {
|
|
482
|
+
transaction.ins.push({
|
|
483
|
+
txId: utxo.txid,
|
|
484
|
+
value: new bignumber_1.default(utxo.value).toString(10),
|
|
485
|
+
vout: utxo.vout,
|
|
486
|
+
address: utxo.address,
|
|
487
|
+
derivationPath: utxo.path
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
throw new Error('Invalid address returned from API');
|
|
492
|
+
}
|
|
493
|
+
if (valueAccumulator.isGreaterThanOrEqualTo(totalRequiredBalance)) {
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (valueAccumulator.isLessThan(totalRequiredBalance)) {
|
|
498
|
+
throw new Error('not enough balance 2');
|
|
499
|
+
}
|
|
500
|
+
for (let i = 0; i < details.length; i++) {
|
|
501
|
+
const value = (0, module_kit_1.newAmount)(details[i].amount).blockchain(this.legacy.units).value;
|
|
502
|
+
transaction.outs.push({
|
|
503
|
+
recipient: details[i].to,
|
|
504
|
+
isChange: false,
|
|
505
|
+
value
|
|
506
|
+
});
|
|
507
|
+
valueAccumulator = valueAccumulator.minus(value);
|
|
508
|
+
}
|
|
509
|
+
const lastUsedInternalAddress = Math.max(-1, ...utxos
|
|
510
|
+
.map((utxo) => getPathIndexes(utxo.path))
|
|
511
|
+
.filter((indexes) => indexes[0] === 1)
|
|
512
|
+
.map((indexes) => indexes[1]));
|
|
513
|
+
// If the change is considered dust, the transaction will fail.
|
|
514
|
+
// Dust is a variable value around 300-600 satoshis, depending on the configuration.
|
|
515
|
+
// We set a low fee here to not block any transactions, but it might still fail due to "dust".
|
|
516
|
+
const changeValue = valueAccumulator.minus(wrappedFee);
|
|
517
|
+
if (changeValue.isGreaterThan(new bignumber_1.default(DUST_AMOUNT))) {
|
|
518
|
+
const changeAddressIndex = lastUsedInternalAddress + 1;
|
|
519
|
+
const derivedPublicKey = await this.deriveFromExtendedPublicKey(extendedPublicKey, 1, changeAddressIndex);
|
|
520
|
+
const derivedAddress = await this.getAddressFromPublicKey(derivedPublicKey);
|
|
521
|
+
transaction.outs.push({
|
|
522
|
+
recipient: derivedAddress,
|
|
523
|
+
isChange: true,
|
|
524
|
+
value: changeValue.toString(10),
|
|
525
|
+
derivationPath: `1/${changeAddressIndex}`
|
|
837
526
|
});
|
|
527
|
+
}
|
|
528
|
+
const psbt = new this.bitcoinJS.lib.Psbt();
|
|
529
|
+
// 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.
|
|
530
|
+
psbt.addUnknownKeyValToGlobal({
|
|
531
|
+
key: Buffer.from('amount'),
|
|
532
|
+
value: Buffer.from(details
|
|
533
|
+
.reduce((accumulator, next) => {
|
|
534
|
+
return accumulator.plus((0, module_kit_1.newAmount)(next.amount).blockchain(this.legacy.units).value);
|
|
535
|
+
}, new bignumber_1.default(0))
|
|
536
|
+
.toString())
|
|
537
|
+
});
|
|
538
|
+
const xpubExtendedPublicKey = (0, key_1.convertExtendedPublicKey)(extendedPublicKey, { format: 'encoded', type: 'xpub' });
|
|
539
|
+
const keyPair = this.bip32.fromBase58(xpubExtendedPublicKey.value);
|
|
540
|
+
const replaceByFee = configuration?.replaceByFee ? true : false;
|
|
541
|
+
transaction.ins.forEach((tx) => {
|
|
542
|
+
const indexes = getPathIndexes(tx.derivationPath);
|
|
543
|
+
const childNode = keyPair.derivePath(indexes.join('/'));
|
|
544
|
+
const payment = this.bitcoinJS.lib.payments.p2wpkh({
|
|
545
|
+
pubkey: Buffer.from(childNode.publicKey),
|
|
546
|
+
network: this.bitcoinJS.config.network
|
|
547
|
+
});
|
|
548
|
+
const p2shOutput = payment.output;
|
|
549
|
+
if (!p2shOutput) {
|
|
550
|
+
throw new Error('no p2shOutput');
|
|
551
|
+
}
|
|
552
|
+
psbt.addInput({
|
|
553
|
+
hash: tx.txId,
|
|
554
|
+
index: tx.vout,
|
|
555
|
+
sequence: replaceByFee ? 0xfffffffd : undefined, // Needs to be at least 2 below max int value to be RBF
|
|
556
|
+
witnessUtxo: {
|
|
557
|
+
script: p2shOutput,
|
|
558
|
+
value: parseInt(tx.value, 10)
|
|
559
|
+
},
|
|
560
|
+
bip32Derivation: [
|
|
561
|
+
{
|
|
562
|
+
masterFingerprint: Buffer.from(configuration.masterFingerprint.value, 'hex'),
|
|
563
|
+
pubkey: Buffer.from(childNode.publicKey),
|
|
564
|
+
path: tx.derivationPath
|
|
565
|
+
}
|
|
566
|
+
]
|
|
567
|
+
});
|
|
568
|
+
});
|
|
569
|
+
transaction.outs.forEach((out, index) => {
|
|
570
|
+
psbt.addOutput({ address: out.recipient, value: parseInt(out.value, 10) });
|
|
571
|
+
if (out.derivationPath) {
|
|
572
|
+
// We add the derivation path of our change address to the key value map of the PSBT. This will allow us to later "filter" out this address when displaying the transaction info.
|
|
573
|
+
psbt.addUnknownKeyValToOutput(index, {
|
|
574
|
+
key: Buffer.from('dp'),
|
|
575
|
+
value: Buffer.from(out.derivationPath, 'utf8')
|
|
576
|
+
});
|
|
577
|
+
}
|
|
838
578
|
});
|
|
839
|
-
|
|
579
|
+
return (0, module_kit_1.newUnsignedTransaction)({ psbt: psbt.toHex() });
|
|
580
|
+
}
|
|
581
|
+
async broadcastTransaction(transaction) {
|
|
582
|
+
const hexTransaction = this.bitcoinJS.lib.Psbt.fromHex(transaction.psbt).finalizeAllInputs().extractTransaction().toHex();
|
|
583
|
+
const { data } = await index_1.default.post(`${this.options.network.indexerApi}/api/v2/sendtx/`, hexTransaction);
|
|
584
|
+
return data.result;
|
|
585
|
+
}
|
|
840
586
|
// Custom
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
587
|
+
convertCryptoDerivative(derivative) {
|
|
588
|
+
const hexNode = (0, crypto_1.encodeDerivative)('hex', {
|
|
589
|
+
...derivative,
|
|
590
|
+
secretKey: `00${derivative.secretKey}`
|
|
591
|
+
});
|
|
592
|
+
const extendedSecretKey = {
|
|
844
593
|
type: 'xpriv',
|
|
845
594
|
format: 'hex',
|
|
846
595
|
value: hexNode.secretKey
|
|
847
596
|
};
|
|
848
597
|
return (0, key_1.convertExtendedSecretKey)(extendedSecretKey, { format: 'encoded', type: 'xprv' });
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
|
|
598
|
+
}
|
|
599
|
+
derivativeToBip32Node(derivative) {
|
|
600
|
+
const extendedSecretKey = this.convertCryptoDerivative(derivative);
|
|
852
601
|
return this.bip32.fromBase58(extendedSecretKey.value, this.bitcoinJS.config.network);
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
}());
|
|
602
|
+
}
|
|
603
|
+
}
|
|
856
604
|
exports.BitcoinSegwitProtocolImpl = BitcoinSegwitProtocolImpl;
|
|
857
605
|
// Factory
|
|
858
|
-
function createBitcoinSegwitProtocol(options) {
|
|
859
|
-
if (options === void 0) { options = {}; }
|
|
606
|
+
function createBitcoinSegwitProtocol(options = {}) {
|
|
860
607
|
return new BitcoinSegwitProtocolImpl(options);
|
|
861
608
|
}
|
|
862
|
-
exports.createBitcoinSegwitProtocol = createBitcoinSegwitProtocol;
|
|
863
609
|
//# sourceMappingURL=BitcoinSegwitProtocol.js.map
|