UNPKG

@ledgerhq/coin-tezos

Version:
123 lines 4.42 kB
import { IncorrectTypeError, } from "@ledgerhq/coin-framework/api/index"; import { log } from "@ledgerhq/logs"; import coinConfig from "../config"; import { broadcast, combine, craftTransaction, estimateFees, getBalance, lastBlock, listOperations, rawEncode, } from "../logic"; import api from "../network/tzkt"; export function createApi(config) { coinConfig.setCoinConfig(() => ({ ...config, status: { type: "active" } })); return { broadcast, combine, craftTransaction: craft, estimateFees: estimate, getBalance: balance, lastBlock, listOperations: operations, getBlock(_height) { throw new Error("getBlock is not supported"); }, getBlockInfo(_height) { throw new Error("getBlockInfo is not supported"); }, }; } function isTezosTransactionType(type) { return ["send", "delegate", "undelegate"].includes(type); } async function balance(address) { const value = await getBalance(address); return [ { value, asset: { type: "native" }, }, ]; } async function craft(transactionIntent, customFees) { if (!isTezosTransactionType(transactionIntent.type)) { throw new IncorrectTypeError(transactionIntent.type); } // note that an estimation is always necessary to get gasLimit and storageLimit, if even using custom fees const fee = await estimate(transactionIntent).then(fees => ({ fees: (customFees ?? fees.value).toString(), gasLimit: fees.parameters?.gasLimit?.toString(), storageLimit: fees.parameters?.storageLimit?.toString(), })); const { contents } = await craftTransaction({ address: transactionIntent.sender }, { type: transactionIntent.type, recipient: transactionIntent.recipient, amount: transactionIntent.amount, fee, }); return rawEncode(contents); } async function estimate(transactionIntent) { const senderAccountInfo = await api.getAccountByAddress(transactionIntent.sender); if (senderAccountInfo.type !== "user") throw new Error("unexpected account type"); const { estimatedFees: value, gasLimit, storageLimit, taquitoError, } = await estimateFees({ account: { address: transactionIntent.sender, revealed: senderAccountInfo.revealed, balance: BigInt(senderAccountInfo.balance), // NOTE: previously we checked for .sender.xpub xpub: transactionIntent.senderPublicKey ?? senderAccountInfo.publicKey, }, transaction: { mode: transactionIntent.type, recipient: transactionIntent.recipient, amount: transactionIntent.amount, }, }); if (taquitoError !== undefined) { throw new Error(`Fees estimation failed: ${taquitoError}`); } return { value, parameters: { gasLimit, storageLimit, }, }; } async function fetchNextPage(address, state) { const [operations, newNextCursor] = await listOperations(address, { limit: state.pageSize, token: state.nextCursor, sort: "Ascending", minHeight: state.minHeight, }); const newCurrentIteration = state.currentIteration + 1; let continueIteration = newNextCursor !== ""; if (newCurrentIteration >= state.maxIterations) { log("coin:tezos", "(api/operations): max iterations reached", state.maxIterations); continueIteration = false; } const accumulated = operations.concat(state.accumulator); return { ...state, continueIterations: continueIteration, currentIteration: newCurrentIteration, nextCursor: newNextCursor, accumulator: accumulated, }; } async function operationsFromHeight(address, start) { const firstState = { pageSize: 200, maxIterations: 10, currentIteration: 0, minHeight: start, continueIterations: true, accumulator: [], }; let state = await fetchNextPage(address, firstState); while (state.continueIterations) { state = await fetchNextPage(address, state); } return [state.accumulator, state.nextCursor || ""]; } async function operations(address, { minHeight }) { return operationsFromHeight(address, minHeight); } //# sourceMappingURL=index.js.map