@airgap/bitcoin 0.13.45-beta.1 → 0.13.45-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/package.json +5 -5
  2. package/v0/index.js +10 -10
  3. package/v0/index.js.map +1 -1
  4. package/v0/protocol/BitcoinAddress.js +8 -9
  5. package/v0/protocol/BitcoinAddress.js.map +1 -1
  6. package/v0/protocol/BitcoinCryptoClient.js +16 -85
  7. package/v0/protocol/BitcoinCryptoClient.js.map +1 -1
  8. package/v0/protocol/BitcoinProtocol.js +590 -987
  9. package/v0/protocol/BitcoinProtocol.js.map +1 -1
  10. package/v0/protocol/BitcoinProtocolOptions.js +45 -111
  11. package/v0/protocol/BitcoinProtocolOptions.js.map +1 -1
  12. package/v0/protocol/BitcoinSegwitAddress.js +12 -29
  13. package/v0/protocol/BitcoinSegwitAddress.js.map +1 -1
  14. package/v0/protocol/BitcoinSegwitProtocol.js +348 -483
  15. package/v0/protocol/BitcoinSegwitProtocol.js.map +1 -1
  16. package/v0/protocol/BitcoinTestnetProtocol.js +28 -36
  17. package/v0/protocol/BitcoinTestnetProtocol.js.map +1 -1
  18. package/v0/serializer/validators/transaction-validator.js +22 -30
  19. package/v0/serializer/validators/transaction-validator.js.map +1 -1
  20. package/v0/serializer/validators/validators.js +23 -23
  21. package/v0/serializer/validators/validators.js.map +1 -1
  22. package/v1/block-explorer/BlockCypherBlockExplorer.js +12 -61
  23. package/v1/block-explorer/BlockCypherBlockExplorer.js.map +1 -1
  24. package/v1/data/BitcoinAddress.js +9 -10
  25. package/v1/data/BitcoinAddress.js.map +1 -1
  26. package/v1/data/BitcoinLegacyAddress.js +11 -12
  27. package/v1/data/BitcoinLegacyAddress.js.map +1 -1
  28. package/v1/data/BitcoinSegwitAddress.js +11 -12
  29. package/v1/data/BitcoinSegwitAddress.js.map +1 -1
  30. package/v1/data/BitcoinTaprootAddress.js +31 -22
  31. package/v1/data/BitcoinTaprootAddress.js.map +1 -1
  32. package/v1/index.js +11 -11
  33. package/v1/index.js.map +1 -1
  34. package/v1/module/BitcoinModule.d.ts +1 -1
  35. package/v1/module/BitcoinModule.js +44 -102
  36. package/v1/module/BitcoinModule.js.map +1 -1
  37. package/v1/module.js +2 -3
  38. package/v1/module.js.map +1 -1
  39. package/v1/protocol/BitcoinCryptoClient.js +22 -90
  40. package/v1/protocol/BitcoinCryptoClient.js.map +1 -1
  41. package/v1/protocol/BitcoinLegacyProtocol.js +520 -796
  42. package/v1/protocol/BitcoinLegacyProtocol.js.map +1 -1
  43. package/v1/protocol/BitcoinProtocol.js +735 -1169
  44. package/v1/protocol/BitcoinProtocol.js.map +1 -1
  45. package/v1/protocol/BitcoinSegwitProtocol.js +542 -796
  46. package/v1/protocol/BitcoinSegwitProtocol.js.map +1 -1
  47. package/v1/protocol/BitcoinTaprootProtocol.js +688 -1000
  48. package/v1/protocol/BitcoinTaprootProtocol.js.map +1 -1
  49. package/v1/protocol/BitcoinTestnetProtocol.js +14 -33
  50. package/v1/protocol/BitcoinTestnetProtocol.js.map +1 -1
  51. package/v1/serializer/v3/schemas/converter/transaction-converter.js +29 -52
  52. package/v1/serializer/v3/schemas/converter/transaction-converter.js.map +1 -1
  53. package/v1/serializer/v3/serializer-companion.js +98 -165
  54. package/v1/serializer/v3/serializer-companion.js.map +1 -1
  55. package/v1/serializer/v3/validators/transaction-validator.js +13 -16
  56. package/v1/serializer/v3/validators/transaction-validator.js.map +1 -1
  57. package/v1/serializer/v3/validators/validators.js +122 -213
  58. package/v1/serializer/v3/validators/validators.js.map +1 -1
  59. package/v1/types/crypto.d.ts +1 -1
  60. package/v1/types/key.d.ts +6 -6
  61. package/v1/types/protocol.d.ts +2 -2
  62. package/v1/types/transaction.d.ts +3 -3
  63. package/v1/utils/common.js +4 -6
  64. package/v1/utils/common.js.map +1 -1
  65. package/v1/utils/key.d.ts +5 -6
  66. package/v1/utils/key.js +38 -39
  67. package/v1/utils/key.js.map +1 -1
  68. package/v1/utils/network.js +3 -4
  69. package/v1/utils/network.js.map +1 -1
  70. package/v1/utils/protocol.js +25 -19
  71. package/v1/utils/protocol.js.map +1 -1
  72. package/v1/utils/signature.js +4 -5
  73. package/v1/utils/signature.js.map +1 -1
