Skip to content

Commit a0a3336

Browse files
authored
Fetch token metadata (#99)
* Add accountApiClient and corresponding tests to fetch account balance and metadata * Use accountApiClient within AccountController to fetch token metadata and balance - Introduce 'getTokenBalanceAndMetadata' to account controllers - Add placeholder icons for missing network/token SVGs - Replace hardcoded ETH token details in UI with dynamic values * 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 * Update native-token-periodic permission * Fix linting problems * Minor tidy ups to metadata client implementation - Introduce ACCOUNT_API_BASE_URL to snap config and enforce presence - Rename tokenMetadataClient to blockchainMetadataClient - Improve dynamic chain handling and call encoding in token metadata client - Add tests for BlockchainTokenMetadataClient * Remove errant console.logs from debugging * Update build-lint-test action - Add ACCOUNT_API_BASE_URL - Move configuration out of individual steps to avoid duplication * Ignore iconUrl received from AccountAPI * Decompose token balance and metadata out of account controller into TokenMetadataService. * Fix linting problems in tests
1 parent eda8860 commit a0a3336

34 files changed

Lines changed: 1379 additions & 233 deletions

.github/workflows/build-lint-test.yml

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@ name: Build, Lint, and Test
33
on:
44
workflow_call:
55

6+
env:
7+
SNAP_ENV: ${{ vars.SNAP_ENV }}
8+
PRICE_API_BASE_URL: ${{ vars.PRICE_API_BASE_URL }}
9+
STORE_PERMISSIONS_ENABLED: ${{ vars.STORE_PERMISSIONS_ENABLED }}
10+
USE_EOA_ACCOUNT: ${{ vars.USE_EOA_ACCOUNT }}
11+
ACCOUNT_API_BASE_URL: ${{ vars.ACCOUNT_API_BASE_URL }}
12+
613
jobs:
714
prepare:
815
name: Prepare
916
runs-on: ubuntu-latest
10-
env:
11-
SNAP_ENV: ${{ vars.SNAP_ENV }}
12-
PRICE_API_BASE_URL: ${{ vars.PRICE_API_BASE_URL }}
13-
STORE_PERMISSIONS_ENABLED: ${{ vars.STORE_PERMISSIONS_ENABLED }}
14-
USE_EOA_ACCOUNT: ${{ vars.USE_EOA_ACCOUNT }}
1517
strategy:
1618
matrix:
1719
node-version: [21.x]
@@ -32,11 +34,6 @@ jobs:
3234
validate-changelog:
3335
name: Validate changelog
3436
runs-on: ubuntu-latest
35-
env:
36-
SNAP_ENV: ${{ vars.SNAP_ENV }}
37-
PRICE_API_BASE_URL: ${{ vars.PRICE_API_BASE_URL }}
38-
STORE_PERMISSIONS_ENABLED: ${{ vars.STORE_PERMISSIONS_ENABLED }}
39-
USE_EOA_ACCOUNT: ${{ vars.USE_EOA_ACCOUNT }}
4037
needs:
4138
- prepare
4239
strategy:
@@ -59,11 +56,6 @@ jobs:
5956
build:
6057
name: Build
6158
runs-on: ubuntu-latest
62-
env:
63-
SNAP_ENV: ${{ vars.SNAP_ENV }}
64-
PRICE_API_BASE_URL: ${{ vars.PRICE_API_BASE_URL }}
65-
STORE_PERMISSIONS_ENABLED: ${{ vars.STORE_PERMISSIONS_ENABLED }}
66-
USE_EOA_ACCOUNT: ${{ vars.USE_EOA_ACCOUNT }}
6759
needs:
6860
- prepare
6961
strategy:
@@ -96,10 +88,6 @@ jobs:
9688
lint:
9789
name: Lint
9890
runs-on: ubuntu-latest
99-
env:
100-
SNAP_ENV: ${{ vars.SNAP_ENV }}
101-
PRICE_API_BASE_URL: ${{ vars.PRICE_API_BASE_URL }}
102-
STORE_PERMISSIONS_ENABLED: ${{ vars.STORE_PERMISSIONS_ENABLED }}
10391
needs:
10492
- prepare
10593
strategy:
@@ -122,11 +110,6 @@ jobs:
122110
test:
123111
name: Test
124112
runs-on: ubuntu-latest
125-
env:
126-
SNAP_ENV: ${{ vars.SNAP_ENV }}
127-
PRICE_API_BASE_URL: ${{ vars.PRICE_API_BASE_URL }}
128-
STORE_PERMISSIONS_ENABLED: ${{ vars.STORE_PERMISSIONS_ENABLED }}
129-
USE_EOA_ACCOUNT: ${{ vars.USE_EOA_ACCOUNT }}
130113
needs:
131114
- prepare
132115
- build

packages/gator-permissions-snap/.env.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ USE_EOA_ACCOUNT=false
1515
# Prod
1616
SNAP_ENV=production
1717
STORE_PERMISSIONS_ENABLED=false
18-
PRICE_API_BASE_URL=https://price.api.cx.metamask.io
18+
PRICE_API_BASE_URL=https://price.api.cx.metamask.io
19+
ACCOUNT_API_BASE_URL=https://account.api.cx.metamask.io

packages/gator-permissions-snap/snap.config.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const {
1010
PRICE_API_BASE_URL,
1111
STORE_PERMISSIONS_ENABLED,
1212
USE_EOA_ACCOUNT,
13+
ACCOUNT_API_BASE_URL,
1314
} = process.env;
1415

1516
if (!SNAP_ENV) {
@@ -36,9 +37,7 @@ if (
3637
}
3738

3839
if (!USE_EOA_ACCOUNT) {
39-
throw new Error(
40-
'STORE_PERMISSIONS_ENABLED must be set as an environment variable.',
41-
);
40+
throw new Error('USE_EOA_ACCOUNT must be set as an environment variable.');
4241
}
4342

4443
if (USE_EOA_ACCOUNT !== 'true' && USE_EOA_ACCOUNT !== 'false') {
@@ -47,6 +46,12 @@ if (USE_EOA_ACCOUNT !== 'true' && USE_EOA_ACCOUNT !== 'false') {
4746
);
4847
}
4948

49+
if (!ACCOUNT_API_BASE_URL) {
50+
throw new Error(
51+
'ACCOUNT_API_BASE_URL must be set as an environment variable.',
52+
);
53+
}
54+
5055
const config: SnapConfig = {
5156
bundler: 'webpack',
5257
input: resolve(__dirname, 'src/index.ts'),
@@ -62,6 +67,7 @@ const config: SnapConfig = {
6267
PRICE_API_BASE_URL,
6368
STORE_PERMISSIONS_ENABLED,
6469
USE_EOA_ACCOUNT,
70+
ACCOUNT_API_BASE_URL,
6571
},
6672
};
6773

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": "B/45l1lyLyqYX2GkYxvKAmCCWOCSu030Do+IEMdQV+c=",
10+
"shasum": "daaQiXVVVvJGgI2PHBl9UFJmPMxoie2tGD1TOxPIQmE=",
1111
"location": {
1212
"npm": {
1313
"filePath": "dist/bundle.js",

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type SupportedChainId = SupportedChains[number]['id'];
1414
* Base class for account controllers that provides common functionality.
1515
*/
1616
export abstract class BaseAccountController {
17-
#snapsProvider: SnapsProvider;
17+
readonly #snapsProvider: SnapsProvider;
1818

1919
protected supportedChains: SupportedChains;
2020

@@ -37,7 +37,7 @@ export abstract class BaseAccountController {
3737
snapsProvider: SnapsProvider;
3838
supportedChains?: SupportedChains;
3939
}) {
40-
// only validate if supportedChains is specified, as it will default to ALL_SUPPORTED_CHAINS
40+
// only validate if supportedChains is specified, as it will default to #allSupportedChains
4141
if (config.supportedChains) {
4242
this.#validateSupportedChains(config.supportedChains);
4343
}

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

Lines changed: 9 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ 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 type { Hex } from 'viem';
9+
import { type Address } from 'viem';
910

1011
import type { SupportedChains } from './baseAccountController';
1112
import { BaseAccountController } from './baseAccountController';
@@ -16,10 +17,6 @@ import type {
1617
FactoryArgs,
1718
} from './types';
1819

19-
export type EthereumProvider = {
20-
request: (args: { method: string; params?: any[] }) => Promise<any>;
21-
};
22-
2320
/**
2421
* Controls EOA account operations including address retrieval, delegation signing, and balance queries.
2522
*/
@@ -29,7 +26,7 @@ export class EoaAccountController
2926
{
3027
#accountAddress: Address | null = null;
3128

32-
#ethereumProvider: EthereumProvider;
29+
#ethereumProvider: SnapsEthereumProvider;
3330

3431
/**
3532
* Initializes a new EoaAccountController instance.
@@ -40,10 +37,11 @@ export class EoaAccountController
4037
*/
4138
constructor(config: {
4239
snapsProvider: SnapsProvider;
43-
ethereumProvider: EthereumProvider;
40+
ethereumProvider: SnapsEthereumProvider;
4441
supportedChains?: SupportedChains;
4542
}) {
4643
super(config);
44+
4745
this.#ethereumProvider = config.ethereumProvider;
4846
}
4947

@@ -58,7 +56,7 @@ export class EoaAccountController
5856
return this.#accountAddress;
5957
}
6058

61-
const accounts = await this.#ethereumProvider.request({
59+
const accounts = await this.#ethereumProvider.request<Hex[]>({
6260
method: 'eth_requestAccounts',
6361
});
6462

@@ -102,7 +100,7 @@ export class EoaAccountController
102100

103101
const address = await this.#getAccountAddress();
104102

105-
const selectedChain = await this.#ethereumProvider.request({
103+
const selectedChain = await this.#ethereumProvider.request<Hex>({
106104
method: 'eth_chainId',
107105
params: [],
108106
});
@@ -118,7 +116,7 @@ export class EoaAccountController
118116
delegation,
119117
});
120118

