Skip to content

Commit 98220df

Browse files
authored
fix: fix add custom assets (#8872)
## Explanation <!-- Thanks for your contribution! Take a moment to answer these questions so that reviewers have the information they need to properly understand your changes: * What is the current state of things and why does it need to change? * What is the solution your changes offer and how does it work? * Are there any changes whose purpose might not obvious to those unfamiliar with the domain? * If your primary goal was to update one package but you found you had to update another one along the way, why did you do so? * If you had to upgrade a dependency, why did you do so? --> ## References <!-- Are there any issues that this pull request is tied to? Are there other links that reviewers should consult to understand these changes better? Are there client or consumer pull requests to adopt any breaking changes? For example: * Fixes #12345 * Related to #67890 --> ## Checklist - [ ] I've updated the test suite for new or updated code as appropriate - [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [ ] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md) - [ ] I've introduced [breaking changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md) in this PR and have prepared draft pull requests for clients and consumer packages to resolve them <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches `addCustomAsset` state writes and its follow-up `getAssets` request parameters, which can affect token rendering and immediate post-import fetching behavior across chains. > > **Overview** > Fixes custom-asset import UX by having `addCustomAsset` immediately **seed `assetsBalance` with `{ amount: '0' }`** for the newly added asset (without overwriting an existing balance), allowing the UI to render the token before the next pipeline fetch. > > Also tightens the post-import refresh by explicitly fetching `balance`, `metadata`, and `price` for *fungible* assets on the token’s chain, and adds regression tests + a changelog entry for the behavior. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8c40ecf. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 5d3f7a1 commit 98220df

3 files changed

Lines changed: 43 additions & 0 deletions

File tree

packages/assets-controller/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Fixed
1111

1212
- Export `SnapControllerSnapInstalledEvent` from `AssetsControllerMessenger` allowed events type ([#8868](https://github.com/MetaMask/core/pull/8868))
13+
- `addCustomAsset` now immediately seeds `assetsBalance` with a zero amount for the newly added asset, so the UI can render it before the next pipeline fetch ([#8872](https://github.com/MetaMask/core/pull/8872))
1314

1415
## [8.0.0]
1516

packages/assets-controller/src/AssetsController.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,37 @@ describe('AssetsController', () => {
523523
expect(controller.state.customAssets[MOCK_ACCOUNT_ID]).toHaveLength(2);
524524
});
525525
});
526+
527+
it('seeds assetsBalance with a zero amount for a newly added custom asset', async () => {
528+
await withController(async ({ controller }) => {
529+
await controller.addCustomAsset(MOCK_ACCOUNT_ID, MOCK_ASSET_ID);
530+
531+
expect(
532+
controller.state.assetsBalance[MOCK_ACCOUNT_ID]?.[MOCK_ASSET_ID],
533+
).toStrictEqual({ amount: '0' });
534+
});
535+
});
536+
537+
it('does not overwrite an existing balance when re-adding a custom asset', async () => {
538+
await withController(
539+
{
540+
state: {
541+
assetsBalance: {
542+
[MOCK_ACCOUNT_ID]: {
543+
[MOCK_ASSET_ID]: { amount: '1000000' },
544+
},
545+
},
546+
},
547+
},
548+
async ({ controller }) => {
549+
await controller.addCustomAsset(MOCK_ACCOUNT_ID, MOCK_ASSET_ID);
550+
551+
expect(
552+
controller.state.assetsBalance[MOCK_ACCOUNT_ID]?.[MOCK_ASSET_ID],
553+
).toStrictEqual({ amount: '1000000' });
554+
},
555+
);
556+
});
526557
});
527558

528559
describe('removeCustomAsset', () => {

packages/assets-controller/src/AssetsController.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,6 +1689,15 @@ export class AssetsController extends BaseController<
16891689
(state.assetsInfo as Record<string, AssetMetadata>)[normalizedAssetId] =
16901690
assetMetadata;
16911691
}
1692+
1693+
// Seed a zero balance so the UI can render the asset immediately,
1694+
// before the next pipeline fetch returns the real amount.
1695+
const balances = state.assetsBalance as Record<
1696+
string,
1697+
Record<string, AssetBalance>
1698+
>;
1699+
balances[accountId] ??= {};
1700+
balances[accountId][normalizedAssetId] ??= { amount: '0' };
16921701
});
16931702

16941703
// Fetch data for the newly added custom asset (merge to preserve other chains)
@@ -1697,6 +1706,8 @@ export class AssetsController extends BaseController<
16971706
const chainId = extractChainId(normalizedAssetId);
16981707
await this.getAssets([account], {
16991708
chainIds: [chainId],
1709+
dataTypes: ['balance', 'metadata', 'price'],
1710+
assetTypes: ['fungible'],
17001711
forceUpdate: true,
17011712
updateMode: 'merge',
17021713
});

0 commit comments

Comments
 (0)