@@ -1,15 +1,4 @@
1
1
  "use strict";
2
- var __assign = (this && this.__assign) || function () {
3
- __assign = Object.assign || function(t) {
4
- for (var s, i = 1, n = arguments.length; i < n; i++) {
5
- s = arguments[i];
6
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
- t[p] = s[p];
8
- }
9
- return t;
10
- };
11
- return __assign.apply(this, arguments);
12
- };
13
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
3
  if (k2 === undefined) k2 = k;
15
4
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -26,85 +15,49 @@ 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 (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
- };
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.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");
39
+ exports.BITCOIN_MAINNET_PROTOCOL_NETWORK = exports.BitcoinProtocolImpl = void 0;
40
+ exports.createBitcoinProtocol = createBitcoinProtocol;
41
+ exports.createBitcoinProtocolOptions = createBitcoinProtocolOptions;
42
+ const coinlib_core_1 = require("@airgap/coinlib-core");
43
+ const index_1 = __importDefault(require("@airgap/coinlib-core/dependencies/src/axios-0.19.0/index"));
44
+ const BigInteger = __importStar(require("@airgap/coinlib-core/dependencies/src/bigi-1.4.2"));
45
+ const bignumber_1 = __importDefault(require("@airgap/coinlib-core/dependencies/src/bignumber.js-9.0.0/bignumber"));
46
+ const bitcoinMessage = __importStar(require("@airgap/coinlib-core/dependencies/src/bitcoinjs-message-2.1.1/index"));
47
+ const BitGo = __importStar(require("@airgap/coinlib-core/dependencies/src/bitgo-utxo-lib-5d91049fd7a988382df81c8260e244ee56d57aac/src/index"));
48
+ const errors_1 = require("@airgap/coinlib-core/errors");
49
+ const crypto_1 = require("@airgap/crypto");
50
+ const module_kit_1 = require("@airgap/module-kit");
51
+ const BitcoinAddress_1 = require("../data/BitcoinAddress");
52
+ const common_1 = require("../utils/common");
53
+ const key_1 = require("../utils/key");
54
+ const network_1 = require("../utils/network");
55
+ const signature_1 = require("../utils/signature");
56
+ const BitcoinCryptoClient_1 = require("./BitcoinCryptoClient");
101
57
  // Implementation
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; }
58
+ const DUST_AMOUNT = 50;
59
+ class BitcoinProtocolImpl {
60
+ constructor(options = {}, keyConfiguration, bitcoinJS = BitGo, bitcoinJSMessage = bitcoinMessage) {
108
61
  this._isBitcoinProtocol = true;
109
62
  // Common
110
63
  this.units = {
@@ -135,7 +88,7 @@ var BitcoinProtocolImpl = /** @class */ (function () {
135
88
  defaults: this.feeDefaults
136
89
  },
137
90
  account: {
138
- standardDerivationPath: "m/44'/0'/0'",
91
+ standardDerivationPath: `m/44'/0'/0'`,
139
92
  address: {
140
93
  isCaseSensitive: true,
141
94
  placeholder: '1ABC...',
@@ -156,7 +109,7 @@ var BitcoinProtocolImpl = /** @class */ (function () {
156
109
  }
157
110
  };
158
111
  this.cryptoClient = new BitcoinCryptoClient_1.BitcoinCryptoClient(this, this.bitcoinJS);
159
- this.keyConfiguration = keyConfiguration !== null && keyConfiguration !== void 0 ? keyConfiguration : {
112
+ this.keyConfiguration = keyConfiguration ?? {
160
113
  xpriv: {
161
114
  type: 'xprv'
162
115
  },
@@ -165,1134 +118,748 @@ var BitcoinProtocolImpl = /** @class */ (function () {
165
118
  }
166
119
  };
167
120
  }
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.');
121
+ async getMetadata() {
122
+ return this.metadata;
123
+ }
124
+ async getAddressFromPublicKey(publicKey) {
125
+ switch (publicKey.type) {
126
+ case 'pub':
127
+ return this.getAddressFromNonExtendedPublicKey(publicKey);
128
+ case 'xpub':
129
+ return this.getAddressFromExtendedPublicKey(publicKey);
130
+ default:
131
+ (0, coinlib_core_1.assertNever)(publicKey);
132
+ throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Public key type is not supported.');
133
+ }
134
+ }
135
+ async getAddressFromNonExtendedPublicKey(publicKey) {
136
+ const hexPublicKey = (0, key_1.convertPublicKey)(publicKey, 'hex');
137
+ const keyPair = this.bitcoinJS.lib.ECPair.fromPublicKeyBuffer(Buffer.from(hexPublicKey.value, 'hex'), this.bitcoinJS.config.network);
138
+ return BitcoinAddress_1.BitcoinAddress.fromECPair(keyPair).asString();
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);
186
205
  }
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.');
206
+ else {
207
+ ourGeneratedAddress = await this.getAddressFromNonExtendedPublicKey(publickey);
235
208
  }
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
- // }
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));
209
+ if (ourGeneratedAddress === address) {
210
+ isOwned = true;
211
+ }
212
+ else {
213
+ for (let x = 0; x < 1000; x++) {
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;
280
220
  }
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
- ]];
221
+ }
392
222
  }
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)];
223
+ }
224
+ if (isChangeAddress && isOwned) {
225
+ uiAlerts.push({
226
+ type: 'success',
227
+ title: {
228
+ type: 'plain',
229
+ value: ''
230
+ },
231
+ description: {
232
+ type: 'plain',
233
+ value: 'Note: your change address has been verified'
234
+ },
235
+ icon: undefined,
236
+ actions: undefined
237
+ });
238
+ }
239
+ else if (isChangeAddress && !isOwned) {
240
+ uiAlerts.push({
241
+ type: 'warning',
242
+ title: {
243
+ type: 'plain',
244
+ value: ''
245
+ },
246
+ description: {
247
+ type: 'plain',
248
+ value: 'Note: your change address has not been verified'
249
+ },
250
+ icon: undefined,
251
+ actions: undefined
252
+ });
253
+ }
254
+ return [
255
+ address,
256
+ {
257
+ isChangeAddress: isChangeAddress,
258
+ isOwned: isOwned,
259
+ path: addressIndex === 0 ? '' : `m/84'/0'/0'/1/${addressIndex}`,
260
+ amount
422
261
  }
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.');
262
+ ];
263
+ }));
264
+ const changeAddressInfo = {};
265
+ changeAddressDatas.forEach((changeAddressData) => {
266
+ changeAddressInfo[changeAddressData[0]] = changeAddressData[1];
267
+ });
268
+ return [
269
+ {
270
+ from: transaction.ins.map((obj) => obj.address),
271
+ to: transaction.outs.map((obj) => obj.recipient),
272
+ isInbound: false,
273
+ amount: (0, module_kit_1.newAmount)(transaction.outs.map((obj) => new bignumber_1.default(obj.value)).reduce((accumulator, currentValue) => accumulator.plus(currentValue)), 'blockchain'),
274
+ fee: (0, module_kit_1.newAmount)(fee, 'blockchain'),
275
+ network: this.options.network,
276
+ changeAddressInfo,
277
+ uiAlerts
278
+ }
279
+ ];
280
+ }
281
+ async verifyMessageWithPublicKey(message, signature, publicKey) {
282
+ const encodedSignature = (0, signature_1.convertSignature)(signature, 'encoded');
283
+ return this.cryptoClient.verifyMessage(message, encodedSignature.value, publicKey.value);
284
+ }
285
+ async encryptAsymmetricWithPublicKey(payload, publicKey) {
286
+ const nonExtendedPublicKey = publicKey.type === 'pub' ? publicKey : await this.deriveFromExtendedPublicKey(publicKey, 0, 0);
287
+ const hexNonExtendedPublicKey = (0, key_1.convertPublicKey)(nonExtendedPublicKey, 'hex');
288
+ return this.cryptoClient.encryptAsymmetric(payload, hexNonExtendedPublicKey.value);
289
+ }
290
+ async getCryptoConfiguration() {
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.');
481
342
  }
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.');
514
- }
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)];
343
+ }
344
+ transactionBuilder.addOutput(output.recipient, new bignumber_1.default(output.value).toNumber());
345
+ }
346
+ for (let i = 0; i < transaction.ins.length; i++) {
347
+ transactionBuilder.sign(i, Buffer.from(hexSecretKey.value, 'hex'));
348
+ }
349
+ return this.createSignedTransaction(transaction, transactionBuilder);
350
+ }
351
+ async signTransactionWithExtendedSecretKey(transaction, extendedSecretKey) {
352
+ const encodedExtendedSecretKey = this.convertExtendedSecretKey(extendedSecretKey, 'encoded');
353
+ const transactionBuilder = new this.bitcoinJS.lib.TransactionBuilder(this.bitcoinJS.config.network);
354
+ const node = this.bitcoinJS.lib.HDNode.fromBase58(encodedExtendedSecretKey.value, this.bitcoinJS.config.network);
355
+ for (const input of transaction.ins) {
356
+ transactionBuilder.addInput(input.txId, input.vout);
357
+ }
358
+ const changeAddressBatchSize = 10;
359
+ const changeAddressMaxAddresses = 500;
360
+ for (const output of transaction.outs) {
361
+ let changeAddressIsValid = false;
362
+ if (output.isChange) {
363
+ const extendedPublicKey = (0, module_kit_1.newExtendedPublicKey)(node.neutered().toBase58(), 'encoded');
364
+ if (output.derivationPath) {
365
+ const derivedPublicKey = await this.deriveFromExtendedPublicKey(extendedPublicKey, 1, parseInt(output.derivationPath, 10));
366
+ const generatedChangeAddress = await this.getAddressFromPublicKey(derivedPublicKey);
367
+ changeAddressIsValid = generatedChangeAddress === output.recipient;
527
368
  }
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));
369
+ else {
370
+ for (let x = 0; x < changeAddressMaxAddresses; x += changeAddressBatchSize) {
371
+ const derivedPublicKeys = await Promise.all(Array.from(new Array(changeAddressBatchSize)).map(async () => {
372
+ return this.deriveFromExtendedPublicKey(extendedPublicKey, 1, x);
373
+ }));
374
+ const addresses = await Promise.all(derivedPublicKeys.map((publicKey) => {
375
+ return this.getAddressFromPublicKey(publicKey);
376
+ }));
377
+ if (addresses.indexOf(output.recipient) >= 0) {
378
+ changeAddressIsValid = true;
379
+ x = changeAddressMaxAddresses;
629
380
  }
630
- return [2 /*return*/, this.createSignedTransaction(transaction, transactionBuilder)];
381
+ }
631
382
  }
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];
383
+ if (!changeAddressIsValid) {
384
+ throw new errors_1.InvalidValueError(coinlib_core_1.Domain.BITCOIN, 'Change address could not be verified.');
385
+ }
386
+ }
387
+ transactionBuilder.addOutput(output.recipient, new bignumber_1.default(output.value).toNumber());
388
+ }
389
+ for (let i = 0; i < transaction.ins.length; i++) {
390
+ transactionBuilder.sign(i, node.derivePath(transaction.ins[i].derivationPath));
391
+ }
392
+ return this.createSignedTransaction(transaction, transactionBuilder);
393
+ }
394
+ createSignedTransaction(unsignedTransaction, transactionBuilder) {
395
+ let fee = new bignumber_1.default(0);
396
+ for (const txIn of unsignedTransaction.ins) {
639
397
  fee = fee.plus(new bignumber_1.default(txIn.value));
640
398
  }
641
- for (var _b = 0, _c = unsignedTransaction.outs; _b < _c.length; _b++) {
642
- var txOut = _c[_b];
399
+ for (const txOut of unsignedTransaction.outs) {
643
400
  fee = fee.minus(new bignumber_1.default(txOut.value));
644
401
  }
645
402
  return (0, module_kit_1.newSignedTransaction)({
646
- from: unsignedTransaction.ins.map(function (obj) { return obj.address; }),
647
- to: unsignedTransaction.outs.map(function (obj) { return obj.recipient; }),
403
+ from: unsignedTransaction.ins.map((obj) => obj.address),
404
+ to: unsignedTransaction.outs.map((obj) => obj.recipient),
648
405
  amount: unsignedTransaction.outs
649
- .map(function (obj) { return new bignumber_1.default(obj.value); })
650
- .reduce(function (accumulator, currentValue) { return accumulator.plus(currentValue); })
406
+ .map((obj) => new bignumber_1.default(obj.value))
407
+ .reduce((accumulator, currentValue) => accumulator.plus(currentValue))
651
408
  .toString(10),
652
409
  fee: fee.toString(10),
653
410
  transaction: transactionBuilder.build().toHex()
654
411
  });
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
- };
412
+ }
413
+ async signMessageWithKeyPair(message, keyPair) {
414
+ const hexSecretKey = keyPair.secretKey.type === 'priv'
415
+ ? (0, key_1.convertSecretKey)(keyPair.secretKey, 'hex')
416
+ : (0, key_1.convertExtendedSecretKey)(keyPair.secretKey, { format: 'hex' });
417
+ const signature = await this.cryptoClient.signMessage(message, { privateKey: hexSecretKey.value });
418
+ return (0, module_kit_1.newSignature)(signature, 'encoded');
419
+ }
420
+ async decryptAsymmetricWithKeyPair(payload, keyPair) {
421
+ let hexSecretKey = undefined;
422
+ if (keyPair.secretKey.type === 'priv') {
423
+ hexSecretKey = (0, key_1.convertSecretKey)(keyPair.secretKey, 'hex');
424
+ }
425
+ else {
426
+ const encodedExtendedSecretKey = this.convertExtendedSecretKey(keyPair.secretKey, 'encoded');
427
+ const node = this.bitcoinJS.lib.HDNode.fromBase58(encodedExtendedSecretKey.value, this.bitcoinJS.config.network);
428
+ const derivedNode = node.derive(0).derive(0);
429
+ hexSecretKey = (0, module_kit_1.newSecretKey)(derivedNode.keyPair.getPrivateKeyBuffer(), 'hex');
430
+ }
431
+ return this.cryptoClient.decryptAsymmetric(payload, { publicKey: '', privateKey: hexSecretKey.value });
432
+ }
433
+ async encryptAESWithSecretKey(payload, secretKey) {
434
+ return this.cryptoClient.encryptAES(payload, secretKey.value);
435
+ }
436
+ async decryptAESWithSecretKey(payload, secretKey) {
437
+ return this.cryptoClient.decryptAES(payload, secretKey.value);
438
+ }
705
439
  // Online
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');
724
- }
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)];
738
- }
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
- }];
824
- }
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
- }];
440
+ async getNetwork() {
441
+ return this.options.network;
442
+ }
443
+ async getTransactionsForPublicKey(publicKey, limit, cursor) {
444
+ switch (publicKey.type) {
445
+ case 'pub':
446
+ return this.getTransactionsForNonExtendedPublicKey(publicKey, limit, cursor);
447
+ case 'xpub':
448
+ return this.getTransactionsForExtendedPublicKey(publicKey, limit, cursor);
449
+ default:
450
+ (0, coinlib_core_1.assertNever)(publicKey);
451
+ throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Public key type not supported');
452
+ }
453
+ }
454
+ async getTransactionsForNonExtendedPublicKey(publicKey, limit, cursor) {
455
+ const address = await this.getAddressFromPublicKey(publicKey);
456
+ return this.getTransactionsForAddresses([address], limit, cursor);
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)
955
480
  }
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
- }];
481
+ for (const vout of transaction.vout) {
482
+ if (vout.addresses) {
483
+ tempAirGapTransactionTo.push(...vout.addresses);
484
+ // If receiving address is our address, and transaction is outbound => our change
485
+ // if (containsSome(vout.addresses, ourAddresses) && !tempAirGapTransactionIsInbound) {
486
+ // remove only if related to this address
487
+ // amount = amount.minus(vout.value)
488
+ // }
489
+ // If receiving address is not ours, and transaction isbound => senders change
490
+ // if (!containsSome(vout.addresses, ourAddresses) && tempAirGapTransactionIsInbound) {
491
+ // amount = amount.minus(vout.value)
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
+ }
991
498
  }
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];
499
+ // deduct fee from amount
500
+ //amount = amount.minus(transaction.fees)
501
+ if (amountNotAdded) {
502
+ amount = amount.plus(transaction.vout[0].value);
1001
503
  }
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.');
504
+ const airGapTransaction = {
505
+ from: tempAirGapTransactionFrom,
506
+ to: tempAirGapTransactionTo,
507
+ isInbound: tempAirGapTransactionIsInbound,
508
+ amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
509
+ fee: (0, module_kit_1.newAmount)(transaction.fees, 'blockchain'),
510
+ status: {
511
+ type: 'applied',
512
+ hash: transaction.txid,
513
+ block: transaction.blockHeight.toString()
514
+ },
515
+ network: this.options.network,
516
+ timestamp: transaction.blockTime
517
+ };
518
+ airGapTransactions.push(airGapTransaction);
519
+ }
520
+ }
521
+ const hasNext = page < data.totalPages;
522
+ return {
523
+ transactions: airGapTransactions,
524
+ cursor: {
525
+ hasNext,
526
+ page: hasNext ? page + 1 : undefined
527
+ }
528
+ };
529
+ }
530
+ async getTransactionsForAddress(address, limit, cursor) {
531
+ return this.getTransactionsForAddresses([address], limit, cursor);
532
+ }
533
+ async getTransactionsForAddresses(addresses, limit, cursor) {
534
+ const airGapTransactions = [];
535
+ const page = cursor?.page ?? 1;
536
+ const url = `${this.options.network.indexerApi}/api/v2/address/${addresses[0]}?page=${page}&pageSize=${limit}&details=txs`;
537
+ const { data } = await index_1.default.get(url, {
538
+ responseType: 'json'
539
+ });
540
+ if (data.page == page) {
541
+ for (const transaction of data.transactions || []) {
542
+ const tempAirGapTransactionFrom = [];
543
+ const tempAirGapTransactionTo = [];
544
+ let tempAirGapTransactionIsInbound = true;
545
+ let amount = new bignumber_1.default(0);
546
+ for (const vin of transaction.vin) {
547
+ if (vin.addresses && (0, common_1.containsSome)(vin.addresses, addresses)) {
548
+ tempAirGapTransactionIsInbound = false;
549
+ }
550
+ tempAirGapTransactionFrom.push(...vin.addresses);
551
+ amount = vin.value ? amount.plus(vin.value) : amount;
1041
552
  }
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)
553
+ for (const vout of transaction.vout) {
554
+ if (vout.addresses) {
555
+ tempAirGapTransactionTo.push(...vout.addresses);
556
+ // If receiving address is our address, and transaction is outbound => our change
557
+ if ((0, common_1.containsSome)(vout.addresses, addresses) && !tempAirGapTransactionIsInbound) {
558
+ // remove only if related to this address
559
+ amount = amount.minus(new bignumber_1.default(vout.value));
1109
560
  }
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
- });
561
+ // If receiving address is not ours, and transaction isbound => senders change
562
+ if (!(0, common_1.containsSome)(vout.addresses, addresses) && tempAirGapTransactionIsInbound) {
563
+ amount = amount.minus(new bignumber_1.default(vout.value));
1117
564
  }
1118
- return [2 /*return*/, transaction];
565
+ }
1119
566
  }
