From 558a90aafa789051849e8e81c412308b4d623ddd Mon Sep 17 00:00:00 2001 From: Dhruv-Mishra Date: Wed, 8 Jan 2025 01:58:41 +0530 Subject: [PATCH 1/9] Added Account Typeguard, allowed address input --- src/account/utils.ts | 24 ++++++++++++++++++++++++ src/module/smart-sessions/usage.ts | 9 +++++---- 2 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 src/account/utils.ts diff --git a/src/account/utils.ts b/src/account/utils.ts new file mode 100644 index 0000000..19612aa --- /dev/null +++ b/src/account/utils.ts @@ -0,0 +1,24 @@ +import { Account, AccountType } from './types'; + +export function isAccount(obj: unknown): obj is Account { + const account = obj as Account; + return ( + typeof obj === 'object' && + obj !== null && + typeof account.address === 'string' && + account.address.startsWith('0x') && + (account.initCode === undefined || + account.initCode !== undefined && + typeof account.initCode === 'string' && + account.address.startsWith('0x')) && + typeof account.type === 'string' && + isAccountType(account.type) && + Array.isArray(account.deployedOnChains) && + account.deployedOnChains.every(chainId => typeof chainId === 'number') + ); +} + +function isAccountType(value: unknown): value is AccountType { + const validTypes: AccountType[] = ['erc7579-implementation', 'kernel', 'safe', 'nexus']; + return typeof value === 'string' && validTypes.includes(value as AccountType); +} diff --git a/src/module/smart-sessions/usage.ts b/src/module/smart-sessions/usage.ts index d660b18..8321e76 100644 --- a/src/module/smart-sessions/usage.ts +++ b/src/module/smart-sessions/usage.ts @@ -25,6 +25,7 @@ import { } from './types' import { LibZip } from 'solady' import { Account, AccountType, Execution } from '../../account' +import { isAccount } from 'src/account/utils' export const getPermissionId = ({ session }: { session: Session }): Hex => { return keccak256( @@ -68,14 +69,14 @@ export const getSessionNonce = async ({ permissionId, }: { client: PublicClient - account: Account + account: Account | Address permissionId: Hex }) => { return (await client.readContract({ address: SMART_SESSIONS_ADDRESS, abi, functionName: 'getNonce', - args: [permissionId, account.address], + args: [permissionId, isAccount(account) ? account.address : account], })) as bigint } @@ -175,14 +176,14 @@ export const isSessionEnabled = async ({ permissionId, }: { client: PublicClient - account: Account + account: Account | Address permissionId: Hex }) => { return (await client.readContract({ address: SMART_SESSIONS_ADDRESS, abi, functionName: 'isPermissionEnabled', - args: [permissionId, account.address], + args: [permissionId, isAccount(account) ? account.address : account], })) as boolean } From 19bfe98e22b29aab4bf3bc04cae6f853324b3f0d Mon Sep 17 00:00:00 2001 From: Dhruv-Mishra Date: Wed, 8 Jan 2025 02:08:06 +0530 Subject: [PATCH 2/9] Added unit tests --- src/account/utils.ts | 2 +- test/unit/account/utils.test.ts | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 test/unit/account/utils.test.ts diff --git a/src/account/utils.ts b/src/account/utils.ts index 19612aa..267d9ff 100644 --- a/src/account/utils.ts +++ b/src/account/utils.ts @@ -10,7 +10,7 @@ export function isAccount(obj: unknown): obj is Account { (account.initCode === undefined || account.initCode !== undefined && typeof account.initCode === 'string' && - account.address.startsWith('0x')) && + account.initCode.startsWith('0x')) && typeof account.type === 'string' && isAccountType(account.type) && Array.isArray(account.deployedOnChains) && diff --git a/test/unit/account/utils.test.ts b/test/unit/account/utils.test.ts new file mode 100644 index 0000000..6aa4279 --- /dev/null +++ b/test/unit/account/utils.test.ts @@ -0,0 +1,67 @@ +import { isAccount } from '../../../src/account/utils'; +import { Account } from '../../../src/account/types'; + +describe('isAccount', () => { + test('should return true for a valid Account object', () => { + const validAccount: Account = { + address: '0x1234567890abcdef', + type: 'kernel', + deployedOnChains: [1, 2, 3] + }; + expect(isAccount(validAccount)).toBe(true); + }); + + test('should return false for an object with an invalid address', () => { + const invalidAccount = { + address: '1234567890abcdef', + type: 'kernel', + deployedOnChains: [1, 2, 3] + }; + expect(isAccount(invalidAccount)).toBe(false); + }); + + test('should return false for an object with an invalid type', () => { + const invalidAccount = { + address: '0x1234567890abcdef', + type: 'invalid-type', + deployedOnChains: [1, 2, 3] + }; + expect(isAccount(invalidAccount)).toBe(false); + }); + + test('should return false for an object with an invalid deployedOnChains', () => { + const invalidAccount = { + address: '0x1234567890abcdef', + type: 'kernel', + deployedOnChains: ['1', '2', '3'] + }; + expect(isAccount(invalidAccount)).toBe(false); + }); + + test('should return false for a non-object input', () => { + expect(isAccount(null)).toBe(false); + expect(isAccount(undefined)).toBe(false); + expect(isAccount(123)).toBe(false); + expect(isAccount('string')).toBe(false); + }); + + test('should return true for a valid Account object with initCode', () => { + const validAccount: Account = { + address: '0x1234567890abcdef', + type: 'kernel', + deployedOnChains: [1, 2, 3], + initCode: '0xabcdef' + }; + expect(isAccount(validAccount)).toBe(true); + }); + + test('should return false for an object with an invalid initCode', () => { + const invalidAccount = { + address: '0x1234567890abcdef', + type: 'kernel', + deployedOnChains: [1, 2, 3], + initCode: 'abcdef' + }; + expect(isAccount(invalidAccount)).toBe(false); + }); +}); \ No newline at end of file From 66747fea593f687717589493fb71ffdfd771baa7 Mon Sep 17 00:00:00 2001 From: Dhruv-Mishra Date: Wed, 8 Jan 2025 02:09:24 +0530 Subject: [PATCH 3/9] Added EOF newline --- test/unit/account/utils.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/account/utils.test.ts b/test/unit/account/utils.test.ts index 6aa4279..0011d6f 100644 --- a/test/unit/account/utils.test.ts +++ b/test/unit/account/utils.test.ts @@ -64,4 +64,4 @@ describe('isAccount', () => { }; expect(isAccount(invalidAccount)).toBe(false); }); -}); \ No newline at end of file +}); From 3e43fa4491893c158556bc9d72b8f955011f0333 Mon Sep 17 00:00:00 2001 From: Dhruv-Mishra Date: Wed, 8 Jan 2025 20:27:53 +0530 Subject: [PATCH 4/9] Resolved comments --- src/account/utils.ts | 4 ++-- test/unit/account/utils.test.ts | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/account/utils.ts b/src/account/utils.ts index 267d9ff..36ca154 100644 --- a/src/account/utils.ts +++ b/src/account/utils.ts @@ -1,12 +1,12 @@ import { Account, AccountType } from './types'; +import { isAddress } from 'viem'; export function isAccount(obj: unknown): obj is Account { const account = obj as Account; return ( typeof obj === 'object' && obj !== null && - typeof account.address === 'string' && - account.address.startsWith('0x') && + isAddress(account.address) && (account.initCode === undefined || account.initCode !== undefined && typeof account.initCode === 'string' && diff --git a/test/unit/account/utils.test.ts b/test/unit/account/utils.test.ts index 0011d6f..fe5fc0c 100644 --- a/test/unit/account/utils.test.ts +++ b/test/unit/account/utils.test.ts @@ -1,10 +1,14 @@ import { isAccount } from '../../../src/account/utils'; import { Account } from '../../../src/account/types'; +import { Address, getAddress } from 'viem'; describe('isAccount', () => { + + const testAddress: Address = getAddress('0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'); + test('should return true for a valid Account object', () => { const validAccount: Account = { - address: '0x1234567890abcdef', + address: testAddress, type: 'kernel', deployedOnChains: [1, 2, 3] }; @@ -22,7 +26,7 @@ describe('isAccount', () => { test('should return false for an object with an invalid type', () => { const invalidAccount = { - address: '0x1234567890abcdef', + address: testAddress, type: 'invalid-type', deployedOnChains: [1, 2, 3] }; @@ -31,7 +35,7 @@ describe('isAccount', () => { test('should return false for an object with an invalid deployedOnChains', () => { const invalidAccount = { - address: '0x1234567890abcdef', + address: testAddress, type: 'kernel', deployedOnChains: ['1', '2', '3'] }; @@ -47,7 +51,7 @@ describe('isAccount', () => { test('should return true for a valid Account object with initCode', () => { const validAccount: Account = { - address: '0x1234567890abcdef', + address: testAddress, type: 'kernel', deployedOnChains: [1, 2, 3], initCode: '0xabcdef' @@ -57,7 +61,7 @@ describe('isAccount', () => { test('should return false for an object with an invalid initCode', () => { const invalidAccount = { - address: '0x1234567890abcdef', + address: testAddress, type: 'kernel', deployedOnChains: [1, 2, 3], initCode: 'abcdef' From c24a8beff106d35fb04a5542c39163ce3c3b1b70 Mon Sep 17 00:00:00 2001 From: Dhruv-Mishra Date: Wed, 8 Jan 2025 23:18:38 +0530 Subject: [PATCH 5/9] Trigger CI rerun --- test/unit/account/utils.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unit/account/utils.test.ts b/test/unit/account/utils.test.ts index fe5fc0c..327ed6d 100644 --- a/test/unit/account/utils.test.ts +++ b/test/unit/account/utils.test.ts @@ -69,3 +69,4 @@ describe('isAccount', () => { expect(isAccount(invalidAccount)).toBe(false); }); }); + From 90efa2d4011ee527820b4a390317f8f57f1b96e5 Mon Sep 17 00:00:00 2001 From: Dhruv-Mishra Date: Wed, 8 Jan 2025 23:37:36 +0530 Subject: [PATCH 6/9] Added isAccount function to index --- src/account/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/account/index.ts b/src/account/index.ts index 5e1c0c5..cc36f75 100644 --- a/src/account/index.ts +++ b/src/account/index.ts @@ -11,5 +11,6 @@ export { encodeValidatorNonce, } from './api' export { SafeHookType } from './safe/types' +export { isAccount } from './utils' export type { Account, AccountType, Execution, InitialModules } from './types' From 7d8dcb7f09387e047cbb68ccc123c7b80b3ab8c4 Mon Sep 17 00:00:00 2001 From: Dhruv-Mishra Date: Wed, 8 Jan 2025 23:39:21 +0530 Subject: [PATCH 7/9] Added isAccount function to index --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index aa2f03f..907ebc6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,7 @@ export { encodeModuleUninstallationData, encodeValidatorNonce, SafeHookType, + isAccount, } from './account' export type { Account, AccountType, Execution, InitialModules } from './account' From dfdc96684ca29972d698b9448e1400204439f1e6 Mon Sep 17 00:00:00 2001 From: Dhruv-Mishra Date: Thu, 9 Jan 2025 01:06:10 +0530 Subject: [PATCH 8/9] Updated import statement --- package.json | 3 ++- src/module/smart-sessions/usage.ts | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 82477cb..b301bcb 100644 --- a/package.json +++ b/package.json @@ -46,5 +46,6 @@ "dependencies": { "dotenv": "^16.4.5", "solady": "^0.0.235" - } + }, + "packageManager": "pnpm@9.15.3+sha512.1f79bc245a66eb0b07c5d4d83131240774642caaa86ef7d0434ab47c0d16f66b04e21e0c086eb61e62c77efc4d7f7ec071afad3796af64892fae66509173893a" } diff --git a/src/module/smart-sessions/usage.ts b/src/module/smart-sessions/usage.ts index 8321e76..a3bf61f 100644 --- a/src/module/smart-sessions/usage.ts +++ b/src/module/smart-sessions/usage.ts @@ -24,8 +24,7 @@ import { SmartSessionModeType, } from './types' import { LibZip } from 'solady' -import { Account, AccountType, Execution } from '../../account' -import { isAccount } from 'src/account/utils' +import { Account, AccountType, Execution, isAccount } from '../../account' export const getPermissionId = ({ session }: { session: Session }): Hex => { return keccak256( From 4a2ae4d23282823ff788372b72aad38ad1210a7b Mon Sep 17 00:00:00 2001 From: Dhruv-Mishra Date: Thu, 9 Jan 2025 01:15:36 +0530 Subject: [PATCH 9/9] Reverting package.json changes --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index b301bcb..82477cb 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,5 @@ "dependencies": { "dotenv": "^16.4.5", "solady": "^0.0.235" - }, - "packageManager": "pnpm@9.15.3+sha512.1f79bc245a66eb0b07c5d4d83131240774642caaa86ef7d0434ab47c0d16f66b04e21e0c086eb61e62c77efc4d7f7ec071afad3796af64892fae66509173893a" + } }