import BigNumber from "bignumber.js"; import { Asset, AssetType, ServerApi } from "xdb-digitalbits-sdk"; import { NATIVE_ASSET_IDENTIFIER } from "../constants/digitalbits"; import { Account, Payment, Token } from "../types"; function isCreateAccount( obj: any ): obj is ServerApi.CreateAccountOperationRecord { return obj.type === "create_account"; } function isAccountMerge( obj: any ): obj is ServerApi.AccountMergeOperationRecord { return obj.type === "account_merge"; } function isPathPayment(obj: any): obj is ServerApi.PathPaymentOperationRecord { return ( // old, soon-to-be-deprecated name obj.type === "path_payment" || // new names obj.type === "path_payment_strict_send" || obj.type === "path_payment_strict_receive" ); } async function getAccountMergePaymentAmount( payment: ServerApi.AccountMergeOperationRecord, publicKey: string ): Promise { try { const effects = await payment.effects(); const accountMergePayment = effects.records.find( record => record.type === "account_credited" && record.account === publicKey ); if (accountMergePayment && "amount" in accountMergePayment) { return accountMergePayment.amount; } return undefined; } catch (e) { return undefined; } } function getMergedAccount(payment: ServerApi.AccountMergeOperationRecord) { return { publicKey: payment.source_account, }; } export async function makeDisplayablePayments( subjectAccount: Account, payments: Array< | ServerApi.CreateAccountOperationRecord | ServerApi.PaymentOperationRecord | ServerApi.PathPaymentOperationRecord > ): Promise { return Promise.all( payments.map( async ( payment: | ServerApi.CreateAccountOperationRecord | ServerApi.PaymentOperationRecord | ServerApi.PathPaymentOperationRecord ): Promise => { const isRecipient = payment.source_account !== subjectAccount.publicKey; let otherAccount: Account; if (isCreateAccount(payment)) { otherAccount = { publicKey: payment.funder, }; } else { otherAccount = { publicKey: isRecipient ? payment.from : payment.to }; } const token: Token = isCreateAccount(payment) ? { type: NATIVE_ASSET_IDENTIFIER as AssetType, code: Asset.native().getCode(), } : { type: payment.asset_type as AssetType, code: payment.asset_code || Asset.native().getCode(), issuer: payment.asset_type === NATIVE_ASSET_IDENTIFIER ? undefined : { key: payment.asset_issuer as string, }, }; // "account_merge" record does not have "amount" property let accountMergePaymentAmount; let mergedAccount; if (isAccountMerge(payment)) { accountMergePaymentAmount = await getAccountMergePaymentAmount( payment, subjectAccount.publicKey ); mergedAccount = getMergedAccount(payment); } let transaction: ServerApi.TransactionRecord | undefined; try { transaction = await payment.transaction(); } catch (e) { // do nothing } return { id: payment.id, isInitialFunding: isCreateAccount(payment), isRecipient, token, amount: new BigNumber( isCreateAccount(payment) ? payment.starting_balance : accountMergePaymentAmount || payment.amount ), timestamp: Math.floor(new Date(payment.created_at).getTime() / 1000), otherAccount, sourceToken: isPathPayment(payment) ? { type: payment.source_asset_type as AssetType, code: payment.source_asset_code || Asset.native().getCode(), issuer: payment.source_asset_type === NATIVE_ASSET_IDENTIFIER ? undefined : { key: payment.source_asset_issuer as string, }, } : undefined, sourceAmount: isPathPayment(payment) ? new BigNumber(payment.source_amount) : undefined, transactionId: payment.transaction_hash, type: payment.type, ...(transaction ? { memo: transaction.memo, memoType: transaction.memo_type, } : {}), mergedAccount, }; } ) ); }