diff --git a/.changeset/wet-swans-greet.md b/.changeset/wet-swans-greet.md new file mode 100644 index 000000000000..8a7c092abc25 --- /dev/null +++ b/.changeset/wet-swans-greet.md @@ -0,0 +1,27 @@ +--- +"@ledgerhq/live-common": minor +"@ledgerhq/coin-framework": minor +"@ledgerhq/actions-root": minor +"@ledgerhq/coin-internet_computer": patch +"@ledgerhq/coin-algorand": patch +"@ledgerhq/coin-filecoin": patch +"@ledgerhq/coin-polkadot": patch +"@ledgerhq/coin-bitcoin": patch +"@ledgerhq/coin-cardano": patch +"@ledgerhq/coin-stellar": patch +"@ledgerhq/coin-vechain": patch +"@ledgerhq/coin-cosmos": patch +"@ledgerhq/coin-elrond": patch +"@ledgerhq/coin-hedera": patch +"@ledgerhq/coin-solana": patch +"@ledgerhq/coin-stacks": patch +"@ledgerhq/coin-tezos": patch +"@ledgerhq/coin-icon": patch +"@ledgerhq/coin-near": patch +"@ledgerhq/coin-tron": patch +"@ledgerhq/coin-evm": patch +"@ledgerhq/coin-ton": patch +"@ledgerhq/coin-xrp": patch +--- + +Bot feature : Add filter for features diff --git a/.github/workflows/bot-nonreg-nitrogen.yml b/.github/workflows/bot-nonreg-nitrogen.yml index a2c74bdd6b21..9baf52a83ed8 100644 --- a/.github/workflows/bot-nonreg-nitrogen.yml +++ b/.github/workflows/bot-nonreg-nitrogen.yml @@ -35,3 +35,4 @@ jobs: BOT_ENVIRONMENT: production # We don't run these currencies daily because fees are expensive BOT_DISABLED_CURRENCIES: bitcoin,ethereum,qtum,decred,cardano,axelar,cosmos,secret_network,avalanche_c_chain,bsc,filecoin,tron,cronos,fantom,boba,telos_evm,polygon_zk_evm,polkadot + BOT_FILTER_FEATURES: send diff --git a/.github/workflows/bot-nonreg-oxygen.yml b/.github/workflows/bot-nonreg-oxygen.yml index 7c470ce3eba1..c63ee0f2f9e3 100644 --- a/.github/workflows/bot-nonreg-oxygen.yml +++ b/.github/workflows/bot-nonreg-oxygen.yml @@ -35,3 +35,4 @@ jobs: BOT_ENVIRONMENT: production # We only run these currencies on a weekly basis because fees are expensive BOT_FILTER_CURRENCIES: qtum,decred,cardano,axelar,cosmos,secret_network,avalanche_c_chain,bsc,filecoin,tron,cronos,fantom,boba,telos_evm,polygon_zk_evm,polkadot + BOT_FILTER_FEATURES: send diff --git a/.github/workflows/bot-testing-nitrogen.yml b/.github/workflows/bot-testing-nitrogen.yml index 883b8687b57a..691459adaf29 100644 --- a/.github/workflows/bot-testing-nitrogen.yml +++ b/.github/workflows/bot-testing-nitrogen.yml @@ -9,6 +9,9 @@ on: currencies: description: currency ids to test, separated with commas (,) required: false + features: + description: features to test(send,sendMax,tokens,staking) + required: false speculos_websocket: description: check to use speculos with Websocket type: boolean @@ -48,4 +51,5 @@ jobs: BOT_ENVIRONMENT: testing BOT_FILTER_FAMILIES: ${{github.event.inputs.families}} BOT_FILTER_CURRENCIES: ${{github.event.inputs.currencies}} + BOT_FILTER_FEATURES: ${{github.event.inputs.features}} SPECULOS_USE_WEBSOCKET: ${{inputs.speculos_websocket}} diff --git a/libs/coin-framework/src/bot/types.ts b/libs/coin-framework/src/bot/types.ts index a36f2e97269f..7d7a701822ff 100644 --- a/libs/coin-framework/src/bot/types.ts +++ b/libs/coin-framework/src/bot/types.ts @@ -78,6 +78,8 @@ export type TransactionRes = { export type MutationSpec = { // Name what this mutation is doing name: string; + // related feature to test + feature?: MutationFeatureType; // The maximum number of times to execute this mutation for a given test run maxRun: number; // Express the transaction to be done @@ -118,7 +120,7 @@ export type AppSpec = { testTimeout?: number; // how much should we retry scan accounts if an error occurs scanAccountsRetries?: number; - // if define, will run the mutations {multipleRuns} times in order to cover 2 txs in the same run and detect possible issues at the "second tx time" + // if defined, will run the mutations {multipleRuns} times in order to cover 2 txs in the same run and detect possible issues at the "second tx time" multipleRuns?: number; // if the nano app depends on an app, name of this app dependency?: string | undefined; @@ -266,3 +268,5 @@ export type FlowDesc = { steps: Array>; fallback?: (arg0: DeviceActionArg>) => Step | null | undefined; }; + +export type MutationFeatureType = "send" | "sendMax" | "tokens" | "staking"; diff --git a/libs/coin-modules/coin-algorand/src/specs.ts b/libs/coin-modules/coin-algorand/src/specs.ts index f361a73cdb87..52d7406278b3 100644 --- a/libs/coin-modules/coin-algorand/src/specs.ts +++ b/libs/coin-modules/coin-algorand/src/specs.ts @@ -70,7 +70,8 @@ const algorand: AppSpec = { mutations: [ { name: "move ~50%", - maxRun: 2, + feature: "send", + maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(0), "Spendable balance is too low"); @@ -104,6 +105,7 @@ const algorand: AppSpec = { }, { name: "send max", + feature: "sendMax", maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, siblings, bridge, maxSpendable }) => { @@ -135,7 +137,8 @@ const algorand: AppSpec = { }, { name: "send ASA ~50%", - maxRun: 2, + feature: "tokens", + maxRun: 1, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(0), "Spendable balance is too low"); const subAccount = sample(getAssetsWithBalance(account)); @@ -178,6 +181,7 @@ const algorand: AppSpec = { }, { name: "opt-In ASA available", + feature: "tokens", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { // maxSpendable is expected to be greater than 100,000 micro-Algos @@ -217,6 +221,7 @@ const algorand: AppSpec = { }, { name: "claim rewards", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { const rewards = (account as AlgorandAccount).algorandResources?.rewards; diff --git a/libs/coin-modules/coin-bitcoin/src/specs.ts b/libs/coin-modules/coin-bitcoin/src/specs.ts index 581937355c74..651722265e32 100644 --- a/libs/coin-modules/coin-bitcoin/src/specs.ts +++ b/libs/coin-modules/coin-bitcoin/src/specs.ts @@ -109,6 +109,7 @@ const bitcoinLikeMutations = ({ }: Arg = {}): MutationSpec[] => [ { name: "move ~50%", + feature: "send", maxRun: 1, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount), "balance is too low"); @@ -144,6 +145,7 @@ const bitcoinLikeMutations = ({ }, { name: "optimize-size", + feature: "send", maxRun: 1, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount), "balance is too low"); @@ -176,6 +178,7 @@ const bitcoinLikeMutations = ({ }, { name: "send 1 utxo", + feature: "send", maxRun: 1, transaction: ({ account, bridge, siblings, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount), "balance is too low"); @@ -249,6 +252,7 @@ const bitcoinLikeMutations = ({ }, { name: "send OP_RETURN transaction", + feature: "send", maxRun: 1, transaction: ({ account, bridge, siblings, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount), "balance is too low"); @@ -282,6 +286,7 @@ const bitcoinLikeMutations = ({ }, { name: "send max", + feature: "sendMax", maxRun: 1, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount), "balance is too low"); diff --git a/libs/coin-modules/coin-cardano/src/specs.ts b/libs/coin-modules/coin-cardano/src/specs.ts index f38d2000b45c..1e7255b1cd0c 100644 --- a/libs/coin-modules/coin-cardano/src/specs.ts +++ b/libs/coin-modules/coin-cardano/src/specs.ts @@ -35,6 +35,7 @@ const cardano: AppSpec = { mutations: [ { name: "move ~10% token", + feature: "tokens", maxRun: 1, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gte(minSpendableRequiredForTokenTx), "balance is too low"); @@ -77,6 +78,7 @@ const cardano: AppSpec = { { testDestination: genericTestDestination, name: "move ~50%", + feature: "send", maxRun: 1, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minBalanceRequired), "balance is too low"); @@ -125,6 +127,7 @@ const cardano: AppSpec = { }, { name: "send max", + feature: "sendMax", maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, siblings, bridge, maxSpendable }) => { @@ -163,6 +166,7 @@ const cardano: AppSpec = { }, { name: "delegate to pool", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { invariant(maxSpendable.gte(minBalanceRequiredForDelegate), "balance is too low"); @@ -195,6 +199,7 @@ const cardano: AppSpec = { }, { name: "redelegate to pool", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { invariant(maxSpendable.gte(minBalanceRequiredForDelegate), "balance is too low"); @@ -225,6 +230,7 @@ const cardano: AppSpec = { }, { name: "undelegate", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { invariant(maxSpendable.gte(minBalanceRequiredForDelegate), "balance is too low"); diff --git a/libs/coin-modules/coin-cosmos/src/specs.ts b/libs/coin-modules/coin-cosmos/src/specs.ts index 7eebed45c163..33aae3cdb7aa 100644 --- a/libs/coin-modules/coin-cosmos/src/specs.ts +++ b/libs/coin-modules/coin-cosmos/src/specs.ts @@ -117,7 +117,8 @@ function cosmosLikeMutations(minimalTransactionAmount: BigNumber): MutationSpec< return [ { name: "send some", - maxRun: 2, + feature: "send", + maxRun: 1, testDestination: genericTestDestination, test: ({ account, accountBeforeTransaction, operation }) => { expect(account.balance.toString()).toBe( @@ -148,6 +149,7 @@ function cosmosLikeMutations(minimalTransactionAmount: BigNumber): MutationSpec< }, { name: "send max", + feature: "sendMax", maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, siblings, bridge, maxSpendable }) => { @@ -172,6 +174,7 @@ function cosmosLikeMutations(minimalTransactionAmount: BigNumber): MutationSpec< }, { name: "delegate new validators", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, siblings }) => { expectSiblingsHaveSpendablePartGreaterThan(siblings, 0.5); @@ -240,7 +243,8 @@ function cosmosLikeMutations(minimalTransactionAmount: BigNumber): MutationSpec< }, { name: "undelegate", - maxRun: 5, + feature: "staking", + maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { invariant(canUndelegate(account as CosmosAccount), "can undelegate"); const { cosmosResources } = account as CosmosAccount; @@ -305,6 +309,7 @@ function cosmosLikeMutations(minimalTransactionAmount: BigNumber): MutationSpec< }, { name: "redelegate", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { const { cosmosResources } = account as CosmosAccount; @@ -381,6 +386,7 @@ function cosmosLikeMutations(minimalTransactionAmount: BigNumber): MutationSpec< }, { name: "claim rewards", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { const { cosmosResources } = account as CosmosAccount; diff --git a/libs/coin-modules/coin-elrond/src/specs.ts b/libs/coin-modules/coin-elrond/src/specs.ts index 8928d7f0309a..4ac98e6dbd4f 100644 --- a/libs/coin-modules/coin-elrond/src/specs.ts +++ b/libs/coin-modules/coin-elrond/src/specs.ts @@ -170,6 +170,7 @@ const elrond: AppSpec = { mutations: [ { name: "send 50%~", + feature: "send", maxRun: 1, deviceAction: acceptMoveBalanceTransaction, transaction: ({ account, siblings, bridge }) => { @@ -204,6 +205,7 @@ const elrond: AppSpec = { }, { name: "send max", + feature: "sendMax", maxRun: 1, deviceAction: acceptMoveBalanceTransaction, transaction: ({ account, siblings, bridge }) => { @@ -236,6 +238,7 @@ const elrond: AppSpec = { }, { name: "move some ESDT", + feature: "tokens", maxRun: 1, deviceAction: acceptEsdtTransferTransaction, transaction: ({ account, siblings, bridge }) => { @@ -273,6 +276,7 @@ const elrond: AppSpec = { }, { name: "delegate 1 EGLD", + feature: "staking", maxRun: 1, deviceAction: acceptDelegateTransaction, transaction: ({ account, bridge }) => { @@ -301,6 +305,7 @@ const elrond: AppSpec = { }, { name: "unDelegate 1 EGLD", + feature: "staking", maxRun: 1, deviceAction: acceptUndelegateTransaction, transaction: ({ account, bridge }) => { @@ -331,6 +336,7 @@ const elrond: AppSpec = { }, { name: "withdraw all EGLD", + feature: "staking", maxRun: 1, deviceAction: acceptWithdrawTransaction, transaction: ({ account, bridge }) => { diff --git a/libs/coin-modules/coin-evm/src/specs.ts b/libs/coin-modules/coin-evm/src/specs.ts index 28bb9da63b8b..7e7971902cf9 100644 --- a/libs/coin-modules/coin-evm/src/specs.ts +++ b/libs/coin-modules/coin-evm/src/specs.ts @@ -225,7 +225,8 @@ const evmBasicMutations: ({ }) => MutationSpec[] = ({ maxAccount }) => [ { name: "move 50%", - maxRun: 2, + feature: "send", + maxRun: 1, testDestination: testCoinDestination, transaction: ({ account, siblings, bridge, maxSpendable }): TransactionRes => { const sibling = pickSiblings(siblings, maxAccount); @@ -266,6 +267,7 @@ const evmBasicMutations: ({ }, { name: "send max", + feature: "sendMax", maxRun: 1, testDestination: testCoinDestination, transaction: ({ account, siblings, bridge }): TransactionRes => { @@ -311,6 +313,7 @@ const evmBasicMutations: ({ const moveErc20Mutation: MutationSpec = { name: "move some ERC20 like (ERC20, BEP20, etc...)", + feature: "tokens", maxRun: 1, testDestination: testTokenDestination, transaction: ({ account, siblings, bridge }): TransactionRes => { diff --git a/libs/coin-modules/coin-filecoin/src/test/bot-specs.ts b/libs/coin-modules/coin-filecoin/src/test/bot-specs.ts index a98d6c2c80dd..578f343a964a 100644 --- a/libs/coin-modules/coin-filecoin/src/test/bot-specs.ts +++ b/libs/coin-modules/coin-filecoin/src/test/bot-specs.ts @@ -30,6 +30,7 @@ const filecoinSpecs: AppSpec = { mutations: [ { name: "Send small to f4 address", + feature: "send", maxRun: 1, deviceAction: generateDeviceActionFlow(BotScenario.F4_RECIPIENT), testDestination: genericTestDestination, @@ -51,6 +52,7 @@ const filecoinSpecs: AppSpec = { }, { name: "Send small to eth address", + feature: "send", maxRun: 1, deviceAction: generateDeviceActionFlow(BotScenario.ETH_RECIPIENT), testDestination: genericTestDestination, @@ -72,6 +74,7 @@ const filecoinSpecs: AppSpec = { }, { name: "Send 50%~", + feature: "send", maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, siblings, bridge }) => { @@ -98,6 +101,7 @@ const filecoinSpecs: AppSpec = { }, { name: "Transfer Max", + feature: "sendMax", maxRun: 1, transaction: ({ account, siblings, bridge }) => { return { @@ -115,6 +119,7 @@ const filecoinSpecs: AppSpec = { }, { name: "Send ~50% WFIL", + feature: "tokens", maxRun: 1, deviceAction: generateDeviceActionFlow(BotScenario.TOKEN_TRANSFER), transaction: ({ account, bridge, maxSpendable }) => { diff --git a/libs/coin-modules/coin-hedera/src/test/bot-specs.ts b/libs/coin-modules/coin-hedera/src/test/bot-specs.ts index fa01b7539a6f..46ba88af52b0 100644 --- a/libs/coin-modules/coin-hedera/src/test/bot-specs.ts +++ b/libs/coin-modules/coin-hedera/src/test/bot-specs.ts @@ -49,7 +49,8 @@ const hedera: AppSpec = { mutations: [ { name: "Send ~50%", - maxRun: 2, + feature: "send", + maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, @@ -83,7 +84,8 @@ const hedera: AppSpec = { }, { name: "Send max", - maxRun: 2, + feature: "sendMax", + maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, @@ -109,7 +111,8 @@ const hedera: AppSpec = { }, { name: "Memo", - maxRun: 2, + feature: "send", + maxRun: 1, transaction: ({ account, siblings, diff --git a/libs/coin-modules/coin-icon/src/specs.ts b/libs/coin-modules/coin-icon/src/specs.ts index 39fb83213ec9..decbdf25ecd1 100644 --- a/libs/coin-modules/coin-icon/src/specs.ts +++ b/libs/coin-modules/coin-icon/src/specs.ts @@ -57,6 +57,7 @@ const icon: AppSpec = { mutations: [ { name: "send 50%~", + feature: "send", maxRun: 1, transaction: ({ account, siblings, bridge }) => { invariant(account.spendableBalance.gt(0), "balance is 0"); @@ -94,6 +95,7 @@ const icon: AppSpec = { }, { name: "send max", + feature: "sendMax", maxRun: 1, transaction: ({ account, siblings, bridge }) => { invariant(account.spendableBalance.gt(0), "balance is 0"); diff --git a/libs/coin-modules/coin-internet_computer/src/test/bot-specs.ts b/libs/coin-modules/coin-internet_computer/src/test/bot-specs.ts index 68a0640197d5..2172c16a5752 100644 --- a/libs/coin-modules/coin-internet_computer/src/test/bot-specs.ts +++ b/libs/coin-modules/coin-internet_computer/src/test/bot-specs.ts @@ -28,6 +28,7 @@ const internetComputerSpecs: AppSpec = { mutations: [ { name: "Send ~50%", + feature: "send", maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, siblings, bridge, maxSpendable }) => { @@ -74,6 +75,7 @@ const internetComputerSpecs: AppSpec = { }, { name: "Transfer Max", + feature: "sendMax", maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, siblings, bridge }) => { diff --git a/libs/coin-modules/coin-near/src/specs.ts b/libs/coin-modules/coin-near/src/specs.ts index edf483d32f3b..25d277b4118a 100644 --- a/libs/coin-modules/coin-near/src/specs.ts +++ b/libs/coin-modules/coin-near/src/specs.ts @@ -27,6 +27,7 @@ const near: AppSpec = { mutations: [ { name: "Move 50% to another account", + feature: "send", maxRun: 1, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount), "balance is too low"); @@ -48,6 +49,7 @@ const near: AppSpec = { }, { name: "Send max to another account", + feature: "sendMax", maxRun: 1, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount), "balance is too low"); @@ -66,6 +68,7 @@ const near: AppSpec = { }, { name: "Stake", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount.plus(stakingFee)), "balance is too low"); @@ -99,6 +102,7 @@ const near: AppSpec = { }, { name: "Unstake", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { invariant(maxSpendable.gt(stakingFee), "balance is too low for fees"); @@ -134,6 +138,7 @@ const near: AppSpec = { }, { name: "Withdraw", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { invariant(maxSpendable.gt(stakingFee), "balance is too low for fees"); diff --git a/libs/coin-modules/coin-polkadot/src/test/bot-specs.ts b/libs/coin-modules/coin-polkadot/src/test/bot-specs.ts index 91bd7ec48ed4..9f47cb9d7492 100644 --- a/libs/coin-modules/coin-polkadot/src/test/bot-specs.ts +++ b/libs/coin-modules/coin-polkadot/src/test/bot-specs.ts @@ -62,7 +62,8 @@ const polkadot: AppSpec = { mutations: [ { name: "send 50%~", - maxRun: 4, + feature: "send", + maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, siblings, bridge }) => { invariant((account as PolkadotAccount).polkadotResources, "polkadot resource"); @@ -107,6 +108,7 @@ const polkadot: AppSpec = { }, { name: "send max", + feature: "sendMax", maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, siblings, bridge }) => { @@ -133,6 +135,7 @@ const polkadot: AppSpec = { }, { name: "bond - bondExtra", + feature: "staking", maxRun: 1, transaction: ({ siblings, account, bridge }) => { expectSiblingsHaveSpendablePartGreaterThan(siblings, 0.5); @@ -181,7 +184,8 @@ const polkadot: AppSpec = { }, { name: "unbond", - maxRun: 2, + feature: "staking", + maxRun: 1, transaction: ({ account, bridge }) => { const { polkadotResources } = account as PolkadotAccount; invariant(polkadotResources, "polkadot"); @@ -205,6 +209,7 @@ const polkadot: AppSpec = { }, { name: "rebond", + feature: "staking", maxRun: 1, transaction: ({ account, bridge }) => { const { polkadotResources } = account as PolkadotAccount; @@ -230,6 +235,7 @@ const polkadot: AppSpec = { }, { name: "nominate", + feature: "staking", maxRun: 1, transaction: ({ account, bridge }) => { invariant((account as PolkadotAccount).polkadotResources, "polkadot"); @@ -255,7 +261,8 @@ const polkadot: AppSpec = { }, { name: "withdraw", - maxRun: 2, + feature: "staking", + maxRun: 1, transaction: ({ account, bridge }) => { const { polkadotResources } = account as PolkadotAccount; invariant(polkadotResources, "polkadot"); diff --git a/libs/coin-modules/coin-solana/src/specs.ts b/libs/coin-modules/coin-solana/src/specs.ts index d33a8fbdfb61..f29a2d7cc013 100644 --- a/libs/coin-modules/coin-solana/src/specs.ts +++ b/libs/coin-modules/coin-solana/src/specs.ts @@ -39,7 +39,8 @@ const solana: AppSpec = { mutations: [ { name: "Transfer ~50%", - maxRun: 2, + feature: "send", + maxRun: 1, testDestination: genericTestDestination, deviceAction: acceptTransferTransaction, transaction: ({ account, siblings, bridge, maxSpendable }) => { @@ -60,6 +61,7 @@ const solana: AppSpec = { }, { name: "Transfer Max", + feature: "sendMax", maxRun: 1, deviceAction: acceptTransferTransaction, transaction: ({ account, siblings, bridge, maxSpendable }) => { @@ -83,6 +85,7 @@ const solana: AppSpec = { }, { name: "Delegate", + feature: "staking", maxRun: 1, deviceAction: acceptStakeCreateAccountTransaction, transaction: ({ account, bridge, siblings }) => { @@ -153,6 +156,7 @@ const solana: AppSpec = { }, { name: "Deactivate Activating Delegation", + feature: "staking", maxRun: 1, deviceAction: acceptStakeUndelegateTransaction, transaction: ({ account, bridge }) => { @@ -213,6 +217,7 @@ const solana: AppSpec = { }, { name: "Deactivate Active Delegation", + feature: "staking", maxRun: 1, deviceAction: acceptStakeUndelegateTransaction, transaction: ({ account, bridge }) => { @@ -270,6 +275,7 @@ const solana: AppSpec = { }, { name: "Reactivate Deactivating Delegation", + feature: "staking", maxRun: 1, deviceAction: acceptStakeDelegateTransaction, transaction: ({ account, bridge }) => { @@ -339,6 +345,7 @@ const solana: AppSpec = { }, { name: "Activate Inactive Delegation", + feature: "staking", maxRun: 1, deviceAction: acceptStakeDelegateTransaction, transaction: ({ account, bridge }) => { @@ -407,6 +414,7 @@ const solana: AppSpec = { }, { name: "Withdraw Delegation", + feature: "staking", maxRun: 1, deviceAction: acceptStakeWithdrawTransaction, transaction: ({ account, bridge }) => { diff --git a/libs/coin-modules/coin-stacks/src/test/bot-specs.ts b/libs/coin-modules/coin-stacks/src/test/bot-specs.ts index 1d5e539382ab..2605ff8a2fc5 100644 --- a/libs/coin-modules/coin-stacks/src/test/bot-specs.ts +++ b/libs/coin-modules/coin-stacks/src/test/bot-specs.ts @@ -27,6 +27,7 @@ const stacksSpecs: AppSpec = { mutations: [ { name: "Send 50%~", + feature: "send", maxRun: 1, transaction: ({ account, siblings, bridge }) => { const sibling = pickSiblings(siblings, 2); @@ -57,6 +58,7 @@ const stacksSpecs: AppSpec = { }, { name: "Transfer Max", + feature: "sendMax", maxRun: 1, transaction: ({ account, siblings, bridge }) => { const sibling = pickSiblings(siblings, 2); diff --git a/libs/coin-modules/coin-stellar/src/test/bot-specs.ts b/libs/coin-modules/coin-stellar/src/test/bot-specs.ts index 433cc37eaee5..0df1071af444 100644 --- a/libs/coin-modules/coin-stellar/src/test/bot-specs.ts +++ b/libs/coin-modules/coin-stellar/src/test/bot-specs.ts @@ -38,7 +38,8 @@ const stellar: AppSpec = { mutations: [ { name: "move ~50% XLM", - maxRun: 2, + feature: "send", + maxRun: 1, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minAmountCutoff), "XLM balance is too low"); @@ -112,7 +113,8 @@ const stellar: AppSpec = { }, { name: "Send max XLM", - maxRun: 2, + feature: "sendMax", + maxRun: 1, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minAmountCutoff), "XLM balance is too low"); @@ -177,6 +179,7 @@ const stellar: AppSpec = { }, { name: "add USDC asset", + feature: "tokens", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { invariant(maxSpendable.gt(reserve), "XLM balance is too low 1"); @@ -217,6 +220,7 @@ const stellar: AppSpec = { }, { name: "move ~50% USDC asset", + feature: "tokens", maxRun: 1, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minAmountCutoff), "XLM balance is too low"); diff --git a/libs/coin-modules/coin-tezos/src/test/bot-specs.ts b/libs/coin-modules/coin-tezos/src/test/bot-specs.ts index 5cd1c726f468..1aaaa691d87c 100644 --- a/libs/coin-modules/coin-tezos/src/test/bot-specs.ts +++ b/libs/coin-modules/coin-tezos/src/test/bot-specs.ts @@ -43,6 +43,7 @@ const tezos: AppSpec = { mutations: [ { name: "send unrevealed", + feature: "send", maxRun: 1, testDestination: genericTestDestination, transaction: ({ maxSpendable, account, siblings, bridge }) => { @@ -61,7 +62,8 @@ const tezos: AppSpec = { }, { name: "send revealed", - maxRun: 2, + feature: "send", + maxRun: 1, testDestination: genericTestDestination, transaction: ({ maxSpendable, account, siblings, bridge }) => { expectRevealed(account); @@ -79,7 +81,8 @@ const tezos: AppSpec = { }, { name: "send max (non delegating)", - maxRun: 3, + feature: "sendMax", + maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(!isAccountDelegating(account), "account must not be delegating"); @@ -96,6 +99,7 @@ const tezos: AppSpec = { }, { name: "delegate unrevealed", + feature: "staking", maxRun: 1, transaction: ({ account, bridge }) => { expectUnrevealed(account); @@ -109,6 +113,7 @@ const tezos: AppSpec = { }, { name: "delegate revealed", + feature: "staking", maxRun: 1, transaction: ({ account, bridge }) => { expectRevealed(account); @@ -122,6 +127,7 @@ const tezos: AppSpec = { }, { name: "undelegate unrevealed", + feature: "staking", maxRun: 1, transaction: ({ account, bridge }) => { invariant(getAccountDelegationSync(account), "account must be delegating"); @@ -134,6 +140,7 @@ const tezos: AppSpec = { }, { name: "undelegate revealed", + feature: "staking", maxRun: 1, transaction: ({ account, bridge }) => { invariant(getAccountDelegationSync(account), "account must be delegating"); diff --git a/libs/coin-modules/coin-ton/src/specs.ts b/libs/coin-modules/coin-ton/src/specs.ts index 8f57116d2175..b809b2ce461c 100644 --- a/libs/coin-modules/coin-ton/src/specs.ts +++ b/libs/coin-modules/coin-ton/src/specs.ts @@ -54,6 +54,7 @@ const tonSpecs: AppSpec = { mutations: [ { name: "Send ~50%", + feature: "send", maxRun: 1, testDestination, transaction: ({ account, siblings, bridge, maxSpendable }) => { @@ -90,6 +91,7 @@ const tonSpecs: AppSpec = { }, { name: "Transfer Max", + feature: "sendMax", maxRun: 1, transaction: ({ account, siblings, bridge }) => { const updates: Array> = [ @@ -118,6 +120,7 @@ const tonSpecs: AppSpec = { }, { name: "Send ~50% jUSDT", + feature: "tokens", maxRun: 1, deviceAction: generateDeviceActionFlow(BotScenario.TOKEN_TRANSFER), transaction: ({ account, bridge, maxSpendable, siblings }) => { diff --git a/libs/coin-modules/coin-tron/src/test/bot-specs.ts b/libs/coin-modules/coin-tron/src/test/bot-specs.ts index 4eed642209a7..035e5030ab75 100644 --- a/libs/coin-modules/coin-tron/src/test/bot-specs.ts +++ b/libs/coin-modules/coin-tron/src/test/bot-specs.ts @@ -53,7 +53,8 @@ const tron: AppSpec = { mutations: [ { name: "move 50% to another account", - maxRun: 2, + feature: "send", + maxRun: 1, testDestination, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount), "balance is too low"); @@ -83,6 +84,7 @@ const tron: AppSpec = { }, { name: "send max to another account", + feature: "sendMax", maxRun: 1, testDestination, transaction: ({ account, siblings, bridge, maxSpendable }) => { diff --git a/libs/coin-modules/coin-vechain/src/test/bot-specs.ts b/libs/coin-modules/coin-vechain/src/test/bot-specs.ts index 18f3165fc6f6..b12fff9afc36 100644 --- a/libs/coin-modules/coin-vechain/src/test/bot-specs.ts +++ b/libs/coin-modules/coin-vechain/src/test/bot-specs.ts @@ -50,6 +50,7 @@ const vet: AppSpec = { mutations: [ { name: "move ~50% VET", + feature: "send", maxRun: 1, transaction: ({ account, @@ -87,6 +88,7 @@ const vet: AppSpec = { }, { name: "move all VET", + feature: "sendMax", maxRun: 1, transaction: ({ account, @@ -124,6 +126,7 @@ const vtho: AppSpec = { mutations: [ { name: "move ~50% VTHO", + feature: "tokens", maxRun: 1, transaction: ({ account, @@ -168,6 +171,7 @@ const vtho: AppSpec = { }, { name: "move all VTHO", + feature: "tokens", maxRun: 1, transaction: ({ account, diff --git a/libs/coin-modules/coin-xrp/src/test/bot-specs.ts b/libs/coin-modules/coin-xrp/src/test/bot-specs.ts index 7f474ede9155..0a5841d5d3ea 100644 --- a/libs/coin-modules/coin-xrp/src/test/bot-specs.ts +++ b/libs/coin-modules/coin-xrp/src/test/bot-specs.ts @@ -24,7 +24,8 @@ const xrp: AppSpec = { mutations: [ { name: "move ~50%", - maxRun: 2, + feature: "send", + maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minAmountCutoff), "balance is too low"); diff --git a/libs/ledger-live-common/src/bot/cli.ts b/libs/ledger-live-common/src/bot/cli.ts index 9b10618be248..6e147aa25ddb 100644 --- a/libs/ledger-live-common/src/bot/cli.ts +++ b/libs/ledger-live-common/src/bot/cli.ts @@ -8,10 +8,16 @@ const { BOT_FILTER_FAMILIES, BOT_DISABLED_CURRENCIES, BOT_DISABLED_FAMILIES, + BOT_FILTER_FEATURES, } = process.env; const arg: Partial<{ - filter: Partial<{ currencies: string[]; families: string[]; mutation: string }>; + filter: Partial<{ + currencies: string[]; + families: string[]; + mutation: string; + features: string[]; + }>; disabled: Partial<{ currencies: string[]; families: string[] }>; }> = {}; @@ -34,4 +40,8 @@ if (BOT_DISABLED_FAMILIES) { arg.disabled.families = BOT_DISABLED_FAMILIES.split(","); } +if (BOT_FILTER_FEATURES) { + arg.filter.features = BOT_FILTER_FEATURES.split(","); +} + bot(arg); diff --git a/libs/ledger-live-common/src/bot/index.test.ts b/libs/ledger-live-common/src/bot/index.test.ts index 990db61de51d..cc52326af016 100644 --- a/libs/ledger-live-common/src/bot/index.test.ts +++ b/libs/ledger-live-common/src/bot/index.test.ts @@ -15,6 +15,21 @@ describe("getSpecs", () => { expect(specs.every(spec => spec.currency.family === "bitcoin")).toEqual(true); }); + it("should filter by feature correctly", () => { + setSupportedCurrencies(["bitcoin"]); + const specs = getSpecs({ disabled: {}, filter: { features: ["send"] } }); + expect(specs[0].mutations.length).toBeGreaterThan(0); + expect(specs[0].mutations.every(spec => spec.feature === "send")).toEqual(true); + }); + + it("should filter multiple features correctly", () => { + setSupportedCurrencies(["bitcoin"]); + const currentFilter = ["send", "sendMax"]; + const specs = getSpecs({ disabled: {}, filter: { features: currentFilter } }); + expect(specs[0].mutations.length).toBeGreaterThan(0); + expect(specs[0].mutations.every(spec => currentFilter.includes(spec.feature))).toEqual(true); + }); + it("should disable currencies correctly", () => { setSupportedCurrencies(["bitcoin", "ethereum", "digibyte"]); const specs = getSpecs({ disabled: { currencies: ["digibyte"] }, filter: {} }); diff --git a/libs/ledger-live-common/src/bot/index.ts b/libs/ledger-live-common/src/bot/index.ts index 55af76a8240f..166beb55324b 100644 --- a/libs/ledger-live-common/src/bot/index.ts +++ b/libs/ledger-live-common/src/bot/index.ts @@ -35,7 +35,12 @@ import { sha256 } from "../crypto"; import { getDefaultAccountName } from "@ledgerhq/live-wallet/accountName"; type Arg = Partial<{ - filter: Partial<{ currencies: string[]; families: string[]; mutation: string }>; + filter: Partial<{ + currencies: string[]; + families: string[]; + mutation: string; + features: string[]; + }>; disabled: Partial<{ currencies: string[]; families: string[] }>; }>; const usd = getFiatCurrencyByTicker("USD"); @@ -105,6 +110,7 @@ export function getSpecs({ disabled, filter }) { const filteredCurrencies = filter?.currencies || []; const filteredFamilies = filter?.families || []; const filteredMutation = filter?.mutation; + const filteredFeatures = filter.features || []; let disabledCurrencies = disabled?.currencies || []; let disabledFamilies = disabled?.families || []; @@ -155,6 +161,13 @@ export function getSpecs({ disabled, filter }) { }; } + if (filteredFeatures) { + spec = { + ...spec, + mutations: spec.mutations.filter(m => filteredFeatures.includes(m.feature)), + }; + } + specs.push(spec); } } diff --git a/libs/ledger-live-common/src/families/aptos/specs.ts b/libs/ledger-live-common/src/families/aptos/specs.ts index caa42eb8944b..1e9be968c1df 100644 --- a/libs/ledger-live-common/src/families/aptos/specs.ts +++ b/libs/ledger-live-common/src/families/aptos/specs.ts @@ -29,6 +29,7 @@ const aptos: AppSpec = { mutations: [ { name: "Send ~50%", + feature: "send", maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, siblings, bridge, maxSpendable }) => { diff --git a/libs/ledger-live-common/src/families/casper/specs.ts b/libs/ledger-live-common/src/families/casper/specs.ts index 448c92e06e94..a34792f648a5 100644 --- a/libs/ledger-live-common/src/families/casper/specs.ts +++ b/libs/ledger-live-common/src/families/casper/specs.ts @@ -30,6 +30,7 @@ const casperSpecs: AppSpec = { mutations: [ { name: "Send ~50%", + feature: "send", maxRun: 1, testDestination: genericTestDestination, transaction: ({ account, siblings, bridge, maxSpendable }) => { @@ -76,6 +77,7 @@ const casperSpecs: AppSpec = { }, { name: "Transfer Max", + feature: "sendMax", maxRun: 1, transaction: ({ account, siblings, bridge }) => { const updates: Array> = [ diff --git a/libs/ledger-live-common/src/families/celo/specs/createActivateVoteMutation.ts b/libs/ledger-live-common/src/families/celo/specs/createActivateVoteMutation.ts index e8b6090b4252..cac68d94f569 100644 --- a/libs/ledger-live-common/src/families/celo/specs/createActivateVoteMutation.ts +++ b/libs/ledger-live-common/src/families/celo/specs/createActivateVoteMutation.ts @@ -8,7 +8,8 @@ const minimalAmount = parseCurrencyUnit(currency.units[0], "0.001"); export const createActivateVoteMutation = (): MutationSpec => ({ name: "Celo: Activate Vote", - maxRun: 5, + feature: "staking", + maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { const { celoResources } = account as CeloAccount; invariant(celoResources?.registrationStatus, "Celo: Activate Vote | Account is not registered"); diff --git a/libs/ledger-live-common/src/families/celo/specs/createLockMutation.ts b/libs/ledger-live-common/src/families/celo/specs/createLockMutation.ts index 971db3969d7b..6a930caf91bf 100644 --- a/libs/ledger-live-common/src/families/celo/specs/createLockMutation.ts +++ b/libs/ledger-live-common/src/families/celo/specs/createLockMutation.ts @@ -8,6 +8,7 @@ const minimalAmount = parseCurrencyUnit(currency.units[0], "0.005"); export const createLockMutation = (): MutationSpec => ({ name: "Celo: Lock", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { const { celoResources } = account as CeloAccount; diff --git a/libs/ledger-live-common/src/families/celo/specs/createRegisterAccountMutation.ts b/libs/ledger-live-common/src/families/celo/specs/createRegisterAccountMutation.ts index f35cd3674b4e..75ec62e26a4a 100644 --- a/libs/ledger-live-common/src/families/celo/specs/createRegisterAccountMutation.ts +++ b/libs/ledger-live-common/src/families/celo/specs/createRegisterAccountMutation.ts @@ -8,6 +8,7 @@ const minimalAmount = parseCurrencyUnit(currency.units[0], "0.001"); export const createRegisterAccountMutation = (): MutationSpec => ({ name: "Celo: Register Account", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { const { celoResources } = account as CeloAccount; diff --git a/libs/ledger-live-common/src/families/celo/specs/createRevokeVoteMutation.ts b/libs/ledger-live-common/src/families/celo/specs/createRevokeVoteMutation.ts index f6214d9be021..19db20ebdc0c 100644 --- a/libs/ledger-live-common/src/families/celo/specs/createRevokeVoteMutation.ts +++ b/libs/ledger-live-common/src/families/celo/specs/createRevokeVoteMutation.ts @@ -8,7 +8,8 @@ const minimalAmount = parseCurrencyUnit(currency.units[0], "0.001"); export const createRevokeVoteMutation = (): MutationSpec => ({ name: "Celo: RevokeVote", - maxRun: 5, + feature: "staking", + maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount), "Celo: Revoke Vote | balance is too low"); diff --git a/libs/ledger-live-common/src/families/celo/specs/createSendMutation.ts b/libs/ledger-live-common/src/families/celo/specs/createSendMutation.ts index 5641f7e13397..29a8bd5693ce 100644 --- a/libs/ledger-live-common/src/families/celo/specs/createSendMutation.ts +++ b/libs/ledger-live-common/src/families/celo/specs/createSendMutation.ts @@ -10,6 +10,7 @@ export const minimalAmount = parseCurrencyUnit(currency.units[0], "0.001"); export const createSend50PercentMutation = (): MutationSpec => ({ name: "Celo: Move 50% to another account", + feature: "send", maxRun: 1, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount), "Celo: Move 50% | balance is too low"); @@ -25,6 +26,7 @@ export const createSend50PercentMutation = (): MutationSpec => ({ export const createSendMaxMutation = (): MutationSpec => ({ name: "Celo: Send max to another account", + feature: "sendMax", maxRun: 1, transaction: ({ account, siblings, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount), "Celo: Send Max | Balance is too low"); diff --git a/libs/ledger-live-common/src/families/celo/specs/createUnlockMutation.ts b/libs/ledger-live-common/src/families/celo/specs/createUnlockMutation.ts index bb7c81b3cb4b..60a3c3dd0882 100644 --- a/libs/ledger-live-common/src/families/celo/specs/createUnlockMutation.ts +++ b/libs/ledger-live-common/src/families/celo/specs/createUnlockMutation.ts @@ -9,6 +9,7 @@ const minimalAmount = parseCurrencyUnit(currency.units[0], "0.001"); export const createUnlockMutation = (): MutationSpec => ({ name: "Celo: Unlock", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount), "Celo: Unlock | balance is too low"); diff --git a/libs/ledger-live-common/src/families/celo/specs/createVoteMutation.ts b/libs/ledger-live-common/src/families/celo/specs/createVoteMutation.ts index 7ca7d6c996d7..9a89c4c9d35a 100644 --- a/libs/ledger-live-common/src/families/celo/specs/createVoteMutation.ts +++ b/libs/ledger-live-common/src/families/celo/specs/createVoteMutation.ts @@ -12,6 +12,7 @@ const minimalAmount = parseCurrencyUnit(currency.units[0], "0.001"); export const createVoteMutation = (): MutationSpec => ({ name: "Celo: Vote", + feature: "staking", maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { invariant(maxSpendable.gt(minimalAmount), "Celo: Vote | balance is too low"); diff --git a/libs/ledger-live-common/src/families/celo/specs/createWithdrawMutation.ts b/libs/ledger-live-common/src/families/celo/specs/createWithdrawMutation.ts index a9c547b448b1..a1c8cb14dc40 100644 --- a/libs/ledger-live-common/src/families/celo/specs/createWithdrawMutation.ts +++ b/libs/ledger-live-common/src/families/celo/specs/createWithdrawMutation.ts @@ -9,7 +9,8 @@ const minimalAmount = parseCurrencyUnit(currency.units[0], "0.001"); export const createWithdrawMutation = (): MutationSpec => ({ name: "Celo: Withdraw", - maxRun: 5, + feature: "staking", + maxRun: 1, transaction: ({ account, bridge, maxSpendable }) => { const celoAccount = account as CeloAccount; const { celoResources } = celoAccount; diff --git a/tools/actions/composites/bot/action.yml b/tools/actions/composites/bot/action.yml index 4dff574ab72d..62364b61337b 100644 --- a/tools/actions/composites/bot/action.yml +++ b/tools/actions/composites/bot/action.yml @@ -10,6 +10,9 @@ inputs: BOT_FILTER_CURRENCIES: description: "currencies to filter on" required: false + BOT_FILTER_FEATURES: + description: "features to filter on" + required: false BOT_DISABLED_FAMILIES: description: "disabled families" required: false @@ -74,6 +77,7 @@ runs: GITHUB_WORKFLOW: ${{ github.workflow }} BOT_FILTER_FAMILIES: ${{ inputs.BOT_FILTER_FAMILIES }} BOT_FILTER_CURRENCIES: ${{ inputs.BOT_FILTER_CURRENCIES }} + BOT_FILTER_FEATURES: ${{ inputs.BOT_FILTER_FEATURES }} BOT_DISABLED_FAMILIES: ${{ inputs.BOT_DISABLED_FAMILIES }} BOT_DISABLED_CURRENCIES: ${{ inputs.BOT_DISABLED_CURRENCIES }} SHOW_LEGACY_NEW_ACCOUNT: ${{ inputs.SHOW_LEGACY_NEW_ACCOUNT }}