Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions packages/money-account-upgrade-controller/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,15 @@
* https://jestjs.io/docs/configuration
*/

const merge = require('deepmerge');
const path = require('path');

const baseConfig = require('../../jest.config.packages');

const displayName = path.basename(__dirname);

module.exports = merge(baseConfig, {
// The display name when running multiple projects
module.exports = {
...baseConfig,
displayName,

// An object that configures minimum threshold enforcement for coverage results
coverageThreshold: {
global: {
branches: 100,
Expand All @@ -23,4 +20,13 @@ module.exports = merge(baseConfig, {
statements: 100,
},
},
});
// The base config's `^@metamask/(.+)$` mapper rewrites every `@metamask/*`
// import without honouring the package.json `exports` field, which breaks
// subpath imports like `@metamask/smart-accounts-kit/utils`. Resolve those
// explicitly here, before falling through to the base mapper.
moduleNameMapper: {
'^@metamask/smart-accounts-kit/utils$':
require.resolve('@metamask/smart-accounts-kit/utils'),
...baseConfig.moduleNameMapper,
},
};
6 changes: 5 additions & 1 deletion packages/money-account-upgrade-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,16 @@
"test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch"
},
"dependencies": {
"@metamask/authenticated-user-storage": "^1.0.0",
"@metamask/base-controller": "^9.1.0",
"@metamask/chomp-api-service": "^3.0.0",
"@metamask/keyring-controller": "^25.3.0",
"@metamask/messenger": "^1.2.0",
"@metamask/network-controller": "^30.1.0",
"@metamask/utils": "^11.9.0"
"@metamask/smart-accounts-kit": "^1.3.0",
"@metamask/utils": "^11.9.0",
"uuid": "^8.3.2",
"viem": "^2.46.2"
},
"devDependencies": {
"@metamask/auto-changelog": "^6.1.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ const MOCK_CONFIG: UpgradeConfig = {

const MOCK_INIT_CONFIG = {
delegatorImplAddress: MOCK_CONFIG.delegatorImplAddress,
musdTokenAddress: MOCK_CONFIG.musdTokenAddress,
redeemerEnforcer: MOCK_CONFIG.redeemerEnforcer,
valueLteEnforcer: MOCK_CONFIG.valueLteEnforcer,
};
Expand All @@ -41,7 +40,7 @@ const MOCK_SERVICE_DETAILS_RESPONSE = {
vedaProtocol: {
supportedTokens: [
{
tokenAddress: MOCK_CONFIG.erc20TransferAmountEnforcer,
tokenAddress: MOCK_CONFIG.musdTokenAddress,
tokenDecimals: 18,
},
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { AuthenticatedUserStorageServiceListDelegationsAction } from '@metamask/authenticated-user-storage';
import type {
ControllerGetStateAction,
ControllerStateChangedEvent,
Expand All @@ -8,10 +9,12 @@ import type {
ChompApiServiceAssociateAddressAction,
ChompApiServiceCreateUpgradeAction,
ChompApiServiceGetServiceDetailsAction,
ChompApiServiceVerifyDelegationAction,
} from '@metamask/chomp-api-service';
import type {
KeyringControllerSignEip7702AuthorizationAction,
KeyringControllerSignPersonalMessageAction,
KeyringControllerSignTypedMessageAction,
} from '@metamask/keyring-controller';
import type { Messenger } from '@metamask/messenger';
import type {
Expand All @@ -22,6 +25,7 @@ import type { Hex } from '@metamask/utils';

import type { MoneyAccountUpgradeControllerMethodActions } from './MoneyAccountUpgradeController-method-action-types';
import { associateAddressStep } from './steps/associate-address';
import { buildDelegationStep } from './steps/build-delegations';
import { eip7702AuthorizationStep } from './steps/eip-7702-authorization';
import type { Step } from './steps/step';
import type { InitConfig } from './types';
Expand Down Expand Up @@ -49,10 +53,13 @@ type AllowedActions =
| ChompApiServiceAssociateAddressAction
| ChompApiServiceCreateUpgradeAction
| ChompApiServiceGetServiceDetailsAction
| ChompApiServiceVerifyDelegationAction
| KeyringControllerSignEip7702AuthorizationAction
| KeyringControllerSignPersonalMessageAction
| KeyringControllerSignTypedMessageAction
| NetworkControllerFindNetworkClientIdByChainIdAction
| NetworkControllerGetNetworkClientByIdAction;
| NetworkControllerGetNetworkClientByIdAction
| AuthenticatedUserStorageServiceListDelegationsAction;

export type MoneyAccountUpgradeControllerStateChangedEvent =
ControllerStateChangedEvent<
Expand All @@ -79,9 +86,19 @@ export class MoneyAccountUpgradeController extends BaseController<
MoneyAccountUpgradeControllerState,
MoneyAccountUpgradeControllerMessenger
> {
#config?: { chainId: Hex; delegatorImplAddress: Hex };

readonly #steps: Step[] = [associateAddressStep, eip7702AuthorizationStep];
#config?: {
chainId: Hex;
delegateAddress: Hex;
delegatorImplAddress: Hex;
musdTokenAddress: Hex;
vedaVaultAdapterAddress: Hex;
};

readonly #steps: Step[] = [
associateAddressStep,
eip7702AuthorizationStep,
buildDelegationStep,
];

/**
* Constructor for the MoneyAccountUpgradeController.
Expand Down Expand Up @@ -140,7 +157,10 @@ export class MoneyAccountUpgradeController extends BaseController<

this.#config = {
chainId,
delegateAddress: chain.autoDepositDelegate,
delegatorImplAddress: initConfig.delegatorImplAddress,
musdTokenAddress: vedaProtocol.supportedTokens[0].tokenAddress,
vedaVaultAdapterAddress: vedaProtocol.adapterAddress,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import { associateAddressStep } from './associate-address';

const MOCK_ADDRESS = '0xabcdef1234567890abcdef1234567890abcdef12' as Hex;
const MOCK_CHAIN_ID = '0x1' as Hex;
const MOCK_DELEGATE = '0x1111111111111111111111111111111111111111' as Hex;
const MOCK_DELEGATOR_IMPL = '0x2222222222222222222222222222222222222222' as Hex;
const MOCK_TOKEN = '0x3333333333333333333333333333333333333333' as Hex;
const MOCK_VAULT_ADAPTER = '0x4444444444444444444444444444444444444444' as Hex;
const MOCK_SIGNATURE = '0xdeadbeefcafebabe';
const MOCK_NOW = new Date('2026-04-17T12:00:00.000Z').getTime();

Expand Down Expand Up @@ -64,6 +67,20 @@ function setup(): {
return { messenger, mocks };
}

async function run(
messenger: MoneyAccountUpgradeControllerMessenger,
): ReturnType<typeof associateAddressStep.run> {
return associateAddressStep.run({
messenger,
address: MOCK_ADDRESS,
chainId: MOCK_CHAIN_ID,
delegateAddress: MOCK_DELEGATE,
delegatorImplAddress: MOCK_DELEGATOR_IMPL,
musdTokenAddress: MOCK_TOKEN,
vedaVaultAdapterAddress: MOCK_VAULT_ADAPTER,
});
}

describe('associateAddressStep', () => {
beforeEach(() => {
jest.useFakeTimers();
Expand All @@ -81,12 +98,7 @@ describe('associateAddressStep', () => {
it('signs the CHOMP Authentication message with the given address', async () => {
const { messenger, mocks } = setup();

await associateAddressStep.run({
messenger,
address: MOCK_ADDRESS,
chainId: MOCK_CHAIN_ID,
delegatorImplAddress: MOCK_DELEGATOR_IMPL,
});
await run(messenger);

expect(mocks.signPersonalMessage).toHaveBeenCalledWith({
data: `CHOMP Authentication ${MOCK_NOW}`,
Expand All @@ -97,12 +109,7 @@ describe('associateAddressStep', () => {
it('submits the signature, timestamp, and address to the CHOMP API', async () => {
const { messenger, mocks } = setup();

await associateAddressStep.run({
messenger,
address: MOCK_ADDRESS,
chainId: MOCK_CHAIN_ID,
delegatorImplAddress: MOCK_DELEGATOR_IMPL,
});
await run(messenger);

expect(mocks.associateAddress).toHaveBeenCalledWith({
signature: MOCK_SIGNATURE,
Expand All @@ -114,12 +121,7 @@ describe('associateAddressStep', () => {
it('returns "completed" when CHOMP creates the association', async () => {
const { messenger } = setup();

const result = await associateAddressStep.run({
messenger,
address: MOCK_ADDRESS,
chainId: MOCK_CHAIN_ID,
delegatorImplAddress: MOCK_DELEGATOR_IMPL,
});
const result = await run(messenger);

expect(result).toBe('completed');
});
Expand All @@ -131,12 +133,7 @@ describe('associateAddressStep', () => {
status: 'active',
});

const result = await associateAddressStep.run({
messenger,
address: MOCK_ADDRESS,
chainId: MOCK_CHAIN_ID,
delegatorImplAddress: MOCK_DELEGATOR_IMPL,
});
const result = await run(messenger);

expect(result).toBe('already-done');
});
Expand All @@ -145,28 +142,14 @@ describe('associateAddressStep', () => {
const { messenger, mocks } = setup();
mocks.signPersonalMessage.mockRejectedValue(new Error('signing failed'));

await expect(
associateAddressStep.run({
messenger,
address: MOCK_ADDRESS,
chainId: MOCK_CHAIN_ID,
delegatorImplAddress: MOCK_DELEGATOR_IMPL,
}),
).rejects.toThrow('signing failed');
await expect(run(messenger)).rejects.toThrow('signing failed');
expect(mocks.associateAddress).not.toHaveBeenCalled();
});

it('propagates errors from the CHOMP API', async () => {
const { messenger, mocks } = setup();
mocks.associateAddress.mockRejectedValue(new Error('api failed'));

await expect(
associateAddressStep.run({
messenger,
address: MOCK_ADDRESS,
chainId: MOCK_CHAIN_ID,
delegatorImplAddress: MOCK_DELEGATOR_IMPL,
}),
).rejects.toThrow('api failed');
await expect(run(messenger)).rejects.toThrow('api failed');
});
});
Loading
Loading