@ledgerhq/coin-ton
Version:
135 lines • 6.39 kB
JavaScript
import { botTest, pickSiblings } from "@ledgerhq/coin-framework/bot/specs";
import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets";
import { DeviceModelId } from "@ledgerhq/devices";
import BigNumber from "bignumber.js";
import expect from "expect";
import invariant from "invariant";
import { generateDeviceActionFlow } from "./speculos-deviceActions";
import { BotScenario } from "./utils";
const MIN_SAFE = new BigNumber(1.5e7); // approx two txs' fees (0.015 TON)
export const testDestination = ({ destination, destinationBeforeTransaction, sendingOperation, }) => {
const amount = sendingOperation.value;
const inOp = destination.operations.find(op => op.hash === sendingOperation.hash && op.type === "IN");
const inFees = inOp?.fee ?? BigNumber(0);
botTest("account balance increased with transaction amount", () => expect(destination.balance.toString()).toBe(destinationBeforeTransaction.balance.plus(amount).minus(inFees).toString()));
botTest("operation amount is consistent with sendingOperation", () => expect({
type: inOp?.type,
amount: inOp?.value?.toString(),
}).toMatchObject({
type: "IN",
amount: amount.toString(),
}));
};
const tonSpecs = {
name: "TON",
currency: getCryptoCurrencyById("ton"),
appQuery: {
model: DeviceModelId.nanoSP,
appName: "TON",
},
genericDeviceAction: generateDeviceActionFlow(BotScenario.DEFAULT),
testTimeout: 6 * 60 * 1000,
minViableAmount: MIN_SAFE,
transactionCheck: ({ maxSpendable }) => {
invariant(maxSpendable.gt(MIN_SAFE), "balance is too low");
},
mutations: [
{
name: "Send ~50%",
feature: "send",
maxRun: 1,
testDestination,
transaction: ({ account, siblings, bridge, maxSpendable }) => {
invariant(maxSpendable.gt(MIN_SAFE), "balance is too low");
const updates = [
{ recipient: pickSiblings(siblings).freshAddress },
{ amount: maxSpendable.div(2).integerValue() },
{ comment: { isEncrypted: false, text: "LL Bot" } },
];
return {
transaction: bridge.createTransaction(account),
updates,
};
},
test: ({ accountBeforeTransaction, operation, account, transaction }) => {
// we don't know the exact amount in fees, so we accept +- 20% of expected fees
const baseAmount = accountBeforeTransaction.balance.minus(transaction.amount);
const maxBalance = baseAmount.minus(transaction.fees.multipliedBy(0.8).integerValue());
const minBalance = baseAmount.minus(transaction.fees.multipliedBy(1.2).integerValue());
botTest("account spendable balance decreased with operation", () => {
expect(account.spendableBalance.lte(maxBalance)).toBe(true);
expect(account.spendableBalance.gte(minBalance)).toBe(true);
});
botTest("operation comment", () => expect(operation.extra).toMatchObject({
comment: transaction.comment,
}));
},
},
{
name: "Transfer Max",
feature: "sendMax",
maxRun: 1,
transaction: ({ account, siblings, bridge }) => {
const updates = [
{ recipient: pickSiblings(siblings).freshAddress },
{ useAllAmount: true },
{ comment: { isEncrypted: false, text: "LL Bot" } },
];
return {
transaction: bridge.createTransaction(account),
updates,
};
},
testDestination,
test: ({ account, transaction, operation }) => {
botTest("account spendable balance is zero", () => expect(account.spendableBalance.toFixed()).toBe("0"));
botTest("operation comment", () => expect(operation.extra).toMatchObject({
comment: transaction.comment,
}));
},
},
{
name: "Send ~50% jUSDT",
feature: "tokens",
maxRun: 1,
deviceAction: generateDeviceActionFlow(BotScenario.TOKEN_TRANSFER),
transaction: ({ account, bridge, maxSpendable, siblings }) => {
invariant(maxSpendable.gt(0), "Spendable balance is too low");
const subAccount = account.subAccounts?.find(a => a.type === "TokenAccount" && a.spendableBalance.gt(0));
const recipient = siblings[0].freshAddress;
invariant(subAccount && subAccount.type === "TokenAccount", "no subAccount with jUSDT");
const amount = subAccount.balance.div(1.9 + 0.2 * Math.random()).integerValue();
const updates = [
{
subAccountId: subAccount.id,
},
{
recipient,
},
{
amount,
},
];
if (Math.random() < 0.5)
updates.push({ comment: { isEncrypted: false, text: "LL Bot" } });
return {
transaction: bridge.createTransaction(account),
updates,
};
},
test: ({ account, accountBeforeTransaction, operation, transaction, status }) => {
const subAccountId = transaction.subAccountId;
const subAccount = account.subAccounts?.find(sa => sa.id === subAccountId);
const subAccountBeforeTransaction = accountBeforeTransaction.subAccounts?.find(sa => sa.id === subAccountId);
botTest("subAccount balance moved with the tx status amount", () => expect(subAccount?.balance.toString()).toBe(subAccountBeforeTransaction?.balance.minus(status.amount).toString()));
botTest("operation comment", () => expect(operation.extra).toMatchObject({
comment: transaction.comment,
}));
},
},
],
};
export default {
tonSpecs,
};
//# sourceMappingURL=specs.js.map