@ledgerhq/coin-algorand
Version:
Ledger Algorand Coin integration
91 lines (76 loc) • 2.62 kB
text/typescript
import { encode as msgpackEncode } from "algo-msgpack-with-bigint";
import type {
EncodedSignedTransaction as AlgoSignedTransactionPayload,
Transaction as AlgoTransaction,
EncodedTransaction as AlgoTransactionPayload,
} from "algosdk";
import {
makeAssetTransferTxnWithSuggestedParams,
makePaymentTxnWithSuggestedParams,
} from "algosdk";
import algorandAPI from "./api";
import { extractTokenId } from "./tokens";
import type { AlgorandAccount, Transaction } from "./types";
export const buildTransactionPayload = async (
account: AlgorandAccount,
transaction: Transaction,
): Promise<AlgoTransactionPayload> => {
const { amount, recipient, mode, memo, assetId, subAccountId } = transaction;
const subAccount = subAccountId
? account.subAccounts && account.subAccounts.find(t => t.id === subAccountId)
: null;
const note = memo ? new TextEncoder().encode(memo) : undefined;
const params = await algorandAPI.getTransactionParams();
let algoTxn: AlgoTransaction;
if (subAccount || (assetId && mode === "optIn")) {
const targetAssetId =
subAccount && subAccount.type === "TokenAccount"
? extractTokenId(subAccount.token.id)
: assetId
? extractTokenId(assetId)
: "";
if (!targetAssetId) {
throw new Error("Token Asset Id not found");
}
algoTxn = makeAssetTransferTxnWithSuggestedParams(
account.freshAddress,
recipient,
undefined,
undefined,
amount.toNumber(),
note,
Number(targetAssetId),
params,
undefined,
);
} else {
algoTxn = makePaymentTxnWithSuggestedParams(
account.freshAddress,
recipient,
amount.toNumber(),
undefined,
note,
params,
);
}
// Bit of safety: set tx validity to the next 1000 blocks
algoTxn.firstRound = params.lastRound;
algoTxn.lastRound = params.lastRound + 1000;
// Flaw in the SDK: payload isn't sorted, but it needs to be for msgPack encoding
const sorted = Object.fromEntries(
Object.entries(algoTxn.get_obj_for_encoding()).sort(),
) as AlgoTransactionPayload;
return sorted;
};
export const encodeToSign = (payload: AlgoTransactionPayload): string => {
const msgPackEncoded = msgpackEncode(payload);
return Buffer.from(msgPackEncoded).toString("hex");
};
export const encodeToBroadcast = (payload: AlgoTransactionPayload, signature: Buffer): Buffer => {
const signedPayload: AlgoSignedTransactionPayload = {
sig: signature,
txn: payload,
};
const msgPackEncoded = msgpackEncode(signedPayload);
return Buffer.from(msgPackEncoded);
};