UNPKG

@ledgerhq/coin-stacks

Version:
203 lines 8.23 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.findNextNonce = exports.mapTxToOps = exports.mapPendingTxToOps = exports.getAddress = exports.getUnit = exports.getTxToBroadcast = void 0; exports.reconciliatePublicKey = reconciliatePublicKey; const bignumber_js_1 = require("bignumber.js"); const transactions_1 = require("@stacks/transactions"); const index_1 = require("@ledgerhq/coin-framework/account/index"); const index_2 = require("../../network/index"); const currencies_1 = require("@ledgerhq/cryptoassets/currencies"); const operation_1 = require("@ledgerhq/coin-framework/operation"); const logs_1 = require("@ledgerhq/logs"); const getTxToBroadcast = async (operation, signature, rawData) => { const { value, recipients, fee, extra: { memo }, } = operation; const { anchorMode, network, xpub } = rawData; const options = { amount: (0, bignumber_js_1.BigNumber)(value).minus(fee).toFixed(), recipient: recipients[0], anchorMode, memo, network: index_2.StacksNetwork[network], publicKey: xpub, fee: (0, bignumber_js_1.BigNumber)(fee).toFixed(), nonce: operation.transactionSequenceNumber ?? 0, }; const tx = await (0, transactions_1.makeUnsignedSTXTokenTransfer)(options); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore need to ignore the TS error here tx.auth.spendingCondition.signature = (0, transactions_1.createMessageSignature)(signature); return Buffer.from(tx.serialize()); }; exports.getTxToBroadcast = getTxToBroadcast; const getUnit = () => (0, currencies_1.getCryptoCurrencyById)("stacks").units[0]; exports.getUnit = getUnit; const getAddress = (account) => ({ address: account.freshAddress, derivationPath: account.freshAddressPath }); exports.getAddress = getAddress; const getMemo = (memoHex) => { if (memoHex?.substring(0, 2) === "0x") { // eslint-disable-next-line no-control-regex return Buffer.from(memoHex.substring(2), "hex").toString().replace(/\x00/g, ""); // NOTE: couldn't use replaceAll because it's not supported in node 14 } return ""; }; const mapPendingTxToOps = (accountID, address) => (tx) => { const { sender_address, receipt_time, fee_rate, tx_id, token_transfer, tx_status, nonce } = tx; if (tx.tx_type !== "token_transfer" || tx_status !== "pending") { return []; } const memo = getMemo(token_transfer.memo); const feeToUse = new bignumber_js_1.BigNumber(fee_rate || "0"); const date = new Date(receipt_time * 1000); const operationCommons = { hash: tx_id, fee: feeToUse, accountId: accountID, senders: [sender_address], recipients: [token_transfer.recipient_address], transactionSequenceNumber: nonce, value: new bignumber_js_1.BigNumber(token_transfer.amount).plus(feeToUse), date, extra: { memo, }, blockHeight: null, blockHash: null, }; const isSending = address === sender_address; const isReceiving = token_transfer.recipient_address === address; const ops = []; if (isSending) { const type = "OUT"; ops.push({ ...operationCommons, id: (0, operation_1.encodeOperationId)(accountID, tx_id, type), type, }); } else if (isReceiving) { const type = "IN"; ops.push({ ...operationCommons, id: (0, operation_1.encodeOperationId)(accountID, tx_id, type), type, }); } return ops; }; exports.mapPendingTxToOps = mapPendingTxToOps; const mapTxToOps = (accountID, address) => (tx) => { try { const { tx_id, fee_rate, nonce, block_height, burn_block_time, sender_address, block_hash: blockHash, } = tx.tx; const { stx_received: receivedValue, stx_sent: sentValue } = tx; let recipients = []; if (tx.tx.tx_type === "token_transfer" && tx.tx.token_transfer) { recipients = [tx.tx.token_transfer.recipient_address]; } const memoHex = tx.tx.token_transfer?.memo; const memo = getMemo(memoHex ?? ""); const ops = []; const date = new Date(burn_block_time * 1000); const feeToUse = new bignumber_js_1.BigNumber(fee_rate || "0"); const isSending = sentValue !== "0" && receivedValue === "0"; const isReceiving = receivedValue !== "0"; const operationCommons = { hash: tx_id, blockHeight: block_height, blockHash, fee: feeToUse, accountId: accountID, senders: [sender_address], transactionSequenceNumber: nonce, date, extra: { memo, }, }; if (isSending) { const type = "OUT"; let internalOperations = undefined; if (tx.tx.tx_type === "contract_call" && tx.tx.contract_call) { internalOperations = []; const deserialized = (0, transactions_1.deserializeCV)(tx.tx.contract_call.function_args[0].hex); const decodedArgs = (0, transactions_1.cvToJSON)(deserialized); for (const [idx, t] of decodedArgs.value.entries()) { internalOperations.push({ ...operationCommons, id: (0, operation_1.encodeSubOperationId)(accountID, tx_id, type, idx), contract: "send-many", type, value: new bignumber_js_1.BigNumber(t.value.ustx.value), senders: [sender_address], recipients: [t.value.to.value], extra: { memo: getMemo(t.value.memo?.value ?? ""), }, }); } } ops.push({ ...operationCommons, id: (0, operation_1.encodeOperationId)(accountID, tx_id, type), value: new bignumber_js_1.BigNumber(sentValue), recipients, type, internalOperations, }); } if (isReceiving) { const type = "IN"; ops.push({ ...operationCommons, id: (0, operation_1.encodeOperationId)(accountID, tx_id, type), value: new bignumber_js_1.BigNumber(receivedValue), recipients: recipients.length ? recipients : [address], type, }); } return ops; } catch (err) { (0, logs_1.log)("warn", "mapTxToOps failed for stacks", err); return []; } }; exports.mapTxToOps = mapTxToOps; function reconciliatePublicKey(publicKey, initialAccount) { if (publicKey) return publicKey; if (initialAccount) { const { xpubOrAddress } = (0, index_1.decodeAccountId)(initialAccount.id); return xpubOrAddress; } throw new Error("publicKey wasn't properly restored"); } const findNextNonce = async (senderAddress, pendingOps) => { let nextNonce = (0, bignumber_js_1.BigNumber)(0); for (const op of pendingOps) { const nonce = op.transactionSequenceNumber ? new bignumber_js_1.BigNumber(op.transactionSequenceNumber) : new bignumber_js_1.BigNumber(0); if (nonce.gt(nextNonce)) { nextNonce = nonce; } } const allMempoolTxns = await (0, index_2.fetchFullMempoolTxs)(senderAddress); for (const tx of allMempoolTxns) { const nonce = (0, bignumber_js_1.BigNumber)(tx.nonce); if (nonce.gt(nextNonce)) { nextNonce = nonce; } } if (!nextNonce.eq(0)) { nextNonce = nextNonce.plus(1); } const nonceResp = await (0, index_2.fetchNonce)(senderAddress); const possibleNextNonce = new bignumber_js_1.BigNumber(nonceResp.possible_next_nonce); if (possibleNextNonce.gt(nextNonce)) { nextNonce = possibleNextNonce; } return nextNonce; }; exports.findNextNonce = findNextNonce; //# sourceMappingURL=misc.js.map