From bdbe277182dd4b31a304b13ed253a87fb729b5f1 Mon Sep 17 00:00:00 2001 From: Ulisses Ferreira Date: Thu, 1 Oct 2026 16:13:47 +0100 Subject: [PATCH] feat(tron-wallet-snap): return live data from listAccountAssets and getAccountBalances --- packages/tron-wallet-snap/CHANGELOG.md | 2 +- packages/tron-wallet-snap/jest.config.js | 8 +- packages/tron-wallet-snap/snap.manifest.json | 2 +- .../src/handlers/keyring/keyring.test.ts | 111 +++++++++++- .../src/handlers/keyring/keyring.ts | 8 +- .../services/accounts/AccountsService.test.ts | 42 ++--- .../src/services/accounts/AccountsService.ts | 5 +- .../src/services/assets/AssetsService.test.ts | 167 ++++++++++-------- .../src/services/assets/AssetsService.ts | 29 ++- 9 files changed, 262 insertions(+), 112 deletions(-) diff --git a/packages/tron-wallet-snap/CHANGELOG.md b/packages/tron-wallet-snap/CHANGELOG.md index 807c39d53..481501f0e 100644 --- a/packages/tron-wallet-snap/CHANGELOG.md +++ b/packages/tron-wallet-snap/CHANGELOG.md @@ -15,12 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Render the confirmation "Estimated changes" section with the shared `EstimatedChanges` component from `@metamask/snap-networks-utils` ([#396](https://github.com/MetaMask/internal-snaps/pull/396)) - Estimated changes from the previous scan now stay visible while a confirmation re-scans, instead of showing a loading skeleton +- `listAccountAssets` and `getAccountBalances` now fetch live assets and balances from the chain instead of returning persisted state. ([#388](https://github.com/MetaMask/internal-snaps/pull/388)) ### Fixed - Show "Estimated changes are not available" instead of "No estimated changes" when the transaction scan returns an error result, such as for a malformed transaction ([#396](https://github.com/MetaMask/internal-snaps/pull/396)) - Report the MetaMask origin as lowercase `metamask` instead of `MetaMask` for MetaMask-initiated operations, so the origin matches the value used by the other non-EVM snaps and granted to the keyring methods, and so transaction scan requests are attributed to `https://metamask.io`. The confirmation UI keeps displaying `MetaMask`. ([#392](https://github.com/MetaMask/internal-snaps/pull/392)) -- Show "Estimated changes are not available" instead of "No estimated changes" when the transaction scan returns an error result, such as for a malformed transaction ([#396](https://github.com/MetaMask/internal-snaps/pull/396)) ## [4.0.0] diff --git a/packages/tron-wallet-snap/jest.config.js b/packages/tron-wallet-snap/jest.config.js index 947d0368e..1a54e0191 100644 --- a/packages/tron-wallet-snap/jest.config.js +++ b/packages/tron-wallet-snap/jest.config.js @@ -19,10 +19,10 @@ module.exports = { // An object that configures minimum threshold enforcement for coverage results coverageThreshold: { global: { - branches: 72.49, - functions: 79.91, - lines: 85.79, - statements: 85.79, + branches: 72.95, + functions: 81.35, + lines: 86.34, + statements: 86.34, }, }, }; diff --git a/packages/tron-wallet-snap/snap.manifest.json b/packages/tron-wallet-snap/snap.manifest.json index 770eb56b0..591213db9 100644 --- a/packages/tron-wallet-snap/snap.manifest.json +++ b/packages/tron-wallet-snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/internal-snaps.git" }, "source": { - "shasum": "1IlkNeNaW28YQoE0wK3OdDJctxoEBDqK6cxLQ0GyifY=", + "shasum": "JwSeAIv5PbUj0SDJ6LqTDU7fsVM6YGRA2wrVKuN/OzE=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/tron-wallet-snap/src/handlers/keyring/keyring.test.ts b/packages/tron-wallet-snap/src/handlers/keyring/keyring.test.ts index ba66a5481..386a55cfb 100644 --- a/packages/tron-wallet-snap/src/handlers/keyring/keyring.test.ts +++ b/packages/tron-wallet-snap/src/handlers/keyring/keyring.test.ts @@ -11,7 +11,8 @@ import { } from '@metamask/snaps-sdk'; import type { SnapClient } from '../../clients/snap/SnapClient'; -import { Network } from '../../constants'; +import { KnownCaip19Id, Network } from '../../constants'; +import type { AssetEntity } from '../../entities/assets'; import type { AccountsService } from '../../services/accounts/AccountsService'; import type { AssetsService } from '../../services/assets/AssetsService'; import type { ConfirmationHandler } from '../../services/confirmation/ConfirmationHandler'; @@ -65,6 +66,23 @@ describe('KeyringHandler', () => { let mockWalletService: jest.Mocked; let mockConfirmationHandler: jest.Mocked; + const mockLiveAsset: AssetEntity = { + assetType: KnownCaip19Id.TrxMainnet, + keyringAccountId: mockAccount.id, + network: Network.Mainnet, + symbol: 'TRX', + decimals: 6, + rawAmount: '1000000', + uiAmount: '1', + iconUrl: '', + }; + + const mockShastaAsset: AssetEntity = { + ...mockLiveAsset, + assetType: KnownCaip19Id.TrxShasta, + network: Network.Shasta, + }; + beforeEach(() => { mockSnapClient = { scheduleBackgroundEvent: jest.fn().mockResolvedValue(undefined), @@ -84,7 +102,9 @@ describe('KeyringHandler', () => { }), } as unknown as jest.Mocked; mockAssetsService = { - getAccountAssets: jest.fn().mockResolvedValue([]), + fetchAccountAssets: jest + .fn() + .mockResolvedValue([mockLiveAsset, mockShastaAsset]), } as unknown as jest.Mocked; mockTransactionsService = { checkAddressActivity: jest.fn(), @@ -670,15 +690,28 @@ describe('KeyringHandler', () => { }); describe('getAccountAssets', () => { - it('returns asset types for an account', async () => { + it('fetches live assets for all account scopes and returns their asset types', async () => { const result = await keyringHandler.getAccountAssets(mockAccount.id); - expect(result).toStrictEqual([]); - expect(mockAssetsService.getAccountAssets).toHaveBeenCalledWith( - mockAccount.id, + expect(result).toStrictEqual([ + KnownCaip19Id.TrxMainnet, + KnownCaip19Id.TrxShasta, + ]); + expect(mockAssetsService.fetchAccountAssets).toHaveBeenCalledWith( + mockAccount, ); }); + it('propagates fetch failures', async () => { + mockAssetsService.fetchAccountAssets.mockRejectedValue( + new Error('network error'), + ); + + await expect( + keyringHandler.getAccountAssets(mockAccount.id), + ).rejects.toThrow('network error'); + }); + it('throws when the account is not found', async () => { mockAccountsService.findById.mockResolvedValue(null); @@ -688,6 +721,72 @@ describe('KeyringHandler', () => { }); }); + describe('getAccountBalances', () => { + it('fetches live balances for the account and returns the balance record', async () => { + const result = await keyringHandler.getAccountBalances(mockAccount.id, [ + KnownCaip19Id.TrxMainnet, + ]); + + expect(result).toStrictEqual({ + [KnownCaip19Id.TrxMainnet]: { + amount: '1', + unit: 'TRX', + }, + }); + expect(mockAssetsService.fetchAccountAssets).toHaveBeenCalledWith( + mockAccount, + ); + }); + + it('excludes token assets with zero balance', async () => { + const zeroBalanceToken: AssetEntity = { + ...mockLiveAsset, + assetType: KnownCaip19Id.UsdtMainnet, + rawAmount: '0', + uiAmount: '0', + }; + + mockAssetsService.fetchAccountAssets.mockResolvedValue([ + mockLiveAsset, + zeroBalanceToken, + ]); + + const result = await keyringHandler.getAccountBalances(mockAccount.id, [ + KnownCaip19Id.TrxMainnet, + KnownCaip19Id.UsdtMainnet, + ]); + + expect(result).toStrictEqual({ + [KnownCaip19Id.TrxMainnet]: { + amount: '1', + unit: 'TRX', + }, + }); + }); + + it('propagates fetch failures', async () => { + mockAssetsService.fetchAccountAssets.mockRejectedValue( + new Error('network error'), + ); + + await expect( + keyringHandler.getAccountBalances(mockAccount.id, [ + KnownCaip19Id.TrxMainnet, + ]), + ).rejects.toThrow('network error'); + }); + + it('throws when the account is not found', async () => { + mockAccountsService.findById.mockResolvedValue(null); + + await expect( + keyringHandler.getAccountBalances(mockAccount.id, [ + KnownCaip19Id.TrxMainnet, + ]), + ).rejects.toThrow('not found'); + }); + }); + describe('getAccountTransactions', () => { it('returns paginated transactions for an account', async () => { const result = await keyringHandler.getAccountTransactions( diff --git a/packages/tron-wallet-snap/src/handlers/keyring/keyring.ts b/packages/tron-wallet-snap/src/handlers/keyring/keyring.ts index 01507b548..1989b705d 100644 --- a/packages/tron-wallet-snap/src/handlers/keyring/keyring.ts +++ b/packages/tron-wallet-snap/src/handlers/keyring/keyring.ts @@ -183,12 +183,12 @@ export class KeyringHandler implements KeyringSnapRpc { try { validateRequest({ accountId }, ListAccountAssetsStruct); - await this.#getAccountOrThrow(accountId); + const account = await this.#getAccountOrThrow(accountId); this.#logger.info('Listing account assets', { accountId }); const assetEntities = - await this.#assetsService.getAccountAssets(accountId); + await this.#assetsService.fetchAccountAssets(account); const result = assetEntities .filter( (asset) => @@ -275,9 +275,9 @@ export class KeyringHandler implements KeyringSnapRpc { this.#logger.info('Getting account balances', { accountId, assets }); - await this.#getAccountOrThrow(accountId); + const account = await this.#getAccountOrThrow(accountId); - const assetsList = await this.#assetsService.getAccountAssets(accountId); + const assetsList = await this.#assetsService.fetchAccountAssets(account); const assetsToUse = assetsList .filter((asset) => assets.includes(asset.assetType)) diff --git a/packages/tron-wallet-snap/src/services/accounts/AccountsService.test.ts b/packages/tron-wallet-snap/src/services/accounts/AccountsService.test.ts index 8c7b4c15f..dfee0a039 100644 --- a/packages/tron-wallet-snap/src/services/accounts/AccountsService.test.ts +++ b/packages/tron-wallet-snap/src/services/accounts/AccountsService.test.ts @@ -111,7 +111,7 @@ type WithAccountsServiceCallback = (payload: { mockConfigProvider: { config: Config }; mockLogger: Logger; mockAssetsService: jest.Mocked< - Pick + Pick >; mockSnapClient: jest.Mocked< Pick @@ -268,9 +268,9 @@ async function withAccountsService( }; const mockAssetsService: jest.Mocked< - Pick + Pick > = { - fetchAssetsAndBalancesForAccount: jest.fn().mockResolvedValue([]), + fetchAccountAssetsByScope: jest.fn().mockResolvedValue([]), saveMany: jest.fn().mockResolvedValue(undefined), }; @@ -1053,21 +1053,21 @@ describe('AccountsService', () => { ...MOCK_CONFIG, activeNetworks: [Network.Mainnet, Network.Shasta], }; - mockAssetsService.fetchAssetsAndBalancesForAccount.mockResolvedValue( + mockAssetsService.fetchAccountAssetsByScope.mockResolvedValue( mockAssets, ); await accountsService.synchronize([account]); expect( - mockAssetsService.fetchAssetsAndBalancesForAccount, + mockAssetsService.fetchAccountAssetsByScope, ).toHaveBeenCalledTimes(2); expect( - mockAssetsService.fetchAssetsAndBalancesForAccount, - ).toHaveBeenCalledWith(Network.Mainnet, account); + mockAssetsService.fetchAccountAssetsByScope, + ).toHaveBeenCalledWith(account, Network.Mainnet); expect( - mockAssetsService.fetchAssetsAndBalancesForAccount, - ).toHaveBeenCalledWith(Network.Shasta, account); + mockAssetsService.fetchAccountAssetsByScope, + ).toHaveBeenCalledWith(account, Network.Shasta); expect(mockAssetsService.saveMany).toHaveBeenCalledWith( expect.arrayContaining(mockAssets), ); @@ -1154,7 +1154,7 @@ describe('AccountsService', () => { ...MOCK_CONFIG, activeNetworks: [Network.Mainnet], }; - mockAssetsService.fetchAssetsAndBalancesForAccount + mockAssetsService.fetchAccountAssetsByScope .mockRejectedValueOnce(new Error('grpc unavailable')) .mockResolvedValueOnce(healthyAssets); @@ -1199,7 +1199,7 @@ describe('AccountsService', () => { throw new Error('toString boom'); }, }; - mockAssetsService.fetchAssetsAndBalancesForAccount.mockRejectedValue( + mockAssetsService.fetchAccountAssetsByScope.mockRejectedValue( hostileReason, ); @@ -1238,7 +1238,7 @@ describe('AccountsService', () => { await accountsService.synchronize([account]); expect( - mockAssetsService.fetchAssetsAndBalancesForAccount, + mockAssetsService.fetchAccountAssetsByScope, ).not.toHaveBeenCalled(); expect(mockAssetsService.saveMany).toHaveBeenCalledWith([]); }, @@ -1417,8 +1417,8 @@ describe('AccountsService', () => { await accountsService.synchronize([account]); expect( - mockAssetsService.fetchAssetsAndBalancesForAccount, - ).toHaveBeenCalledWith(Network.Mainnet, account); + mockAssetsService.fetchAccountAssetsByScope, + ).toHaveBeenCalledWith(account, Network.Mainnet); expect( mockTransactionsService.fetchNewTransactionsForAccount, ).toHaveBeenCalledWith(Network.Mainnet, account); @@ -1463,7 +1463,7 @@ describe('AccountsService', () => { ]); expect( - mockAssetsService.fetchAssetsAndBalancesForAccount, + mockAssetsService.fetchAccountAssetsByScope, ).toHaveBeenCalledTimes(1); expect( mockTransactionsService.fetchNewTransactionsForAccount, @@ -1488,7 +1488,7 @@ describe('AccountsService', () => { await accountsService.synchronize([account]); expect( - mockAssetsService.fetchAssetsAndBalancesForAccount, + mockAssetsService.fetchAccountAssetsByScope, ).toHaveBeenCalledTimes(2); }, ); @@ -1511,14 +1511,14 @@ describe('AccountsService', () => { ]); expect( - mockAssetsService.fetchAssetsAndBalancesForAccount, + mockAssetsService.fetchAccountAssetsByScope, ).toHaveBeenCalledTimes(2); expect( - mockAssetsService.fetchAssetsAndBalancesForAccount, - ).toHaveBeenCalledWith(Network.Mainnet, accountA); + mockAssetsService.fetchAccountAssetsByScope, + ).toHaveBeenCalledWith(accountA, Network.Mainnet); expect( - mockAssetsService.fetchAssetsAndBalancesForAccount, - ).toHaveBeenCalledWith(Network.Mainnet, accountB); + mockAssetsService.fetchAccountAssetsByScope, + ).toHaveBeenCalledWith(accountB, Network.Mainnet); }, ); }); diff --git a/packages/tron-wallet-snap/src/services/accounts/AccountsService.ts b/packages/tron-wallet-snap/src/services/accounts/AccountsService.ts index d5bcfe83a..7f512b976 100644 --- a/packages/tron-wallet-snap/src/services/accounts/AccountsService.ts +++ b/packages/tron-wallet-snap/src/services/accounts/AccountsService.ts @@ -522,10 +522,7 @@ export class AccountsService { const assetResponses = await Promise.allSettled( combinations.map(async ({ account, scope }) => { - return this.#assetsService.fetchAssetsAndBalancesForAccount( - scope, - account, - ); + return this.#assetsService.fetchAccountAssetsByScope(account, scope); }), ); diff --git a/packages/tron-wallet-snap/src/services/assets/AssetsService.test.ts b/packages/tron-wallet-snap/src/services/assets/AssetsService.test.ts index 756208616..a3dc99249 100644 --- a/packages/tron-wallet-snap/src/services/assets/AssetsService.test.ts +++ b/packages/tron-wallet-snap/src/services/assets/AssetsService.test.ts @@ -376,7 +376,36 @@ async function withAssetsService( } describe('AssetsService', () => { - describe('fetchAssetsAndBalancesForAccount', () => { + describe('fetchAccountAssets', () => { + it('fetches live assets for all the account scopes', async () => { + await withAssetsService(async ({ assetsService }) => { + const mainnetAsset = { + assetType: KnownCaip19Id.TrxMainnet, + } as AssetEntity; + const shastaAsset = { + assetType: KnownCaip19Id.TrxShasta, + } as AssetEntity; + const account: KeyringAccount = { + ...mockAccount, + scopes: [Network.Mainnet, Network.Shasta], + }; + const spy = jest + .spyOn(assetsService, 'fetchAccountAssetsByScope') + .mockResolvedValueOnce([mainnetAsset]) + .mockResolvedValueOnce([shastaAsset]); + + expect(await assetsService.fetchAccountAssets(account)).toStrictEqual([ + mainnetAsset, + shastaAsset, + ]); + expect(spy).toHaveBeenCalledTimes(2); + expect(spy).toHaveBeenNthCalledWith(1, account, Network.Mainnet); + expect(spy).toHaveBeenNthCalledWith(2, account, Network.Shasta); + }); + }); + }); + + describe('fetchAccountAssetsByScope', () => { describe('inactive account fallback', () => { it('falls back to TRC20 balance endpoint when account info fails (inactive account)', async () => { await withAssetsService( @@ -409,9 +438,9 @@ describe('AssetsService', () => { }), ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -451,9 +480,9 @@ describe('AssetsService', () => { [], ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); const bandwidthAsset = assets.find( @@ -487,9 +516,9 @@ describe('AssetsService', () => { [], ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect(assets.length).toBeGreaterThan(0); @@ -523,9 +552,9 @@ describe('AssetsService', () => { [], ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect(mockSnapClient.trackError).toHaveBeenCalledTimes(1); @@ -582,9 +611,9 @@ describe('AssetsService', () => { }), ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -624,9 +653,9 @@ describe('AssetsService', () => { new Error('Resources endpoint unavailable'), ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -660,9 +689,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -686,9 +715,9 @@ describe('AssetsService', () => { getMockAccountResources({ freeNetUsed: 200 }), ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -712,9 +741,9 @@ describe('AssetsService', () => { getMockAccountResources({ freeNetUsed: 326, NetLimit: 16 }), ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -742,9 +771,9 @@ describe('AssetsService', () => { }), ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -768,9 +797,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -795,9 +824,9 @@ describe('AssetsService', () => { getMockAccountResources({}), ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -822,9 +851,9 @@ describe('AssetsService', () => { getMockAccountResources({ NetLimit: 48 }), ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -852,9 +881,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); const readyForWithdrawalAsset = findAsset( @@ -885,9 +914,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); const readyForWithdrawalAsset = findAsset( @@ -921,9 +950,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); const readyForWithdrawalAsset = findAsset( @@ -956,9 +985,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); const readyForWithdrawalAsset = findAsset( @@ -994,9 +1023,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); const readyForWithdrawalAsset = findAsset( @@ -1026,9 +1055,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); const inLockPeriodAsset = findAsset( @@ -1062,9 +1091,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); const inLockPeriodAsset = findAsset( @@ -1098,9 +1127,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); const inLockPeriodAsset = findAsset( @@ -1139,9 +1168,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); const inLockPeriodAsset = findAsset( @@ -1177,9 +1206,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); const inLockPeriodAsset = findAsset( @@ -1207,9 +1236,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); const inLockPeriodAsset = findAsset( @@ -1236,9 +1265,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -1262,9 +1291,9 @@ describe('AssetsService', () => { getMockAccountResources({ EnergyLimit: 329 }), ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -1288,9 +1317,9 @@ describe('AssetsService', () => { getMockAccountResources({ EnergyLimit: 5000, EnergyUsed: 4383 }), ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -1314,9 +1343,9 @@ describe('AssetsService', () => { getMockAccountResources({ EnergyLimit: 46, EnergyUsed: 6511 }), ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -1340,9 +1369,9 @@ describe('AssetsService', () => { ); mockTronHttpClient.getAccountResources.mockResolvedValue({}); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -1366,9 +1395,9 @@ describe('AssetsService', () => { getMockAccountResources({ EnergyLimit: 329 }), ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -1393,9 +1422,9 @@ describe('AssetsService', () => { mockTronHttpClient.getAccountResources.mockResolvedValue({}); mockTronHttpClient.getReward.mockResolvedValue(0); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -1419,9 +1448,9 @@ describe('AssetsService', () => { mockTronHttpClient.getAccountResources.mockResolvedValue({}); mockTronHttpClient.getReward.mockResolvedValue(5000000); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); const stakingRewardsAsset = findAsset( @@ -1450,9 +1479,9 @@ describe('AssetsService', () => { new Error('API Error'), ); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( @@ -2991,9 +3020,9 @@ describe('AssetsService', () => { }); mockTronHttpClient.getReward.mockResolvedValue(0); - const assets = await assetsService.fetchAssetsAndBalancesForAccount( - Network.Mainnet, + const assets = await assetsService.fetchAccountAssetsByScope( mockAccount, + Network.Mainnet, ); expect( diff --git a/packages/tron-wallet-snap/src/services/assets/AssetsService.ts b/packages/tron-wallet-snap/src/services/assets/AssetsService.ts index 181a0555e..8f18541e1 100644 --- a/packages/tron-wallet-snap/src/services/assets/AssetsService.ts +++ b/packages/tron-wallet-snap/src/services/assets/AssetsService.ts @@ -83,9 +83,17 @@ export class AssetsService { return this.#snapAdapter.getAccountAssetByID(accountId, assetId); } - async fetchAssetsAndBalancesForAccount( - scope: Network, + /** + * Fetches live assets and balances for the given account from the chain, + * for a single scope. + * + * @param account - The account to fetch live assets for. + * @param scope - The scope to fetch live assets for. + * @returns The live assets. + */ + async fetchAccountAssetsByScope( account: KeyringAccount, + scope: Network, ): Promise { if (await this.#shouldReturnAssetsFromCore()) { return this.#coreAdapter.fetchAssetsAndBalancesForAccount(scope, account); @@ -94,6 +102,23 @@ export class AssetsService { return this.#snapAdapter.fetchAssetsAndBalancesForAccount(scope, account); } + /** + * Fetches live assets and balances for the given account across all its + * scopes from the chain. + * + * @param account - The account to fetch live assets for. + * @returns The live assets. + */ + async fetchAccountAssets(account: KeyringAccount): Promise { + const results = await Promise.all( + account.scopes.map((scope) => + this.fetchAccountAssetsByScope(account, scope as Network), + ), + ); + + return results.flat(); + } + async saveMany(assets: AssetEntity[]): Promise { if (await this.#shouldReturnAssetsFromCore()) { return this.#coreAdapter.saveMany(assets);