@taquito/taquito
Version:
High level functionality that builds upon the other packages in the Tezos Typescript Library Suite.
1,233 lines (1,202 loc) • 327 kB
JavaScript
import { OpKind, RpcClient } from '@taquito/rpc';
export { OpKind } from '@taquito/rpc';
import { HttpResponseError, STATUS_CODE } from '@taquito/http-utils';
import { TezosToolkitConfigError, ParameterValidationError, RpcError, TaquitoError, NetworkError, InvalidOperationHashError, InvalidViewParameterError, DeprecationError, InvalidChainIdError, InvalidOperationKindError as InvalidOperationKindError$1, PublicKeyNotFoundError, ProhibitedActionError, InvalidProofError, InvalidAddressError, InvalidAmountError, InvalidStakingAddressError, InvalidKeyHashError as InvalidKeyHashError$1, InvalidContractAddressError, InvalidFinalizeUnstakeAmountError } from '@taquito/core';
import { Observable, ReplaySubject, range, of, combineLatest, from, defer, concat, BehaviorSubject, throwError, EMPTY, Subject, NEVER, timer } from 'rxjs';
import { switchMap, concatMap, endWith, tap, share, map, filter, first, catchError, distinctUntilChanged, takeWhile, startWith, timeout, mergeMap, shareReplay, takeUntil, retry, distinctUntilKeyChanged } from 'rxjs/operators';
import BigNumber, { BigNumber as BigNumber$1 } from 'bignumber.js';
import { validateOperation, ValidationResult, format, InvalidOperationKindError, validateAddress, validateChain, validateContractAddress, b58DecodeAndCheckPrefix, publicKeyHashPrefixes, PrefixV2, publicKeyPrefixes, validateKeyHash, InvalidKeyHashError, payloadLength, encodeExpr } from '@taquito/utils';
import { Schema, ParameterSchema, ViewSchema, EventSchema, MichelsonMap, Token } from '@taquito/michelson-encoder';
export { MichelsonMap, Token, UnitValue } from '@taquito/michelson-encoder';
import { Parser, packDataBytes } from '@taquito/michel-codec';
import { LocalForger } from '@taquito/local-forging';
import { InMemorySigner } from '@taquito/signer';
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
function __awaiter(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());
});
}
function __classPrivateFieldGet(receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
}
function __classPrivateFieldSet(receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
function formatErrorMessage(error, stringToReplace) {
const body = JSON.parse(error.body);
if (body[0] && body[0].kind && body[0].msg) {
const newBody = JSON.stringify({
kind: body[0].kind,
id: body[0].id,
msg: body[0].msg.replace(stringToReplace, ''),
});
return new HttpResponseError(`Http error response: (${error.status}) ${newBody}`, error.status, error.statusText, newBody, error.url);
}
else {
return error;
}
}
class RpcInjector {
constructor(context) {
this.context = context;
}
inject(signedOperationBytes) {
return __awaiter(this, void 0, void 0, function* () {
let hash;
try {
hash = yield this.context.rpc.injectOperation(signedOperationBytes);
}
catch (error) {
const stringToStrip = '. You may want to use --replace to provide adequate fee and replace it';
if (error instanceof HttpResponseError && error.message.includes(stringToStrip)) {
throw formatErrorMessage(error, stringToStrip);
}
else {
throw error;
}
}
return hash;
});
}
}
/**
* @category Error
* @description Error that indicates no signer has been configured in the TezosToolkit instance
*/
class UnconfiguredSignerError extends TezosToolkitConfigError {
constructor() {
super();
this.name = 'UnconfiguredSignerError';
this.message =
'No signer has been configured. Please configure one by calling setProvider({signer}) on your TezosToolkit instance.';
}
}
/**
* @description Default signer implementation which does nothing and produce invalid signature
* @throw {@link UnconfiguredSignerError}
*/
class NoopSigner {
publicKey() {
return __awaiter(this, void 0, void 0, function* () {
throw new UnconfiguredSignerError();
});
}
publicKeyHash() {
return __awaiter(this, void 0, void 0, function* () {
throw new UnconfiguredSignerError();
});
}
secretKey() {
return __awaiter(this, void 0, void 0, function* () {
throw new UnconfiguredSignerError();
});
}
sign(_bytes, _watermark) {
return __awaiter(this, void 0, void 0, function* () {
throw new UnconfiguredSignerError();
});
}
}
function createObservableFromSubscription(sub) {
return new Observable((subscriber) => {
sub.on('data', (data) => {
subscriber.next(data);
});
sub.on('error', (error) => {
subscriber.error(error);
});
sub.on('close', () => {
subscriber.complete();
});
return () => {
sub.close();
};
});
}
const attachKind = (op, kind) => {
return Object.assign(Object.assign({}, op), { kind });
};
const findWithKind = (arr, kind) => {
if (Array.isArray(arr)) {
const found = arr.find((op) => op.kind === kind);
if (found && isKind(found, kind)) {
return found;
}
}
};
const isKind = (op, kind) => {
return op.kind === kind;
};
const isOpWithGasBuffer = (op) => {
var _a;
if (op.kind === OpKind.TRANSACTION && ((_a = op.destination) === null || _a === void 0 ? void 0 : _a.startsWith('KT1'))) {
return true;
}
else {
return ([
'origination',
'register_global_constant',
'transfer_ticket',
'update_consensus_key',
'update_companion_key',
'smart_rollup_add_messages',
'smart_rollup_originate',
].indexOf(op.kind) !== -1);
}
};
const isOpWithFee = (op) => {
return ([
'transaction',
'delegation',
'origination',
'reveal',
'register_global_constant',
'increase_paid_storage',
'transfer_ticket',
'update_consensus_key',
'update_companion_key',
'smart_rollup_add_messages',
'smart_rollup_originate',
'smart_rollup_execute_outbox_message',
].indexOf(op.kind) !== -1);
};
const isOpRequireReveal = (op) => {
return ([
'transaction',
'delegation',
'origination',
'register_global_constant',
'increase_paid_storage',
'transfer_ticket',
'update_consensus_key',
'update_companion_key',
'smart_rollup_add_messages',
'smart_rollup_originate',
'smart_rollup_execute_outbox_message',
].indexOf(op.kind) !== -1);
};
const isSourceOp = (op) => {
return ['transaction', 'delegation', 'origination', 'reveal', 'ballot'].indexOf(op.kind) !== -1;
};
const hasMetadata = (op) => {
return 'metadata' in op;
};
const hasMetadataWithResult = (op) => {
return hasMetadata(op) && 'operation_result' in op.metadata;
};
const hasMetadataWithInternalOperationResult = (op) => {
return hasMetadata(op) && 'internal_operation_results' in op.metadata;
};
// value is based on octez-client reveal operation gasLimit of each address type in Tallinn Protocol
const REVEAL_GAS_LIMIT = {
TZ1: 171,
TZ2: 157,
TZ3: 447,
TZ4: 3252,
};
// value is based on octez-client reveal operation fee of each address type in Tallinn Protocol
const REVEAL_FEE = {
TZ1: 278,
TZ2: 277,
TZ3: 306,
TZ4: 736,
};
// value is based on octez-client reveal operation storageLimit of all address type in Tallinn Protocol
const REVEAL_STORAGE_LIMIT = 0;
// protocol constants in Tallinn Protocol
// NOTE: When updating constants here, also check:
// website/src/config/tezos-constants.mjs (documentation constants, versioned by doc version)
const ORIGINATION_SIZE = 257;
// protocol constants in Tallinn Protocol
const COST_PER_BYTE = 250;
var Protocols;
(function (Protocols) {
Protocols["Pt24m4xi"] = "Pt24m4xiPbLDhVgVfABUjirbmda3yohdN82Sp9FeuAXJ4eV9otd";
Protocols["PsBABY5H"] = "PsBABY5HQTSkA4297zNHfsZNKtxULfL18y95qb3m53QJiXGmrbU";
Protocols["PsBabyM1"] = "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS";
Protocols["PsCARTHA"] = "PsCARTHAGazKbHtnKfLzQg3kms52kSRpgnDY982a9oYsSXRLQEb";
Protocols["PsDELPH1"] = "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo";
Protocols["PtEdo2Zk"] = "PtEdo2ZkT9oKpimTah6x2embF25oss54njMuPzkJTEi5RqfdZFA";
Protocols["PsFLorena"] = "PsFLorenaUUuikDWvMDr6fGBRG8kt3e3D3fHoXK1j1BFRxeSH4i";
Protocols["PtGRANADs"] = "PtGRANADsDU8R9daYKAgWnQYAJ64omN1o3KMGVCykShA97vQbvV";
Protocols["PtHangz2"] = "PtHangz2aRngywmSRGGvrcTyMbbdpWdpFKuS4uMWxg2RaH9i1qx";
Protocols["PsiThaCa"] = "PsiThaCaT47Zboaw71QWScM8sXeMM7bbQFncK9FLqYc6EKdpjVP";
Protocols["Psithaca2"] = "Psithaca2MLRFYargivpo7YvUr7wUDqyxrdhC5CQq78mRvimz6A";
Protocols["PtJakart2"] = "PtJakart2xVj7pYXJBXrqHgd82rdkLey5ZeeGwDgPp9rhQUbSqY";
Protocols["PtKathman"] = "PtKathmankSpLLDALzWw7CGD2j2MtyveTwboEYokqUCP4a1LxMg";
Protocols["PtLimaPtL"] = "PtLimaPtLMwfNinJi9rCfDPWea8dFgTZ1MeJ9f1m2SRic6ayiwW";
Protocols["PtMumbaii"] = "PtMumbaiiFFEGbew1rRjzSPyzRbA51Tm3RVZL5suHPxSZYDhCEc";
Protocols["PtMumbai2"] = "PtMumbai2TmsJHNGRkD8v8YDbtao7BLUC3wjASn1inAKLFCjaH1";
Protocols["PtNairobi"] = "PtNairobiyssHuh87hEhfVBGCVrK3WnS8Z2FT4ymB5tAa4r1nQf";
Protocols["ProxfordY"] = "ProxfordYmVfjWnRcgjWH36fW6PArwqykTFzotUxRs6gmTcZDuH";
Protocols["PtParisBx"] = "PtParisBxoLz5gzMmn3d9WBQNoPSZakgnkMC2VNuQ3KXfUtUQeZ";
Protocols["PsParisCZ"] = "PsParisCZo7KAh1Z1smVd9ZMZ1HHn5gkzbM94V3PLCpknFWhUAi";
Protocols["PsQuebecn"] = "PsQuebecnLByd3JwTiGadoG4nGWi3HYiLXUjkibeFV8dCFeVMUg";
Protocols["PsRiotuma"] = "PsRiotumaAMotcRoDWW1bysEhQy2n1M5fy8JgRp8jjRfHGmfeA7";
Protocols["PtSeouLou"] = "PtSeouLouXkxhg39oWzjxDWaCydNfR3RxCUrNe4Q9Ro8BTehcbh";
Protocols["PtTALLiNt"] = "PtTALLiNtPec7mE7yY4m3k26J8Qukef3E3ehzhfXgFZKGtDdAXu";
Protocols["ProtoALpha"] = "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK";
})(Protocols || (Protocols = {}));
const protocols = {
'004': [Protocols.Pt24m4xi],
'005': [Protocols.PsBABY5H, Protocols.PsBabyM1],
'006': [Protocols.PsCARTHA],
'007': [Protocols.PsDELPH1],
'008': [Protocols.PtEdo2Zk], // edonet v2
'009': [Protocols.PsFLorena],
'010': [Protocols.PtGRANADs],
'011': [Protocols.PtHangz2], // hangzhou v2,
'012': [Protocols.PsiThaCa, Protocols.Psithaca2],
'013': [Protocols.PtJakart2],
'014': [Protocols.PtKathman],
'015': [Protocols.PtLimaPtL],
'016': [Protocols.PtMumbai2], // mumbai v2
'017': [Protocols.PtNairobi],
'019': [Protocols.ProxfordY],
'020': [Protocols.PtParisBx, Protocols.PsParisCZ],
'021': [Protocols.PsQuebecn],
'022': [Protocols.PsRiotuma],
'023': [Protocols.PtSeouLou],
'024': [Protocols.PtTALLiNt],
'025': [Protocols.ProtoALpha],
};
var ChainIds;
(function (ChainIds) {
ChainIds["MAINNET"] = "NetXdQprcVkpaWU";
ChainIds["GHOSTNET"] = "NetXnHfVqm9iesp";
ChainIds["SHADOWNET"] = "NetXsqzbfFenSTS";
ChainIds["CARTHAGENET"] = "NetXjD3HPJJjmcd";
ChainIds["DELPHINET"] = "NetXm8tYqnMWky1";
ChainIds["EDONET"] = "NetXSgo1ZT2DRUG";
ChainIds["FLORENCENET"] = "NetXxkAx4woPLyu";
ChainIds["GRANADANET"] = "NetXz969SFaFn8k";
ChainIds["HANGZHOUNET"] = "NetXZSsxBpMQeAT";
ChainIds["ITHACANET"] = "NetXbhmtAbMukLc";
ChainIds["JAKARTANET2"] = "NetXLH1uAxK7CCh";
ChainIds["KATHMANDUNET"] = "NetXazhm4yetmff";
ChainIds["LIMANET"] = "NetXizpkH94bocH";
ChainIds["MUMBAINET"] = "NetXQw6nWSnrJ5t";
ChainIds["MUMBAINET2"] = "NetXgbcrNtXD2yA";
ChainIds["NAIROBINET"] = "NetXyuzvDo2Ugzb";
ChainIds["OXFORDNET2"] = "NetXxWsskGahzQB";
ChainIds["PARISBNET"] = "NetXo8SqH1c38SS";
ChainIds["PARISCNET"] = "NetXXWAHLEvre9b";
ChainIds["QUEBECNET"] = "NetXuTeGinLEqxp";
ChainIds["RIONET"] = "NetXPdgaoabtBth";
ChainIds["SEOULNET"] = "NetXd56aBs1aeW3";
ChainIds["TALLINNNET"] = "NetXe8DbhW9A1eS";
})(ChainIds || (ChainIds = {}));
const getRevealGasLimit = (address) => Math.round((getRevealGasLimitInternal(address) * 37) / 10);
const getRevealGasLimitInternal = (address) => {
switch (address.substring(0, 3)) {
case 'tz1':
return REVEAL_GAS_LIMIT.TZ1;
case 'tz2':
return REVEAL_GAS_LIMIT.TZ2;
case 'tz3':
return REVEAL_GAS_LIMIT.TZ3;
case 'tz4':
return REVEAL_GAS_LIMIT.TZ4;
default:
throw new Error(`Cannot estimate reveal gas limit for ${address}`);
}
};
const getRevealFee = (address) => Math.round((getRevealFeeInternal(address) * 12) / 10);
const getRevealFeeInternal = (address) => {
switch (address.substring(0, 3)) {
case 'tz1':
return REVEAL_FEE.TZ1;
case 'tz2':
return REVEAL_FEE.TZ2;
case 'tz3':
return REVEAL_FEE.TZ3;
case 'tz4':
return REVEAL_FEE.TZ4 * 1.7;
default:
throw new Error(`Cannot estimate reveal fee for ${address}`);
}
};
const isErrorWithMessage = (error) => {
return 'with' in error;
};
/**
* @category Error
* @description Generic tezos error that will be thrown when a mistake occurs when doing an operation; more details here https://tezos.gitlab.io/api/errors.html
*/
class TezosOperationError extends RpcError {
constructor(errors, errorDetails, operationsWithResults) {
super();
this.errors = errors;
this.errorDetails = errorDetails;
this.operationsWithResults = operationsWithResults;
this.name = 'TezosOperationError';
// Last error is 'often' the one with more detail
this.lastError = errors[errors.length - 1];
this.message = `(${this.kind}) ${this.id}`;
if (isErrorWithMessage(this.lastError)) {
if (this.lastError.with.string) {
this.message = this.lastError.with.string;
}
else if (this.lastError.with.int) {
this.message = this.lastError.with.int;
}
else {
this.message = JSON.stringify(this.lastError.with);
}
}
}
get id() {
return this.lastError.id;
}
get kind() {
return this.lastError.kind;
}
}
/**
* @category Error
* @description Tezos error that will be thrown when a mistake happens during the preapply stage
*/
class TezosPreapplyFailureError extends Error {
constructor(result) {
super();
this.result = result;
this.name = 'TezosPreapplyFailureError';
this.message = 'Preapply returned an unexpected result';
}
}
// Flatten all operation content results and internal operation results into a single array
// Some cases where we can have multiple operation results or internal operation results are:
// - When an operation includes a reveal operation
// - When an operation is made using the batch API
// - Smart contract call can contains internal operation results when they call other smart contract internally or originate contracts
const flattenOperationResult = (response) => {
const results = Array.isArray(response) ? response : [response];
const returnedResults = [];
for (let i = 0; i < results.length; i++) {
for (let j = 0; j < results[i].contents.length; j++) {
const content = results[i].contents[j];
if (hasMetadataWithResult(content) && 'fee' in content) {
returnedResults.push(Object.assign({ fee: content.fee }, content.metadata.operation_result));
if (Array.isArray(content.metadata.internal_operation_results)) {
content.metadata.internal_operation_results.forEach((x) => returnedResults.push(x.result));
}
}
}
}
return returnedResults;
};
/***
* @description Flatten all error from preapply response (including internal error)
*/
const flattenErrors = (response, status = 'failed') => {
const results = Array.isArray(response) ? response : [response];
let errors = [];
// Transaction that do not fail will be backtracked in case one failure occur
for (let i = 0; i < results.length; i++) {
for (let j = 0; j < results[i].contents.length; j++) {
const content = results[i].contents[j];
if (hasMetadata(content)) {
if (hasMetadataWithResult(content) &&
content.metadata.operation_result.status === status) {
errors = errors.concat(content.metadata.operation_result.errors || []);
}
if (hasMetadataWithInternalOperationResult(content) &&
Array.isArray(content.metadata.internal_operation_results)) {
for (const internalResult of content.metadata.internal_operation_results) {
if ('result' in internalResult && internalResult.result.status === status) {
errors = errors.concat(internalResult.result.errors || []);
}
}
}
}
}
}
return errors;
};
/**
* @category Error
* @description Error that indicates a general failure happening during an origination operation.
*/
class OriginationOperationError extends TaquitoError {
constructor(message) {
super();
this.message = message;
this.name = 'OriginationOperationError';
}
}
/**
* @category Error
* @description Error that indicates an invalid estimate value being passed
*/
class InvalidEstimateValueError extends ParameterValidationError {
constructor(message) {
super();
this.message = message;
this.name = 'InvalidEstimateValueError';
}
}
const receiptFromOperation = (op, { ALLOCATION_BURN, ORIGINATION_BURN } = {
ALLOCATION_BURN: 257,
ORIGINATION_BURN: 257,
}) => {
BigNumber.config({ DECIMAL_PLACES: 0, ROUNDING_MODE: BigNumber.ROUND_UP });
const operationResults = flattenOperationResult({ contents: op });
let totalMilliGas = new BigNumber(0);
let totalStorage = new BigNumber(0);
let totalFee = new BigNumber(0);
let totalOriginationBurn = new BigNumber(0);
let totalAllocationBurn = new BigNumber(0);
let totalPaidStorageDiff = new BigNumber(0);
operationResults.forEach((result) => {
totalFee = totalFee.plus(result.fee || 0);
totalOriginationBurn = totalOriginationBurn.plus(Array.isArray(result.originated_contracts)
? result.originated_contracts.length * ORIGINATION_BURN
: 0);
totalAllocationBurn = totalAllocationBurn.plus('allocated_destination_contract' in result ? ALLOCATION_BURN : 0);
totalMilliGas = totalMilliGas.plus(result.consumed_milligas || 0);
totalPaidStorageDiff = totalPaidStorageDiff.plus('paid_storage_size_diff' in result ? Number(result.paid_storage_size_diff) || 0 : 0);
});
totalStorage = totalStorage
.plus(totalAllocationBurn)
.plus(totalOriginationBurn)
.plus(totalPaidStorageDiff);
return {
totalFee,
totalMilliGas,
totalGas: totalMilliGas.dividedBy(1000),
totalStorage,
totalAllocationBurn,
totalOriginationBurn,
totalPaidStorageDiff,
totalStorageBurn: new BigNumber(totalStorage.multipliedBy(COST_PER_BYTE)),
};
};
/**
* @category Error
* @description Error that indicates invalid confirmation count has been passed or configured
*/
class InvalidConfirmationCountError extends ParameterValidationError {
constructor(invalidConfirmations) {
super();
this.invalidConfirmations = invalidConfirmations;
this.name = 'InvalidConfirmationCountError';
this.message = `Invalid confirmation count ${invalidConfirmations} expecting at least 1`;
}
}
/**
* @category Error
* @description Error that indicates that confirmation polling timed out
*/
class ConfirmationTimeoutError extends NetworkError {
constructor(message) {
super();
this.message = message;
this.name = 'ConfirmationTimeoutError';
}
}
/**
* @category Error
* @description Error that indicates an error being returned from the RPC response
*/
class RPCResponseError extends RpcError {
constructor(message, cause) {
super();
this.message = message;
this.cause = cause;
this.name = 'RPCResponseError';
}
}
/**
* @category Error
* @description Error that indicates undefined confirmation has not been specified or configured
*/
class ConfirmationUndefinedError extends TezosToolkitConfigError {
constructor() {
super();
this.name = 'ConfirmationUndefinedError';
this.message = 'Default confirmation count can not be undefined';
}
}
/**
* @category Error
* @description Error that indicates a generic failure when trying to fetch an observable
*/
class ObservableError extends NetworkError {
constructor(message) {
super();
this.message = message;
this.name = 'ObservableError';
}
}
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(first()).toPromise();
});
}
/**
* @description Receipt expose the total amount of tezos 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 ObservableError('Unable to get operation results');
}
return 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 ReplaySubject(1);
this._includedInBlock = new ReplaySubject(1);
this._included = false;
this.newHead$ = this._newHead$.pipe(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 range(prevHead + 1, newHead.header.level - prevHead - 1).pipe(concatMap((level) => this.context.readProvider.getBlock(level)), endWith(newHead));
}), tap((newHead) => (this.lastHead = newHead)), share({
connector: () => new ReplaySubject(1),
resetOnError: false,
resetOnComplete: false,
resetOnRefCountZero: true,
}));
// Observable that emit once operation is seen in a block
this.confirmed$ = this.newHead$.pipe(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;
}
}
}
}), filter((x) => {
return typeof x !== 'undefined';
}), first(), share({
connector: () => new ReplaySubject(1),
resetOnError: false,
resetOnComplete: false,
resetOnRefCountZero: true,
}));
if (validateOperation(this.opHash) !== ValidationResult.VALID) {
throw new InvalidOperationHashError(this.opHash);
}
this.confirmed$
.pipe(first(), catchError(() => of(undefined)))
.subscribe();
}
getCurrentConfirmation() {
return __awaiter(this, void 0, void 0, function* () {
if (!this._included) {
return 0;
}
return combineLatest([this._includedInBlock, from(this.context.readProvider.getBlock('head'))])
.pipe(map(([foundAtBlock, head]) => {
return head.header.level - foundAtBlock.header.level + 1;
}), first())
.toPromise();
});
}
isInCurrentBranch() {
return __awaiter(this, arguments, void 0, function* (tipBlockIdentifier = 'head') {
// 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(first()).toPromise();
if (!inclusionBlock) {
throw new 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 InvalidConfirmationCountError(confirmations);
}
const { defaultConfirmationCount } = this.context.config;
const conf = confirmations !== undefined ? confirmations : defaultConfirmationCount;
if (conf === undefined) {
throw new ConfirmationUndefinedError();
}
return combineLatest([this._includedInBlock, this.newHead$]).pipe(distinctUntilChanged(([, previousHead], [, newHead]) => {
return previousHead.hash === newHead.hash;
}), 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),
};
}), takeWhile(({ completed }) => !completed, true));
}
/**
*
* @param confirmations [0] Number of confirmation to wait for
*/
confirmation(confirmations) {
return this.confirmationObservable(confirmations).toPromise();
}
}
const WALLET_BATCH_KINDS = [
OpKind.REVEAL,
OpKind.ORIGINATION,
OpKind.TRANSACTION,
OpKind.DELEGATION,
OpKind.REGISTER_GLOBAL_CONSTANT,
OpKind.INCREASE_PAID_STORAGE,
OpKind.TRANSFER_TICKET,
];
class BatchWalletOperation extends WalletOperation {
constructor(opHash, context, newHead$) {
super(opHash, context, newHead$);
this.opHash = opHash;
this.context = context;
this.getOriginatedContractAddresses = () => __awaiter(this, void 0, void 0, function* () {
const opResult = yield this.operationResults();
if (!opResult) {
throw new ObservableError('Unable to fetch operation results');
}
else {
const originationOpResults = opResult.filter((x) => x.kind === 'origination');
let addresses = [];
for (const res of originationOpResults) {
if (res.metadata.operation_result.originated_contracts) {
addresses = [...addresses, ...res.metadata.operation_result.originated_contracts];
}
}
return addresses;
}
});
}
revealOperation() {
return __awaiter(this, void 0, void 0, function* () {
const operationResult = yield this.operationResults();
if (!operationResult) {
throw new ObservableError('Unable to fetch operation results');
}
else {
return operationResult.find((x) => x.kind === OpKind.REVEAL);
}
});
}
status() {
return __awaiter(this, void 0, void 0, function* () {
if (!this._included) {
return 'pending';
}
const op = yield this.operationResults();
if (op) {
return (op
.filter((result) => WALLET_BATCH_KINDS.indexOf(result.kind) !== -1)
.map((result) => {
if (hasMetadataWithResult(result)) {
const opResult = result.metadata.operation_result;
return opResult.status;
}
else {
return 'unknown';
}
})[0] || 'unknown');
}
else {
throw new ObservableError('Unable to fetch operation results');
}
});
}
}
class DelegationWalletOperation extends WalletOperation {
constructor(opHash, context, newHead$) {
super(opHash, context, newHead$);
this.opHash = opHash;
this.context = context;
}
revealOperation() {
return __awaiter(this, void 0, void 0, function* () {
const operationResult = yield this.operationResults();
if (operationResult) {
return operationResult.find((x) => x.kind === OpKind.REVEAL);
}
else {
throw new ObservableError('Unable to fetch operation result');
}
});
}
delegationOperation() {
return __awaiter(this, void 0, void 0, function* () {
const operationResult = yield this.operationResults();
if (operationResult) {
return operationResult.find((x) => x.kind === OpKind.DELEGATION);
}
else {
throw new ObservableError('Unable to fetch operation result');
}
});
}
status() {
return __awaiter(this, void 0, void 0, function* () {
if (!this._included) {
return 'pending';
}
const op = yield this.delegationOperation();
if (!op) {
return 'unknown';
}
return op.metadata.operation_result.status;
});
}
}
class IncreasePaidStorageWalletOperation extends WalletOperation {
constructor(opHash, context, newHead$) {
super(opHash, context, newHead$);
this.opHash = opHash;
this.context = context;
}
revealOperation() {
return __awaiter(this, void 0, void 0, function* () {
const operationResult = yield this.operationResults();
if (!operationResult) {
throw new ObservableError('Unable to fetch operation result');
}
else {
return operationResult.find((x) => x.kind === OpKind.REVEAL);
}
});
}
increasePaidStorageOperation() {
return __awaiter(this, void 0, void 0, function* () {
const operationResult = yield this.operationResults();
if (!operationResult) {
throw new ObservableError('Unable to fetch operation result');
}
else {
return operationResult.find((x) => x.kind === OpKind.INCREASE_PAID_STORAGE);
}
});
}
status() {
return __awaiter(this, void 0, void 0, function* () {
if (!this._included) {
return 'pending';
}
const op = yield this.increasePaidStorageOperation();
if (!op) {
return 'unknown';
}
return op.metadata.operation_result.status;
});
}
}
class OriginationWalletOperation extends WalletOperation {
constructor(opHash, context, newHead$) {
super(opHash, context, newHead$);
this.opHash = opHash;
this.context = context;
}
originationOperation() {
return __awaiter(this, void 0, void 0, function* () {
const operationResult = yield this.operationResults();
if (operationResult) {
return findWithKind(operationResult, OpKind.ORIGINATION);
}
else {
throw new ObservableError('Unable to fetch operation result');
}
});
}
revealOperation() {
return __awaiter(this, void 0, void 0, function* () {
const operationResult = yield this.operationResults();
if (operationResult) {
return findWithKind(operationResult, OpKind.REVEAL);
}
else {
throw new ObservableError('Unable to fetch operation result');
}
});
}
status() {
return __awaiter(this, void 0, void 0, function* () {
if (!this._included) {
return 'pending';
}
const op = yield this.originationOperation();
if (!op) {
return 'unknown';
}
return op.metadata.operation_result.status;
});
}
contract() {
return __awaiter(this, void 0, void 0, function* () {
const op = yield this.originationOperation();
const address = ((op === null || op === void 0 ? void 0 : op.metadata.operation_result.originated_contracts) || [])[0];
return this.context.wallet.at(address);
});
}
}
class TransactionWalletOperation extends WalletOperation {
constructor(opHash, context, newHead$) {
super(opHash, context, newHead$);
this.opHash = opHash;
this.context = context;
}
revealOperation() {
return __awaiter(this, void 0, void 0, function* () {
const operationResult = yield this.operationResults();
if (!operationResult) {
throw new ObservableError('operationResult returned undefined');
}
return operationResult.find((x) => x.kind === OpKind.REVEAL);
});
}
transactionOperation() {
return __awaiter(this, void 0, void 0, function* () {
const operationResult = yield this.operationResults();
if (!operationResult) {
throw new ObservableError('operationResult returned undefined');
}
return operationResult.find((x) => x.kind === OpKind.TRANSACTION);
});
}
status() {
return __awaiter(this, void 0, void 0, function* () {
if (!this._included) {
return 'pending';
}
const op = yield this.transactionOperation();
if (!op) {
return 'unknown';
}
return op.metadata.operation_result.status;
});
}
}
class TransferTicketWalletOperation extends WalletOperation {
constructor(opHash, context, newHead$) {
super(opHash, context, newHead$);
this.opHash = opHash;
this.context = context;
}
revealOperation() {
return __awaiter(this, void 0, void 0, function* () {
const operationResult = yield this.operationResults();
if (!operationResult) {
throw new ObservableError('operationResult returned undefined');
}
return operationResult.find((x) => x.kind === OpKind.REVEAL);
});
}
transferTicketOperation() {
return __awaiter(this, void 0, void 0, function* () {
const operationResult = yield this.operationResults();
if (!operationResult) {
throw new ObservableError('operationResult returned undefined');
}
return operationResult.find((x) => x.kind === OpKind.TRANSFER_TICKET);
});
}
status() {
return __awaiter(this, void 0, void 0, function* () {
if (!this._included) {
return 'pending';
}
const op = yield this.transferTicketOperation();
if (!op) {
return 'unknown';
}
return op.metadata.operation_result.status;
});
}
}
class RegisterGlobalConstantWalletOperation extends WalletOperation {
constructor(opHash, context, newHead$) {
super(opHash, context, newHead$);
this.opHash = opHash;
this.context = context;
}
revealOperation() {
return __awaiter(this, void 0, void 0, function* () {
const operationResult = yield this.operationResults();
if (!operationResult) {
throw new ObservableError('operationResult returned undefined');
}
return operationResult.find((x) => x.kind === OpKind.REVEAL);
});
}
registerGlobalConstantOperation() {
return __awaiter(this, void 0, void 0, function* () {
const operationResult = yield this.operationResults();
if (operationResult) {
return findWithKind(operationResult, OpKind.REGISTER_GLOBAL_CONSTANT);
}
else {
throw new ObservableError('Unable to fetch operation result');
}
});
}
status() {
return __awaiter(this, void 0, void 0, function* () {
if (!this._included) {
return 'pending';
}
const op = yield this.registerGlobalConstantOperation();
if (!op) {
return 'unknown';
}
return op.metadata.operation_result.status;
});
}
globalConstantHash() {
return __awaiter(this, void 0, void 0, function* () {
const op = yield this.registerGlobalConstantOperation();
return op === null || op === void 0 ? void 0 : op.metadata.operation_result.global_address;
});
}
}
function timeoutAfter(timeoutMillisec) {
return function inner(source) {
return new BehaviorSubject(null).pipe(timeout({
each: timeoutMillisec,
with: () => throwError(() => new ConfirmationTimeoutError(`Confirmation polling timed out`)),
}), mergeMap(() => source));
};
}
const createNewPollingBasedHeadObservable = (sharedHeadOb, context, _scheduler) => {
return sharedHeadOb.pipe(timeoutAfter(context.config.confirmationPollingTimeoutSecond * 1000), share({
connector: () => new ReplaySubject(1),
resetOnError: false,
resetOnComplete: false,
resetOnRefCountZero: true,
}));
};
class OperationFactory {
constructor(context) {
this.context = context;
// Cache the last block for one second across all operations
this.sharedHeadObs = defer(() => {
return createObservableFromSubscription(this.context.stream.subscribeBlock('head'));
});
}
createNewHeadObservable() {
return __awaiter(this, void 0, void 0, function* () {
return createNewPollingBasedHeadObservable(this.sharedHeadObs, this.context);
});
}
createPastBlockWalker(startBlock, count = 1) {
return from(this.context.readProvider.getBlock(startBlock)).pipe(switchMap((block) => {
if (count === 1) {
return of(block);
}
return range(block.header.level, count - 1).pipe(startWith(block), concatMap((level) => __awaiter(this, void 0, void 0, function* () {
return this.context.readProvider.getBlock(typeof level === 'number' ? level : level.header.level);
})));
}));
}
createHeadObservableFromConfig(_a) {
return __awaiter(this, arguments, void 0, function* ({ blockIdentifier }) {
const observableSequence = [];
if (blockIdentifier) {
observableSequence.push(this.createPastBlockWalker(blockIdentifier));
}
observableSequence.push(yield this.createNewHeadObservable());
return concat(...observableSequence);
});
}
createOperation(hash_1) {
return __awaiter(this, arguments, void 0, function* (hash, config = {}) {
return new WalletOperation(hash, this.context.clone(), yield this.createHeadObservableFromConfig(config));
});
}
createBatchOperation(hash_1) {
return __awaiter(this, arguments, void 0, function* (hash, config = {}) {
return new BatchWalletOperation(hash, this.context.clone(), yield this.createHeadObservableFromConfig(config));
});
}
createTransactionOperation(hash_1) {
return __awaiter(this, arguments, void 0, function* (hash, config = {}) {
return new TransactionWalletOperation(hash, this.context.clone(), yield this.createHeadObservableFromConfig(config));
});
}
createTransferTicketOperation(hash_1) {
return __awaiter(this, arguments, void 0, function* (hash, config = {}) {
return new TransferTicketWalletOperation(hash, this.context.clone(), yield this.createHeadObservableFromConfig(config));
});
}
createDelegationOperation(hash_1) {
return __awaiter(this, arguments, void 0, function* (hash, config = {}) {
return new DelegationWalletOperation(hash, this.context.clone(), yield this.createHeadObservableFromConfig(config));
});
}
createOriginationOperation(hash_1) {
return __awaiter(this, arguments, void 0, function* (hash, config = {}) {
return new OriginationWalletOperation(hash, this.context.clone(), yield this.createHeadObservableFromConfig(config));
});
}
createIncreasePaidStorageOperation(hash_1) {
return __awaiter(this, arguments, void 0, function* (hash, config = {}) {
return new IncreasePaidStorageWalletOperation(hash, this.context.clone(), yield this.createHeadObservableFromConfig(config));
});
}
createRegisterGlobalConstantOperation(hash_1) {
return __awaiter(this, arguments, void 0, function* (hash, config = {}) {
return new RegisterGlobalConstantWalletOperation(hash, this.context.clone(), yield this.createHeadObservableFromConfig(config));
});
}
}
/**
* @description Utility class to interact with Tezos operations
*/
class Operation {
get includedInBlock() {
return this._foundAt;
}
/**
*
* @param hash Operation hash
* @param raw Raw operation that was injected
* @param context Taquito context allowing access to rpc and signer
* @throws {@link InvalidOperationHashError}
*/
constructor(hash, raw, results, context) {
this.hash = hash;
this.raw = raw;
this.results = results;
this.context = context;
this._pollingConfig$ = new ReplaySubject(1);
this.currentHead$ = this._pollingConfig$.pipe(switchMap((config) => {
return new BehaviorSubject(config).pipe(timeout({
each: config.timeout * 1000,
with: () => throwError(() => new ConfirmationTimeoutError(`Confirmation polling timed out`)),
}));
}), switchMap(() => {
return defer(() => createObservableFromSubscription(this.context.stream.subscribeBlock('head'))).pipe(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 range(prevHead + 1, newHead.header.level - prevHead - 1).pipe(concatMap((level) => this.context.readProvider.getBlock(level)), endWith(newHead));
}), tap((newHead) => (this.lastHead = newHead)));
}), shareReplay({ refCount: true }));
// Observable that emit once operation is seen in a block
this.confirmed$ = this.currentHead$.pipe(map((head) => {
for (let i = 3; i >= 0; i--) {
head.operations[i].forEach((op) => {
if (op.hash === this.hash) {
this._foundAt = head.header.level;
}
});
}
if (head.header.level - this._foundAt >= 0) {
return this._foundAt;
}
}), filter((x) => x !== undefined), first(), shareReplay());
this._foundAt = Number.POSITIVE_INFINITY;
if (validateOperation(this.hash) !== ValidationResult.VALID) {
throw new InvalidOperationHashError(this.hash);
}
this.confirmed$
.pipe(first(), catchError(() => {
return of(EMPTY);
}))
.subscribe();
}
get revealOperation() {
return (Array.isArray(this.results) &&
this.results.find((op) => op.kind === 'reveal'));
}
get revealStatus() {
if (this.revealOperation) {
return this.revealOperation.metadata.operation_result.status;
}
else {
return 'unknown';
}
}
get status() {
return (this.results.map((result) => {
if (hasMetadataWithResult(result)) {
return result.metadata.operation_result.status;
}
else {
return 'unknown';
}
})[0] || 'unknown');
}
/**
*
* @param confirmations [0] Number of confirmation to wait for
* @param timeout [180] Timeout
*/
confirmation(confirmations, timeout) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof confirmations !== 'undefined' && confirmations < 1) {
throw new InvalidConfirmationCountError(confirmations);
}
const { defaultConfirmationCount, confirmationPollingTimeoutSecond } = this.context.config;
this._pollingConfig$.next({
timeout: timeout || confirmationPollingTimeoutSecond,
});
const conf = confirmations !== undefined ? confirmations : defaultConfirmationCount;