UNPKG

airgap-coin-lib

Version:

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

638 lines 35.1 kB
"use strict"; 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 index_1 = require("../../../dependencies/src/axios-0.19.0/index"); var bignumber_1 = require("../../../dependencies/src/bignumber.js-9.0.0/bignumber"); var TezosProtocol_1 = require("../TezosProtocol"); var TezosRewardsCalculationDefault = /** @class */ (function () { function TezosRewardsCalculationDefault(protocol) { this.protocol = protocol; this.blockLevelFieldNameMap = new Map(); this.tezosNodeConstants = {}; } TezosRewardsCalculationDefault.prototype.getConstants = function (currentLevel, useHead) { return __awaiter(this, void 0, void 0, function () { var _a; return __generator(this, function (_b) { switch (_b.label) { case 0: _a = this; return [4 /*yield*/, index_1.default.get(this.protocol.jsonRPCAPI + "/chains/main/blocks/" + (useHead ? 'head' : currentLevel) + "/context/constants")]; case 1: _a.tezosNodeConstants = (_b.sent()).data; return [2 /*return*/]; } }); }); }; TezosRewardsCalculationDefault.prototype.calculateRewards = function (bakerAddress, cycle, breakdownRewards, currentCycleIn) { if (breakdownRewards === void 0) { breakdownRewards = true; } return __awaiter(this, void 0, void 0, function () { var currentCycle, _a, calculatingLevel, computedRewards, snapshotLevel, bakerInfo, stakingBalance; return __generator(this, function (_b) { switch (_b.label) { case 0: if (!(currentCycleIn !== null && currentCycleIn !== void 0)) return [3 /*break*/, 1]; _a = currentCycleIn; return [3 /*break*/, 3]; case 1: return [4 /*yield*/, this.protocol.fetchCurrentCycle()]; case 2: _a = (_b.sent()); _b.label = 3; case 3: currentCycle = (_a); calculatingLevel = this.cycleToBlockLevel(cycle); return [4 /*yield*/, this.getConstants(calculatingLevel, currentCycle < cycle)]; case 4: _b.sent(); if (!(cycle < currentCycle)) return [3 /*break*/, 6]; return [4 /*yield*/, this.calculatePastRewards(bakerAddress, cycle, breakdownRewards)]; case 5: computedRewards = _b.sent(); return [3 /*break*/, 8]; case 6: return [4 /*yield*/, this.calculateFutureRewards(bakerAddress, cycle, currentCycle, breakdownRewards)]; case 7: computedRewards = _b.sent(); _b.label = 8; case 8: return [4 /*yield*/, this.computeSnapshotBlockLevel(Math.min(cycle, currentCycle))]; case 9: snapshotLevel = _b.sent(); return [4 /*yield*/, this.fetchBakerInfo(bakerAddress, snapshotLevel).catch(function () { return { staking_balance: '0', delegated_contracts: [] }; })]; case 10: bakerInfo = _b.sent(); stakingBalance = new bignumber_1.default(bakerInfo.staking_balance); return [2 /*return*/, { baker: bakerAddress, stakingBalance: stakingBalance.toFixed(), bakingRewards: computedRewards.bakingRewards, endorsingRewards: computedRewards.endorsingRewards, bakingDeposits: computedRewards.bakingRewardsDetails .map(function (detail) { return (detail && detail.deposit ? (detail.deposit ? parseInt(detail.deposit) : 0) : 0); }) .reduce(function (a, b) { return a + b; }, 0) .toString(), endorsingDeposits: computedRewards.endorsingRewardsDetails .map(function (detail) { return (detail && detail.deposit ? (detail.deposit ? parseInt(detail.deposit) : 0) : 0); }) .reduce(function (a, b) { return a + b; }, 0) .toString(), cycle: cycle, fees: computedRewards.fees, totalRewards: computedRewards.totalRewards, snapshotBlockLevel: snapshotLevel, delegatedContracts: bakerInfo.delegated_contracts, bakingRewardsDetails: computedRewards.bakingRewardsDetails, endorsingRewardsDetails: computedRewards.endorsingRewardsDetails, deposit: computedRewards.deposit, endorsingRightsCount: computedRewards.endorsingRightsCount }]; } }); }); }; TezosRewardsCalculationDefault.prototype.calculatePastRewards = function (bakerAddress, cycle, breakdownRewards) { return __awaiter(this, void 0, void 0, function () { var computedBakingRewards, computedEndorsingRewards, fees, totalRewards, deposit, endorsingRightsCount, bakedBlocks, endorsingOperations, frozenBalance; return __generator(this, function (_a) { switch (_a.label) { case 0: computedBakingRewards = { totalBakingRewards: '0', rewardsDetails: [] }; computedEndorsingRewards = { totalEndorsingRewards: '0', rewardsDetails: [] }; fees = '0'; totalRewards = '0'; deposit = '0'; endorsingRightsCount = 0; if (!breakdownRewards) return [3 /*break*/, 6]; return [4 /*yield*/, this.fetchBlocksForBaker(bakerAddress, cycle)]; case 1: bakedBlocks = _a.sent(); if (!(bakedBlocks.length > 0)) return [3 /*break*/, 3]; return [4 /*yield*/, this.computeBakingRewards(bakedBlocks, false)]; case 2: computedBakingRewards = _a.sent(); _a.label = 3; case 3: return [4 /*yield*/, this.fetchEndorsementOperations(cycle, bakerAddress)]; case 4: endorsingOperations = _a.sent(); return [4 /*yield*/, this.computeEndorsingRewards(endorsingOperations, false)]; case 5: computedEndorsingRewards = _a.sent(); endorsingRightsCount = endorsingOperations.reduce(function (current, next) { return current + next.number_of_slots; }, 0); _a.label = 6; case 6: return [4 /*yield*/, this.fetchFrozenBalances(this.cycleToBlockLevel(cycle + 1), bakerAddress)]; case 7: frozenBalance = (_a.sent()).find(function (fb) { return fb.cycle == cycle; }); if (frozenBalance) { fees = frozenBalance.fees; totalRewards = frozenBalance.rewards; deposit = frozenBalance.deposit; } return [2 /*return*/, { bakingRewards: computedBakingRewards.totalBakingRewards, endorsingRewards: computedEndorsingRewards.totalEndorsingRewards, totalRewards: totalRewards, fees: fees, bakingRewardsDetails: computedBakingRewards.rewardsDetails, endorsingRewardsDetails: computedEndorsingRewards.rewardsDetails, endorsingRightsCount: endorsingRightsCount, deposit: deposit }]; } }); }); }; TezosRewardsCalculationDefault.prototype.calculateFutureRewards = function (bakerAddress, cycle, currentCycle, breakdownRewards) { return __awaiter(this, void 0, void 0, function () { var computedBakingRewards, computedEndorsingRewards, fees, totalRewards, endorsingRightsCount, bakingRights, endorsingRights, frozenBalances, lastFrozenBalance; return __generator(this, function (_a) { switch (_a.label) { case 0: computedBakingRewards = { totalBakingRewards: '0', rewardsDetails: [] }; computedEndorsingRewards = { totalEndorsingRewards: '0', rewardsDetails: [] }; fees = '0'; totalRewards = '0'; endorsingRightsCount = 0; if (cycle - currentCycle > 5) { throw new Error('Provided cycle is invalid'); } if (!breakdownRewards) return [3 /*break*/, 5]; return [4 /*yield*/, this.fetchBakingRights(bakerAddress, cycle)]; case 1: bakingRights = _a.sent(); return [4 /*yield*/, this.computeBakingRewards(bakingRights, true)]; case 2: computedBakingRewards = _a.sent(); return [4 /*yield*/, this.fetchEndorsingRights(bakerAddress, cycle)]; case 3: endorsingRights = _a.sent(); return [4 /*yield*/, this.computeEndorsingRewards(endorsingRights, true)]; case 4: computedEndorsingRewards = _a.sent(); endorsingRightsCount = endorsingRights.reduce(function (current, next) { return current + next.number_of_slots; }, 0); _a.label = 5; case 5: totalRewards = new bignumber_1.default(computedBakingRewards.totalBakingRewards) .plus(new bignumber_1.default(computedEndorsingRewards.totalEndorsingRewards)) .toFixed(); return [4 /*yield*/, this.fetchFrozenBalances('head', bakerAddress)]; case 6: frozenBalances = _a.sent(); if (frozenBalances.length > 0) { lastFrozenBalance = frozenBalances[frozenBalances.length - 1]; fees = lastFrozenBalance.fees; } return [2 /*return*/, { bakingRewards: computedBakingRewards.totalBakingRewards, endorsingRewards: computedEndorsingRewards.totalEndorsingRewards, totalRewards: totalRewards, fees: fees, bakingRewardsDetails: computedBakingRewards.rewardsDetails, endorsingRewardsDetails: computedEndorsingRewards.rewardsDetails, endorsingRightsCount: endorsingRightsCount, deposit: '0' }]; } }); }); }; TezosRewardsCalculationDefault.prototype.fetchEndorsementOperations = function (cycle, bakerAddress) { return __awaiter(this, void 0, void 0, function () { var cycleStartLevel, cycleEndLevel, query, result; return __generator(this, function (_a) { switch (_a.label) { case 0: cycleStartLevel = this.cycleToBlockLevel(cycle); cycleEndLevel = cycleStartLevel + this.tezosNodeConstants.blocks_per_cycle; query = { fields: ['level', 'delegate', 'number_of_slots', 'block_level'], predicates: [ { field: 'kind', operation: 'eq', set: ['endorsement'], inverse: false }, { field: 'level', operation: 'between', set: [cycleStartLevel, cycleEndLevel], inverse: false }, { field: 'delegate', operation: 'eq', set: [bakerAddress] } ] }; return [4 /*yield*/, index_1.default.post(this.protocol.baseApiUrl + "/v2/data/tezos/" + this.protocol.baseApiNetwork + "/operations", query, { headers: this.protocol.headers })]; case 1: result = _a.sent(); return [2 /*return*/, result.data]; } }); }); }; TezosRewardsCalculationDefault.prototype.fetchFrozenBalances = function (blockLevel, bakerAddress) { 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.get(this.protocol.jsonRPCAPI + "/chains/main/blocks/" + blockLevel + "/context/delegates/" + bakerAddress + "/frozen_balance_by_cycle")]; case 1: result = _a.sent(); return [2 /*return*/, result.data]; } }); }); }; TezosRewardsCalculationDefault.prototype.computeBakingRewards = function (bakingRights, isFutureCycle) { return __awaiter(this, void 0, void 0, function () { var result, rewardsByLevel; return __generator(this, function (_a) { result = new bignumber_1.default(0); rewardsByLevel = []; result = new bignumber_1.default(bakingRights.length * this.tezosNodeConstants.block_reward); return [2 /*return*/, { totalBakingRewards: result.toFixed(), rewardsDetails: rewardsByLevel }]; }); }); }; // be aware this function IS NOT identical to the one in TezosRewardCalculation005 TezosRewardsCalculationDefault.prototype.computeEndorsingRewards = function (endorsingRights, isFutureCycle) { return __awaiter(this, void 0, void 0, function () { var priorities, rewardsByLevel, levels, result; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: priorities = []; rewardsByLevel = []; if (!!isFutureCycle) return [3 /*break*/, 2]; levels = endorsingRights.map(function (er) { return er.level; }); if (!(levels.length > 0)) return [3 /*break*/, 2]; return [4 /*yield*/, this.fetchBlockPriorities(levels)]; case 1: priorities = _a.sent(); _a.label = 2; case 2: result = endorsingRights.reduce(function (current, next) { var priority = 0; if (!isFutureCycle) { var block = priorities.find(function (p) { return p.level === next.level; }); if (block === undefined) { throw new Error('Cannot find block priority'); } priority = block.priority; } var reward = _this.specificEndorsingCalculation(priority, next.number_of_slots); rewardsByLevel.push({ level: next.level, amount: reward.toFixed(), deposit: _this.tezosNodeConstants.endorsement_security_deposit }); return current.plus(reward); }, new bignumber_1.default(0)); return [2 /*return*/, { totalEndorsingRewards: result.toFixed(), rewardsDetails: rewardsByLevel }]; } }); }); }; TezosRewardsCalculationDefault.prototype.specificEndorsingCalculation = function (priority, number_of_slots) { var multiplier = new bignumber_1.default(this.tezosNodeConstants.endorsement_reward).div(new bignumber_1.default(priority + 1)); var reward = new bignumber_1.default(number_of_slots).times(multiplier); return reward; }; TezosRewardsCalculationDefault.prototype.computeSnapshotBlockLevel = function (cycle, blockLevel) { return __awaiter(this, void 0, void 0, function () { var level, snapshotNumberResult, snapshotNumber, delegationCycle, firstDelegationCycleBlocklLevel, numberOfSnapshotsBeforeDelegationCycle, totalSnapshotNumber, snapshotBlockLevel; return __generator(this, function (_a) { switch (_a.label) { case 0: level = blockLevel === undefined ? this.cycleToBlockLevel(cycle) : blockLevel; return [4 /*yield*/, index_1.default.get(this.protocol.jsonRPCAPI + "/chains/main/blocks/" + level + "/context/raw/json/cycle/" + cycle + "/roll_snapshot")]; case 1: snapshotNumberResult = _a.sent(); snapshotNumber = snapshotNumberResult.data; delegationCycle = cycle - 7; firstDelegationCycleBlocklLevel = this.cycleToBlockLevel(delegationCycle); numberOfSnapshotsBeforeDelegationCycle = firstDelegationCycleBlocklLevel / this.tezosNodeConstants.blocks_per_roll_snapshot; totalSnapshotNumber = numberOfSnapshotsBeforeDelegationCycle + snapshotNumber + 1; snapshotBlockLevel = totalSnapshotNumber * this.tezosNodeConstants.blocks_per_roll_snapshot; return [2 /*return*/, snapshotBlockLevel]; } }); }); }; TezosRewardsCalculationDefault.prototype.fetchBakerInfo = function (bakerAddress, blockLevel) { return __awaiter(this, void 0, void 0, function () { var bakerInfoResult; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, index_1.default.get(this.protocol.jsonRPCAPI + "/chains/main/blocks/" + blockLevel + "/context/delegates/" + bakerAddress)]; case 1: bakerInfoResult = _a.sent(); return [2 /*return*/, bakerInfoResult.data]; } }); }); }; TezosRewardsCalculationDefault.prototype.fetchBlocksForBaker = function (bakerAddress, cycle) { return __awaiter(this, void 0, void 0, function () { var query, result; return __generator(this, function (_a) { switch (_a.label) { case 0: query = { fields: ['level', 'priority'], predicates: [ { field: 'baker', operation: 'eq', set: [bakerAddress], inverse: false }, { field: 'meta_cycle', operation: 'eq', set: [cycle], inverse: false } ] }; return [4 /*yield*/, index_1.default.post(this.protocol.baseApiUrl + "/v2/data/tezos/" + this.protocol.baseApiNetwork + "/blocks", query, { headers: this.protocol.headers })]; case 1: result = _a.sent(); return [2 /*return*/, result.data]; } }); }); }; TezosRewardsCalculationDefault.prototype.fetchBlockLevelFieldName = function (entity) { return __awaiter(this, void 0, void 0, function () { var result; var _this = this; return __generator(this, function (_a) { result = this.blockLevelFieldNameMap.get(entity); if (result) { return [2 /*return*/, result]; } if (this.fetchBlockLevelFieldPromise) { return [2 /*return*/, this.fetchBlockLevelFieldPromise]; } this.fetchBlockLevelFieldPromise = index_1.default.get(this.protocol.baseApiUrl + "/v2/metadata/tezos/" + this.protocol.baseApiNetwork + "/" + entity + "/attributes", { headers: this.protocol.headers }).then(function (response) { var name = 'block_level'; var fieldNames = response.data.map(function (metadata) { return metadata.name; }); if (fieldNames.includes('level')) { name = 'level'; } _this.blockLevelFieldNameMap.set(entity, name); return name; }).finally(function () { _this.fetchBlockLevelFieldPromise = undefined; }); return [2 /*return*/, this.fetchBlockLevelFieldPromise]; }); }); }; TezosRewardsCalculationDefault.prototype.fetchBakingRights = function (bakerAddress, cycle) { return __awaiter(this, void 0, void 0, function () { var startLevel, endLevel, blockLevelFieldName, query, result; return __generator(this, function (_a) { switch (_a.label) { case 0: startLevel = this.cycleToBlockLevel(cycle); endLevel = startLevel + this.tezosNodeConstants.blocks_per_cycle; return [4 /*yield*/, this.fetchBlockLevelFieldName('baking_rights')]; case 1: blockLevelFieldName = _a.sent(); query = { fields: ['priority', blockLevelFieldName], predicates: [ { field: 'delegate', operation: 'eq', set: [bakerAddress] }, { field: 'priority', operation: 'eq', set: [0] }, { field: blockLevelFieldName, operation: 'between', set: [startLevel, endLevel] } ], orderBy: [ { field: blockLevelFieldName, direction: 'desc' } ], limit: 10000 }; return [4 /*yield*/, index_1.default .post(this.protocol.baseApiUrl + "/v2/data/tezos/" + this.protocol.baseApiNetwork + "/baking_rights", query, { headers: this.protocol.headers }) .then(function (result) { return result.data; }) .catch(function (error) { return []; })]; case 2: result = _a.sent(); return [2 /*return*/, result.map(function (bakingRight) { return { level: bakingRight[blockLevelFieldName], priority: bakingRight.priority, delegate: bakerAddress }; })]; } }); }); }; TezosRewardsCalculationDefault.prototype.fetchEndorsingRights = function (bakerAddress, cycle) { return __awaiter(this, void 0, void 0, function () { var startLevel, endLevel, blockLevelFieldName, query, result; return __generator(this, function (_a) { switch (_a.label) { case 0: startLevel = this.cycleToBlockLevel(cycle); endLevel = startLevel + this.tezosNodeConstants.blocks_per_cycle; return [4 /*yield*/, this.fetchBlockLevelFieldName('endorsing_rights')]; case 1: blockLevelFieldName = _a.sent(); query = { fields: [blockLevelFieldName], predicates: [ { field: 'delegate', operation: 'eq', set: [bakerAddress] }, { field: blockLevelFieldName, operation: 'between', set: [startLevel, endLevel] } ], aggregation: [ { field: 'slot', function: 'count' } ], limit: 100000 }; return [4 /*yield*/, index_1.default .post(this.protocol.baseApiUrl + "/v2/data/tezos/" + this.protocol.baseApiNetwork + "/endorsing_rights", query, { headers: this.protocol.headers }) .then(function (result) { return result.data; }) .catch(function (error) { return []; })]; case 2: result = _a.sent(); return [2 /*return*/, result.map(function (endorsingRight) { return { level: endorsingRight[blockLevelFieldName], delegate: bakerAddress, number_of_slots: Number(endorsingRight.count_slot) }; })]; } }); }); }; TezosRewardsCalculationDefault.prototype.fetchEndorsementOperationCountAndTotalFees = function (blockLevels) { return __awaiter(this, void 0, void 0, function () { var query, result, map, _i, _a, op; return __generator(this, function (_b) { switch (_b.label) { case 0: query = { fields: ['block_level'], predicates: [ { field: 'block_level', operation: 'in', set: blockLevels, inverse: false } ], aggregation: [ { field: 'fee', function: 'sum' }, { field: 'number_of_slots', function: 'sum' } ] }; return [4 /*yield*/, index_1.default.post(this.protocol.baseApiUrl + "/v2/data/tezos/" + this.protocol.baseApiNetwork + "/operations", query, { headers: this.protocol.headers })]; case 1: result = _b.sent(); map = new Map(); for (_i = 0, _a = result.data; _i < _a.length; _i++) { op = _a[_i]; map.set(op.block_level, op); } return [2 /*return*/, map]; } }); }); }; TezosRewardsCalculationDefault.prototype.fetchBlockPriorities = function (blockLevels) { return __awaiter(this, void 0, void 0, function () { var query, result; return __generator(this, function (_a) { switch (_a.label) { case 0: query = { fields: ['priority', 'level'], predicates: [ { field: 'level', operation: 'in', set: blockLevels, inverse: false } ] }; return [4 /*yield*/, index_1.default.post(this.protocol.baseApiUrl + "/v2/data/tezos/" + this.protocol.baseApiNetwork + "/blocks", query, { headers: this.protocol.headers })]; case 1: result = _a.sent(); return [2 /*return*/, result.data]; } }); }); }; TezosRewardsCalculationDefault.prototype.cycleToBlockLevel = function (cycle) { var _a; var blockPerCycle = (_a = this.tezosNodeConstants.blocks_per_cycle, (_a !== null && _a !== void 0 ? _a : TezosProtocol_1.TezosProtocol.BLOCKS_PER_CYCLE[this.protocol.options.network.extras.network])); return (cycle * blockPerCycle) + 1; }; return TezosRewardsCalculationDefault; }()); exports.TezosRewardsCalculationDefault = TezosRewardsCalculationDefault; //# sourceMappingURL=TezosRewardCalculationDefault.js.map