@airgap/bitcoin 0.13.45-beta.3 → 0.13.45-beta.4
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 +9 -8
- package/v0/protocol/BitcoinAddress.js.map +1 -1
- package/v0/protocol/BitcoinCryptoClient.js +85 -16
- package/v0/protocol/BitcoinCryptoClient.js.map +1 -1
- package/v0/protocol/BitcoinProtocol.js +987 -590
- package/v0/protocol/BitcoinProtocol.js.map +1 -1
- package/v0/protocol/BitcoinProtocolOptions.js +111 -45
- package/v0/protocol/BitcoinProtocolOptions.js.map +1 -1
- package/v0/protocol/BitcoinSegwitAddress.js +29 -12
- package/v0/protocol/BitcoinSegwitAddress.js.map +1 -1
- package/v0/protocol/BitcoinSegwitProtocol.js +483 -348
- package/v0/protocol/BitcoinSegwitProtocol.js.map +1 -1
- package/v0/protocol/BitcoinTestnetProtocol.js +36 -28
- package/v0/protocol/BitcoinTestnetProtocol.js.map +1 -1
- package/v0/serializer/validators/transaction-validator.js +30 -22
- 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 +61 -12
- package/v1/block-explorer/BlockCypherBlockExplorer.js.map +1 -1
- package/v1/data/BitcoinAddress.js +10 -9
- package/v1/data/BitcoinAddress.js.map +1 -1
- package/v1/data/BitcoinLegacyAddress.js +12 -11
- package/v1/data/BitcoinLegacyAddress.js.map +1 -1
- package/v1/data/BitcoinSegwitAddress.js +12 -11
- package/v1/data/BitcoinSegwitAddress.js.map +1 -1
- package/v1/data/BitcoinTaprootAddress.js +22 -31
- 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 +102 -44
- package/v1/module/BitcoinModule.js.map +1 -1
- package/v1/module.js +3 -2
- package/v1/module.js.map +1 -1
- package/v1/protocol/BitcoinCryptoClient.js +90 -22
- package/v1/protocol/BitcoinCryptoClient.js.map +1 -1
- package/v1/protocol/BitcoinLegacyProtocol.js +796 -520
- package/v1/protocol/BitcoinLegacyProtocol.js.map +1 -1
- package/v1/protocol/BitcoinProtocol.js +1169 -735
- package/v1/protocol/BitcoinProtocol.js.map +1 -1
- package/v1/protocol/BitcoinSegwitProtocol.js +796 -542
- package/v1/protocol/BitcoinSegwitProtocol.js.map +1 -1
- package/v1/protocol/BitcoinTaprootProtocol.js +1000 -688
- package/v1/protocol/BitcoinTaprootProtocol.js.map +1 -1
- package/v1/protocol/BitcoinTestnetProtocol.js +33 -14
- package/v1/protocol/BitcoinTestnetProtocol.js.map +1 -1
- package/v1/serializer/v3/schemas/converter/transaction-converter.js +52 -29
- package/v1/serializer/v3/schemas/converter/transaction-converter.js.map +1 -1
- package/v1/serializer/v3/serializer-companion.js +165 -98
- package/v1/serializer/v3/serializer-companion.js.map +1 -1
- package/v1/serializer/v3/validators/transaction-validator.js +16 -13
- package/v1/serializer/v3/validators/transaction-validator.js.map +1 -1
- package/v1/serializer/v3/validators/validators.js +213 -122
- 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 +6 -4
- package/v1/utils/common.js.map +1 -1
- package/v1/utils/key.d.ts +6 -5
- package/v1/utils/key.js +39 -38
- package/v1/utils/key.js.map +1 -1
- package/v1/utils/network.js +4 -3
- package/v1/utils/network.js.map +1 -1
- package/v1/utils/protocol.js +19 -25
- package/v1/utils/protocol.js.map +1 -1
- package/v1/utils/signature.js +5 -4
- package/v1/utils/signature.js.map +1 -1
|
@@ -1,4 +1,15 @@
|
|
|
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
|
+
};
|
|
2
13
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
14
|
if (k2 === undefined) k2 = k;
|
|
4
15
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -15,49 +26,85 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
26
|
}) : function(o, v) {
|
|
16
27
|
o["default"] = v;
|
|
17
28
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) ||
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
};
|
|
27
|
-
return function (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
37
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
38
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
39
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
40
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
41
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
42
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
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
|
+
};
|
|
35
81
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
82
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
83
|
};
|
|
38
84
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.BITCOIN_MAINNET_PROTOCOL_NETWORK = exports.BitcoinProtocolImpl = void 0;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const signature_1 = require("../utils/signature");
|
|
56
|
-
const BitcoinCryptoClient_1 = require("./BitcoinCryptoClient");
|
|
85
|
+
exports.createBitcoinProtocolOptions = exports.BITCOIN_MAINNET_PROTOCOL_NETWORK = exports.createBitcoinProtocol = exports.BitcoinProtocolImpl = void 0;
|
|
86
|
+
var coinlib_core_1 = require("@airgap/coinlib-core");
|
|
87
|
+
var index_1 = __importDefault(require("@airgap/coinlib-core/dependencies/src/axios-0.19.0/index"));
|
|
88
|
+
var BigInteger = __importStar(require("@airgap/coinlib-core/dependencies/src/bigi-1.4.2"));
|
|
89
|
+
var bignumber_1 = __importDefault(require("@airgap/coinlib-core/dependencies/src/bignumber.js-9.0.0/bignumber"));
|
|
90
|
+
var bitcoinMessage = __importStar(require("@airgap/coinlib-core/dependencies/src/bitcoinjs-message-2.1.1/index"));
|
|
91
|
+
var BitGo = __importStar(require("@airgap/coinlib-core/dependencies/src/bitgo-utxo-lib-5d91049fd7a988382df81c8260e244ee56d57aac/src/index"));
|
|
92
|
+
var errors_1 = require("@airgap/coinlib-core/errors");
|
|
93
|
+
var crypto_1 = require("@airgap/crypto");
|
|
94
|
+
var module_kit_1 = require("@airgap/module-kit");
|
|
95
|
+
var BitcoinAddress_1 = require("../data/BitcoinAddress");
|
|
96
|
+
var common_1 = require("../utils/common");
|
|
97
|
+
var key_1 = require("../utils/key");
|
|
98
|
+
var network_1 = require("../utils/network");
|
|
99
|
+
var signature_1 = require("../utils/signature");
|
|
100
|
+
var BitcoinCryptoClient_1 = require("./BitcoinCryptoClient");
|
|
57
101
|
// Implementation
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
102
|
+
var DUST_AMOUNT = 50;
|
|
103
|
+
var BitcoinProtocolImpl = /** @class */ (function () {
|
|
104
|
+
function BitcoinProtocolImpl(options, keyConfiguration, bitcoinJS, bitcoinJSMessage) {
|
|
105
|
+
if (options === void 0) { options = {}; }
|
|
106
|
+
if (bitcoinJS === void 0) { bitcoinJS = BitGo; }
|
|
107
|
+
if (bitcoinJSMessage === void 0) { bitcoinJSMessage = bitcoinMessage; }
|
|
61
108
|
this._isBitcoinProtocol = true;
|
|
62
109
|
// Common
|
|
63
110
|
this.units = {
|
|
@@ -88,7 +135,7 @@ class BitcoinProtocolImpl {
|
|
|
88
135
|
defaults: this.feeDefaults
|
|
89
136
|
},
|
|
90
137
|
account: {
|
|
91
|
-
standardDerivationPath:
|
|
138
|
+
standardDerivationPath: "m/44'/0'/0'",
|
|
92
139
|
address: {
|
|
93
140
|
isCaseSensitive: true,
|
|
94
141
|
placeholder: '1ABC...',
|
|
@@ -109,7 +156,7 @@ class BitcoinProtocolImpl {
|
|
|
109
156
|
}
|
|
110
157
|
};
|
|
111
158
|
this.cryptoClient = new BitcoinCryptoClient_1.BitcoinCryptoClient(this, this.bitcoinJS);
|
|
112
|
-
this.keyConfiguration = keyConfiguration
|
|
159
|
+
this.keyConfiguration = keyConfiguration !== null && keyConfiguration !== void 0 ? keyConfiguration : {
|
|
113
160
|
xpriv: {
|
|
114
161
|
type: 'xprv'
|
|
115
162
|
},
|
|
@@ -118,748 +165,1134 @@ class BitcoinProtocolImpl {
|
|
|
118
165
|
}
|
|
119
166
|
};
|
|
120
167
|
}
|
|
121
|
-
|
|
122
|
-
return this
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
async getAddressFromExtendedPublicKey(extendedPublicKey) {
|
|
141
|
-
const encodedExtendedPublicKey = this.convertExtendedPublicKey(extendedPublicKey, 'encoded');
|
|
142
|
-
const node = this.bitcoinJS.lib.HDNode.fromBase58(encodedExtendedPublicKey.value, this.bitcoinJS.config.network);
|
|
143
|
-
return BitcoinAddress_1.BitcoinAddress.fromHDNode(node).asString();
|
|
144
|
-
}
|
|
145
|
-
async deriveFromExtendedPublicKey(extendedPublicKey, visibilityIndex, addressIndex) {
|
|
146
|
-
const encodedExtendedPublicKey = this.convertExtendedPublicKey(extendedPublicKey, 'encoded');
|
|
147
|
-
const childPublicKey = this.bitcoinJS.lib.HDNode.fromBase58(encodedExtendedPublicKey.value, this.bitcoinJS.config.network)
|
|
148
|
-
.derive(visibilityIndex)
|
|
149
|
-
.derive(addressIndex)
|
|
150
|
-
.getPublicKeyBuffer();
|
|
151
|
-
return (0, module_kit_1.newPublicKey)(childPublicKey.toString('hex'), 'hex');
|
|
152
|
-
}
|
|
153
|
-
async getDetailsFromTransaction(transaction, _publicKey) {
|
|
154
|
-
switch (transaction.type) {
|
|
155
|
-
case 'signed':
|
|
156
|
-
return this.getDetailsFromSignedTransaction(transaction);
|
|
157
|
-
case 'unsigned':
|
|
158
|
-
return this.getDetailsFromUnsignedTransaction(transaction, _publicKey);
|
|
159
|
-
default:
|
|
160
|
-
(0, coinlib_core_1.assertNever)(transaction);
|
|
161
|
-
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Unsupported transaction type.');
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
async getDetailsFromSignedTransaction(transaction) {
|
|
165
|
-
const tx = {
|
|
166
|
-
from: transaction.from,
|
|
167
|
-
to: [],
|
|
168
|
-
isInbound: false,
|
|
169
|
-
amount: (0, module_kit_1.newAmount)(transaction.amount, 'blockchain'),
|
|
170
|
-
fee: (0, module_kit_1.newAmount)(transaction.fee, 'blockchain'),
|
|
171
|
-
network: this.options.network
|
|
172
|
-
};
|
|
173
|
-
const bitcoinTx = this.bitcoinJS.lib.Transaction.fromHex(transaction.transaction);
|
|
174
|
-
bitcoinTx.outs.forEach((output) => {
|
|
175
|
-
const address = this.bitcoinJS.lib.address.fromOutputScript(output.script, this.bitcoinJS.config.network);
|
|
176
|
-
// only works if one output is target and rest is change, but this way we can filter out change addresses
|
|
177
|
-
// if (new BigNumber(output.value).isEqualTo(transaction.amount)) {
|
|
178
|
-
tx.to.push(address);
|
|
179
|
-
// }
|
|
180
|
-
});
|
|
181
|
-
return [tx];
|
|
182
|
-
}
|
|
183
|
-
async getDetailsFromUnsignedTransaction(transaction, publickey) {
|
|
184
|
-
let fee = new bignumber_1.default(0);
|
|
185
|
-
for (const txIn of transaction.ins) {
|
|
186
|
-
fee = fee.plus(new bignumber_1.default(txIn.value));
|
|
187
|
-
}
|
|
188
|
-
for (const txOut of transaction.outs) {
|
|
189
|
-
fee = fee.minus(new bignumber_1.default(txOut.value));
|
|
190
|
-
}
|
|
191
|
-
const uiAlerts = [];
|
|
192
|
-
const changeAddressDatas = await Promise.all(transaction.outs.map(async (obj) => {
|
|
193
|
-
let isChangeAddress = obj.isChange ? obj.isChange : false;
|
|
194
|
-
let isOwned = false;
|
|
195
|
-
let addressIndex = 0;
|
|
196
|
-
const address = obj.recipient;
|
|
197
|
-
const amount = obj.value;
|
|
198
|
-
let ourGeneratedAddress;
|
|
199
|
-
if (isChangeAddress) {
|
|
200
|
-
const splitPath = obj.derivationPath.split('/');
|
|
201
|
-
addressIndex = +splitPath[splitPath.length - 1];
|
|
202
|
-
if (publickey.type === 'xpub') {
|
|
203
|
-
const ourPublickey = await this.deriveFromExtendedPublicKey(publickey, 1, addressIndex);
|
|
204
|
-
ourGeneratedAddress = await this.getAddressFromPublicKey(ourPublickey);
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
ourGeneratedAddress = await this.getAddressFromNonExtendedPublicKey(publickey);
|
|
208
|
-
}
|
|
209
|
-
if (ourGeneratedAddress === address) {
|
|
210
|
-
isOwned = true;
|
|
168
|
+
BitcoinProtocolImpl.prototype.getMetadata = function () {
|
|
169
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
170
|
+
return __generator(this, function (_a) {
|
|
171
|
+
return [2 /*return*/, this.metadata];
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
BitcoinProtocolImpl.prototype.getAddressFromPublicKey = function (publicKey) {
|
|
176
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
177
|
+
return __generator(this, function (_a) {
|
|
178
|
+
switch (publicKey.type) {
|
|
179
|
+
case 'pub':
|
|
180
|
+
return [2 /*return*/, this.getAddressFromNonExtendedPublicKey(publicKey)];
|
|
181
|
+
case 'xpub':
|
|
182
|
+
return [2 /*return*/, this.getAddressFromExtendedPublicKey(publicKey)];
|
|
183
|
+
default:
|
|
184
|
+
(0, coinlib_core_1.assertNever)(publicKey);
|
|
185
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Public key type is not supported.');
|
|
211
186
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
187
|
+
return [2 /*return*/];
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
BitcoinProtocolImpl.prototype.getAddressFromNonExtendedPublicKey = function (publicKey) {
|
|
192
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
193
|
+
var hexPublicKey, keyPair;
|
|
194
|
+
return __generator(this, function (_a) {
|
|
195
|
+
hexPublicKey = (0, key_1.convertPublicKey)(publicKey, 'hex');
|
|
196
|
+
keyPair = this.bitcoinJS.lib.ECPair.fromPublicKeyBuffer(Buffer.from(hexPublicKey.value, 'hex'), this.bitcoinJS.config.network);
|
|
197
|
+
return [2 /*return*/, BitcoinAddress_1.BitcoinAddress.fromECPair(keyPair).asString()];
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
BitcoinProtocolImpl.prototype.getAddressFromExtendedPublicKey = function (extendedPublicKey) {
|
|
202
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
203
|
+
var encodedExtendedPublicKey, node;
|
|
204
|
+
return __generator(this, function (_a) {
|
|
205
|
+
encodedExtendedPublicKey = this.convertExtendedPublicKey(extendedPublicKey, 'encoded');
|
|
206
|
+
node = this.bitcoinJS.lib.HDNode.fromBase58(encodedExtendedPublicKey.value, this.bitcoinJS.config.network);
|
|
207
|
+
return [2 /*return*/, BitcoinAddress_1.BitcoinAddress.fromHDNode(node).asString()];
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
BitcoinProtocolImpl.prototype.deriveFromExtendedPublicKey = function (extendedPublicKey, visibilityIndex, addressIndex) {
|
|
212
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
213
|
+
var encodedExtendedPublicKey, childPublicKey;
|
|
214
|
+
return __generator(this, function (_a) {
|
|
215
|
+
encodedExtendedPublicKey = this.convertExtendedPublicKey(extendedPublicKey, 'encoded');
|
|
216
|
+
childPublicKey = this.bitcoinJS.lib.HDNode.fromBase58(encodedExtendedPublicKey.value, this.bitcoinJS.config.network)
|
|
217
|
+
.derive(visibilityIndex)
|
|
218
|
+
.derive(addressIndex)
|
|
219
|
+
.getPublicKeyBuffer();
|
|
220
|
+
return [2 /*return*/, (0, module_kit_1.newPublicKey)(childPublicKey.toString('hex'), 'hex')];
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
BitcoinProtocolImpl.prototype.getDetailsFromTransaction = function (transaction, _publicKey) {
|
|
225
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
226
|
+
return __generator(this, function (_a) {
|
|
227
|
+
switch (transaction.type) {
|
|
228
|
+
case 'signed':
|
|
229
|
+
return [2 /*return*/, this.getDetailsFromSignedTransaction(transaction)];
|
|
230
|
+
case 'unsigned':
|
|
231
|
+
return [2 /*return*/, this.getDetailsFromUnsignedTransaction(transaction, _publicKey)];
|
|
232
|
+
default:
|
|
233
|
+
(0, coinlib_core_1.assertNever)(transaction);
|
|
234
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Unsupported transaction type.');
|
|
222
235
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
type: 'plain',
|
|
248
|
-
value: 'Note: your change address has not been verified'
|
|
249
|
-
},
|
|
250
|
-
icon: undefined,
|
|
251
|
-
actions: undefined
|
|
236
|
+
return [2 /*return*/];
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
};
|
|
240
|
+
BitcoinProtocolImpl.prototype.getDetailsFromSignedTransaction = function (transaction) {
|
|
241
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
242
|
+
var tx, bitcoinTx;
|
|
243
|
+
var _this = this;
|
|
244
|
+
return __generator(this, function (_a) {
|
|
245
|
+
tx = {
|
|
246
|
+
from: transaction.from,
|
|
247
|
+
to: [],
|
|
248
|
+
isInbound: false,
|
|
249
|
+
amount: (0, module_kit_1.newAmount)(transaction.amount, 'blockchain'),
|
|
250
|
+
fee: (0, module_kit_1.newAmount)(transaction.fee, 'blockchain'),
|
|
251
|
+
network: this.options.network
|
|
252
|
+
};
|
|
253
|
+
bitcoinTx = this.bitcoinJS.lib.Transaction.fromHex(transaction.transaction);
|
|
254
|
+
bitcoinTx.outs.forEach(function (output) {
|
|
255
|
+
var address = _this.bitcoinJS.lib.address.fromOutputScript(output.script, _this.bitcoinJS.config.network);
|
|
256
|
+
// only works if one output is target and rest is change, but this way we can filter out change addresses
|
|
257
|
+
// if (new BigNumber(output.value).isEqualTo(transaction.amount)) {
|
|
258
|
+
tx.to.push(address);
|
|
259
|
+
// }
|
|
252
260
|
});
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
+
return [2 /*return*/, [tx]];
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
};
|
|
265
|
+
BitcoinProtocolImpl.prototype.getDetailsFromUnsignedTransaction = function (transaction, publickey) {
|
|
266
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
267
|
+
var fee, _i, _a, txIn, _b, _c, txOut, uiAlerts, changeAddressDatas, changeAddressInfo;
|
|
268
|
+
var _this = this;
|
|
269
|
+
return __generator(this, function (_d) {
|
|
270
|
+
switch (_d.label) {
|
|
271
|
+
case 0:
|
|
272
|
+
fee = new bignumber_1.default(0);
|
|
273
|
+
for (_i = 0, _a = transaction.ins; _i < _a.length; _i++) {
|
|
274
|
+
txIn = _a[_i];
|
|
275
|
+
fee = fee.plus(new bignumber_1.default(txIn.value));
|
|
276
|
+
}
|
|
277
|
+
for (_b = 0, _c = transaction.outs; _b < _c.length; _b++) {
|
|
278
|
+
txOut = _c[_b];
|
|
279
|
+
fee = fee.minus(new bignumber_1.default(txOut.value));
|
|
280
|
+
}
|
|
281
|
+
uiAlerts = [];
|
|
282
|
+
return [4 /*yield*/, Promise.all(transaction.outs.map(function (obj) { return __awaiter(_this, void 0, void 0, function () {
|
|
283
|
+
var isChangeAddress, isOwned, addressIndex, address, amount, ourGeneratedAddress, splitPath, ourPublickey, x, ourPublickey;
|
|
284
|
+
return __generator(this, function (_a) {
|
|
285
|
+
switch (_a.label) {
|
|
286
|
+
case 0:
|
|
287
|
+
isChangeAddress = obj.isChange ? obj.isChange : false;
|
|
288
|
+
isOwned = false;
|
|
289
|
+
addressIndex = 0;
|
|
290
|
+
address = obj.recipient;
|
|
291
|
+
amount = obj.value;
|
|
292
|
+
if (!isChangeAddress) return [3 /*break*/, 11];
|
|
293
|
+
splitPath = obj.derivationPath.split('/');
|
|
294
|
+
addressIndex = +splitPath[splitPath.length - 1];
|
|
295
|
+
if (!(publickey.type === 'xpub')) return [3 /*break*/, 3];
|
|
296
|
+
return [4 /*yield*/, this.deriveFromExtendedPublicKey(publickey, 1, addressIndex)];
|
|
297
|
+
case 1:
|
|
298
|
+
ourPublickey = _a.sent();
|
|
299
|
+
return [4 /*yield*/, this.getAddressFromPublicKey(ourPublickey)];
|
|
300
|
+
case 2:
|
|
301
|
+
ourGeneratedAddress = _a.sent();
|
|
302
|
+
return [3 /*break*/, 5];
|
|
303
|
+
case 3: return [4 /*yield*/, this.getAddressFromNonExtendedPublicKey(publickey)];
|
|
304
|
+
case 4:
|
|
305
|
+
ourGeneratedAddress = _a.sent();
|
|
306
|
+
_a.label = 5;
|
|
307
|
+
case 5:
|
|
308
|
+
if (!(ourGeneratedAddress === address)) return [3 /*break*/, 6];
|
|
309
|
+
isOwned = true;
|
|
310
|
+
return [3 /*break*/, 11];
|
|
311
|
+
case 6:
|
|
312
|
+
x = 0;
|
|
313
|
+
_a.label = 7;
|
|
314
|
+
case 7:
|
|
315
|
+
if (!(x < 1000)) return [3 /*break*/, 11];
|
|
316
|
+
return [4 /*yield*/, this.deriveFromExtendedPublicKey(publickey, 1, x)];
|
|
317
|
+
case 8:
|
|
318
|
+
ourPublickey = _a.sent();
|
|
319
|
+
return [4 /*yield*/, this.getAddressFromPublicKey(ourPublickey)];
|
|
320
|
+
case 9:
|
|
321
|
+
ourGeneratedAddress = _a.sent();
|
|
322
|
+
if (ourGeneratedAddress === address) {
|
|
323
|
+
isOwned = true;
|
|
324
|
+
addressIndex = x;
|
|
325
|
+
return [3 /*break*/, 11];
|
|
326
|
+
}
|
|
327
|
+
_a.label = 10;
|
|
328
|
+
case 10:
|
|
329
|
+
x++;
|
|
330
|
+
return [3 /*break*/, 7];
|
|
331
|
+
case 11:
|
|
332
|
+
if (isChangeAddress && isOwned) {
|
|
333
|
+
uiAlerts.push({
|
|
334
|
+
type: 'success',
|
|
335
|
+
title: {
|
|
336
|
+
type: 'plain',
|
|
337
|
+
value: ''
|
|
338
|
+
},
|
|
339
|
+
description: {
|
|
340
|
+
type: 'plain',
|
|
341
|
+
value: 'Note: your change address has been verified'
|
|
342
|
+
},
|
|
343
|
+
icon: undefined,
|
|
344
|
+
actions: undefined
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
else if (isChangeAddress && !isOwned) {
|
|
348
|
+
uiAlerts.push({
|
|
349
|
+
type: 'warning',
|
|
350
|
+
title: {
|
|
351
|
+
type: 'plain',
|
|
352
|
+
value: ''
|
|
353
|
+
},
|
|
354
|
+
description: {
|
|
355
|
+
type: 'plain',
|
|
356
|
+
value: 'Note: your change address has not been verified'
|
|
357
|
+
},
|
|
358
|
+
icon: undefined,
|
|
359
|
+
actions: undefined
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
return [2 /*return*/, [
|
|
363
|
+
address,
|
|
364
|
+
{
|
|
365
|
+
isChangeAddress: isChangeAddress,
|
|
366
|
+
isOwned: isOwned,
|
|
367
|
+
path: addressIndex === 0 ? '' : "m/84'/0'/0'/1/".concat(addressIndex),
|
|
368
|
+
amount: amount
|
|
369
|
+
}
|
|
370
|
+
]];
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
}); }))];
|
|
374
|
+
case 1:
|
|
375
|
+
changeAddressDatas = _d.sent();
|
|
376
|
+
changeAddressInfo = {};
|
|
377
|
+
changeAddressDatas.forEach(function (changeAddressData) {
|
|
378
|
+
changeAddressInfo[changeAddressData[0]] = changeAddressData[1];
|
|
379
|
+
});
|
|
380
|
+
return [2 /*return*/, [
|
|
381
|
+
{
|
|
382
|
+
from: transaction.ins.map(function (obj) { return obj.address; }),
|
|
383
|
+
to: transaction.outs.map(function (obj) { return obj.recipient; }),
|
|
384
|
+
isInbound: false,
|
|
385
|
+
amount: (0, module_kit_1.newAmount)(transaction.outs.map(function (obj) { return new bignumber_1.default(obj.value); }).reduce(function (accumulator, currentValue) { return accumulator.plus(currentValue); }), 'blockchain'),
|
|
386
|
+
fee: (0, module_kit_1.newAmount)(fee, 'blockchain'),
|
|
387
|
+
network: this.options.network,
|
|
388
|
+
changeAddressInfo: changeAddressInfo,
|
|
389
|
+
uiAlerts: uiAlerts
|
|
390
|
+
}
|
|
391
|
+
]];
|
|
261
392
|
}
|
|
262
|
-
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
return this.cryptoConfiguration;
|
|
292
|
-
}
|
|
293
|
-
async getKeyPairFromDerivative(derivative) {
|
|
294
|
-
const node = this.derivativeToBip32Node(derivative);
|
|
295
|
-
return {
|
|
296
|
-
secretKey: (0, module_kit_1.newSecretKey)(node.keyPair.getPrivateKeyBuffer().toString('hex'), 'hex'),
|
|
297
|
-
publicKey: (0, module_kit_1.newPublicKey)(node.keyPair.getPublicKeyBuffer().toString('hex'), 'hex')
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
async getExtendedKeyPairFromDerivative(derivative) {
|
|
301
|
-
const node = this.derivativeToBip32Node(derivative);
|
|
302
|
-
return {
|
|
303
|
-
secretKey: (0, module_kit_1.newExtendedSecretKey)(node.toBase58(), 'encoded'),
|
|
304
|
-
publicKey: (0, module_kit_1.newExtendedPublicKey)(node.neutered().toBase58(), 'encoded')
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
async deriveFromExtendedSecretKey(extendedSecretKey, visibilityIndex, addressIndex) {
|
|
308
|
-
const encodedExtendedSecretKey = this.convertExtendedSecretKey(extendedSecretKey, 'encoded');
|
|
309
|
-
const childSecretKey = this.bitcoinJS.lib.HDNode.fromBase58(encodedExtendedSecretKey.value, this.bitcoinJS.config.network)
|
|
310
|
-
.derive(visibilityIndex)
|
|
311
|
-
.derive(addressIndex)
|
|
312
|
-
.getPrivateKeyBuffer();
|
|
313
|
-
return (0, module_kit_1.newSecretKey)(childSecretKey.toString('hex'), 'hex');
|
|
314
|
-
}
|
|
315
|
-
async signTransactionWithSecretKey(transaction, secretKey) {
|
|
316
|
-
switch (secretKey.type) {
|
|
317
|
-
case 'priv':
|
|
318
|
-
return this.signTransactionWithNonExtendedSecretKey(transaction, secretKey);
|
|
319
|
-
case 'xpriv':
|
|
320
|
-
return this.signTransactionWithExtendedSecretKey(transaction, secretKey);
|
|
321
|
-
default:
|
|
322
|
-
(0, coinlib_core_1.assertNever)(secretKey);
|
|
323
|
-
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Secret key type not supported.');
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
async signTransactionWithNonExtendedSecretKey(transaction, secretKey) {
|
|
327
|
-
const hexSecretKey = (0, key_1.convertSecretKey)(secretKey, 'hex');
|
|
328
|
-
const transactionBuilder = new this.bitcoinJS.lib.TransactionBuilder(this.bitcoinJS.config.network);
|
|
329
|
-
for (const input of transaction.ins) {
|
|
330
|
-
transactionBuilder.addInput(input.txId, input.vout);
|
|
331
|
-
}
|
|
332
|
-
for (const output of transaction.outs) {
|
|
333
|
-
if (output.isChange) {
|
|
334
|
-
const bufferSecretKey = Buffer.from(secretKey.value, 'hex');
|
|
335
|
-
const keyPair = this.bitcoinJS.lib.ECPair(BigInteger.fromBuffer(bufferSecretKey), null, {
|
|
336
|
-
network: this.bitcoinJS.config.network
|
|
337
|
-
});
|
|
338
|
-
const publicKey = (0, module_kit_1.newPublicKey)(keyPair.getPublicKeyBuffer().toString('hex'), 'hex');
|
|
339
|
-
const generatedChangeAddress = await this.getAddressFromPublicKey(publicKey);
|
|
340
|
-
if (generatedChangeAddress !== output.recipient) {
|
|
341
|
-
throw new errors_1.ConditionViolationError(coinlib_core_1.Domain.BITCOIN, 'Change address could not be verified.');
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
};
|
|
396
|
+
BitcoinProtocolImpl.prototype.verifyMessageWithPublicKey = function (message, signature, publicKey) {
|
|
397
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
398
|
+
var encodedSignature;
|
|
399
|
+
return __generator(this, function (_a) {
|
|
400
|
+
encodedSignature = (0, signature_1.convertSignature)(signature, 'encoded');
|
|
401
|
+
return [2 /*return*/, this.cryptoClient.verifyMessage(message, encodedSignature.value, publicKey.value)];
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
};
|
|
405
|
+
BitcoinProtocolImpl.prototype.encryptAsymmetricWithPublicKey = function (payload, publicKey) {
|
|
406
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
407
|
+
var nonExtendedPublicKey, _a, hexNonExtendedPublicKey;
|
|
408
|
+
return __generator(this, function (_b) {
|
|
409
|
+
switch (_b.label) {
|
|
410
|
+
case 0:
|
|
411
|
+
if (!(publicKey.type === 'pub')) return [3 /*break*/, 1];
|
|
412
|
+
_a = publicKey;
|
|
413
|
+
return [3 /*break*/, 3];
|
|
414
|
+
case 1: return [4 /*yield*/, this.deriveFromExtendedPublicKey(publicKey, 0, 0)];
|
|
415
|
+
case 2:
|
|
416
|
+
_a = _b.sent();
|
|
417
|
+
_b.label = 3;
|
|
418
|
+
case 3:
|
|
419
|
+
nonExtendedPublicKey = _a;
|
|
420
|
+
hexNonExtendedPublicKey = (0, key_1.convertPublicKey)(nonExtendedPublicKey, 'hex');
|
|
421
|
+
return [2 /*return*/, this.cryptoClient.encryptAsymmetric(payload, hexNonExtendedPublicKey.value)];
|
|
342
422
|
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
423
|
+
});
|
|
424
|
+
});
|
|
425
|
+
};
|
|
426
|
+
BitcoinProtocolImpl.prototype.getCryptoConfiguration = function () {
|
|
427
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
428
|
+
return __generator(this, function (_a) {
|
|
429
|
+
return [2 /*return*/, this.cryptoConfiguration];
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
};
|
|
433
|
+
BitcoinProtocolImpl.prototype.getKeyPairFromDerivative = function (derivative) {
|
|
434
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
435
|
+
var node;
|
|
436
|
+
return __generator(this, function (_a) {
|
|
437
|
+
node = this.derivativeToBip32Node(derivative);
|
|
438
|
+
return [2 /*return*/, {
|
|
439
|
+
secretKey: (0, module_kit_1.newSecretKey)(node.keyPair.getPrivateKeyBuffer().toString('hex'), 'hex'),
|
|
440
|
+
publicKey: (0, module_kit_1.newPublicKey)(node.keyPair.getPublicKeyBuffer().toString('hex'), 'hex')
|
|
441
|
+
}];
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
};
|
|
445
|
+
BitcoinProtocolImpl.prototype.getExtendedKeyPairFromDerivative = function (derivative) {
|
|
446
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
447
|
+
var node;
|
|
448
|
+
return __generator(this, function (_a) {
|
|
449
|
+
node = this.derivativeToBip32Node(derivative);
|
|
450
|
+
return [2 /*return*/, {
|
|
451
|
+
secretKey: (0, module_kit_1.newExtendedSecretKey)(node.toBase58(), 'encoded'),
|
|
452
|
+
publicKey: (0, module_kit_1.newExtendedPublicKey)(node.neutered().toBase58(), 'encoded')
|
|
453
|
+
}];
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
};
|
|
457
|
+
BitcoinProtocolImpl.prototype.deriveFromExtendedSecretKey = function (extendedSecretKey, visibilityIndex, addressIndex) {
|
|
458
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
459
|
+
var encodedExtendedSecretKey, childSecretKey;
|
|
460
|
+
return __generator(this, function (_a) {
|
|
461
|
+
encodedExtendedSecretKey = this.convertExtendedSecretKey(extendedSecretKey, 'encoded');
|
|
462
|
+
childSecretKey = this.bitcoinJS.lib.HDNode.fromBase58(encodedExtendedSecretKey.value, this.bitcoinJS.config.network)
|
|
463
|
+
.derive(visibilityIndex)
|
|
464
|
+
.derive(addressIndex)
|
|
465
|
+
.getPrivateKeyBuffer();
|
|
466
|
+
return [2 /*return*/, (0, module_kit_1.newSecretKey)(childSecretKey.toString('hex'), 'hex')];
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
};
|
|
470
|
+
BitcoinProtocolImpl.prototype.signTransactionWithSecretKey = function (transaction, secretKey) {
|
|
471
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
472
|
+
return __generator(this, function (_a) {
|
|
473
|
+
switch (secretKey.type) {
|
|
474
|
+
case 'priv':
|
|
475
|
+
return [2 /*return*/, this.signTransactionWithNonExtendedSecretKey(transaction, secretKey)];
|
|
476
|
+
case 'xpriv':
|
|
477
|
+
return [2 /*return*/, this.signTransactionWithExtendedSecretKey(transaction, secretKey)];
|
|
478
|
+
default:
|
|
479
|
+
(0, coinlib_core_1.assertNever)(secretKey);
|
|
480
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Secret key type not supported.');
|
|
368
481
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
482
|
+
return [2 /*return*/];
|
|
483
|
+
});
|
|
484
|
+
});
|
|
485
|
+
};
|
|
486
|
+
BitcoinProtocolImpl.prototype.signTransactionWithNonExtendedSecretKey = function (transaction, secretKey) {
|
|
487
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
488
|
+
var hexSecretKey, transactionBuilder, _i, _a, input, _b, _c, output, bufferSecretKey, keyPair, publicKey, generatedChangeAddress, i;
|
|
489
|
+
return __generator(this, function (_d) {
|
|
490
|
+
switch (_d.label) {
|
|
491
|
+
case 0:
|
|
492
|
+
hexSecretKey = (0, key_1.convertSecretKey)(secretKey, 'hex');
|
|
493
|
+
transactionBuilder = new this.bitcoinJS.lib.TransactionBuilder(this.bitcoinJS.config.network);
|
|
494
|
+
for (_i = 0, _a = transaction.ins; _i < _a.length; _i++) {
|
|
495
|
+
input = _a[_i];
|
|
496
|
+
transactionBuilder.addInput(input.txId, input.vout);
|
|
497
|
+
}
|
|
498
|
+
_b = 0, _c = transaction.outs;
|
|
499
|
+
_d.label = 1;
|
|
500
|
+
case 1:
|
|
501
|
+
if (!(_b < _c.length)) return [3 /*break*/, 5];
|
|
502
|
+
output = _c[_b];
|
|
503
|
+
if (!output.isChange) return [3 /*break*/, 3];
|
|
504
|
+
bufferSecretKey = Buffer.from(secretKey.value, 'hex');
|
|
505
|
+
keyPair = this.bitcoinJS.lib.ECPair(BigInteger.fromBuffer(bufferSecretKey), null, {
|
|
506
|
+
network: this.bitcoinJS.config.network
|
|
507
|
+
});
|
|
508
|
+
publicKey = (0, module_kit_1.newPublicKey)(keyPair.getPublicKeyBuffer().toString('hex'), 'hex');
|
|
509
|
+
return [4 /*yield*/, this.getAddressFromPublicKey(publicKey)];
|
|
510
|
+
case 2:
|
|
511
|
+
generatedChangeAddress = _d.sent();
|
|
512
|
+
if (generatedChangeAddress !== output.recipient) {
|
|
513
|
+
throw new errors_1.ConditionViolationError(coinlib_core_1.Domain.BITCOIN, 'Change address could not be verified.');
|
|
380
514
|
}
|
|
381
|
-
|
|
515
|
+
_d.label = 3;
|
|
516
|
+
case 3:
|
|
517
|
+
transactionBuilder.addOutput(output.recipient, new bignumber_1.default(output.value).toNumber());
|
|
518
|
+
_d.label = 4;
|
|
519
|
+
case 4:
|
|
520
|
+
_b++;
|
|
521
|
+
return [3 /*break*/, 1];
|
|
522
|
+
case 5:
|
|
523
|
+
for (i = 0; i < transaction.ins.length; i++) {
|
|
524
|
+
transactionBuilder.sign(i, Buffer.from(hexSecretKey.value, 'hex'));
|
|
525
|
+
}
|
|
526
|
+
return [2 /*return*/, this.createSignedTransaction(transaction, transactionBuilder)];
|
|
382
527
|
}
|
|
383
|
-
|
|
384
|
-
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
};
|
|
531
|
+
BitcoinProtocolImpl.prototype.signTransactionWithExtendedSecretKey = function (transaction, extendedSecretKey) {
|
|
532
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
533
|
+
var encodedExtendedSecretKey, transactionBuilder, node, _i, _a, input, changeAddressBatchSize, changeAddressMaxAddresses, _loop_1, this_1, _b, _c, output, i;
|
|
534
|
+
var _this = this;
|
|
535
|
+
return __generator(this, function (_d) {
|
|
536
|
+
switch (_d.label) {
|
|
537
|
+
case 0:
|
|
538
|
+
encodedExtendedSecretKey = this.convertExtendedSecretKey(extendedSecretKey, 'encoded');
|
|
539
|
+
transactionBuilder = new this.bitcoinJS.lib.TransactionBuilder(this.bitcoinJS.config.network);
|
|
540
|
+
node = this.bitcoinJS.lib.HDNode.fromBase58(encodedExtendedSecretKey.value, this.bitcoinJS.config.network);
|
|
541
|
+
for (_i = 0, _a = transaction.ins; _i < _a.length; _i++) {
|
|
542
|
+
input = _a[_i];
|
|
543
|
+
transactionBuilder.addInput(input.txId, input.vout);
|
|
544
|
+
}
|
|
545
|
+
changeAddressBatchSize = 10;
|
|
546
|
+
changeAddressMaxAddresses = 500;
|
|
547
|
+
_loop_1 = function (output) {
|
|
548
|
+
var changeAddressIsValid, extendedPublicKey_1, derivedPublicKey, generatedChangeAddress, _loop_2, out_x_1, x;
|
|
549
|
+
return __generator(this, function (_e) {
|
|
550
|
+
switch (_e.label) {
|
|
551
|
+
case 0:
|
|
552
|
+
changeAddressIsValid = false;
|
|
553
|
+
if (!output.isChange) return [3 /*break*/, 8];
|
|
554
|
+
extendedPublicKey_1 = (0, module_kit_1.newExtendedPublicKey)(node.neutered().toBase58(), 'encoded');
|
|
555
|
+
if (!output.derivationPath) return [3 /*break*/, 3];
|
|
556
|
+
return [4 /*yield*/, this_1.deriveFromExtendedPublicKey(extendedPublicKey_1, 1, parseInt(output.derivationPath, 10))];
|
|
557
|
+
case 1:
|
|
558
|
+
derivedPublicKey = _e.sent();
|
|
559
|
+
return [4 /*yield*/, this_1.getAddressFromPublicKey(derivedPublicKey)];
|
|
560
|
+
case 2:
|
|
561
|
+
generatedChangeAddress = _e.sent();
|
|
562
|
+
changeAddressIsValid = generatedChangeAddress === output.recipient;
|
|
563
|
+
return [3 /*break*/, 7];
|
|
564
|
+
case 3:
|
|
565
|
+
_loop_2 = function (x) {
|
|
566
|
+
var derivedPublicKeys, addresses;
|
|
567
|
+
return __generator(this, function (_f) {
|
|
568
|
+
switch (_f.label) {
|
|
569
|
+
case 0: return [4 /*yield*/, Promise.all(Array.from(new Array(changeAddressBatchSize)).map(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
570
|
+
return __generator(this, function (_a) {
|
|
571
|
+
return [2 /*return*/, this.deriveFromExtendedPublicKey(extendedPublicKey_1, 1, x)];
|
|
572
|
+
});
|
|
573
|
+
}); }))];
|
|
574
|
+
case 1:
|
|
575
|
+
derivedPublicKeys = _f.sent();
|
|
576
|
+
return [4 /*yield*/, Promise.all(derivedPublicKeys.map(function (publicKey) {
|
|
577
|
+
return _this.getAddressFromPublicKey(publicKey);
|
|
578
|
+
}))];
|
|
579
|
+
case 2:
|
|
580
|
+
addresses = _f.sent();
|
|
581
|
+
if (addresses.indexOf(output.recipient) >= 0) {
|
|
582
|
+
changeAddressIsValid = true;
|
|
583
|
+
x = changeAddressMaxAddresses;
|
|
584
|
+
}
|
|
585
|
+
out_x_1 = x;
|
|
586
|
+
return [2 /*return*/];
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
};
|
|
590
|
+
x = 0;
|
|
591
|
+
_e.label = 4;
|
|
592
|
+
case 4:
|
|
593
|
+
if (!(x < changeAddressMaxAddresses)) return [3 /*break*/, 7];
|
|
594
|
+
return [5 /*yield**/, _loop_2(x)];
|
|
595
|
+
case 5:
|
|
596
|
+
_e.sent();
|
|
597
|
+
x = out_x_1;
|
|
598
|
+
_e.label = 6;
|
|
599
|
+
case 6:
|
|
600
|
+
x += changeAddressBatchSize;
|
|
601
|
+
return [3 /*break*/, 4];
|
|
602
|
+
case 7:
|
|
603
|
+
if (!changeAddressIsValid) {
|
|
604
|
+
throw new errors_1.InvalidValueError(coinlib_core_1.Domain.BITCOIN, 'Change address could not be verified.');
|
|
605
|
+
}
|
|
606
|
+
_e.label = 8;
|
|
607
|
+
case 8:
|
|
608
|
+
transactionBuilder.addOutput(output.recipient, new bignumber_1.default(output.value).toNumber());
|
|
609
|
+
return [2 /*return*/];
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
};
|
|
613
|
+
this_1 = this;
|
|
614
|
+
_b = 0, _c = transaction.outs;
|
|
615
|
+
_d.label = 1;
|
|
616
|
+
case 1:
|
|
617
|
+
if (!(_b < _c.length)) return [3 /*break*/, 4];
|
|
618
|
+
output = _c[_b];
|
|
619
|
+
return [5 /*yield**/, _loop_1(output)];
|
|
620
|
+
case 2:
|
|
621
|
+
_d.sent();
|
|
622
|
+
_d.label = 3;
|
|
623
|
+
case 3:
|
|
624
|
+
_b++;
|
|
625
|
+
return [3 /*break*/, 1];
|
|
626
|
+
case 4:
|
|
627
|
+
for (i = 0; i < transaction.ins.length; i++) {
|
|
628
|
+
transactionBuilder.sign(i, node.derivePath(transaction.ins[i].derivationPath));
|
|
629
|
+
}
|
|
630
|
+
return [2 /*return*/, this.createSignedTransaction(transaction, transactionBuilder)];
|
|
385
631
|
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
394
|
-
createSignedTransaction(unsignedTransaction, transactionBuilder) {
|
|
395
|
-
let fee = new bignumber_1.default(0);
|
|
396
|
-
for (const txIn of unsignedTransaction.ins) {
|
|
632
|
+
});
|
|
633
|
+
});
|
|
634
|
+
};
|
|
635
|
+
BitcoinProtocolImpl.prototype.createSignedTransaction = function (unsignedTransaction, transactionBuilder) {
|
|
636
|
+
var fee = new bignumber_1.default(0);
|
|
637
|
+
for (var _i = 0, _a = unsignedTransaction.ins; _i < _a.length; _i++) {
|
|
638
|
+
var txIn = _a[_i];
|
|
397
639
|
fee = fee.plus(new bignumber_1.default(txIn.value));
|
|
398
640
|
}
|
|
399
|
-
for (
|
|
641
|
+
for (var _b = 0, _c = unsignedTransaction.outs; _b < _c.length; _b++) {
|
|
642
|
+
var txOut = _c[_b];
|
|
400
643
|
fee = fee.minus(new bignumber_1.default(txOut.value));
|
|
401
644
|
}
|
|
402
645
|
return (0, module_kit_1.newSignedTransaction)({
|
|
403
|
-
from: unsignedTransaction.ins.map((obj)
|
|
404
|
-
to: unsignedTransaction.outs.map((obj)
|
|
646
|
+
from: unsignedTransaction.ins.map(function (obj) { return obj.address; }),
|
|
647
|
+
to: unsignedTransaction.outs.map(function (obj) { return obj.recipient; }),
|
|
405
648
|
amount: unsignedTransaction.outs
|
|
406
|
-
.map((obj)
|
|
407
|
-
.reduce((accumulator, currentValue)
|
|
649
|
+
.map(function (obj) { return new bignumber_1.default(obj.value); })
|
|
650
|
+
.reduce(function (accumulator, currentValue) { return accumulator.plus(currentValue); })
|
|
408
651
|
.toString(10),
|
|
409
652
|
fee: fee.toString(10),
|
|
410
653
|
transaction: transactionBuilder.build().toHex()
|
|
411
654
|
});
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
return this
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
655
|
+
};
|
|
656
|
+
BitcoinProtocolImpl.prototype.signMessageWithKeyPair = function (message, keyPair) {
|
|
657
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
658
|
+
var hexSecretKey, signature;
|
|
659
|
+
return __generator(this, function (_a) {
|
|
660
|
+
switch (_a.label) {
|
|
661
|
+
case 0:
|
|
662
|
+
hexSecretKey = keyPair.secretKey.type === 'priv'
|
|
663
|
+
? (0, key_1.convertSecretKey)(keyPair.secretKey, 'hex')
|
|
664
|
+
: (0, key_1.convertExtendedSecretKey)(keyPair.secretKey, { format: 'hex' });
|
|
665
|
+
return [4 /*yield*/, this.cryptoClient.signMessage(message, { privateKey: hexSecretKey.value })];
|
|
666
|
+
case 1:
|
|
667
|
+
signature = _a.sent();
|
|
668
|
+
return [2 /*return*/, (0, module_kit_1.newSignature)(signature, 'encoded')];
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
});
|
|
672
|
+
};
|
|
673
|
+
BitcoinProtocolImpl.prototype.decryptAsymmetricWithKeyPair = function (payload, keyPair) {
|
|
674
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
675
|
+
var hexSecretKey, encodedExtendedSecretKey, node, derivedNode;
|
|
676
|
+
return __generator(this, function (_a) {
|
|
677
|
+
hexSecretKey = undefined;
|
|
678
|
+
if (keyPair.secretKey.type === 'priv') {
|
|
679
|
+
hexSecretKey = (0, key_1.convertSecretKey)(keyPair.secretKey, 'hex');
|
|
680
|
+
}
|
|
681
|
+
else {
|
|
682
|
+
encodedExtendedSecretKey = this.convertExtendedSecretKey(keyPair.secretKey, 'encoded');
|
|
683
|
+
node = this.bitcoinJS.lib.HDNode.fromBase58(encodedExtendedSecretKey.value, this.bitcoinJS.config.network);
|
|
684
|
+
derivedNode = node.derive(0).derive(0);
|
|
685
|
+
hexSecretKey = (0, module_kit_1.newSecretKey)(derivedNode.keyPair.getPrivateKeyBuffer(), 'hex');
|
|
686
|
+
}
|
|
687
|
+
return [2 /*return*/, this.cryptoClient.decryptAsymmetric(payload, { publicKey: '', privateKey: hexSecretKey.value })];
|
|
688
|
+
});
|
|
689
|
+
});
|
|
690
|
+
};
|
|
691
|
+
BitcoinProtocolImpl.prototype.encryptAESWithSecretKey = function (payload, secretKey) {
|
|
692
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
693
|
+
return __generator(this, function (_a) {
|
|
694
|
+
return [2 /*return*/, this.cryptoClient.encryptAES(payload, secretKey.value)];
|
|
695
|
+
});
|
|
696
|
+
});
|
|
697
|
+
};
|
|
698
|
+
BitcoinProtocolImpl.prototype.decryptAESWithSecretKey = function (payload, secretKey) {
|
|
699
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
700
|
+
return __generator(this, function (_a) {
|
|
701
|
+
return [2 /*return*/, this.cryptoClient.decryptAES(payload, secretKey.value)];
|
|
702
|
+
});
|
|
703
|
+
});
|
|
704
|
+
};
|
|
439
705
|
// Online
|
|
440
|
-
|
|
441
|
-
return this
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
async getTransactionsForExtendedPublicKey(extendedPublicKey, limit, cursor) {
|
|
459
|
-
const encodedExtendedPublicKey = this.convertExtendedPublicKey(extendedPublicKey, 'encoded');
|
|
460
|
-
const page = cursor?.page ?? 1;
|
|
461
|
-
const url = `${this.options.network.indexerApi}/api/v2/xpub/${encodedExtendedPublicKey.value}?details=txs&tokens=used&pageSize=${limit}&page=${page}`;
|
|
462
|
-
const { data } = await index_1.default.get(url, {
|
|
463
|
-
responseType: 'json'
|
|
464
|
-
});
|
|
465
|
-
const ourAddresses = (data.tokens || []).filter((token) => token.type === 'XPUBAddress').map((token) => token.name);
|
|
466
|
-
const airGapTransactions = [];
|
|
467
|
-
if (data.page === page) {
|
|
468
|
-
for (const transaction of data.transactions || []) {
|
|
469
|
-
const tempAirGapTransactionFrom = [];
|
|
470
|
-
const tempAirGapTransactionTo = [];
|
|
471
|
-
let tempAirGapTransactionIsInbound = true;
|
|
472
|
-
let amountNotAdded = true;
|
|
473
|
-
let amount = new bignumber_1.default(0);
|
|
474
|
-
for (const vin of transaction.vin) {
|
|
475
|
-
if ((0, common_1.containsSome)(vin.addresses, ourAddresses)) {
|
|
476
|
-
tempAirGapTransactionIsInbound = false;
|
|
477
|
-
}
|
|
478
|
-
tempAirGapTransactionFrom.push(...vin.addresses);
|
|
479
|
-
// amount = amount.plus(vin.value)
|
|
706
|
+
BitcoinProtocolImpl.prototype.getNetwork = function () {
|
|
707
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
708
|
+
return __generator(this, function (_a) {
|
|
709
|
+
return [2 /*return*/, this.options.network];
|
|
710
|
+
});
|
|
711
|
+
});
|
|
712
|
+
};
|
|
713
|
+
BitcoinProtocolImpl.prototype.getTransactionsForPublicKey = function (publicKey, limit, cursor) {
|
|
714
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
715
|
+
return __generator(this, function (_a) {
|
|
716
|
+
switch (publicKey.type) {
|
|
717
|
+
case 'pub':
|
|
718
|
+
return [2 /*return*/, this.getTransactionsForNonExtendedPublicKey(publicKey, limit, cursor)];
|
|
719
|
+
case 'xpub':
|
|
720
|
+
return [2 /*return*/, this.getTransactionsForExtendedPublicKey(publicKey, limit, cursor)];
|
|
721
|
+
default:
|
|
722
|
+
(0, coinlib_core_1.assertNever)(publicKey);
|
|
723
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Public key type not supported');
|
|
480
724
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
if ((0, common_1.containsSome)(vout.addresses, ourAddresses) && transaction.vout.length > 2) {
|
|
495
|
-
amount = amount.plus(vout.value);
|
|
496
|
-
amountNotAdded = false;
|
|
497
|
-
}
|
|
725
|
+
return [2 /*return*/];
|
|
726
|
+
});
|
|
727
|
+
});
|
|
728
|
+
};
|
|
729
|
+
BitcoinProtocolImpl.prototype.getTransactionsForNonExtendedPublicKey = function (publicKey, limit, cursor) {
|
|
730
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
731
|
+
var address;
|
|
732
|
+
return __generator(this, function (_a) {
|
|
733
|
+
switch (_a.label) {
|
|
734
|
+
case 0: return [4 /*yield*/, this.getAddressFromPublicKey(publicKey)];
|
|
735
|
+
case 1:
|
|
736
|
+
address = _a.sent();
|
|
737
|
+
return [2 /*return*/, this.getTransactionsForAddresses([address], limit, cursor)];
|
|
498
738
|
}
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
739
|
+
});
|
|
740
|
+
});
|
|
741
|
+
};
|
|
742
|
+
BitcoinProtocolImpl.prototype.getTransactionsForExtendedPublicKey = function (extendedPublicKey, limit, cursor) {
|
|
743
|
+
var _a;
|
|
744
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
745
|
+
var encodedExtendedPublicKey, page, url, data, ourAddresses, airGapTransactions, _i, _b, transaction, tempAirGapTransactionFrom, tempAirGapTransactionTo, tempAirGapTransactionIsInbound, amountNotAdded, amount, _c, _d, vin, _e, _f, vout, airGapTransaction, hasNext;
|
|
746
|
+
return __generator(this, function (_g) {
|
|
747
|
+
switch (_g.label) {
|
|
748
|
+
case 0:
|
|
749
|
+
encodedExtendedPublicKey = this.convertExtendedPublicKey(extendedPublicKey, 'encoded');
|
|
750
|
+
page = (_a = cursor === null || cursor === void 0 ? void 0 : cursor.page) !== null && _a !== void 0 ? _a : 1;
|
|
751
|
+
url = "".concat(this.options.network.indexerApi, "/api/v2/xpub/").concat(encodedExtendedPublicKey.value, "?details=txs&tokens=used&pageSize=").concat(limit, "&page=").concat(page);
|
|
752
|
+
return [4 /*yield*/, index_1.default.get(url, {
|
|
753
|
+
responseType: 'json'
|
|
754
|
+
})];
|
|
755
|
+
case 1:
|
|
756
|
+
data = (_g.sent()).data;
|
|
757
|
+
ourAddresses = (data.tokens || []).filter(function (token) { return token.type === 'XPUBAddress'; }).map(function (token) { return token.name; });
|
|
758
|
+
airGapTransactions = [];
|
|
759
|
+
if (data.page === page) {
|
|
760
|
+
for (_i = 0, _b = data.transactions || []; _i < _b.length; _i++) {
|
|
761
|
+
transaction = _b[_i];
|
|
762
|
+
tempAirGapTransactionFrom = [];
|
|
763
|
+
tempAirGapTransactionTo = [];
|
|
764
|
+
tempAirGapTransactionIsInbound = true;
|
|
765
|
+
amountNotAdded = true;
|
|
766
|
+
amount = new bignumber_1.default(0);
|
|
767
|
+
for (_c = 0, _d = transaction.vin; _c < _d.length; _c++) {
|
|
768
|
+
vin = _d[_c];
|
|
769
|
+
if ((0, common_1.containsSome)(vin.addresses, ourAddresses)) {
|
|
770
|
+
tempAirGapTransactionIsInbound = false;
|
|
771
|
+
}
|
|
772
|
+
tempAirGapTransactionFrom.push.apply(tempAirGapTransactionFrom, vin.addresses);
|
|
773
|
+
// amount = amount.plus(vin.value)
|
|
774
|
+
}
|
|
775
|
+
for (_e = 0, _f = transaction.vout; _e < _f.length; _e++) {
|
|
776
|
+
vout = _f[_e];
|
|
777
|
+
if (vout.addresses) {
|
|
778
|
+
tempAirGapTransactionTo.push.apply(tempAirGapTransactionTo, vout.addresses);
|
|
779
|
+
// If receiving address is our address, and transaction is outbound => our change
|
|
780
|
+
// if (containsSome(vout.addresses, ourAddresses) && !tempAirGapTransactionIsInbound) {
|
|
781
|
+
// remove only if related to this address
|
|
782
|
+
// amount = amount.minus(vout.value)
|
|
783
|
+
// }
|
|
784
|
+
// If receiving address is not ours, and transaction isbound => senders change
|
|
785
|
+
// if (!containsSome(vout.addresses, ourAddresses) && tempAirGapTransactionIsInbound) {
|
|
786
|
+
// amount = amount.minus(vout.value)
|
|
787
|
+
// }
|
|
788
|
+
}
|
|
789
|
+
if ((0, common_1.containsSome)(vout.addresses, ourAddresses) && transaction.vout.length > 2) {
|
|
790
|
+
amount = amount.plus(vout.value);
|
|
791
|
+
amountNotAdded = false;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
// deduct fee from amount
|
|
795
|
+
//amount = amount.minus(transaction.fees)
|
|
796
|
+
if (amountNotAdded) {
|
|
797
|
+
amount = amount.plus(transaction.vout[0].value);
|
|
798
|
+
}
|
|
799
|
+
airGapTransaction = {
|
|
800
|
+
from: tempAirGapTransactionFrom,
|
|
801
|
+
to: tempAirGapTransactionTo,
|
|
802
|
+
isInbound: tempAirGapTransactionIsInbound,
|
|
803
|
+
amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
|
|
804
|
+
fee: (0, module_kit_1.newAmount)(transaction.fees, 'blockchain'),
|
|
805
|
+
status: {
|
|
806
|
+
type: 'applied',
|
|
807
|
+
hash: transaction.txid,
|
|
808
|
+
block: transaction.blockHeight.toString()
|
|
809
|
+
},
|
|
810
|
+
network: this.options.network,
|
|
811
|
+
timestamp: transaction.blockTime
|
|
812
|
+
};
|
|
813
|
+
airGapTransactions.push(airGapTransaction);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
hasNext = page < data.totalPages;
|
|
817
|
+
return [2 /*return*/, {
|
|
818
|
+
transactions: airGapTransactions,
|
|
819
|
+
cursor: {
|
|
820
|
+
hasNext: hasNext,
|
|
821
|
+
page: hasNext ? page + 1 : undefined
|
|
822
|
+
}
|
|
823
|
+
}];
|
|
503
824
|
}
|
|
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
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
825
|
+
});
|
|
826
|
+
});
|
|
827
|
+
};
|
|
828
|
+
BitcoinProtocolImpl.prototype.getTransactionsForAddress = function (address, limit, cursor) {
|
|
829
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
830
|
+
return __generator(this, function (_a) {
|
|
831
|
+
return [2 /*return*/, this.getTransactionsForAddresses([address], limit, cursor)];
|
|
832
|
+
});
|
|
833
|
+
});
|
|
834
|
+
};
|
|
835
|
+
BitcoinProtocolImpl.prototype.getTransactionsForAddresses = function (addresses, limit, cursor) {
|
|
836
|
+
var _a;
|
|
837
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
838
|
+
var airGapTransactions, page, url, data, _i, _b, transaction, tempAirGapTransactionFrom, tempAirGapTransactionTo, tempAirGapTransactionIsInbound, amount, _c, _d, vin, _e, _f, vout, airGapTransaction, hasNext;
|
|
839
|
+
return __generator(this, function (_g) {
|
|
840
|
+
switch (_g.label) {
|
|
841
|
+
case 0:
|
|
842
|
+
airGapTransactions = [];
|
|
843
|
+
page = (_a = cursor === null || cursor === void 0 ? void 0 : cursor.page) !== null && _a !== void 0 ? _a : 1;
|
|
844
|
+
url = "".concat(this.options.network.indexerApi, "/api/v2/address/").concat(addresses[0], "?page=").concat(page, "&pageSize=").concat(limit, "&details=txs");
|
|
845
|
+
return [4 /*yield*/, index_1.default.get(url, {
|
|
846
|
+
responseType: 'json'
|
|
847
|
+
})];
|
|
848
|
+
case 1:
|
|
849
|
+
data = (_g.sent()).data;
|
|
850
|
+
if (data.page == page) {
|
|
851
|
+
for (_i = 0, _b = data.transactions || []; _i < _b.length; _i++) {
|
|
852
|
+
transaction = _b[_i];
|
|
853
|
+
tempAirGapTransactionFrom = [];
|
|
854
|
+
tempAirGapTransactionTo = [];
|
|
855
|
+
tempAirGapTransactionIsInbound = true;
|
|
856
|
+
amount = new bignumber_1.default(0);
|
|
857
|
+
for (_c = 0, _d = transaction.vin; _c < _d.length; _c++) {
|
|
858
|
+
vin = _d[_c];
|
|
859
|
+
if (vin.addresses && (0, common_1.containsSome)(vin.addresses, addresses)) {
|
|
860
|
+
tempAirGapTransactionIsInbound = false;
|
|
861
|
+
}
|
|
862
|
+
tempAirGapTransactionFrom.push.apply(tempAirGapTransactionFrom, vin.addresses);
|
|
863
|
+
amount = vin.value ? amount.plus(vin.value) : amount;
|
|
864
|
+
}
|
|
865
|
+
for (_e = 0, _f = transaction.vout; _e < _f.length; _e++) {
|
|
866
|
+
vout = _f[_e];
|
|
867
|
+
if (vout.addresses) {
|
|
868
|
+
tempAirGapTransactionTo.push.apply(tempAirGapTransactionTo, vout.addresses);
|
|
869
|
+
// If receiving address is our address, and transaction is outbound => our change
|
|
870
|
+
if ((0, common_1.containsSome)(vout.addresses, addresses) && !tempAirGapTransactionIsInbound) {
|
|
871
|
+
// remove only if related to this address
|
|
872
|
+
amount = amount.minus(new bignumber_1.default(vout.value));
|
|
873
|
+
}
|
|
874
|
+
// If receiving address is not ours, and transaction isbound => senders change
|
|
875
|
+
if (!(0, common_1.containsSome)(vout.addresses, addresses) && tempAirGapTransactionIsInbound) {
|
|
876
|
+
amount = amount.minus(new bignumber_1.default(vout.value));
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
// deduct fee from amount
|
|
881
|
+
amount = amount.minus(new bignumber_1.default(transaction.fees));
|
|
882
|
+
airGapTransaction = {
|
|
883
|
+
from: tempAirGapTransactionFrom,
|
|
884
|
+
to: tempAirGapTransactionTo,
|
|
885
|
+
isInbound: tempAirGapTransactionIsInbound,
|
|
886
|
+
amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
|
|
887
|
+
fee: (0, module_kit_1.newAmount)(transaction.fees, 'blockchain'),
|
|
888
|
+
status: {
|
|
889
|
+
type: 'applied',
|
|
890
|
+
hash: transaction.txid,
|
|
891
|
+
block: transaction.blockHeight.toString()
|
|
892
|
+
},
|
|
893
|
+
network: this.options.network,
|
|
894
|
+
timestamp: transaction.blockTime
|
|
895
|
+
};
|
|
896
|
+
airGapTransactions.push(airGapTransaction);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
hasNext = page < data.totalPages;
|
|
900
|
+
return [2 /*return*/, {
|
|
901
|
+
transactions: airGapTransactions,
|
|
902
|
+
cursor: {
|
|
903
|
+
hasNext: hasNext,
|
|
904
|
+
page: hasNext ? page + 1 : undefined
|
|
905
|
+
}
|
|
906
|
+
}];
|
|
907
|
+
}
|
|
908
|
+
});
|
|
909
|
+
});
|
|
910
|
+
};
|
|
911
|
+
BitcoinProtocolImpl.prototype.getBalanceOfPublicKey = function (publicKey) {
|
|
912
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
913
|
+
return __generator(this, function (_a) {
|
|
914
|
+
switch (publicKey.type) {
|
|
915
|
+
case 'pub':
|
|
916
|
+
return [2 /*return*/, this.getBalanceOfNonExtendedPublicKey(publicKey)];
|
|
917
|
+
case 'xpub':
|
|
918
|
+
return [2 /*return*/, this.getBalanceOfExtendedPublicKey(publicKey)];
|
|
919
|
+
default:
|
|
920
|
+
(0, coinlib_core_1.assertNever)(publicKey);
|
|
921
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Unsupported public key type.');
|
|
922
|
+
}
|
|
923
|
+
return [2 /*return*/];
|
|
924
|
+
});
|
|
925
|
+
});
|
|
926
|
+
};
|
|
927
|
+
BitcoinProtocolImpl.prototype.getBalanceOfNonExtendedPublicKey = function (publicKey) {
|
|
928
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
929
|
+
var address;
|
|
930
|
+
return __generator(this, function (_a) {
|
|
931
|
+
switch (_a.label) {
|
|
932
|
+
case 0: return [4 /*yield*/, this.getAddressFromPublicKey(publicKey)];
|
|
933
|
+
case 1:
|
|
934
|
+
address = _a.sent();
|
|
935
|
+
return [2 /*return*/, this.getBalanceOfAddresses([address])];
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
});
|
|
939
|
+
};
|
|
940
|
+
BitcoinProtocolImpl.prototype.getBalanceOfExtendedPublicKey = function (extendedPublicKey) {
|
|
941
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
942
|
+
var encodedExtendedPublicKey, data;
|
|
943
|
+
return __generator(this, function (_a) {
|
|
944
|
+
switch (_a.label) {
|
|
945
|
+
case 0:
|
|
946
|
+
encodedExtendedPublicKey = this.convertExtendedPublicKey(extendedPublicKey, 'encoded');
|
|
947
|
+
return [4 /*yield*/, index_1.default.get("".concat(this.options.network.indexerApi, "/api/v2/xpub/").concat(encodedExtendedPublicKey.value, "?pageSize=1"), {
|
|
948
|
+
responseType: 'json'
|
|
949
|
+
})];
|
|
950
|
+
case 1:
|
|
951
|
+
data = (_a.sent()).data;
|
|
952
|
+
return [2 /*return*/, {
|
|
953
|
+
total: (0, module_kit_1.newAmount)(data.balance, 'blockchain')
|
|
954
|
+
}];
|
|
552
955
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
956
|
+
});
|
|
957
|
+
});
|
|
958
|
+
};
|
|
959
|
+
BitcoinProtocolImpl.prototype.getBalanceOfAddress = function (address) {
|
|
960
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
961
|
+
return __generator(this, function (_a) {
|
|
962
|
+
return [2 /*return*/, this.getBalanceOfAddresses([address])];
|
|
963
|
+
});
|
|
964
|
+
});
|
|
965
|
+
};
|
|
966
|
+
BitcoinProtocolImpl.prototype.getBalanceOfAddresses = function (addresses) {
|
|
967
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
968
|
+
var valueAccumulator, _i, addresses_1, address, data;
|
|
969
|
+
return __generator(this, function (_a) {
|
|
970
|
+
switch (_a.label) {
|
|
971
|
+
case 0:
|
|
972
|
+
valueAccumulator = new bignumber_1.default(0);
|
|
973
|
+
_i = 0, addresses_1 = addresses;
|
|
974
|
+
_a.label = 1;
|
|
975
|
+
case 1:
|
|
976
|
+
if (!(_i < addresses_1.length)) return [3 /*break*/, 4];
|
|
977
|
+
address = addresses_1[_i];
|
|
978
|
+
return [4 /*yield*/, index_1.default.get("".concat(this.options.network.indexerApi, "/api/v2/address/").concat(address, "?details=basic"), {
|
|
979
|
+
responseType: 'json'
|
|
980
|
+
})];
|
|
981
|
+
case 2:
|
|
982
|
+
data = (_a.sent()).data;
|
|
983
|
+
valueAccumulator = valueAccumulator.plus(new bignumber_1.default(data.balance));
|
|
984
|
+
_a.label = 3;
|
|
985
|
+
case 3:
|
|
986
|
+
_i++;
|
|
987
|
+
return [3 /*break*/, 1];
|
|
988
|
+
case 4: return [2 /*return*/, {
|
|
989
|
+
total: (0, module_kit_1.newAmount)(valueAccumulator, 'blockchain')
|
|
990
|
+
}];
|
|
991
|
+
}
|
|
992
|
+
});
|
|
993
|
+
});
|
|
994
|
+
};
|
|
995
|
+
BitcoinProtocolImpl.prototype.getTransactionMaxAmountWithPublicKey = function (publicKey, to, configuration) {
|
|
996
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
997
|
+
return __generator(this, function (_a) {
|
|
998
|
+
switch (_a.label) {
|
|
999
|
+
case 0: return [4 /*yield*/, this.getBalanceOfPublicKey(publicKey)];
|
|
1000
|
+
case 1: return [2 /*return*/, (_a.sent()).total];
|
|
1001
|
+
}
|
|
1002
|
+
});
|
|
1003
|
+
});
|
|
1004
|
+
};
|
|
1005
|
+
BitcoinProtocolImpl.prototype.getTransactionFeeWithPublicKey = function (_publicKey, _details, _configuration) {
|
|
1006
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1007
|
+
var result, estimatedFee, feeStepFactor, mediumFee, lowFee, highFee;
|
|
1008
|
+
return __generator(this, function (_a) {
|
|
1009
|
+
switch (_a.label) {
|
|
1010
|
+
case 0: return [4 /*yield*/, index_1.default.get("".concat(this.options.network.indexerApi, "/api/v2/estimatefee/5"))];
|
|
1011
|
+
case 1:
|
|
1012
|
+
result = (_a.sent()).data.result;
|
|
1013
|
+
estimatedFee = new bignumber_1.default((0, module_kit_1.newAmount)(result, 'BTC').blockchain(this.units).value);
|
|
1014
|
+
if (estimatedFee.isZero()) {
|
|
1015
|
+
return [2 /*return*/, this.feeDefaults];
|
|
1016
|
+
}
|
|
1017
|
+
feeStepFactor = new bignumber_1.default(0.5);
|
|
1018
|
+
mediumFee = estimatedFee;
|
|
1019
|
+
lowFee = mediumFee.minus(mediumFee.times(feeStepFactor)).integerValue(bignumber_1.default.ROUND_FLOOR);
|
|
1020
|
+
highFee = mediumFee.plus(mediumFee.times(feeStepFactor)).integerValue(bignumber_1.default.ROUND_FLOOR);
|
|
1021
|
+
return [2 /*return*/, {
|
|
1022
|
+
low: (0, module_kit_1.newAmount)(lowFee, 'blockchain'),
|
|
1023
|
+
medium: (0, module_kit_1.newAmount)(mediumFee, 'blockchain'),
|
|
1024
|
+
high: (0, module_kit_1.newAmount)(highFee, 'blockchain')
|
|
1025
|
+
}];
|
|
1026
|
+
}
|
|
1027
|
+
});
|
|
1028
|
+
});
|
|
1029
|
+
};
|
|
1030
|
+
BitcoinProtocolImpl.prototype.prepareTransactionWithPublicKey = function (publicKey, details, configuration) {
|
|
1031
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1032
|
+
return __generator(this, function (_a) {
|
|
1033
|
+
switch (publicKey.type) {
|
|
1034
|
+
case 'pub':
|
|
1035
|
+
return [2 /*return*/, this.prepareTransactionWithNonExtendedPublicKey(publicKey, details, configuration)];
|
|
1036
|
+
case 'xpub':
|
|
1037
|
+
return [2 /*return*/, this.prepareTransactionWithExtendedPublicKey(publicKey, details, configuration)];
|
|
1038
|
+
default:
|
|
1039
|
+
(0, coinlib_core_1.assertNever)(publicKey);
|
|
1040
|
+
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Unuspported public key type.');
|
|
1041
|
+
}
|
|
1042
|
+
return [2 /*return*/];
|
|
1043
|
+
});
|
|
1044
|
+
});
|
|
1045
|
+
};
|
|
1046
|
+
BitcoinProtocolImpl.prototype.prepareTransactionWithNonExtendedPublicKey = function (publicKey, details, configuration) {
|
|
1047
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1048
|
+
var fee, estimatedFee, wrappedFee, transaction, address, utxos, totalRequiredBalance, valueAccumulator, _i, utxos_1, utxo, i, value, changeValue;
|
|
1049
|
+
var _this = this;
|
|
1050
|
+
return __generator(this, function (_a) {
|
|
1051
|
+
switch (_a.label) {
|
|
1052
|
+
case 0:
|
|
1053
|
+
if (!((configuration === null || configuration === void 0 ? void 0 : configuration.fee) !== undefined)) return [3 /*break*/, 1];
|
|
1054
|
+
fee = configuration.fee;
|
|
1055
|
+
return [3 /*break*/, 3];
|
|
1056
|
+
case 1: return [4 /*yield*/, this.getTransactionFeeWithPublicKey(publicKey, details)];
|
|
1057
|
+
case 2:
|
|
1058
|
+
estimatedFee = _a.sent();
|
|
1059
|
+
fee = estimatedFee.medium;
|
|
1060
|
+
_a.label = 3;
|
|
1061
|
+
case 3:
|
|
1062
|
+
wrappedFee = new bignumber_1.default((0, module_kit_1.newAmount)(fee).blockchain(this.units).value);
|
|
1063
|
+
transaction = (0, module_kit_1.newUnsignedTransaction)({
|
|
1064
|
+
ins: [],
|
|
1065
|
+
outs: []
|
|
1066
|
+
});
|
|
1067
|
+
return [4 /*yield*/, this.getAddressFromPublicKey(publicKey)];
|
|
1068
|
+
case 4:
|
|
1069
|
+
address = _a.sent();
|
|
1070
|
+
return [4 /*yield*/, index_1.default.get("".concat(this.options.network.indexerApi, "/api/v2/utxo/").concat(address), {
|
|
1071
|
+
responseType: 'json'
|
|
1072
|
+
})];
|
|
1073
|
+
case 5:
|
|
1074
|
+
utxos = (_a.sent()).data;
|
|
1075
|
+
totalRequiredBalance = details
|
|
1076
|
+
.map(function (_a) {
|
|
1077
|
+
var amount = _a.amount;
|
|
1078
|
+
return new bignumber_1.default((0, module_kit_1.newAmount)(amount).blockchain(_this.units).value);
|
|
1079
|
+
})
|
|
1080
|
+
.reduce(function (accumulator, currentValue) { return accumulator.plus(currentValue); })
|
|
1081
|
+
.plus(wrappedFee);
|
|
1082
|
+
valueAccumulator = new bignumber_1.default(0);
|
|
1083
|
+
for (_i = 0, utxos_1 = utxos; _i < utxos_1.length; _i++) {
|
|
1084
|
+
utxo = utxos_1[_i];
|
|
1085
|
+
valueAccumulator = valueAccumulator.plus(new bignumber_1.default(utxo.value));
|
|
1086
|
+
transaction.ins.push({
|
|
1087
|
+
txId: utxo.txid,
|
|
1088
|
+
value: new bignumber_1.default(utxo.value).toString(10),
|
|
1089
|
+
vout: utxo.vout,
|
|
1090
|
+
address: address
|
|
1091
|
+
});
|
|
1092
|
+
if (valueAccumulator.isGreaterThanOrEqualTo(totalRequiredBalance)) {
|
|
1093
|
+
break;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
if (valueAccumulator.isLessThan(totalRequiredBalance)) {
|
|
1097
|
+
throw new errors_1.BalanceError(coinlib_core_1.Domain.BITCOIN, "not enough balance, having ".concat(valueAccumulator.toFixed(), " of ").concat(totalRequiredBalance.toFixed()));
|
|
1098
|
+
}
|
|
1099
|
+
// tx.addInput(utxo.txid, utxo.vout)
|
|
1100
|
+
for (i = 0; i < details.length; i++) {
|
|
1101
|
+
value = (0, module_kit_1.newAmount)(details[i].amount).blockchain(this.units).value;
|
|
1102
|
+
transaction.outs.push({
|
|
1103
|
+
recipient: details[i].to,
|
|
1104
|
+
isChange: false,
|
|
1105
|
+
value: value
|
|
1106
|
+
});
|
|
1107
|
+
valueAccumulator = valueAccumulator.minus(value);
|
|
1108
|
+
// tx.addOutput(details[i].to, details[i].amount)
|
|
560
1109
|
}
|
|
561
|
-
|
|
562
|
-
if (
|
|
563
|
-
|
|
1110
|
+
changeValue = valueAccumulator.minus(wrappedFee);
|
|
1111
|
+
if (changeValue.isGreaterThan(new bignumber_1.default(DUST_AMOUNT))) {
|
|
1112
|
+
transaction.outs.push({
|
|
1113
|
+
recipient: address,
|
|
1114
|
+
isChange: true,
|
|
1115
|
+
value: changeValue.toString(10)
|
|
1116
|
+
});
|
|
564
1117
|
}
|
|
565
|
-
|
|
1118
|
+
return [2 /*return*/, transaction];
|
|
566
1119
|
}
|
|
567
|
-
|
|
568
|
-
amount = amount.minus(new bignumber_1.default(transaction.fees));
|
|
569
|
-
const airGapTransaction = {
|
|
570
|
-
from: tempAirGapTransactionFrom,
|
|
571
|
-
to: tempAirGapTransactionTo,
|
|
572
|
-
isInbound: tempAirGapTransactionIsInbound,
|
|
573
|
-
amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
|
|
574
|
-
fee: (0, module_kit_1.newAmount)(transaction.fees, 'blockchain'),
|
|
575
|
-
status: {
|
|
576
|
-
type: 'applied',
|
|
577
|
-
hash: transaction.txid,
|
|
578
|
-
block: transaction.blockHeight.toString()
|
|
579
|
-
},
|
|
580
|
-
network: this.options.network,
|
|
581
|
-
timestamp: transaction.blockTime
|
|
582
|
-
};
|
|
583
|
-
airGapTransactions.push(airGapTransaction);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
const hasNext = page < data.totalPages;
|
|
587
|
-
return {
|
|
588
|
-
transactions: airGapTransactions,
|
|
589
|
-
cursor: {
|
|
590
|
-
hasNext,
|
|
591
|
-
page: hasNext ? page + 1 : undefined
|
|
592
|
-
}
|
|
593
|
-
};
|
|
594
|
-
}
|
|
595
|
-
async getBalanceOfPublicKey(publicKey) {
|
|
596
|
-
switch (publicKey.type) {
|
|
597
|
-
case 'pub':
|
|
598
|
-
return this.getBalanceOfNonExtendedPublicKey(publicKey);
|
|
599
|
-
case 'xpub':
|
|
600
|
-
return this.getBalanceOfExtendedPublicKey(publicKey);
|
|
601
|
-
default:
|
|
602
|
-
(0, coinlib_core_1.assertNever)(publicKey);
|
|
603
|
-
throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Unsupported public key type.');
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
async getBalanceOfNonExtendedPublicKey(publicKey) {
|
|
607
|
-
const address = await this.getAddressFromPublicKey(publicKey);
|
|
608
|
-
return this.getBalanceOfAddresses([address]);
|
|
609
|
-
}
|
|
610
|
-
async getBalanceOfExtendedPublicKey(extendedPublicKey) {
|
|
611
|
-
const encodedExtendedPublicKey = this.convertExtendedPublicKey(extendedPublicKey, 'encoded');
|
|
612
|
-
const { data } = await index_1.default.get(`${this.options.network.indexerApi}/api/v2/xpub/${encodedExtendedPublicKey.value}?pageSize=1`, {
|
|
613
|
-
responseType: 'json'
|
|
1120
|
+
});
|
|
614
1121
|
});
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
1122
|
+
};
|
|
1123
|
+
BitcoinProtocolImpl.prototype.prepareTransactionWithExtendedPublicKey = function (extendedPublicKey, details, configuration) {
|
|
1124
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1125
|
+
var targetFee, estimatedFee, wrappedFee, transaction, utxos, totalRequiredBalance, valueAccumulator, getPathIndexes, _i, utxos_2, utxo, indexes, derivedPublicKey, derivedAddress, i, value, lastUsedInternalAddress, changeValue, changeAddressIndex, derivedPublicKey, derivedAddress;
|
|
1126
|
+
var _this = this;
|
|
1127
|
+
return __generator(this, function (_a) {
|
|
1128
|
+
switch (_a.label) {
|
|
1129
|
+
case 0:
|
|
1130
|
+
if (!((configuration === null || configuration === void 0 ? void 0 : configuration.fee) !== undefined)) return [3 /*break*/, 1];
|
|
1131
|
+
targetFee = configuration.fee;
|
|
1132
|
+
return [3 /*break*/, 3];
|
|
1133
|
+
case 1: return [4 /*yield*/, this.getTransactionFeeWithPublicKey(extendedPublicKey, details)];
|
|
1134
|
+
case 2:
|
|
1135
|
+
estimatedFee = _a.sent();
|
|
1136
|
+
targetFee = estimatedFee.medium;
|
|
1137
|
+
_a.label = 3;
|
|
1138
|
+
case 3:
|
|
1139
|
+
wrappedFee = new bignumber_1.default((0, module_kit_1.newAmount)(targetFee).blockchain(this.units).value);
|
|
1140
|
+
transaction = (0, module_kit_1.newUnsignedTransaction)({
|
|
1141
|
+
ins: [],
|
|
1142
|
+
outs: []
|
|
1143
|
+
});
|
|
1144
|
+
return [4 /*yield*/, index_1.default
|
|
1145
|
+
.get("".concat(this.options.network.indexerApi, "/api/v2/utxo/").concat(extendedPublicKey.value, "?confirmed=true"), {
|
|
1146
|
+
responseType: 'json'
|
|
1147
|
+
})
|
|
1148
|
+
.catch(function (error) {
|
|
1149
|
+
throw new errors_1.NetworkError(coinlib_core_1.Domain.BITCOIN, error);
|
|
1150
|
+
})];
|
|
1151
|
+
case 4:
|
|
1152
|
+
utxos = (_a.sent()).data;
|
|
1153
|
+
if (utxos.length <= 0) {
|
|
1154
|
+
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
|
|
1155
|
+
}
|
|
1156
|
+
totalRequiredBalance = details
|
|
1157
|
+
.map(function (_a) {
|
|
1158
|
+
var amount = _a.amount;
|
|
1159
|
+
return new bignumber_1.default((0, module_kit_1.newAmount)(amount).blockchain(_this.units).value);
|
|
1160
|
+
})
|
|
1161
|
+
.reduce(function (accumulator, currentValue) { return accumulator.plus(currentValue); })
|
|
1162
|
+
.plus(wrappedFee);
|
|
1163
|
+
valueAccumulator = new bignumber_1.default(0);
|
|
1164
|
+
getPathIndexes = function (path) {
|
|
1165
|
+
var result = path
|
|
1166
|
+
.split('/')
|
|
1167
|
+
.slice(-2)
|
|
1168
|
+
.map(function (item) { return parseInt(item, 10); })
|
|
1169
|
+
.filter(function (item) { return !isNaN(item); });
|
|
1170
|
+
if (result.length !== 2) {
|
|
1171
|
+
throw new errors_1.ConditionViolationError(coinlib_core_1.Domain.BITCOIN, 'Unexpected path format');
|
|
1172
|
+
}
|
|
1173
|
+
return [result[0], result[1]];
|
|
1174
|
+
};
|
|
1175
|
+
_i = 0, utxos_2 = utxos;
|
|
1176
|
+
_a.label = 5;
|
|
1177
|
+
case 5:
|
|
1178
|
+
if (!(_i < utxos_2.length)) return [3 /*break*/, 9];
|
|
1179
|
+
utxo = utxos_2[_i];
|
|
1180
|
+
valueAccumulator = valueAccumulator.plus(utxo.value);
|
|
1181
|
+
indexes = getPathIndexes(utxo.path);
|
|
1182
|
+
return [4 /*yield*/, this.deriveFromExtendedPublicKey(extendedPublicKey, indexes[0], indexes[1])];
|
|
1183
|
+
case 6:
|
|
1184
|
+
derivedPublicKey = _a.sent();
|
|
1185
|
+
return [4 /*yield*/, this.getAddressFromPublicKey(derivedPublicKey)];
|
|
1186
|
+
case 7:
|
|
1187
|
+
derivedAddress = _a.sent();
|
|
1188
|
+
if (derivedAddress === utxo.address) {
|
|
1189
|
+
transaction.ins.push({
|
|
1190
|
+
txId: utxo.txid,
|
|
1191
|
+
value: new bignumber_1.default(utxo.value).toString(10),
|
|
1192
|
+
vout: utxo.vout,
|
|
1193
|
+
address: utxo.address,
|
|
1194
|
+
derivationPath: indexes.join('/')
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1197
|
+
else {
|
|
1198
|
+
throw new errors_1.InvalidValueError(coinlib_core_1.Domain.BITCOIN, "Invalid address ".concat(JSON.stringify(utxo.address), " returned from API"));
|
|
1199
|
+
}
|
|
1200
|
+
if (valueAccumulator.isGreaterThanOrEqualTo(totalRequiredBalance)) {
|
|
1201
|
+
return [3 /*break*/, 9];
|
|
1202
|
+
}
|
|
1203
|
+
_a.label = 8;
|
|
1204
|
+
case 8:
|
|
1205
|
+
_i++;
|
|
1206
|
+
return [3 /*break*/, 5];
|
|
1207
|
+
case 9:
|
|
1208
|
+
if (valueAccumulator.isLessThan(totalRequiredBalance)) {
|
|
1209
|
+
throw new errors_1.BalanceError(coinlib_core_1.Domain.BITCOIN, 'not enough balance');
|
|
1210
|
+
}
|
|
1211
|
+
for (i = 0; i < details.length; i++) {
|
|
1212
|
+
value = (0, module_kit_1.newAmount)(details[i].amount).blockchain(this.units).value;
|
|
1213
|
+
transaction.outs.push({
|
|
1214
|
+
recipient: details[i].to,
|
|
1215
|
+
isChange: false,
|
|
1216
|
+
value: value,
|
|
1217
|
+
derivationPath: '' // TODO: Remove this as soon as our serializer supports optional properties
|
|
1218
|
+
});
|
|
1219
|
+
valueAccumulator = valueAccumulator.minus(value);
|
|
1220
|
+
}
|
|
1221
|
+
lastUsedInternalAddress = Math.max.apply(Math, __spreadArray([-1], utxos
|
|
1222
|
+
.map(function (utxo) { return getPathIndexes(utxo.path); })
|
|
1223
|
+
.filter(function (indexes) { return indexes[0] === 1; })
|
|
1224
|
+
.map(function (indexes) { return indexes[1]; }), false));
|
|
1225
|
+
changeValue = valueAccumulator.minus(wrappedFee);
|
|
1226
|
+
if (!changeValue.isGreaterThan(new bignumber_1.default(DUST_AMOUNT))) return [3 /*break*/, 12];
|
|
1227
|
+
changeAddressIndex = lastUsedInternalAddress + 1;
|
|
1228
|
+
return [4 /*yield*/, this.deriveFromExtendedPublicKey(extendedPublicKey, 1, changeAddressIndex)];
|
|
1229
|
+
case 10:
|
|
1230
|
+
derivedPublicKey = _a.sent();
|
|
1231
|
+
return [4 /*yield*/, this.getAddressFromPublicKey(derivedPublicKey)];
|
|
1232
|
+
case 11:
|
|
1233
|
+
derivedAddress = _a.sent();
|
|
1234
|
+
transaction.outs.push({
|
|
1235
|
+
recipient: derivedAddress,
|
|
1236
|
+
isChange: true,
|
|
1237
|
+
value: changeValue.toString(10),
|
|
1238
|
+
derivationPath: changeAddressIndex.toString()
|
|
1239
|
+
});
|
|
1240
|
+
_a.label = 12;
|
|
1241
|
+
case 12: return [2 /*return*/, transaction];
|
|
1242
|
+
}
|
|
723
1243
|
});
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
const wrappedFee = new bignumber_1.default((0, module_kit_1.newAmount)(targetFee).blockchain(this.units).value);
|
|
737
|
-
const transaction = (0, module_kit_1.newUnsignedTransaction)({
|
|
738
|
-
ins: [],
|
|
739
|
-
outs: []
|
|
740
|
-
});
|
|
741
|
-
const { data: utxos } = await index_1.default
|
|
742
|
-
.get(`${this.options.network.indexerApi}/api/v2/utxo/${extendedPublicKey.value}?confirmed=true`, {
|
|
743
|
-
responseType: 'json'
|
|
744
|
-
})
|
|
745
|
-
.catch((error) => {
|
|
746
|
-
throw new errors_1.NetworkError(coinlib_core_1.Domain.BITCOIN, error);
|
|
747
|
-
});
|
|
748
|
-
if (utxos.length <= 0) {
|
|
749
|
-
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
|
|
750
|
-
}
|
|
751
|
-
const totalRequiredBalance = details
|
|
752
|
-
.map(({ amount }) => new bignumber_1.default((0, module_kit_1.newAmount)(amount).blockchain(this.units).value))
|
|
753
|
-
.reduce((accumulator, currentValue) => accumulator.plus(currentValue))
|
|
754
|
-
.plus(wrappedFee);
|
|
755
|
-
let valueAccumulator = new bignumber_1.default(0);
|
|
756
|
-
const getPathIndexes = (path) => {
|
|
757
|
-
const result = path
|
|
758
|
-
.split('/')
|
|
759
|
-
.slice(-2)
|
|
760
|
-
.map((item) => parseInt(item, 10))
|
|
761
|
-
.filter((item) => !isNaN(item));
|
|
762
|
-
if (result.length !== 2) {
|
|
763
|
-
throw new errors_1.ConditionViolationError(coinlib_core_1.Domain.BITCOIN, 'Unexpected path format');
|
|
764
|
-
}
|
|
765
|
-
return [result[0], result[1]];
|
|
766
|
-
};
|
|
767
|
-
for (const utxo of utxos) {
|
|
768
|
-
valueAccumulator = valueAccumulator.plus(utxo.value);
|
|
769
|
-
const indexes = getPathIndexes(utxo.path);
|
|
770
|
-
const derivedPublicKey = await this.deriveFromExtendedPublicKey(extendedPublicKey, indexes[0], indexes[1]);
|
|
771
|
-
const derivedAddress = await this.getAddressFromPublicKey(derivedPublicKey);
|
|
772
|
-
if (derivedAddress === utxo.address) {
|
|
773
|
-
transaction.ins.push({
|
|
774
|
-
txId: utxo.txid,
|
|
775
|
-
value: new bignumber_1.default(utxo.value).toString(10),
|
|
776
|
-
vout: utxo.vout,
|
|
777
|
-
address: utxo.address,
|
|
778
|
-
derivationPath: indexes.join('/')
|
|
779
|
-
});
|
|
780
|
-
}
|
|
781
|
-
else {
|
|
782
|
-
throw new errors_1.InvalidValueError(coinlib_core_1.Domain.BITCOIN, `Invalid address ${JSON.stringify(utxo.address)} returned from API`);
|
|
783
|
-
}
|
|
784
|
-
if (valueAccumulator.isGreaterThanOrEqualTo(totalRequiredBalance)) {
|
|
785
|
-
break;
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
if (valueAccumulator.isLessThan(totalRequiredBalance)) {
|
|
789
|
-
throw new errors_1.BalanceError(coinlib_core_1.Domain.BITCOIN, 'not enough balance');
|
|
790
|
-
}
|
|
791
|
-
for (let i = 0; i < details.length; i++) {
|
|
792
|
-
const value = (0, module_kit_1.newAmount)(details[i].amount).blockchain(this.units).value;
|
|
793
|
-
transaction.outs.push({
|
|
794
|
-
recipient: details[i].to,
|
|
795
|
-
isChange: false,
|
|
796
|
-
value,
|
|
797
|
-
derivationPath: '' // TODO: Remove this as soon as our serializer supports optional properties
|
|
798
|
-
});
|
|
799
|
-
valueAccumulator = valueAccumulator.minus(value);
|
|
800
|
-
}
|
|
801
|
-
const lastUsedInternalAddress = Math.max(-1, ...utxos
|
|
802
|
-
.map((utxo) => getPathIndexes(utxo.path))
|
|
803
|
-
.filter((indexes) => indexes[0] === 1)
|
|
804
|
-
.map((indexes) => indexes[1]));
|
|
805
|
-
// If the change is considered dust, the transaction will fail.
|
|
806
|
-
// Dust is a variable value around 300-600 satoshis, depending on the configuration.
|
|
807
|
-
// We set a low fee here to not block any transactions, but it might still fail due to "dust".
|
|
808
|
-
const changeValue = valueAccumulator.minus(wrappedFee);
|
|
809
|
-
if (changeValue.isGreaterThan(new bignumber_1.default(DUST_AMOUNT))) {
|
|
810
|
-
const changeAddressIndex = lastUsedInternalAddress + 1;
|
|
811
|
-
const derivedPublicKey = await this.deriveFromExtendedPublicKey(extendedPublicKey, 1, changeAddressIndex);
|
|
812
|
-
const derivedAddress = await this.getAddressFromPublicKey(derivedPublicKey);
|
|
813
|
-
transaction.outs.push({
|
|
814
|
-
recipient: derivedAddress,
|
|
815
|
-
isChange: true,
|
|
816
|
-
value: changeValue.toString(10),
|
|
817
|
-
derivationPath: changeAddressIndex.toString()
|
|
1244
|
+
});
|
|
1245
|
+
};
|
|
1246
|
+
BitcoinProtocolImpl.prototype.broadcastTransaction = function (transaction) {
|
|
1247
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1248
|
+
var data;
|
|
1249
|
+
return __generator(this, function (_a) {
|
|
1250
|
+
switch (_a.label) {
|
|
1251
|
+
case 0: return [4 /*yield*/, index_1.default.post("".concat(this.options.network.indexerApi, "/api/v2/sendtx/"), transaction.transaction)];
|
|
1252
|
+
case 1:
|
|
1253
|
+
data = (_a.sent()).data;
|
|
1254
|
+
return [2 /*return*/, data.result];
|
|
1255
|
+
}
|
|
818
1256
|
});
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
}
|
|
822
|
-
async broadcastTransaction(transaction) {
|
|
823
|
-
const { data } = await index_1.default.post(`${this.options.network.indexerApi}/api/v2/sendtx/`, transaction.transaction);
|
|
824
|
-
return data.result;
|
|
825
|
-
}
|
|
1257
|
+
});
|
|
1258
|
+
};
|
|
826
1259
|
// Custom
|
|
827
|
-
convertExtendedSecretKey(extendedSecretKey, targetFormat) {
|
|
1260
|
+
BitcoinProtocolImpl.prototype.convertExtendedSecretKey = function (extendedSecretKey, targetFormat) {
|
|
828
1261
|
return (0, key_1.convertExtendedSecretKey)(extendedSecretKey, {
|
|
829
1262
|
format: targetFormat,
|
|
830
1263
|
type: this.keyConfiguration.xpriv.type,
|
|
831
1264
|
hashFunction: this.bitcoinJS.config.network.hashFunctions.address
|
|
832
1265
|
});
|
|
833
|
-
}
|
|
834
|
-
convertExtendedPublicKey(extendedPublicKey, targetFormat) {
|
|
1266
|
+
};
|
|
1267
|
+
BitcoinProtocolImpl.prototype.convertExtendedPublicKey = function (extendedPublicKey, targetFormat) {
|
|
835
1268
|
return (0, key_1.convertExtendedPublicKey)(extendedPublicKey, {
|
|
836
1269
|
format: targetFormat,
|
|
837
1270
|
type: this.keyConfiguration.xpub.type,
|
|
838
1271
|
hashFunction: this.bitcoinJS.config.network.hashFunctions.address
|
|
839
1272
|
});
|
|
840
|
-
}
|
|
841
|
-
convertCryptoDerivative(derivative) {
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
secretKey: `00${derivative.secretKey}`
|
|
845
|
-
});
|
|
846
|
-
const extendedSecretKey = {
|
|
1273
|
+
};
|
|
1274
|
+
BitcoinProtocolImpl.prototype.convertCryptoDerivative = function (derivative) {
|
|
1275
|
+
var hexNode = (0, crypto_1.encodeDerivative)('hex', __assign(__assign({}, derivative), { secretKey: "00".concat(derivative.secretKey) }));
|
|
1276
|
+
var extendedSecretKey = {
|
|
847
1277
|
type: 'xpriv',
|
|
848
1278
|
format: 'hex',
|
|
849
1279
|
value: hexNode.secretKey
|
|
850
1280
|
};
|
|
851
1281
|
return this.convertExtendedSecretKey(extendedSecretKey, 'encoded');
|
|
852
|
-
}
|
|
853
|
-
derivativeToBip32Node(derivative) {
|
|
854
|
-
|
|
1282
|
+
};
|
|
1283
|
+
BitcoinProtocolImpl.prototype.derivativeToBip32Node = function (derivative) {
|
|
1284
|
+
var extendedSecretKey = this.convertCryptoDerivative(derivative);
|
|
855
1285
|
return this.bitcoinJS.lib.HDNode.fromBase58(extendedSecretKey.value, this.bitcoinJS.config.network);
|
|
856
|
-
}
|
|
857
|
-
|
|
1286
|
+
};
|
|
1287
|
+
return BitcoinProtocolImpl;
|
|
1288
|
+
}());
|
|
858
1289
|
exports.BitcoinProtocolImpl = BitcoinProtocolImpl;
|
|
859
1290
|
// Factory
|
|
860
|
-
function createBitcoinProtocol(options
|
|
1291
|
+
function createBitcoinProtocol(options) {
|
|
1292
|
+
if (options === void 0) { options = {}; }
|
|
861
1293
|
return new BitcoinProtocolImpl(options);
|
|
862
1294
|
}
|
|
1295
|
+
exports.createBitcoinProtocol = createBitcoinProtocol;
|
|
863
1296
|
exports.BITCOIN_MAINNET_PROTOCOL_NETWORK = {
|
|
864
1297
|
name: 'Mainnet',
|
|
865
1298
|
type: 'mainnet',
|
|
@@ -867,12 +1300,13 @@ exports.BITCOIN_MAINNET_PROTOCOL_NETWORK = {
|
|
|
867
1300
|
blockExplorerUrl: 'https://live.blockcypher.com/btc',
|
|
868
1301
|
indexerApi: 'https://bitcoin.prod.gke.papers.tech'
|
|
869
1302
|
};
|
|
870
|
-
|
|
871
|
-
function createBitcoinProtocolOptions(network
|
|
1303
|
+
var DEFAULT_BITCOIN_PROTOCOL_NETWORK = exports.BITCOIN_MAINNET_PROTOCOL_NETWORK;
|
|
1304
|
+
function createBitcoinProtocolOptions(network) {
|
|
1305
|
+
if (network === void 0) { network = {}; }
|
|
872
1306
|
return {
|
|
873
1307
|
network: network.type === 'custom'
|
|
874
|
-
? {
|
|
875
|
-
: { ...DEFAULT_BITCOIN_PROTOCOL_NETWORK, ...network }
|
|
1308
|
+
? __assign(__assign(__assign({}, DEFAULT_BITCOIN_PROTOCOL_NETWORK), { bitcoinjsNetworkName: 'bitcoin' }), network) : __assign(__assign({}, DEFAULT_BITCOIN_PROTOCOL_NETWORK), network)
|
|
876
1309
|
};
|
|
877
1310
|
}
|
|
1311
|
+
exports.createBitcoinProtocolOptions = createBitcoinProtocolOptions;
|
|
878
1312
|
//# sourceMappingURL=BitcoinProtocol.js.map
|