1120
- });
567
+ // deduct fee from amount
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'
1121
614
  });
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
- }
615
+ return {
616
+ total: (0, module_kit_1.newAmount)(data.balance, 'blockchain')
617
+ };
618
+ }
619
+ async getBalanceOfAddress(address) {
620
+ return this.getBalanceOfAddresses([address]);
621
+ }
622
+ async getBalanceOfAddresses(addresses) {
623
+ let valueAccumulator = new bignumber_1.default(0);
624
+ // The API doesn't support batch checking of balances, so we have to do it manually
625
+ for (const address of addresses) {
626
+ const { data } = await index_1.default.get(`${this.options.network.indexerApi}/api/v2/address/${address}?details=basic`, {
627
+ responseType: 'json'
628
+ });
629
+ valueAccumulator = valueAccumulator.plus(new bignumber_1.default(data.balance));
630
+ }
631
+ return {
632
+ total: (0, module_kit_1.newAmount)(valueAccumulator, 'blockchain')
633
+ };
634
+ }
635
+ async getTransactionMaxAmountWithPublicKey(publicKey, to, configuration) {
636
+ return (await this.getBalanceOfPublicKey(publicKey)).total;
637
+ }
638
+ async getTransactionFeeWithPublicKey(_publicKey, _details, _configuration) {
639
+ const result = (await index_1.default.get(`${this.options.network.indexerApi}/api/v2/estimatefee/5`)).data.result;
640
+ const estimatedFee = new bignumber_1.default((0, module_kit_1.newAmount)(result, 'BTC').blockchain(this.units).value);
641
+ if (estimatedFee.isZero()) {
642
+ return this.feeDefaults;
643
+ }
644
+ const feeStepFactor = new bignumber_1.default(0.5);
645
+ const mediumFee = estimatedFee;
646
+ const lowFee = mediumFee.minus(mediumFee.times(feeStepFactor)).integerValue(bignumber_1.default.ROUND_FLOOR);
647
+ const highFee = mediumFee.plus(mediumFee.times(feeStepFactor)).integerValue(bignumber_1.default.ROUND_FLOOR);
648
+ return {
649
+ low: (0, module_kit_1.newAmount)(lowFee, 'blockchain'),
650
+ medium: (0, module_kit_1.newAmount)(mediumFee, 'blockchain'),
651
+ high: (0, module_kit_1.newAmount)(highFee, 'blockchain')
652
+ };
653
+ }
654
+ async prepareTransactionWithPublicKey(publicKey, details, configuration) {
655
+ switch (publicKey.type) {
656
+ case 'pub':
657
+ return this.prepareTransactionWithNonExtendedPublicKey(publicKey, details, configuration);
658
+ case 'xpub':
659
+ return this.prepareTransactionWithExtendedPublicKey(publicKey, details, configuration);
660
+ default:
661
+ (0, coinlib_core_1.assertNever)(publicKey);
662
+ throw new errors_1.UnsupportedError(coinlib_core_1.Domain.BITCOIN, 'Unuspported public key type.');
663
+ }
664
+ }
665
+ async prepareTransactionWithNonExtendedPublicKey(publicKey, details, configuration) {
666
+ let fee;
667
+ if (configuration?.fee !== undefined) {
668
+ fee = configuration.fee;
669
+ }
670
+ else {
671
+ const estimatedFee = await this.getTransactionFeeWithPublicKey(publicKey, details);
672
+ fee = estimatedFee.medium;
673
+ }
674
+ const wrappedFee = new bignumber_1.default((0, module_kit_1.newAmount)(fee).blockchain(this.units).value);
675
+ const transaction = (0, module_kit_1.newUnsignedTransaction)({
676
+ ins: [],
677
+ outs: []
678
+ });
679
+ const address = await this.getAddressFromPublicKey(publicKey);
680
+ const { data: utxos } = await index_1.default.get(`${this.options.network.indexerApi}/api/v2/utxo/${address}`, {
681
+ responseType: 'json'
682
+ });
683
+ const totalRequiredBalance = details
684
+ .map(({ amount }) => new bignumber_1.default((0, module_kit_1.newAmount)(amount).blockchain(this.units).value))
685
+ .reduce((accumulator, currentValue) => accumulator.plus(currentValue))
686
+ .plus(wrappedFee);
687
+ let valueAccumulator = new bignumber_1.default(0);
688
+ for (const utxo of utxos) {
689
+ valueAccumulator = valueAccumulator.plus(new bignumber_1.default(utxo.value));
690
+ transaction.ins.push({
691
+ txId: utxo.txid,
692
+ value: new bignumber_1.default(utxo.value).toString(10),
693
+ vout: utxo.vout,
694
+ address
695
+ });
696
+ if (valueAccumulator.isGreaterThanOrEqualTo(totalRequiredBalance)) {
697
+ break;
698
+ }
699
+ }
700
+ if (valueAccumulator.isLessThan(totalRequiredBalance)) {
701
+ throw new errors_1.BalanceError(coinlib_core_1.Domain.BITCOIN, `not enough balance, having ${valueAccumulator.toFixed()} of ${totalRequiredBalance.toFixed()}`);
702
+ }
703
+ // tx.addInput(utxo.txid, utxo.vout)
704
+ for (let i = 0; i < details.length; i++) {
705
+ const value = (0, module_kit_1.newAmount)(details[i].amount).blockchain(this.units).value;
706
+ transaction.outs.push({
707
+ recipient: details[i].to,
708
+ isChange: false,
709
+ value
710
+ });
711
+ valueAccumulator = valueAccumulator.minus(value);
712
+ // tx.addOutput(details[i].to, details[i].amount)
713
+ }
714
+ // If the change is considered dust, the transaction will fail.
715
+ // Dust is a variable value around 300-600 satoshis, depending on the configuration.
716
+ // We set a low fee here to not block any transactions, but it might still fail due to "dust".
717
+ const changeValue = valueAccumulator.minus(wrappedFee);
718
+ if (changeValue.isGreaterThan(new bignumber_1.default(DUST_AMOUNT))) {
719
+ transaction.outs.push({
720
+ recipient: address,
721
+ isChange: true,
722
+ value: changeValue.toString(10)
1243
723
  });
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
- }
724
+ }
725
+ return transaction;
726
+ }
727
+ async prepareTransactionWithExtendedPublicKey(extendedPublicKey, details, configuration) {
728
+ let targetFee;
729
+ if (configuration?.fee !== undefined) {
730
+ targetFee = configuration.fee;
731
+ }
732
+ else {
733
+ const estimatedFee = await this.getTransactionFeeWithPublicKey(extendedPublicKey, details);
734
+ targetFee = estimatedFee.medium;
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()
1256
818
  });
