// SPDX-FileCopyrightText: © 2026 LEDGER SAS // SPDX-License-Identifier: Apache-2.0 import type { StellarContext } from '../config' import type { Operation as StellarSdkOperation, Transaction as StellarSdkTransaction, xdr, } from '@stellar/stellar-sdk' import { NetworkDown } from '@ledgerhq/live-network/errors' import { Memo } from '@stellar/stellar-sdk' import { getRecipientAccount, loadAccount } from '../network' import { StellarAssetRequired, StellarMuxedAccountNotExist } from '../types' import { buildChangeTrustOperation, buildCreateAccountOperation, buildPaymentOperation, buildTransactionBuilder, } from './sdkWrapper' export async function craftTransaction( context: StellarContext, account: { address: string }, transaction: { type: string recipient: string amount: bigint fee: bigint assetCode?: string | undefined assetIssuer?: string | undefined memoType?: string | null | undefined memoValue?: string | null | undefined } ): Promise<{ transaction: StellarSdkTransaction; xdr: string; signatureBase: string }> { const config = await context.config() const { amount, recipient, fee, memoType, memoValue, type, assetCode, assetIssuer } = transaction const source = await loadAccount(config, account.address) if (!source) { throw new NetworkDown() } const transactionBuilder = buildTransactionBuilder(source, fee) let operation: xdr.Operation | null = null if (type === 'changeTrust') { if (!assetCode || !assetIssuer) { throw new StellarAssetRequired('') } operation = buildChangeTrustOperation(assetCode, assetIssuer) } else { // Payment const recipientAccount = await getRecipientAccount(config, { recipient, }) if (recipientAccount?.id) { operation = buildPaymentOperation({ unit: config.unit, destination: recipient, amount, assetCode, assetIssuer, }) } else { if (recipientAccount?.isMuxedAccount) { throw new StellarMuxedAccountNotExist('') } operation = buildCreateAccountOperation(config.unit, recipient, amount) } } transactionBuilder.addOperation(operation) const memo = buildMemo(memoType, memoValue) if (memo) { transactionBuilder.addMemo(memo) } const craftedTransaction = transactionBuilder.setTimeout(0).build() return { transaction: craftedTransaction, xdr: craftedTransaction.toXDR(), signatureBase: craftedTransaction.signatureBase().toString('base64'), } } function buildMemo( memoType?: string | null | undefined, memoValue?: string | null | undefined ): Memo | null { if (memoType && memoValue) { switch (memoType) { case 'MEMO_TEXT': return Memo.text(memoValue) case 'MEMO_ID': return Memo.id(memoValue) case 'MEMO_HASH': return Memo.hash(memoValue) case 'MEMO_RETURN': return Memo.return(memoValue) } } return null }