Skip to content

Commit 7e5ff79

Browse files
committed
Add fallback to onchain metadata for any chain other than mainnet. Don't even try to return iconUrl, because we can't do anything with it anyways
1 parent 5be330c commit 7e5ff79

15 files changed

Lines changed: 446 additions & 255 deletions

File tree

packages/gator-permissions-snap/snap.manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"url": "https://github.com/MetaMask/snap-7715-permissions.git"
88
},
99
"source": {
10-
"shasum": "8RuzV/zrJlK0VNzSDBoQQ8t1ecofnqNn8WL7MwNKfAE=",
10+
"shasum": "lDkiV/mNq1vl4SG72M9dcOe2EuQQGhrmR+8QEsDeD9E=",
1111
"location": {
1212
"npm": {
1313
"filePath": "dist/bundle.js",

packages/gator-permissions-snap/src/accountController/baseAccountController.ts

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import type { SnapsProvider } from '@metamask/snaps-sdk';
44
import * as chains from 'viem/chains';
55
import type { Address } from 'viem';
66

7+
import type { AccountApiClient } from '../clients/accountApiClient';
78
import type {
8-
AccountApiClient,
9+
TokenMetadataClient,
910
TokenBalanceAndMetadata,
10-
} from '../clients/accountApiClient';
11+
} from '../core/types';
1112
import type {
1213
AccountOptionsBase,
1314
GetTokenBalanceAndMetadataOptions,
@@ -28,6 +29,8 @@ export abstract class BaseAccountController {
2829

2930
readonly #accountApiClient: AccountApiClient;
3031

32+
readonly #tokenMetadataClient: TokenMetadataClient;
33+
3134
protected supportedChains: SupportedChains;
3235

3336
// the intersection between chains supported by viem, and chains supported by the delegator contracts
@@ -45,11 +48,13 @@ export abstract class BaseAccountController {
4548
* @param config.snapsProvider - The provider for interacting with snaps.
4649
* @param config.supportedChains - The supported blockchain chains.
4750
* @param config.accountApiClient - The client for interacting with the account API.
51+
* @param config.tokenMetadataClient - The client for interacting with the token metadata.
4852
*/
4953
constructor(config: {
5054
snapsProvider: SnapsProvider;
5155
supportedChains?: SupportedChains;
5256
accountApiClient: AccountApiClient;
57+
tokenMetadataClient: TokenMetadataClient;
5358
}) {
5459
// only validate if supportedChains is specified, as it will default to ALL_SUPPORTED_CHAINS
5560
if (config.supportedChains) {
@@ -58,6 +63,7 @@ export abstract class BaseAccountController {
5863

5964
this.#snapsProvider = config.snapsProvider;
6065
this.#accountApiClient = config.accountApiClient;
66+
this.#tokenMetadataClient = config.tokenMetadataClient;
6167
this.supportedChains =
6268
config.supportedChains ?? BaseAccountController.#allSupportedChains;
6369
}
@@ -173,6 +179,26 @@ export abstract class BaseAccountController {
173179
options: AccountOptionsBase,
174180
): Promise<Address>;
175181

182+
/**
183+
* Gets the appropriate token metadata client for the given chain ID.
184+
* Uses the account API client for mainnet (chain ID 1) and the blockchain client for other chains.
185+
*
186+
* @param params - The parameters object
187+
* @param params.chainId - The chain ID to get the client for
188+
* @returns The appropriate token metadata client
189+
*/
190+
#getTokenMetadataClientForChainId({
191+
chainId,
192+
}: {
193+
chainId: number;
194+
}): TokenMetadataClient {
195+
if (this.#accountApiClient.isChainIdSupported({ chainId })) {
196+
return this.#accountApiClient;
197+
}
198+
199+
return this.#tokenMetadataClient;
200+
}
201+
176202
/**
177203
* Retrieves the token balance and metadata for the account.
178204
*
@@ -190,12 +216,13 @@ export abstract class BaseAccountController {
190216

191217
const account = await this.getAccountAddress({ chainId });
192218

193-
const balanceAndMetadata =
194-
await this.#accountApiClient.getTokenBalanceAndMetadata({
195-
chainId,
196-
account,
197-
assetAddress,
198-
});
219+
const client = this.#getTokenMetadataClientForChainId({ chainId });
220+
221+
const balanceAndMetadata = await client.getTokenBalanceAndMetadata({
222+
chainId,
223+
account,
224+
assetAddress,
225+
});
199226

200227
logger.debug(
201228
'accountController:getTokenBalanceAndMetadata() - balance and metadata resolved',

packages/gator-permissions-snap/src/accountController/eoaAccountController.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import {
44
type Delegation,
55
type DeleGatorEnvironment,
66
} from '@metamask/delegation-toolkit';
7-
import type { SnapsProvider } from '@metamask/snaps-sdk';
8-
import { type Address, type Hex } from 'viem';
7+
import type { SnapsEthereumProvider, SnapsProvider } from '@metamask/snaps-sdk';
8+
import { Hex, type Address } from 'viem';
99

1010
import { AccountApiClient } from '../clients/accountApiClient';
1111
import type { SupportedChains } from './baseAccountController';
@@ -16,10 +16,7 @@ import type {
1616
SignDelegationOptions,
1717
FactoryArgs,
1818
} from './types';
19-
20-
export type EthereumProvider = {
21-
request: (args: { method: string; params?: any[] }) => Promise<any>;
22-
};
19+
import type { TokenMetadataClient } from '../core/types';
2320

2421
/**
2522
* Controls EOA account operations including address retrieval, delegation signing, and balance queries.
@@ -30,7 +27,7 @@ export class EoaAccountController
3027
{
3128
#accountAddress: Address | null = null;
3229

33-
#ethereumProvider: EthereumProvider;
30+
#ethereumProvider: SnapsEthereumProvider;
3431

3532
/**
3633
* Initializes a new EoaAccountController instance.
@@ -42,11 +39,13 @@ export class EoaAccountController
4239
*/
4340
constructor(config: {
4441
snapsProvider: SnapsProvider;
45-
ethereumProvider: EthereumProvider;
42+
ethereumProvider: SnapsEthereumProvider;
4643
supportedChains?: SupportedChains;
44+
tokenMetadataClient: TokenMetadataClient;
4745
accountApiClient: AccountApiClient;
4846
}) {
4947
super(config);
48+
5049
this.#ethereumProvider = config.ethereumProvider;
5150
}
5251

@@ -61,7 +60,7 @@ export class EoaAccountController
6160
return this.#accountAddress;
6261
}
6362

64-
const accounts = await this.#ethereumProvider.request({
63+
const accounts = await this.#ethereumProvider.request<Hex[]>({
6564
method: 'eth_requestAccounts',
6665
});
6766

@@ -105,7 +104,7 @@ export class EoaAccountController
105104

106105
const address = await this.#getAccountAddress();
107106

108-
const selectedChain = await this.#ethereumProvider.request({
107+
const selectedChain = await this.#ethereumProvider.request<Hex>({
109108
method: 'eth_chainId',
110109
params: [],
111110
});
@@ -121,7 +120,7 @@ export class EoaAccountController
121120
delegation,
122121
});
123122

