@ledgerhq/coin-tron
Version:
Ledger Tron Coin integration
121 lines (102 loc) • 3.86 kB
text/typescript
import { SignerContext } from "@ledgerhq/coin-framework/signer";
import { SignOperationEvent, SignOperationFnSignature, TokenAccount } from "@ledgerhq/types-live";
import BigNumber from "bignumber.js";
import { Observable } from "rxjs";
import {
claimRewardTronTransaction,
createTronTransaction,
freezeTronTransaction,
legacyUnfreezeTronTransaction,
unDelegateResourceTransaction,
unfreezeTronTransaction,
voteTronSuperRepresentatives,
withdrawExpireUnfreezeTronTransaction,
} from "../network";
import { Transaction, TronAccount, TronSigner } from "../types";
import { buildOptimisticOperation } from "./buildOptimisticOperation";
import getEstimatedFees from "./getEstimateFees";
export const buildSignOperation =
(signerContext: SignerContext<TronSigner>): SignOperationFnSignature<Transaction, TronAccount> =>
({ account, transaction, deviceId }): Observable<SignOperationEvent> =>
new Observable(o => {
async function main() {
const subAccount =
transaction.subAccountId && account.subAccounts
? account.subAccounts.find(sa => sa.id === transaction.subAccountId)
: undefined;
const fee = await getEstimatedFees(account, transaction, subAccount);
const balance = subAccount
? subAccount.balance
: BigNumber.max(0, account.spendableBalance.minus(fee));
if (transaction.useAllAmount) {
transaction = { ...transaction }; // transaction object must not be mutated
transaction.amount = balance; // force the amount to be the max
}
const {
raw_data_hex: rawDataHex,
raw_data: rawData,
txID: hash,
} = await prepareTransactionForSignature(account, subAccount, transaction);
o.next({
type: "device-signature-requested",
});
const txArg = {
rawDataHex,
// only for trc10, we need to put the token ledger signature
tokenSignature:
subAccount &&
subAccount.type === "TokenAccount" &&
subAccount.token.id.includes("trc10")
? subAccount.token.ledgerSignature
: undefined,
};
// Sign by device
const signature = await signerContext(deviceId, signer =>
signer.sign(
account.freshAddressPath,
txArg.rawDataHex ?? "", //FIXME: why rawDataHex could be undefined? This shouldn't be the case.
txArg.tokenSignature ? [txArg.tokenSignature] : [],
),
);
o.next({
type: "device-signature-granted",
});
const operation = buildOptimisticOperation(account, subAccount, transaction, fee, hash);
o.next({
type: "signed",
signedOperation: {
operation,
signature,
rawData,
},
});
}
main().then(
() => o.complete(),
e => o.error(e),
);
});
const prepareTransactionForSignature = (
account: TronAccount,
subAccount: TokenAccount | undefined,
transaction: Transaction,
) => {
switch (transaction.mode) {
case "freeze":
return freezeTronTransaction(account, transaction);
case "unfreeze":
return unfreezeTronTransaction(account, transaction);
case "vote":
return voteTronSuperRepresentatives(account, transaction);
case "claimReward":
return claimRewardTronTransaction(account);
case "withdrawExpireUnfreeze":
return withdrawExpireUnfreezeTronTransaction(account, transaction);
case "unDelegateResource":
return unDelegateResourceTransaction(account, transaction);
case "legacyUnfreeze":
return legacyUnfreezeTronTransaction(account, transaction);
default:
return createTronTransaction(account, transaction, subAccount);
}
};