@mavrykdynamics/taquito
Version:
High level functionality that builds upon the other packages in the Mavryk Typescript Library Suite.
158 lines (157 loc) • 7.82 kB
JavaScript
"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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WalletOperation = void 0;
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const receipt_1 = require("./receipt");
const taquito_utils_1 = require("@mavrykdynamics/taquito-utils");
const errors_1 = require("../errors");
const errors_2 = require("./errors");
const taquito_core_1 = require("@mavrykdynamics/taquito-core");
const MAX_BRANCH_ANCESTORS = 60;
/**
* @description WalletOperation allows to monitor operation inclusion on chains and surface information related to the operation
*/
class WalletOperation {
operationResults() {
return __awaiter(this, void 0, void 0, function* () {
return this._operationResult.pipe((0, operators_1.first)()).toPromise();
});
}
/**
* @description Receipt expose the total amount of mavryk token burn and spent on fees
* The promise returned by receipt will resolve only once the transaction is included
*/
receipt() {
return __awaiter(this, void 0, void 0, function* () {
const results = yield this.operationResults();
if (!results) {
throw new errors_2.ObservableError('Unable to get operation results');
}
return (0, receipt_1.receiptFromOperation)(results);
});
}
/**
*
* @param opHash Operation hash
* @param raw Raw operation that was injected
* @param context Taquito context allowing access to rpc and signer
* @throws {InvalidOperationHashError}
*/
constructor(opHash, context, _newHead$) {
this.opHash = opHash;
this.context = context;
this._newHead$ = _newHead$;
this._operationResult = new rxjs_1.ReplaySubject(1);
this._includedInBlock = new rxjs_1.ReplaySubject(1);
this._included = false;
this.newHead$ = this._newHead$.pipe((0, operators_1.switchMap)((newHead) => {
var _a, _b;
const prevHead = (_b = (_a = this.lastHead) === null || _a === void 0 ? void 0 : _a.header.level) !== null && _b !== void 0 ? _b : newHead.header.level - 1;
return (0, rxjs_1.range)(prevHead + 1, newHead.header.level - prevHead - 1).pipe((0, operators_1.concatMap)((level) => this.context.readProvider.getBlock(level)), (0, operators_1.endWith)(newHead));
}), (0, operators_1.tap)((newHead) => (this.lastHead = newHead)), (0, operators_1.share)({
connector: () => new rxjs_1.ReplaySubject(1),
resetOnError: false,
resetOnComplete: false,
resetOnRefCountZero: false,
}));
// Observable that emit once operation is seen in a block
this.confirmed$ = this.newHead$.pipe((0, operators_1.map)((head) => {
for (const opGroup of head.operations) {
for (const op of opGroup) {
if (op.hash === this.opHash) {
this._included = true;
this._includedInBlock.next(head);
this._operationResult.next(op.contents);
// Return the block where the operation was found
return head;
}
}
}
}), (0, operators_1.filter)((x) => {
return typeof x !== 'undefined';
}), (0, operators_1.first)(), (0, operators_1.share)({
connector: () => new rxjs_1.ReplaySubject(1),
resetOnError: false,
resetOnComplete: false,
resetOnRefCountZero: false,
}));
if ((0, taquito_utils_1.validateOperation)(this.opHash) !== taquito_utils_1.ValidationResult.VALID) {
throw new taquito_core_1.InvalidOperationHashError(this.opHash);
}
this.confirmed$
.pipe((0, operators_1.first)(), (0, operators_1.catchError)(() => (0, rxjs_1.of)(undefined)))
.subscribe();
}
getCurrentConfirmation() {
return __awaiter(this, void 0, void 0, function* () {
if (!this._included) {
return 0;
}
return (0, rxjs_1.combineLatest)([this._includedInBlock, (0, rxjs_1.from)(this.context.readProvider.getBlock('head'))])
.pipe((0, operators_1.map)(([foundAtBlock, head]) => {
return head.header.level - foundAtBlock.header.level + 1;
}), (0, operators_1.first)())
.toPromise();
});
}
isInCurrentBranch(tipBlockIdentifier = 'head') {
return __awaiter(this, void 0, void 0, function* () {
// By default it is assumed that the operation is in the current branch
if (!this._included) {
return true;
}
const tipBlockHeaderLevel = yield this.context.readProvider.getBlockLevel(tipBlockIdentifier);
const inclusionBlock = yield this._includedInBlock.pipe((0, operators_1.first)()).toPromise();
if (!inclusionBlock) {
throw new errors_2.ObservableError('Inclusion block is undefined');
}
const levelDiff = (tipBlockHeaderLevel - inclusionBlock.header.level);
// Block produced before the operation is included are assumed to be part of the current branch
if (levelDiff <= 0) {
return true;
}
const tipBlockLevel = Math.min(inclusionBlock.header.level + levelDiff, inclusionBlock.header.level + MAX_BRANCH_ANCESTORS);
const blocks = new Set(yield this.context.readProvider.getLiveBlocks(tipBlockLevel));
return blocks.has(inclusionBlock.hash);
});
}
confirmationObservable(confirmations) {
if (typeof confirmations !== 'undefined' && confirmations < 1) {
throw new errors_1.InvalidConfirmationCountError(confirmations);
}
const { defaultConfirmationCount } = this.context.config;
const conf = confirmations !== undefined ? confirmations : defaultConfirmationCount;
if (conf === undefined) {
throw new errors_2.ConfirmationUndefinedError();
}
return (0, rxjs_1.combineLatest)([this._includedInBlock, this.newHead$]).pipe((0, operators_1.distinctUntilChanged)(([, previousHead], [, newHead]) => {
return previousHead.hash === newHead.hash;
}), (0, operators_1.map)(([foundAtBlock, head]) => {
return {
block: head,
expectedConfirmation: conf,
currentConfirmation: head.header.level - foundAtBlock.header.level + 1,
completed: head.header.level - foundAtBlock.header.level >= conf - 1,
isInCurrentBranch: () => this.isInCurrentBranch(head.hash),
};
}), (0, operators_1.takeWhile)(({ completed }) => !completed, true));
}
/**
*
* @param confirmations [0] Number of confirmation to wait for
*/
confirmation(confirmations) {
return this.confirmationObservable(confirmations).toPromise();
}
}
exports.WalletOperation = WalletOperation;