UNPKG

@ledgerhq/coin-hedera

Version:
181 lines 8.22 kB
import { AccountUpdateTransaction, ContractExecuteTransaction, ContractFunctionParameters, ContractId, Hbar, TokenAssociateTransaction, TransferTransaction, } from "@hashgraph/sdk"; import BigNumber from "bignumber.js"; import invariant from "invariant"; import { DEFAULT_GAS_LIMIT, HEDERA_TRANSACTION_MODES, TRANSACTION_VALID_DURATION_SECONDS, } from "../constants"; import { rpcClient } from "../network/rpc"; import { createTransactionId } from "../network/utils"; import { hasSpecificIntentData, serializeTransaction, toEVMAddress } from "./utils"; async function buildUnsignedCoinTransaction({ account, transaction, }) { const accountId = account.accountId; const hbarAmount = Hbar.fromTinybars(transaction.amount); const tx = new TransferTransaction() .setTransactionValidDuration(TRANSACTION_VALID_DURATION_SECONDS) .setTransactionId(transaction.transactionId) .setTransactionMemo(transaction.memo) .addHbarTransfer(accountId, hbarAmount.negated()) .addHbarTransfer(transaction.recipient, hbarAmount); if (transaction.maxFee) { tx.setMaxTransactionFee(Hbar.fromTinybars(transaction.maxFee.toNumber())); } return tx.freezeWith(await rpcClient.getInstance()); } async function buildUnsignedHTSTokenTransaction({ account, transaction, }) { const accountId = account.accountId; const tokenId = transaction.tokenAddress; const tx = new TransferTransaction() .setTransactionValidDuration(TRANSACTION_VALID_DURATION_SECONDS) .setTransactionId(transaction.transactionId) .setTransactionMemo(transaction.memo) .addTokenTransfer(tokenId, accountId, transaction.amount.negated().toNumber()) .addTokenTransfer(tokenId, transaction.recipient, transaction.amount.toNumber()); if (transaction.maxFee) { tx.setMaxTransactionFee(Hbar.fromTinybars(transaction.maxFee.toNumber())); } return tx.freezeWith(await rpcClient.getInstance()); } async function buildUnsignedERC20TokenTransaction({ transaction, }) { const contractId = ContractId.fromEvmAddress(0, 0, transaction.tokenAddress); const recipientEvmAddress = await toEVMAddress(transaction.recipient); invariant(recipientEvmAddress, `hedera: EVM address is missing ${transaction.recipient}`); const gas = transaction.gasLimit.toNumber(); // create function parameters for ERC20 transfer function // transfer(address to, uint256 amount) returns (bool) const functionParameters = new ContractFunctionParameters() .addAddress(recipientEvmAddress) .addUint256(transaction.amount.toNumber()); const tx = new ContractExecuteTransaction() .setTransactionValidDuration(TRANSACTION_VALID_DURATION_SECONDS) .setTransactionId(transaction.transactionId) .setTransactionMemo(transaction.memo ?? "") .setContractId(contractId) .setGas(gas) .setFunction("transfer", functionParameters); if (transaction.maxFee) { tx.setMaxTransactionFee(Hbar.fromTinybars(transaction.maxFee.toNumber())); } return tx.freezeWith(await rpcClient.getInstance()); } async function buildTokenAssociateTransaction({ account, transaction, }) { const accountId = account.accountId; const tx = new TokenAssociateTransaction() .setTransactionValidDuration(TRANSACTION_VALID_DURATION_SECONDS) .setTransactionId(transaction.transactionId) .setTransactionMemo(transaction.memo) .setAccountId(accountId) .setTokenIds([transaction.tokenId]); if (transaction.maxFee) { tx.setMaxTransactionFee(Hbar.fromTinybars(transaction.maxFee.toNumber())); } return tx.freezeWith(await rpcClient.getInstance()); } async function buildUnsignedUpdateAccountTransaction({ account, transaction, }) { const accountId = account.accountId; const tx = new AccountUpdateTransaction() .setTransactionValidDuration(TRANSACTION_VALID_DURATION_SECONDS) .setTransactionId(transaction.transactionId) .setTransactionMemo(transaction.memo ?? "") .setAccountId(accountId); if (transaction.maxFee) { tx.setMaxTransactionFee(Hbar.fromTinybars(transaction.maxFee.toNumber())); } if (typeof transaction.stakingNodeId === "number") { tx.setStakedNodeId(transaction.stakingNodeId); } if (transaction.stakingNodeId === null) { tx.clearStakedNodeId(); } return tx.freezeWith(await rpcClient.getInstance()); } function isStakingMode(type) { return (type === HEDERA_TRANSACTION_MODES.Redelegate || type === HEDERA_TRANSACTION_MODES.Undelegate || type === HEDERA_TRANSACTION_MODES.Delegate); } export async function craftTransaction({ txIntent, customFees, config, }) { const account = { accountId: txIntent.sender }; const maxFee = customFees ? new BigNumber(customFees.value.toString()) : undefined; const transactionId = await createTransactionId(account.accountId, config); let tx; if (txIntent.type === HEDERA_TRANSACTION_MODES.TokenAssociate) { invariant(txIntent.asset.type !== "native", "hedera: invalid asset type"); invariant("assetReference" in txIntent.asset, "hedera: assetReference is missing"); tx = await buildTokenAssociateTransaction({ account, transaction: { type: txIntent.type, transactionId, tokenId: txIntent.asset.assetReference, memo: txIntent.memo.value, maxFee, }, }); } else if (txIntent.type === HEDERA_TRANSACTION_MODES.Send && txIntent.asset.type === "hts") { invariant("assetReference" in txIntent.asset, "hedera: no assetReference in token transfer"); const amount = new BigNumber(txIntent.amount.toString()); tx = await buildUnsignedHTSTokenTransaction({ account, transaction: { type: txIntent.type, transactionId, tokenAddress: txIntent.asset.assetReference, amount, recipient: txIntent.recipient, memo: txIntent.memo.value, maxFee, }, }); } else if (txIntent.type === HEDERA_TRANSACTION_MODES.Send && txIntent.asset.type === "erc20") { invariant("assetReference" in txIntent.asset, "hedera: no assetReference in token transfer"); const amount = new BigNumber(txIntent.amount.toString()); const gasLimit = hasSpecificIntentData(txIntent, "erc20") ? new BigNumber(txIntent.data.gasLimit.toString()) : DEFAULT_GAS_LIMIT; tx = await buildUnsignedERC20TokenTransaction({ transaction: { type: txIntent.type, transactionId, tokenAddress: txIntent.asset.assetReference, amount, recipient: txIntent.recipient, memo: txIntent.memo.value, maxFee, gasLimit, }, }); } else if (isStakingMode(txIntent.type)) { const stakingNodeId = hasSpecificIntentData(txIntent, "staking") ? txIntent.data.stakingNodeId : undefined; tx = await buildUnsignedUpdateAccountTransaction({ account, transaction: { type: txIntent.type, transactionId, memo: txIntent.memo.value, maxFee, stakingNodeId, }, }); } // HEDERA_TRANSACTION_MODES.ClaimRewards is just a coin transfer that triggers staking rewards claim else { const amount = new BigNumber(txIntent.amount.toString()); tx = await buildUnsignedCoinTransaction({ account, transaction: { type: HEDERA_TRANSACTION_MODES.Send, transactionId, amount, recipient: txIntent.recipient, memo: txIntent.memo.value, maxFee, }, }); } const serializedTx = serializeTransaction(tx); return { tx, serializedTx }; } //# sourceMappingURL=craftTransaction.js.map