1257
- });
1258
- };
819
+ }
820
+ return transaction;
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
+ }
1259
826
  // Custom
1260
- BitcoinProtocolImpl.prototype.convertExtendedSecretKey = function (extendedSecretKey, targetFormat) {
827
+ convertExtendedSecretKey(extendedSecretKey, targetFormat) {
1261
828
  return (0, key_1.convertExtendedSecretKey)(extendedSecretKey, {
1262
829
  format: targetFormat,
1263
830
  type: this.keyConfiguration.xpriv.type,
1264
831
  hashFunction: this.bitcoinJS.config.network.hashFunctions.address
1265
832
  });
1266
- };
1267
- BitcoinProtocolImpl.prototype.convertExtendedPublicKey = function (extendedPublicKey, targetFormat) {
833
+ }
834
+ convertExtendedPublicKey(extendedPublicKey, targetFormat) {
1268
835
  return (0, key_1.convertExtendedPublicKey)(extendedPublicKey, {
1269
836
  format: targetFormat,
1270
837
  type: this.keyConfiguration.xpub.type,
1271
838
  hashFunction: this.bitcoinJS.config.network.hashFunctions.address
1272
839
  });
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 = {
840
+ }
841
+ convertCryptoDerivative(derivative) {
842
+ const hexNode = (0, crypto_1.encodeDerivative)('hex', {
843
+ ...derivative,
844
+ secretKey: `00${derivative.secretKey}`
845
+ });
846
+ const extendedSecretKey = {
1277
847
  type: 'xpriv',
1278
848
  format: 'hex',
1279
849
  value: hexNode.secretKey
1280
850
  };
1281
851
  return this.convertExtendedSecretKey(extendedSecretKey, 'encoded');
1282
- };
1283
- BitcoinProtocolImpl.prototype.derivativeToBip32Node = function (derivative) {
1284
- var extendedSecretKey = this.convertCryptoDerivative(derivative);
852
+ }
853
+ derivativeToBip32Node(derivative) {
854
+ const extendedSecretKey = this.convertCryptoDerivative(derivative);
1285
855
  return this.bitcoinJS.lib.HDNode.fromBase58(extendedSecretKey.value, this.bitcoinJS.config.network);
1286
- };
1287
- return BitcoinProtocolImpl;
1288
- }());
856
+ }
857
+ }
1289
858
  exports.BitcoinProtocolImpl = BitcoinProtocolImpl;
