Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 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
3 changes: 2 additions & 1 deletion packages/snap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
},
"dependencies": {
"@metamask/snaps-sdk": "^6.10.0",
"ethers": "6.13.5"
"ethers": "6.13.5",
"genlayer-js": "0.11.2"
},
"devDependencies": {
"@jest/globals": "^29.5.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/snap/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/yeagerai/genlayer-wallet.git"
},
"source": {
"shasum": "Tm5p6ufbiQHZ2cOoBfl9XlhT4DJpnq3wZBzepoxOJwI=",
"shasum": "eY80XAM15OdmyAec7lzqcy7C3T6bQ611scgsLt6STec=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
62 changes: 49 additions & 13 deletions packages/snap/src/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
// Mock modules before importing
import { installSnap } from '@metamask/snaps-jest';
import { UserInputEventType } from '@metamask/snaps-sdk';

import { onTransaction, onUserInput } from '.';
import type { AdvancedOptionsFormState } from './components';
import { StateManager } from './libs/StateManager';
import { getTransactionStorageKey } from './transactions/transaction';

jest.mock('genlayer-js', () => ({
abi: {
calldata: {
decode: jest.fn(),
},
},
chains: {
localnet: {
consensusMainContract: {
abi: [],
},
},
},
}));

jest.mock('ethers', () => ({
Interface: jest.fn(),
decodeRlp: jest.fn(),
getBytes: jest.fn(),
}));

jest.mock('./libs/StateManager');
jest.mock('./transactions/transaction');

describe('Snap Handlers', () => {
let snap: any;
Expand All @@ -22,16 +46,26 @@ describe('Snap Handlers', () => {
});

describe('onTransaction handler', () => {
it('should set currentTo and return the interface id', async () => {
const transaction = { to: '0x123456', value: '0xabc' };
it('should set currentStorageKey and return the interface id', async () => {
const transaction = {
to: '0x123456',
value: '0xabc',
data: '0xa9059cbb00000000',
};
const mockStorageKey = '0x123456_a9059cbb';

(getTransactionStorageKey as jest.Mock).mockReturnValue(mockStorageKey);
(StateManager.set as jest.Mock).mockResolvedValue(undefined);
jest.spyOn(snap, 'request').mockResolvedValue('test-interface-id');

const result = await onTransaction({ transaction } as Parameters<
typeof onTransaction
>[0]);

expect(getTransactionStorageKey).toHaveBeenCalledWith(transaction);
expect(StateManager.set).toHaveBeenCalledWith(
'currentTo',
transaction.to,
'currentStorageKey',
mockStorageKey,
);
expect(result).toEqual({ id: 'test-interface-id' });
});
Expand All @@ -40,6 +74,7 @@ describe('Snap Handlers', () => {
describe('onUserInput handler', () => {
it('should handle an InputChangeEvent for "number-of-appeals"', async () => {
const interfaceId = 'interface-id-2';
const mockStorageKey = '0xabcdef_a9059cbb';
const event = {
type: UserInputEventType.InputChangeEvent,
name: 'number-of-appeals',
Expand All @@ -48,10 +83,10 @@ describe('Snap Handlers', () => {
const getMock = jest
.spyOn(StateManager, 'get')
.mockImplementation(async (key: string | undefined) => {
if (key === 'currentTo') {
return '0xABCDEF';
if (key === 'currentStorageKey') {
return mockStorageKey;
}
if (key === '0xABCDEF') {
if (key === mockStorageKey) {
return { 'number-of-appeals': '2' };
}
return {};
Expand All @@ -62,8 +97,8 @@ describe('Snap Handlers', () => {
await onUserInput({ id: interfaceId, event } as Parameters<
typeof onUserInput
>[0]);
expect(getMock).toHaveBeenCalledWith('currentTo');
expect(getMock).toHaveBeenCalledWith('0xABCDEF');
expect(getMock).toHaveBeenCalledWith('currentStorageKey');
expect(getMock).toHaveBeenCalledWith(mockStorageKey);
expect(requestMock).toHaveBeenCalledWith({
method: 'snap_updateInterface',
params: {
Expand All @@ -77,6 +112,7 @@ describe('Snap Handlers', () => {

it('should handle a FormSubmitEvent for "advanced-options-form"', async () => {
const interfaceId = 'interface-id-3';
const mockStorageKey = '0xabcdef_a9059cbb';
const advancedOptionsData: AdvancedOptionsFormState = {
'leader-timeout-input': '60',
'validator-timeout-input': '30',
Expand All @@ -93,8 +129,8 @@ describe('Snap Handlers', () => {
const getMock = jest
.spyOn(StateManager, 'get')
.mockImplementation(async (key: string | undefined) => {
if (key === 'currentTo') {
return '0xABCDEF';
if (key === 'currentStorageKey') {
return mockStorageKey;
}
return {};
});
Expand All @@ -107,8 +143,8 @@ describe('Snap Handlers', () => {
await onUserInput({ id: interfaceId, event } as unknown as Parameters<
typeof onUserInput
>[0]);
expect(getMock).toHaveBeenCalledWith('currentTo');
expect(setMock).toHaveBeenCalledWith('0xABCDEF', advancedOptionsData);
expect(getMock).toHaveBeenCalledWith('currentStorageKey');
expect(setMock).toHaveBeenCalledWith(mockStorageKey, advancedOptionsData);
expect(requestMock).toHaveBeenCalledWith({
method: 'snap_updateInterface',
params: {
Expand Down
20 changes: 13 additions & 7 deletions packages/snap/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import { UserInputEventType } from '@metamask/snaps-sdk';
import type { AdvancedOptionsFormState } from './components';
import { AdvancedOptionsForm, TransactionConfig } from './components';
import { StateManager } from './libs/StateManager';
import { getTransactionStorageKey } from './transactions/transaction';

export const onTransaction: OnTransactionHandler = async ({ transaction }) => {
await StateManager.set('currentTo', transaction.to ?? 'default');
const storageKey = getTransactionStorageKey(transaction);
await StateManager.set('currentStorageKey', storageKey);

const interfaceId = await snap.request({
method: 'snap_createInterface',
Expand All @@ -27,9 +29,10 @@ export const onUserInput: OnUserInputHandler = async ({ id, event }) => {
event.type === UserInputEventType.InputChangeEvent &&
event.name === 'number-of-appeals'
) {
const currentTo = await StateManager.get('currentTo');
const persistedData = (await StateManager.get(currentTo)) || {};
const currentStorageKey = await StateManager.get('currentStorageKey');
const persistedData = (await StateManager.get(currentStorageKey)) || {};
persistedData['number-of-appeals'] = event.value as string;

await snap.request({
method: 'snap_updateInterface',
params: {
Expand All @@ -38,6 +41,7 @@ export const onUserInput: OnUserInputHandler = async ({ id, event }) => {
},
});
}

if (event.type === UserInputEventType.ButtonClickEvent) {
switch (event.name) {
case 'cancel_config':
Expand All @@ -52,11 +56,12 @@ export const onUserInput: OnUserInputHandler = async ({ id, event }) => {

case 'advanced_options':
// eslint-disable-next-line no-case-declarations
const currentTo = await StateManager.get('currentTo');
const currentStorageKey = await StateManager.get('currentStorageKey');
// eslint-disable-next-line no-case-declarations
const persistedData = (await StateManager.get(
currentTo,
currentStorageKey,
)) as AdvancedOptionsFormState;

await snap.request({
method: 'snap_updateInterface',
params: {
Expand All @@ -75,9 +80,10 @@ export const onUserInput: OnUserInputHandler = async ({ id, event }) => {
event.type === UserInputEventType.FormSubmitEvent &&
event.name === 'advanced-options-form'
) {
const currentTo = await StateManager.get('currentTo');
const currentStorageKey = await StateManager.get('currentStorageKey');
const value = event.value as AdvancedOptionsFormState;
await StateManager.set(currentTo, value);
await StateManager.set(currentStorageKey, value);

await snap.request({
method: 'snap_updateInterface',
params: {
Expand Down
3 changes: 1 addition & 2 deletions packages/snap/src/libs/StateManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ export class StateManager {
method: 'snap_manageState',
params: { operation: 'get' },
})) as Record<string, any> | null;

return state && key in state ? state[key] : undefined;
return state && key in state ? state[key] : null;
}

static async set(key: string, value: any): Promise<void> {
Expand Down
Loading