121-
const signature = await this.#ethereumProvider.request({
119+
const signature = await this.#ethereumProvider.request<Hex>({
122120
method: 'eth_signTypedData_v4',
123121
params: [address, signArgs],
124122
});
@@ -198,30 +196,6 @@ export class EoaAccountController
198196
};
199197
}
200198

201-
/**
202-
* Retrieves the balance of the EOA account.
203-
* @param options - The options object containing chain information.
204-
* @returns The account balance in hex format.
205-
*/
206-
public async getAccountBalance(options: AccountOptionsBase): Promise<Hex> {
207-
logger.debug('eoaAccountController:getAccountBalance()');
208-
209-
this.assertIsSupportedChainId(options.chainId);
210-
211-
const address = await this.#getAccountAddress();
212-
213-
const provider = this.createExperimentalProviderRequestProvider(
214-
options.chainId,
215-
);
216-
217-
const balance = await provider.request({
218-
method: 'eth_getBalance',
219-
params: [address, 'latest'],
220-
});
221-
222-
return balance as Hex;
223-
}
224-
225199
/**
226200
* Retrieves the delegation manager address.
227201
* @param options - The options object containing chain information.

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

Lines changed: 8 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -207,40 +207,24 @@ export class SmartAccountController
207207
}
208208

209209
/**
210-
* Retrieves the balance of the smart account.
210+
* Retrieves the environment for the current account.
211211
*
212212
* @param options - The base account options including chainId.
213-
* @returns A promise resolving to the account balance as a hex string.
213+
* @returns A promise resolving to a DeleGatorEnvironment.
214214
*/
215-
public async getAccountBalance(options: AccountOptionsBase): Promise<Hex> {
216-
logger.debug('accountController:getAccountBalance()');
217-
218-
const { chainId } = options;
215+
public async getEnvironment(
216+
options: AccountOptionsBase,
217+
): Promise<DeleGatorEnvironment> {
218+
logger.debug('accountController:getEnvironment()');
219219

220220
const smartAccount = await this.#getMetaMaskSmartAccount(options);
221221

222222
logger.debug(
223-
'accountController:getAccountBalance() - smartAccount resolved',
223+
'accountController:getEnvironment() - smartAccount resolved',
224224
smartAccount,
225225
);
226226

227-
this.assertIsSupportedChainId(chainId);
228-
229-
const provider = this.createExperimentalProviderRequestProvider(chainId);
230-
231-
const accountAddress = await smartAccount.getAddress();
232-
233-
const balance = await provider.request({
234-
method: 'eth_getBalance',
235-
params: [accountAddress, 'latest'],
236-
});
237-
238-
logger.debug(
239-
'accountController:getAccountBalance() - balance resolved',
240-
balance,
241-
);
242-
243-
return balance as Hex;
227+
return smartAccount.environment;
244228
}
245229

246230
/**
@@ -272,25 +256,4 @@ export class SmartAccountController
272256

273257
return { ...delegation, signature };
274258
}
275-
276-
/**
277-
* Retrieves the environment for the current account.
278-
*
279-
* @param options - The base account options including chainId.
280-
* @returns A promise resolving to a DeleGatorEnvironment.
281-
*/
282-
public async getEnvironment(
283-
options: AccountOptionsBase,
284-
): Promise<DeleGatorEnvironment> {
285-
logger.debug('accountController:getEnvironment()');
286-
287-
const smartAccount = await this.#getMetaMaskSmartAccount(options);
288-
289-
logger.debug(
290-
'accountController:getEnvironment() - smartAccount resolved',
291-
smartAccount,
292-
);
293-
294-
return smartAccount.environment;
295-
}
296259
}

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,6 @@ export type AccountController = {
4646
*/
4747
getAccountMetadata(options: AccountOptionsBase): Promise<FactoryArgs>;
4848

49-
/**
50-
* Retrieves the balance of the smart account.
51-
*/
52-
getAccountBalance(options: AccountOptionsBase): Promise<Hex>;
53-
5449
/**
5550
* Retrieves the delegation manager address for the current account.
5651
*/

0 commit comments

Comments
 (0)