1290
859
  // Factory
1291
- function createBitcoinProtocol(options) {
1292
- if (options === void 0) { options = {}; }
860
+ function createBitcoinProtocol(options = {}) {
1293
861
  return new BitcoinProtocolImpl(options);
1294
862
  }
1295
- exports.createBitcoinProtocol = createBitcoinProtocol;
1296
863
  exports.BITCOIN_MAINNET_PROTOCOL_NETWORK = {
1297
864
  name: 'Mainnet',
1298
865
  type: 'mainnet',
@@ -1300,13 +867,12 @@ exports.BITCOIN_MAINNET_PROTOCOL_NETWORK = {
1300
867
  blockExplorerUrl: 'https://live.blockcypher.com/btc',
1301
868
  indexerApi: 'https://bitcoin.prod.gke.papers.tech'
1302
869
  };
1303
- var DEFAULT_BITCOIN_PROTOCOL_NETWORK = exports.BITCOIN_MAINNET_PROTOCOL_NETWORK;
1304
- function createBitcoinProtocolOptions(network) {
1305
- if (network === void 0) { network = {}; }
870
+ const DEFAULT_BITCOIN_PROTOCOL_NETWORK = exports.BITCOIN_MAINNET_PROTOCOL_NETWORK;
871
+ function createBitcoinProtocolOptions(network = {}) {
1306
872
  return {
1307
873
  network: network.type === 'custom'
1308
- ? __assign(__assign(__assign({}, DEFAULT_BITCOIN_PROTOCOL_NETWORK), { bitcoinjsNetworkName: 'bitcoin' }), network) : __assign(__assign({}, DEFAULT_BITCOIN_PROTOCOL_NETWORK), network)
874
+ ? { ...DEFAULT_BITCOIN_PROTOCOL_NETWORK, bitcoinjsNetworkName: 'bitcoin', ...network }
875
+ : { ...DEFAULT_BITCOIN_PROTOCOL_NETWORK, ...network }
1309
876
  };
1310
877
  }
1311
- exports.createBitcoinProtocolOptions = createBitcoinProtocolOptions;
1312
878
  //# sourceMappingURL=BitcoinProtocol.js.map