UNPKG

airgap-coin-lib

Version:

The airgap-coin-lib is a protocol agnostic library to prepare, sign and broadcast cryptocurrency transactions.

880 lines 115 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { 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; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); var taquito_local_forging_1 = require("../../dependencies/src/@taquito/local-forging-6.3.5-beta.0/packages/taquito-local-forging/src/taquito-local-forging"); var sodium = require("libsodium-wrappers"); var index_1 = require("../../dependencies/src/axios-0.19.0/index"); var bignumber_1 = require("../../dependencies/src/bignumber.js-9.0.0/bignumber"); var index_2 = require("../../dependencies/src/bip39-2.5.0/index"); var bs58check = require("../../dependencies/src/bs58check-2.1.2/index"); var index_3 = require("../../dependencies/src/hd-wallet-js-b216450e56954a6e82ace0aade9474673de5d9d5/src/index"); var IAirGapTransaction_1 = require("../../interfaces/IAirGapTransaction"); var ErrorWithData_1 = require("../../utils/ErrorWithData"); var ProtocolSymbols_1 = require("../../utils/ProtocolSymbols"); var subProtocols_1 = require("../../utils/subProtocols"); var NonExtendedProtocol_1 = require("../NonExtendedProtocol"); var TezosRewardCalculation005_1 = require("./rewardcalculation/TezosRewardCalculation005"); var TezosRewardCalculation006_1 = require("./rewardcalculation/TezosRewardCalculation006"); var TezosRewardCalculationDefault_1 = require("./rewardcalculation/TezosRewardCalculationDefault"); var TezosProtocolOptions_1 = require("./TezosProtocolOptions"); var TezosOperationType_1 = require("./types/TezosOperationType"); var TezosCryptoClient_1 = require("./TezosCryptoClient"); var assert_1 = require("../../utils/assert"); var MAX_OPERATIONS_PER_GROUP = 200; var GAS_LIMIT_PLACEHOLDER = '1040000'; var STORAGE_LIMIT_PLACEHOLDER = '60000'; var MINIMAL_FEE = 100; var MINIMAL_FEE_PER_GAS_UNIT = 0.1; var MINIMAL_FEE_PER_BYTE = 1; var TezosDelegatorAction; (function (TezosDelegatorAction) { TezosDelegatorAction["DELEGATE"] = "delegate"; TezosDelegatorAction["UNDELEGATE"] = "undelegate"; TezosDelegatorAction["CHANGE_BAKER"] = "change_baker"; })(TezosDelegatorAction = exports.TezosDelegatorAction || (exports.TezosDelegatorAction = {})); // 8.25% var SELF_BOND_REQUIREMENT = 0.0825; var TezosNetwork; (function (TezosNetwork) { TezosNetwork["MAINNET"] = "mainnet"; TezosNetwork["DELPHINET"] = "delphinet"; })(TezosNetwork = exports.TezosNetwork || (exports.TezosNetwork = {})); var TezosProtocol = /** @class */ (function (_super) { __extends(TezosProtocol, _super); function TezosProtocol(options) { if (options === void 0) { options = new TezosProtocolOptions_1.TezosProtocolOptions(); } var _this = _super.call(this) || this; _this.options = options; _this.symbol = 'XTZ'; _this.name = 'Tezos'; _this.marketSymbol = 'xtz'; _this.feeSymbol = 'xtz'; _this.decimals = 6; _this.feeDecimals = 6; // micro tez is the smallest, 1000000 microtez is 1 tez _this.identifier = ProtocolSymbols_1.MainProtocolSymbols.XTZ; // tezbox default _this.feeDefaults = { low: '0.001420', medium: '0.001520', high: '0.003000' }; _this.units = [ { unitSymbol: 'XTZ', factor: '1' } ]; _this.supportsHD = false; _this.standardDerivationPath = "m/44h/1729h/0h/0h"; _this.addressIsCaseSensitive = true; _this.addressValidationPattern = '^(tz1|tz2|tz3|KT1)[1-9A-Za-z]{33}$'; _this.addressPlaceholder = 'tz1...'; // https://gitlab.com/tezos/tezos/-/blob/master/docs/whitedoc/proof_of_stake.rst // cycle has 4096 blocks, which are at least one minute apart _this.minCycleDuration = 4096 * 60 * 1000; // ms _this.transactionFee = new bignumber_1.default('1400'); _this.originationSize = new bignumber_1.default('257'); _this.storageCostPerByte = new bignumber_1.default('1000'); _this.revealFee = new bignumber_1.default('1300'); _this.activationBurn = _this.originationSize.times(_this.storageCostPerByte); _this.originationBurn = _this.originationSize.times(_this.storageCostPerByte); // https://tezos.stackexchange.com/a/787 // Tezos - We need to wrap these in Buffer due to non-compatible browser polyfills _this.tezosPrefixes = { tz1: Buffer.from(new Uint8Array([6, 161, 159])), tz2: Buffer.from(new Uint8Array([6, 161, 161])), tz3: Buffer.from(new Uint8Array([6, 161, 164])), kt: Buffer.from(new Uint8Array([2, 90, 121])), edpk: Buffer.from(new Uint8Array([13, 15, 37, 217])), edsk: Buffer.from(new Uint8Array([43, 246, 78, 7])), edsig: Buffer.from(new Uint8Array([9, 245, 205, 134, 18])), branch: Buffer.from(new Uint8Array([1, 52])) }; _this.headers = { 'Content-Type': 'application/json', apiKey: 'airgap00391' }; _this.rewardCalculations = { alpha: new TezosRewardCalculationDefault_1.TezosRewardsCalculationDefault(_this), babylon: new TezosRewardCalculation005_1.TezosRewardsCalculation005(_this), cartha: new TezosRewardCalculation006_1.TezosRewardsCalculation006(_this) }; _this.headers.apiKey = options.network.extras.conseilApiKey; return _this; } Object.defineProperty(TezosProtocol.prototype, "subProtocols", { get: function () { return subProtocols_1.getSubProtocolsByIdentifier(this.identifier, this.options.network); }, enumerable: true, configurable: true }); Object.defineProperty(TezosProtocol.prototype, "jsonRPCAPI", { // TODO: Should we remove these getters and replace the calls to `this.options.network...`? get: function () { return this.options.network.rpcUrl; }, enumerable: true, configurable: true }); Object.defineProperty(TezosProtocol.prototype, "baseApiUrl", { get: function () { return this.options.network.extras.conseilUrl; }, enumerable: true, configurable: true }); Object.defineProperty(TezosProtocol.prototype, "baseApiNetwork", { get: function () { return this.options.network.extras.conseilNetwork; }, enumerable: true, configurable: true }); TezosProtocol.prototype.getBlockExplorerLinkForAddress = function (address) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, this.options.network.blockExplorer.getAddressLink(address)]; }); }); }; TezosProtocol.prototype.getBlockExplorerLinkForTxId = function (txId) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, this.options.network.blockExplorer.getTransactionLink(txId)]; }); }); }; TezosProtocol.prototype.getPublicKeyFromMnemonic = function (mnemonic, derivationPath, password) { return __awaiter(this, void 0, void 0, function () { var secret; return __generator(this, function (_a) { secret = index_2.mnemonicToSeed(mnemonic, password); return [2 /*return*/, this.getPublicKeyFromHexSecret(secret, derivationPath)]; }); }); }; TezosProtocol.prototype.getPrivateKeyFromMnemonic = function (mnemonic, derivationPath, password) { return __awaiter(this, void 0, void 0, function () { var secret; return __generator(this, function (_a) { secret = index_2.mnemonicToSeed(mnemonic, password); return [2 /*return*/, this.getPrivateKeyFromHexSecret(secret, derivationPath)]; }); }); }; /** * Returns the PublicKey as String, derived from a supplied hex-string * @param secret HEX-Secret from BIP39 * @param derivationPath DerivationPath for Key */ TezosProtocol.prototype.getPublicKeyFromHexSecret = function (secret, derivationPath) { return __awaiter(this, void 0, void 0, function () { var publicKey; return __generator(this, function (_a) { publicKey = index_3.generateWalletUsingDerivationPath(Buffer.from(secret, 'hex'), derivationPath) // TODO: Look into typings .publicKey; return [2 /*return*/, Buffer.from(publicKey).toString('hex')]; }); }); }; /** * Returns the PrivateKey as Buffer, derived from a supplied hex-string * @param secret HEX-Secret from BIP39 * @param derivationPath DerivationPath for Key */ TezosProtocol.prototype.getPrivateKeyFromHexSecret = function (secret, derivationPath) { return __awaiter(this, void 0, void 0, function () { var secretKey; return __generator(this, function (_a) { secretKey = index_3.generateWalletUsingDerivationPath(Buffer.from(secret, 'hex'), derivationPath) // TODO: Look into typings .secretKey; return [2 /*return*/, Buffer.from(secretKey)]; }); }); }; TezosProtocol.prototype.getAddressFromPublicKey = function (publicKey) { return __awaiter(this, void 0, void 0, function () { var payload, address; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, sodium.ready]; case 1: _a.sent(); payload = sodium.crypto_generichash(20, Buffer.from(publicKey, 'hex')); address = bs58check.encode(Buffer.concat([this.tezosPrefixes.tz1, Buffer.from(payload)])); return [2 /*return*/, address]; } }); }); }; TezosProtocol.prototype.getAddressesFromPublicKey = function (publicKey) { return __awaiter(this, void 0, void 0, function () { var address; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getAddressFromPublicKey(publicKey)]; case 1: address = _a.sent(); return [2 /*return*/, [address]]; } }); }); }; TezosProtocol.prototype.getTransactionsFromPublicKey = function (publicKey, limit, cursor) { return __awaiter(this, void 0, void 0, function () { var addresses; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getAddressesFromPublicKey(publicKey)]; case 1: addresses = _a.sent(); return [2 /*return*/, this.getTransactionsFromAddresses(addresses, limit, cursor)]; } }); }); }; TezosProtocol.prototype.getTransactionsFromAddresses = function (addresses, limit, cursor) { return __awaiter(this, void 0, void 0, function () { var allTransactions, lastEntryBlockLevel; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, Promise.all(addresses.map(function (address) { var getRequestBody = function () { var body = { fields: ['status', 'amount', 'fee', 'source', 'destination', 'operation_group_hash', 'timestamp', 'block_level'], predicates: [ { field: 'source', operation: 'eq', set: [address], inverse: false, group: 'a' }, { field: 'destination', operation: 'eq', set: [address], inverse: false, group: 'b' }, { field: 'kind', operation: 'eq', set: ['transaction'], inverse: false, group: 'a' }, { field: 'kind', operation: 'eq', set: ['transaction'], inverse: false, group: 'b' } ], orderBy: [ { field: 'block_level', direction: 'desc' } ], limit: limit }; if (cursor && cursor.lastBlockLevel) { body.predicates.push({ field: 'block_level', operation: 'lt', set: [cursor.lastBlockLevel.toString()], inverse: false, group: 'a' }); body.predicates.push({ field: 'block_level', operation: 'lt', set: [cursor.lastBlockLevel.toString()], inverse: false, group: 'b' }); } return body; }; // AirGapTransactionStatus.APPLIED : AirGapTransactionStatus.FAILED return new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () { var result; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, index_1.default .post(this.options.network.extras.conseilUrl + "/v2/data/tezos/" + this.options.network.extras.conseilNetwork + "/operations", getRequestBody(), { headers: this.headers }) .catch(function () { return { data: [] }; })]; case 1: result = _a.sent(); resolve(result.data); return [2 /*return*/]; } }); }); }); }))]; case 1: allTransactions = _a.sent(); allTransactions = allTransactions .reduce(function (current, next) { return current.concat(next); }) .map(function (transaction) { return { amount: new bignumber_1.default(transaction.amount), fee: new bignumber_1.default(transaction.fee), from: [transaction.source], isInbound: addresses.indexOf(transaction.destination) !== -1, protocolIdentifier: _this.identifier, network: _this.options.network, to: [transaction.destination], hash: transaction.operation_group_hash, timestamp: transaction.timestamp / 1000, blockHeight: transaction.block_level, status: transaction.status === 'applied' ? IAirGapTransaction_1.AirGapTransactionStatus.APPLIED : IAirGapTransaction_1.AirGapTransactionStatus.FAILED }; }); lastEntryBlockLevel = allTransactions.length > 0 ? allTransactions[allTransactions.length - 1].blockHeight : 0; return [2 /*return*/, { transactions: allTransactions, cursor: { lastBlockLevel: lastEntryBlockLevel } }]; } }); }); }; TezosProtocol.prototype.signWithPrivateKey = function (privateKey, transaction) { return __awaiter(this, void 0, void 0, function () { var watermark, watermarkedForgedOperationBytesHex, watermarkedForgedOperationBytes, hashedWatermarkedOpBytes, opSignature, signedOpBytes; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, sodium.ready]; case 1: _a.sent(); watermark = '03'; watermarkedForgedOperationBytesHex = watermark + transaction.binaryTransaction; watermarkedForgedOperationBytes = Buffer.from(watermarkedForgedOperationBytesHex, 'hex'); hashedWatermarkedOpBytes = sodium.crypto_generichash(32, watermarkedForgedOperationBytes); opSignature = sodium.crypto_sign_detached(hashedWatermarkedOpBytes, privateKey); signedOpBytes = Buffer.concat([Buffer.from(transaction.binaryTransaction, 'hex'), Buffer.from(opSignature)]); return [2 /*return*/, signedOpBytes.toString('hex')]; } }); }); }; TezosProtocol.prototype.getTransactionDetails = function (unsignedTx) { return __awaiter(this, void 0, void 0, function () { var binaryTransaction, wrappedOperations; return __generator(this, function (_a) { switch (_a.label) { case 0: binaryTransaction = unsignedTx.transaction.binaryTransaction; return [4 /*yield*/, this.unforgeUnsignedTezosWrappedOperation(binaryTransaction)]; case 1: wrappedOperations = _a.sent(); return [2 /*return*/, this.getAirGapTxFromWrappedOperations(wrappedOperations)]; } }); }); }; TezosProtocol.prototype.getTransactionDetailsFromSigned = function (signedTx) { return __awaiter(this, void 0, void 0, function () { var binaryTransaction, wrappedOperations; return __generator(this, function (_a) { switch (_a.label) { case 0: binaryTransaction = signedTx.transaction; return [4 /*yield*/, this.unforgeSignedTezosWrappedOperation(binaryTransaction)]; case 1: wrappedOperations = _a.sent(); return [2 /*return*/, this.getAirGapTxFromWrappedOperations(wrappedOperations)]; } }); }); }; TezosProtocol.prototype.getAirGapTxFromWrappedOperations = function (wrappedOperations) { return __awaiter(this, void 0, void 0, function () { var assertNever; var _this = this; return __generator(this, function (_a) { assertNever = function (x) { return undefined; }; return [2 /*return*/, Promise.all(wrappedOperations.contents.map(function (tezosOperation) { return __awaiter(_this, void 0, void 0, function () { var operation, partialTxs, _a, tezosSpendOperation, tezosOriginationOperation, delegate, delegate; var _this = this; return __generator(this, function (_b) { switch (_b.label) { case 0: partialTxs = []; _a = tezosOperation.kind; switch (_a) { case TezosOperationType_1.TezosOperationType.REVEAL: return [3 /*break*/, 1]; case TezosOperationType_1.TezosOperationType.TRANSACTION: return [3 /*break*/, 2]; case TezosOperationType_1.TezosOperationType.ORIGINATION: return [3 /*break*/, 4]; case TezosOperationType_1.TezosOperationType.DELEGATION: return [3 /*break*/, 5]; case TezosOperationType_1.TezosOperationType.ENDORSEMENT: return [3 /*break*/, 6]; case TezosOperationType_1.TezosOperationType.SEED_NONCE_REVELATION: return [3 /*break*/, 6]; case TezosOperationType_1.TezosOperationType.DOUBLE_ENDORSEMENT_EVIDENCE: return [3 /*break*/, 6]; case TezosOperationType_1.TezosOperationType.DOUBLE_BAKING_EVIDENCE: return [3 /*break*/, 6]; case TezosOperationType_1.TezosOperationType.ACTIVATE_ACCOUNT: return [3 /*break*/, 6]; case TezosOperationType_1.TezosOperationType.PROPOSALS: return [3 /*break*/, 6]; case TezosOperationType_1.TezosOperationType.BALLOT: return [3 /*break*/, 6]; } return [3 /*break*/, 7]; case 1: operation = tezosOperation; partialTxs = [ { from: [operation.source], to: ['Reveal'] } ]; return [3 /*break*/, 8]; case 2: tezosSpendOperation = tezosOperation; operation = tezosSpendOperation; return [4 /*yield*/, this.getTransactionOperationDetails(tezosSpendOperation)]; case 3: partialTxs = _b.sent(); return [3 /*break*/, 8]; case 4: { tezosOriginationOperation = tezosOperation; operation = tezosOriginationOperation; delegate = tezosOriginationOperation.delegate; partialTxs = [ { from: [operation.source], amount: new bignumber_1.default(tezosOriginationOperation.balance).toFixed(), to: [delegate ? "Delegate: " + delegate : 'Origination'] } ]; } return [3 /*break*/, 8]; case 5: { operation = tezosOperation; delegate = operation.delegate; partialTxs = [ { from: [operation.source], to: [delegate ? delegate : 'Undelegate'] } ]; } return [3 /*break*/, 8]; case 6: throw new Error('operation not supported: ' + tezosOperation.kind); case 7: assertNever(tezosOperation.kind); // Exhaustive switch throw new Error('no operation to unforge found'); case 8: return [2 /*return*/, partialTxs.map(function (partialTx) { return __assign({ amount: '0', fee: operation !== undefined ? new bignumber_1.default(operation.fee).toString(10) : '0', from: [], isInbound: false, protocolIdentifier: _this.identifier, network: _this.options.network, to: [], transactionDetails: tezosOperation }, partialTx); })]; } }); }); })).then(function (airGapTxs) { return airGapTxs.reduce(function (flatten, next) { return flatten.concat(next); }, []); })]; }); }); }; TezosProtocol.prototype.getBalanceOfAddresses = function (addresses) { return __awaiter(this, void 0, void 0, function () { var balance, _i, addresses_1, address, data, error_1; return __generator(this, function (_a) { switch (_a.label) { case 0: balance = new bignumber_1.default(0); _i = 0, addresses_1 = addresses; _a.label = 1; case 1: if (!(_i < addresses_1.length)) return [3 /*break*/, 6]; address = addresses_1[_i]; _a.label = 2; case 2: _a.trys.push([2, 4, , 5]); return [4 /*yield*/, index_1.default.get(this.options.network.rpcUrl + "/chains/main/blocks/head/context/contracts/" + address + "/balance")]; case 3: data = (_a.sent()).data; balance = balance.plus(new bignumber_1.default(data)); return [3 /*break*/, 5]; case 4: error_1 = _a.sent(); // if node returns 404 (which means 'no account found'), go with 0 balance if (error_1.response && error_1.response.status !== 404) { throw error_1; } return [3 /*break*/, 5]; case 5: _i++; return [3 /*break*/, 1]; case 6: return [2 /*return*/, balance.toString(10)]; } }); }); }; TezosProtocol.prototype.getBalanceOfPublicKey = function (publicKey) { return __awaiter(this, void 0, void 0, function () { var address; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getAddressFromPublicKey(publicKey)]; case 1: address = _a.sent(); return [2 /*return*/, this.getBalanceOfAddresses([address])]; } }); }); }; TezosProtocol.prototype.getBalanceOfPublicKeyForSubProtocols = function (publicKey, subProtocols) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, Promise.all(subProtocols.map(function (subProtocol) { return subProtocol.getBalanceOfPublicKey(publicKey).catch(function () { return '0'; }); }))]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; TezosProtocol.prototype.getAvailableBalanceOfAddresses = function (addresses) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, this.getBalanceOfAddresses(addresses)]; }); }); }; TezosProtocol.prototype.estimateMaxTransactionValueFromPublicKey = function (publicKey, recipients, fee) { return __awaiter(this, void 0, void 0, function () { var balance, balanceWrapper, maxFee, estimatedFeeDefaults, amountWithoutFees; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getBalanceOfPublicKey(publicKey)]; case 1: balance = _a.sent(); balanceWrapper = new bignumber_1.default(balance).minus(1) // Tezos accounts can never be empty. We must leave at least 1 mutez behind. ; if (!(fee !== undefined)) return [3 /*break*/, 2]; maxFee = new bignumber_1.default(fee); return [3 /*break*/, 4]; case 2: return [4 /*yield*/, this.estimateFeeDefaultsFromPublicKey(publicKey, recipients, [balanceWrapper.toFixed()])]; case 3: estimatedFeeDefaults = _a.sent(); maxFee = new bignumber_1.default(estimatedFeeDefaults.medium).shiftedBy(this.decimals); if (maxFee.gte(balanceWrapper)) { maxFee = new bignumber_1.default(0); } _a.label = 4; case 4: amountWithoutFees = balanceWrapper.minus(maxFee); if (amountWithoutFees.isNegative()) { amountWithoutFees = new bignumber_1.default(0); } return [2 /*return*/, amountWithoutFees.toFixed()]; } }); }); }; TezosProtocol.prototype.estimateFeeDefaultsFromPublicKey = function (publicKey, recipients, values, data) { return __awaiter(this, void 0, void 0, function () { var operations, i, value, recipient, transaction; return __generator(this, function (_a) { if (recipients.length !== values.length) { throw new Error('length of recipients and values does not match!'); } operations = []; for (i = 0; i < values.length; ++i) { value = values[i]; recipient = recipients[i]; transaction = { kind: TezosOperationType_1.TezosOperationType.TRANSACTION, amount: value, destination: recipient, fee: '0' }; operations.push(transaction); } if (recipients.length === 0) { return [2 /*return*/, this.feeDefaults]; } return [2 /*return*/, this.estimateFeeDefaultsForOperations(publicKey, operations)]; }); }); }; TezosProtocol.prototype.estimateFeeDefaultsForOperations = function (publicKey, operations) { return __awaiter(this, void 0, void 0, function () { var estimated, hasReveal, estimatedFee, feeStepFactor, lowFee, mediumFee, highFee; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.prepareOperations(publicKey, operations)]; case 1: estimated = _a.sent(); hasReveal = estimated.contents.some(function (op) { return op.kind === TezosOperationType_1.TezosOperationType.REVEAL; }); estimatedFee = estimated.contents .reduce(function (current, next) { if (next.fee !== undefined) { return current.plus(new bignumber_1.default(next['fee'])); } return current; }, new bignumber_1.default(0)) .minus(hasReveal ? this.revealFee : 0) .div(hasReveal ? estimated.contents.length - 1 : estimated.contents.length); feeStepFactor = new bignumber_1.default(0.1); lowFee = estimatedFee.minus(estimatedFee.times(feeStepFactor).integerValue(bignumber_1.default.ROUND_FLOOR)); mediumFee = estimatedFee; highFee = mediumFee.plus(mediumFee.times(feeStepFactor).integerValue(bignumber_1.default.ROUND_FLOOR)); return [2 /*return*/, { low: lowFee.shiftedBy(-this.feeDecimals).toFixed(), medium: mediumFee.shiftedBy(-this.feeDecimals).toFixed(), high: highFee.shiftedBy(-this.feeDecimals).toFixed() }]; } }); }); }; TezosProtocol.prototype.prepareTransactionFromPublicKey = function (publicKey, recipients, values, fee, data) { return __awaiter(this, void 0, void 0, function () { var transactions; return __generator(this, function (_a) { switch (_a.label) { case 0: if (recipients.length !== values.length) { throw new Error('length of recipients and values does not match!'); } if (recipients.length > MAX_OPERATIONS_PER_GROUP) { throw new Error("this transaction exceeds the maximum allowed number of transactions per operation (" + MAX_OPERATIONS_PER_GROUP + "). Please use the \"prepareTransactionsFromPublicKey\" method instead."); } return [4 /*yield*/, this.prepareTransactionsFromPublicKey(publicKey, recipients, values, fee, data)]; case 1: transactions = _a.sent(); if (transactions.length === 1) { return [2 /*return*/, transactions[0]]; } else { throw new Error('Transaction could not be prepared. More or less than 1 operations have been generated.'); } return [2 /*return*/]; } }); }); }; TezosProtocol.prototype.prepareTransactionsFromPublicKey = function (publicKey, recipients, values, fee, data, operationsPerGroup) { if (operationsPerGroup === void 0) { operationsPerGroup = MAX_OPERATIONS_PER_GROUP; } return __awaiter(this, void 0, void 0, function () { var wrappedValues, wrappedFee, counter, branch, operations, addressIndex, addresses, address, results, accountManager, _a, _b, error_2, balance, _c, wrappedOperations, allOperations, numberOfGroups, i, start, end, operationsGroup, wrappedOperationWithEstimatedGas, _d, _e; return __generator(this, function (_f) { switch (_f.label) { case 0: wrappedValues = values.map(function (value) { return new bignumber_1.default(value); }); wrappedFee = new bignumber_1.default(fee); if (recipients.length !== wrappedValues.length) { throw new Error('length of recipients and values does not match!'); } counter = new bignumber_1.default(1); operations = []; addressIndex = data && data.addressIndex ? data.addressIndex : 0; return [4 /*yield*/, this.getAddressesFromPublicKey(publicKey)]; case 1: addresses = _f.sent(); if (!addresses[addressIndex]) { throw new Error('no kt-address with this index exists'); } address = addresses[addressIndex]; _f.label = 2; case 2: _f.trys.push([2, 6, , 7]); return [4 /*yield*/, Promise.all([ index_1.default.get(this.options.network.rpcUrl + "/chains/main/blocks/head/context/contracts/" + address + "/counter"), index_1.default.get(this.options.network.rpcUrl + "/chains/main/blocks/head/hash"), index_1.default.get(this.options.network.rpcUrl + "/chains/main/blocks/head/context/contracts/" + address + "/manager_key") ])]; case 3: results = _f.sent(); counter = new bignumber_1.default(results[0].data).plus(1); branch = results[1].data; accountManager = results[2].data; if (!!accountManager) return [3 /*break*/, 5]; _b = (_a = operations).push; return [4 /*yield*/, this.createRevealOperation(counter, publicKey, address)]; case 4: _b.apply(_a, [_f.sent()]); counter = counter.plus(1); _f.label = 5; case 5: return [3 /*break*/, 7]; case 6: error_2 = _f.sent(); throw error_2; case 7: _c = bignumber_1.default.bind; return [4 /*yield*/, this.getBalanceOfPublicKey(publicKey)]; case 8: balance = new (_c.apply(bignumber_1.default, [void 0, _f.sent()]))(); wrappedOperations = []; return [4 /*yield*/, this.createTransactionOperations(operations, recipients, wrappedValues, wrappedFee, address, counter, balance)]; case 9: allOperations = _f.sent(); allOperations = operations.concat(allOperations); // if we have a reveal in operations, we need to make sure it is present in the allOperations array numberOfGroups = Math.ceil(allOperations.length / operationsPerGroup); i = 0; _f.label = 10; case 10: if (!(i < numberOfGroups)) return [3 /*break*/, 14]; start = i * operationsPerGroup; end = start + operationsPerGroup; operationsGroup = allOperations.slice(start, end); return [4 /*yield*/, this.estimateAndReplaceLimitsAndFee({ branch: branch, contents: operationsGroup }, false)]; case 11: wrappedOperationWithEstimatedGas = _f.sent(); _e = (_d = wrappedOperations).push; return [4 /*yield*/, this.forgeAndWrapOperations(wrappedOperationWithEstimatedGas)]; case 12: _e.apply(_d, [_f.sent()]); _f.label = 13; case 13: i++; return [3 /*break*/, 10]; case 14: return [2 /*return*/, wrappedOperations]; } }); }); }; TezosProtocol.prototype.getTransactionOperationDetails = function (transactionOperation) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, [ { from: [transactionOperation.source], amount: new bignumber_1.default(transactionOperation.amount).toFixed(), to: [transactionOperation.destination] // contract destination but should be the address of actual receiver } ]]; }); }); }; TezosProtocol.prototype.createTransactionOperations = function (previousOperations, recipients, wrappedValues, wrappedFee, address, counter, balance) { return __awaiter(this, void 0, void 0, function () { var amountUsedByPreviousOperations, operations, i, receivingBalance, _a, spendOperation; return __generator(this, function (_b) { switch (_b.label) { case 0: amountUsedByPreviousOperations = this.getAmountUsedByPreviousOperations(previousOperations); operations = []; if (!amountUsedByPreviousOperations.isZero()) { if (balance.isLessThan(wrappedValues[0].plus(wrappedFee).plus(amountUsedByPreviousOperations))) { // if not, make room for the init fee wrappedValues[0] = wrappedValues[0].minus(amountUsedByPreviousOperations); // deduct fee from balance } } i = 0; _b.label = 1; case 1: if (!(i < recipients.length)) return [3 /*break*/, 4]; _a = bignumber_1.default.bind; return [4 /*yield*/, this.getBalanceOfAddresses([recipients[i]])]; case 2: receivingBalance = new (_a.apply(bignumber_1.default, [void 0, _b.sent()]))(); // if our receiver has 0 balance, the account is not activated yet. if (receivingBalance.isZero() && recipients[i].toLowerCase().startsWith('tz')) { // We have to supply an additional 0.257 XTZ fee for storage_limit costs, which gets automatically deducted from the sender so we just have to make sure enough balance is around if (balance.isLessThan(this.activationBurn.plus(wrappedFee))) { // If we don't have enough funds to pay the activation + fee, we throw an error throw new Error('Insufficient balance to pay activation burn!'); } else if (balance.isLessThan(wrappedValues[i].plus(wrappedFee).plus(this.activationBurn))) { // Check whether the sender has enough to cover the amount to send + fee + activation // If not, we deduct it from amount sent to make room for the activation burn wrappedValues[i] = wrappedValues[i].minus(this.activationBurn); // deduct fee from balance } } if (balance.isEqualTo(wrappedValues[i].plus(wrappedFee))) { // Tezos accounts can never be empty. If user tries to send everything, we must leave 1 mutez behind. wrappedValues[i] = wrappedValues[i].minus(1); } else if (balance.isLessThan(wrappedValues[i].plus(wrappedFee))) { throw new Error('not enough balance'); } spendOperation = { kind: TezosOperationType_1.TezosOperationType.TRANSACTION, fee: wrappedFee.toFixed(), gas_limit: GAS_LIMIT_PLACEHOLDER, storage_limit: STORAGE_LIMIT_PLACEHOLDER, amount: wrappedValues[i].toFixed(), counter: counter.plus(i).toFixed(), destination: recipients[i], source: address }; operations.push(spendOperation); _b.label = 3; case 3: i++; return [3 /*break*/, 1]; case 4: return [2 /*return*/, operations]; } }); }); }; TezosProtocol.prototype.forgeAndWrapOperations = function (tezosWrappedOperation) { return __awaiter(this, void 0, void 0, function () { var binaryTx, error_3; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0,