Skip to content

Commit ba4cf20

Browse files
authored
Reduce usage of @metamask/delegation-toolkit and viem (#107)
* Initial pass at removing @metamask/delegation-toolkit. Dependency remains for SmartContractAccountManager. Fix erc20PeriodicTransfer * Add unit formatting utils. Rename balance utils to value utils. * Remove viem Abi coding, remove viem assertions * Add chainMetadata, resolve lint errors * Fix bug where invalid caveat was added to native token stream permission * Minor improvements: - use string concatenation to produce storage key in profile sync - introduce ZERO_ADDRESS constant that is shared between consumers in gator snap * Fix bug in value parsing where empty part resulted in error. Improve type alignment in SmartAccountController (although the types _were_ identical, it was slightly confusing).
1 parent 7fa5f96 commit ba4cf20

78 files changed

Lines changed: 7577 additions & 1307 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/gator-permissions-snap/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
"test": "jest"
4848
},
4949
"dependencies": {
50+
"@metamask/abi-utils": "^3.0.0",
51+
"@metamask/delegation-core": "0.1.0",
5052
"@metamask/delegation-toolkit": "0.10.2",
5153
"@metamask/profile-sync-controller": "^12.0.0",
5254
"@metamask/snaps-sdk": "^6.17.1",

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": "tmWf9Cs6ZEvAWQ3dATmdBU8nIH8BjJsUHuJfaRcnsZs=",
10+
"shasum": "e/MzuAeBepqg3OfGRH9GUTee7E1tvxWrwDIs9xKk+78=",
1111
"location": {
1212
"npm": {
1313
"filePath": "dist/bundle.js",

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

Lines changed: 18 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,15 @@
11
import { logger } from '@metamask/7715-permissions-shared/utils';
2-
import { CHAIN_ID as ChainsWithDelegatorDeployed } from '@metamask/delegation-toolkit';
32
import type { SnapsProvider } from '@metamask/snaps-sdk';
4-
import * as chains from 'viem/chains';
53

6-
export type SupportedChains =
7-
(typeof chains)[keyof typeof ChainsWithDelegatorDeployed &
8-
keyof typeof chains][];
9-
10-
// all of the chainIds that have delegator contracts deployed
11-
type SupportedChainId = SupportedChains[number]['id'];
4+
import { getChainMetadata } from '../core/chainMetadata';
125

136
/**
147
* Base class for account controllers that provides common functionality.
158
*/
169
export abstract class BaseAccountController {
1710
readonly #snapsProvider: SnapsProvider;
1811

19-
protected supportedChains: SupportedChains;
20-
21-
// the intersection between chains supported by viem, and chains supported by the delegator contracts
22-
// chains is asserted to any here due to the inability to infer the namespace of the global import
23-
static #allSupportedChains = Object.keys(chains)
24-
.filter((name) => name in ChainsWithDelegatorDeployed)
25-
.map(
26-
(name) => (chains as any)[name as keyof typeof chains],
27-
) as SupportedChains;
12+
protected supportedChains: readonly number[];
2813

2914
/**
3015
* Initializes a new BaseAccountController instance.
@@ -35,16 +20,12 @@ export abstract class BaseAccountController {
3520
*/
3621
constructor(config: {
3722
snapsProvider: SnapsProvider;
38-
supportedChains?: SupportedChains;
23+
supportedChains: readonly number[];
3924
}) {
40-
// only validate if supportedChains is specified, as it will default to #allSupportedChains
41-
if (config.supportedChains) {
42-
this.#validateSupportedChains(config.supportedChains);
43-
}
25+
this.#validateSupportedChains(config.supportedChains);
4426

4527
this.#snapsProvider = config.snapsProvider;
46-
this.supportedChains =
47-
config.supportedChains ?? BaseAccountController.#allSupportedChains;
28+
this.supportedChains = config.supportedChains;
4829
}
4930

5031
/**
@@ -53,35 +34,22 @@ export abstract class BaseAccountController {
5334
* @param supportedChains - The chains to validate.
5435
* @throws If no chains are specified or if any chain is not supported.
5536
*/
56-
#validateSupportedChains(supportedChains: SupportedChains) {
37+
#validateSupportedChains(supportedChains: readonly number[]) {
5738
if (supportedChains.length === 0) {
5839
logger.error('No supported chains specified');
5940
throw new Error('No supported chains specified');
6041
}
6142

62-
// Get chain names from config and check if they're supported by delegator
63-
const configuredChains = Object.keys(chains)
64-
.filter((name) => {
65-
// assert chains to any here due to the inability to infer the namespace of the global import
66-
const chain = (chains as any)[name as keyof typeof chains];
67-
return supportedChains.some(
68-
(supportedChain) => supportedChain.id === chain.id,
69-
);
70-
})
71-
.map((name) => name.toLowerCase());
72-
73-
const chainsWithDelegatorDeployed = Object.keys(
74-
ChainsWithDelegatorDeployed,
75-
).map((name) => name.toLowerCase());
76-
77-
const unsupportedChains = configuredChains.filter(
78-
(chain) => !chainsWithDelegatorDeployed.includes(chain),
79-
);
80-
81-
if (unsupportedChains.length > 0) {
82-
logger.error('Unsupported chains specified', unsupportedChains);
43+
// ensure that there is chain metadata for all specified chains
44+
try {
45+
supportedChains.map((chainId) => getChainMetadata({ chainId }));
46+
} catch (error) {
47+
logger.error('Unsupported chains specified', {
48+
supportedChains,
49+
error,
50+
});
8351
throw new Error(
84-
`Unsupported chains specified: ${unsupportedChains.join(', ')}`,
52+
`Unsupported chains specified: ${supportedChains.join(', ')}`,
8553
);
8654
}
8755
}
@@ -92,10 +60,8 @@ export abstract class BaseAccountController {
9260
* @param chainId - The chain ID to validate.
9361
* @throws If the chain ID is not supported.
9462
*/
95-
protected assertIsSupportedChainId(
96-
chainId: number,
97-
): asserts chainId is SupportedChainId {
98-
if (!this.supportedChains.some((chain) => chain.id === chainId)) {
63+
protected assertIsSupportedChainId(chainId: number) {
64+
if (!this.supportedChains.includes(chainId)) {
9965
logger.error(
10066
'accountController:assertIsSupportedChainId() - unsupported chainId',
10167
{
@@ -112,9 +78,7 @@ export abstract class BaseAccountController {
11278
* @param chainId - The chain ID for the provider.
11379
* @returns A provider object with a request method.
11480
*/
115-
protected createExperimentalProviderRequestProvider(
116-
chainId: SupportedChainId,
117-
) {
81+
protected createExperimentalProviderRequestProvider(chainId: number) {
11882
return {
11983
request: async (request: { method: string; params?: unknown[] }) => {
12084
logger.debug(

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

Lines changed: 13 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
import { logger } from '@metamask/7715-permissions-shared/utils';
2-
import {
3-
getDeleGatorEnvironment,
4-
type Delegation,
5-
type DeleGatorEnvironment,
6-
} from '@metamask/delegation-toolkit';
2+
import { type Hex, type Delegation } from '@metamask/delegation-core';
73
import type { SnapsEthereumProvider, SnapsProvider } from '@metamask/snaps-sdk';
8-
import type { Hex } from 'viem';
9-
import { type Address } from 'viem';
104

11-
import type { SupportedChains } from './baseAccountController';
5+
import { getChainMetadata } from '../core/chainMetadata';
126
import { BaseAccountController } from './baseAccountController';
137
import type {
148
AccountController,
@@ -24,7 +18,7 @@ export class EoaAccountController
2418
extends BaseAccountController
2519
implements AccountController
2620
{
27-
#accountAddress: Address | null = null;
21+
#accountAddress: Hex | null = null;
2822

2923
#ethereumProvider: SnapsEthereumProvider;
3024

@@ -38,7 +32,7 @@ export class EoaAccountController
3832
constructor(config: {
3933
snapsProvider: SnapsProvider;
4034
ethereumProvider: SnapsEthereumProvider;
41-
supportedChains?: SupportedChains;
35+
supportedChains: readonly number[];
4236
}) {
4337
super(config);
4438

@@ -49,7 +43,7 @@ export class EoaAccountController
4943
* Gets the connected account address, requesting access if needed.
5044
* @returns The account address.
5145
*/
52-
async #getAccountAddress(): Promise<Address> {
46+
async #getAccountAddress(): Promise<Hex> {
5347
logger.debug('eoaAccountController:#getAccountAddress()');
5448

5549
if (this.#accountAddress) {
@@ -64,7 +58,8 @@ export class EoaAccountController
6458
throw new Error('No accounts found');
6559
}
6660

67-
this.#accountAddress = accounts[0] as Address;
61+
this.#accountAddress = accounts[0] as Hex;
62+
6863
return this.#accountAddress;
6964
}
7065

@@ -76,7 +71,7 @@ export class EoaAccountController
7671
*/
7772
public async getAccountAddress({
7873
chainId,
79-
}: AccountOptionsBase): Promise<Address> {
74+
}: AccountOptionsBase): Promise<Hex> {
8075
logger.debug('eoaAccountController:getAccountAddress()');
8176

8277
this.assertIsSupportedChainId(chainId);
@@ -109,7 +104,10 @@ export class EoaAccountController
109104
throw new Error('Selected chain does not match the requested chain');
110105
}
111106

112-
const delegationManager = await this.getDelegationManager(options);
107+
const {
108+
contracts: { delegationManager },
109+
} = getChainMetadata({ chainId });
110+
113111
const signArgs = this.#getSignDelegationArgs({
114112
chainId,
115113
delegationManager,
@@ -137,7 +135,7 @@ export class EoaAccountController
137135
delegation,
138136
}: {
139137
chainId: number;
140-
delegationManager: Address;
138+
delegationManager: Hex;
141139
delegation: Omit<Delegation, 'signature'>;
142140
}) {
143141
logger.debug('eoaAccountController:#getSignDelegationArgs()');
@@ -195,37 +193,4 @@ export class EoaAccountController
195193
factoryData: undefined,
196194
};
197195
}
198-
199-
/**
200-
* Retrieves the delegation manager address.
201-
* @param options - The options object containing chain information.
202-
* @returns The delegation manager address.
203-
*/
204-
public async getDelegationManager(
205-
options: AccountOptionsBase,
206-
): Promise<Address> {
207-
logger.debug('eoaAccountController:getDelegationManager()');
208-
209-
const { DelegationManager } = await this.getEnvironment(options);
210-
211-
return DelegationManager;
212-
}
213-
214-
/**
215-
* Retrieves the environment for the current account.
216-
* @param options0 - The options object containing chain information.
217-
* @param options0.chainId - The ID of the blockchain chain.
218-
* @returns The DeleGator environment configuration.
219-
*/
220-
public async getEnvironment({
221-
chainId,
222-
}: AccountOptionsBase): Promise<DeleGatorEnvironment> {
223-
logger.debug('eoaAccountController:getEnvironment()');
224-
225-
this.assertIsSupportedChainId(chainId);
226-
227-
const environment = getDeleGatorEnvironment(chainId);
228-
229-
return environment;
230-
}
231196
}

0 commit comments

Comments
 (0)