124-
const signature = await this.#ethereumProvider.request({
123+
const signature = await this.#ethereumProvider.request<Hex>({
125124
method: 'eth_signTypedData_v4',
126125
params: [address, signArgs],
127126
});

packages/gator-permissions-snap/src/accountController/smartAccountController.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import type {
2525
SignDelegationOptions,
2626
FactoryArgs,
2727
} from './types';
28+
import { TokenMetadataClient } from 'src/core/types';
2829

2930
const GET_ENTROPY_SALT = '7715_permissions_provider_snap';
3031
const MULTISIG_THRESHOLD = 1n;
@@ -60,6 +61,7 @@ export class SmartAccountController
6061
snapsProvider: SnapsProvider;
6162
supportedChains?: SupportedChains;
6263
deploymentSalt: Hex;
64+
tokenMetadataClient: TokenMetadataClient;
6365
accountApiClient: AccountApiClient;
6466
}) {
6567
super(config);

packages/gator-permissions-snap/src/accountController/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type {
33
DeleGatorEnvironment,
44
} from '@metamask/delegation-toolkit';
55
import type { Address, Hex } from 'viem';
6-
import type { TokenBalanceAndMetadata } from '../clients/accountApiClient';
6+
import type { TokenBalanceAndMetadata } from '../core/types';
77

88
/**
99
* Base options required for account operations.

packages/gator-permissions-snap/src/clients/accountApiClient.ts

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { logger } from '@metamask/7715-permissions-shared/utils';
2-
import { IconUrls } from '../ui/iconConstant';
32
import { isAddressEqual, zeroAddress, type Address } from 'viem';
3+
import type { TokenBalanceAndMetadata } from '../core/types';
44

55
/**
66
* Response type for token balance data
@@ -28,13 +28,6 @@ type TokenBalanceResponse = {
2828
}[];
2929
};
3030

31-
export type TokenBalanceAndMetadata = {
32-
balance: bigint;
33-
decimals: number;
34-
symbol: string;
35-
iconUrl: string;
36-
};
37-
3831
/**
3932
* Class responsible for fetching account data from the Account API.
4033
*/
@@ -45,14 +38,29 @@ export class AccountApiClient {
4538

4639
readonly #baseUrl: string;
4740

48-
constructor(
49-
baseUrl: string,
50-
fetch: typeof globalThis.fetch = globalThis.fetch,
51-
) {
41+
constructor({
42+
baseUrl,
43+
fetch = globalThis.fetch,
44+
}: {
45+
baseUrl: string;
46+
fetch?: typeof globalThis.fetch;
47+
}) {
5248
this.#fetch = fetch;
5349
this.#baseUrl = baseUrl.replace(/\/+$/u, ''); // Remove trailing slashes
5450
}
5551

52+
/**
53+
* Checks if a chain ID is supported by the account API.
54+
* Currently only mainnet (chain ID 1) is supported.
55+
*
56+
* @param params - The parameters object
57+
* @param params.chainId - The chain ID to check
58+
* @returns True if the chain ID is supported, false otherwise
59+
*/
60+
public isChainIdSupported({ chainId }: { chainId: number }): boolean {
61+
return chainId === 1;
62+
}
63+
5664
/**
5765
* Fetch the token balance and metadata for a given account and token.
5866
*
@@ -128,21 +136,10 @@ export class AccountApiClient {
128136
throw new Error(message);
129137
}
130138

131-
// this is an awkward workaround. We cannot actually use the iconUrl from
132-
// the response, because we must have an SVG literal. The service returns a
133-
// png, and we cannot even fetch it due to CORs if it were svg.
134-
const iconUrl = ICON_URLS[balanceData.iconUrl] ?? IconUrls.notFound.token;
135-
136139
return {
137140
balance: BigInt(accountData.rawBalance),
138141
decimals: balanceData.decimals,
139142
symbol: balanceData.symbol,
140-
iconUrl,
141143
};
142144
}
143145
}
144-
145-
const ICON_URLS: Record<string, string> = {
146-
'https://dev-static.cx.metamask.io/api/v1/tokenIcons/1/0x0000000000000000000000000000000000000000.png':
147-
IconUrls.ethereum.token,
148-
};

0 commit comments

Comments
 (0)