Skip to content

Commit

Permalink
WIP - Manage ownable validator module (#588)
Browse files Browse the repository at this point in the history
* added settings and pages

* implemented installing ownable validator module

* added updateThreshold action implementation

* added implementation for addOwner action

* disabling uninstall button

* Not implemented uninstall module functionality
  • Loading branch information
KannuSingh authored Jun 24, 2024
1 parent e94986f commit 02d2d06
Show file tree
Hide file tree
Showing 17 changed files with 850 additions and 192 deletions.
25 changes: 25 additions & 0 deletions advanced/wallets/react-wallet-v2/src/components/ModuleActions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Fragment, useMemo } from 'react'
import OwnableValidatorActions from '@/views/OwnableValidatorActions'
import { ModuleView } from '@/data/ERC7579ModuleData'
import { Module } from '@rhinestone/module-sdk'

export default function ModuleActions({
accountAddress,
chainId,
view
}: {
accountAddress: string
chainId: string
view?: ModuleView
}) {
const componentView = useMemo(() => {
switch (view) {
case 'OwnableValidatorActions':
return <OwnableValidatorActions accountAddress={accountAddress} chainId={chainId} />
default:
return null
}
}, [accountAddress, chainId, view])

return <Fragment>{componentView}</Fragment>
}
40 changes: 25 additions & 15 deletions advanced/wallets/react-wallet-v2/src/data/ERC7579ModuleData.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//Note: ES6 syntax dont work for this package
// import { MULTI_FACTOR_VALIDATOR_ADDRESS } from '@rhinestone/module-sdk'
import { ModuleType } from '@rhinestone/module-sdk'
const {
MULTI_FACTOR_VALIDATOR_ADDRESS,
OWNABLE_VALIDATOR_ADDRESS,
Expand All @@ -8,61 +8,71 @@ const {
SCHEDULED_TRANSFERS_EXECUTER_ADDRESS
} = require('@rhinestone/module-sdk') as typeof import('@rhinestone/module-sdk')

export const moduleTypeIds = {
validator: 1,
executor: 2,
fallback: 3,
hook: 4
}
export const PERMISSION_VALIDATOR_ADDRESS = '0x6671AD9ED29E2d7a894E80bf48b7Bf03Ee64A0f4'
export type ModuleView =
| 'PermissionValidatorActions'
| 'OwnableValidatorActions'
| 'MFAValidatorActions'
| 'WebAuthnValidatorActions'
| 'ScheduleOrdersExecutorActions'
| 'ScheduleTransfersExecutorActions'

export type Module = {
name: string
type: number
type: ModuleType
url: string
description: string
moduleAddress: string
moduleData: string
view?: ModuleView
}
export const supportedModules: Module[] = [
{
name: 'Permission Validator',
type: 1,
type: 'validator',
url: '/permission-validator',
moduleAddress: PERMISSION_VALIDATOR_ADDRESS,
description: `The Permission Validator module is a module that allows DApp to request permissions from a wallet in order to execute transactions on users's behalf that is scoped with permissions`,
moduleData: '0x'
},
{
name: 'Ownable Validator',
type: 1,
type: 'validator',
url: '/ownable-validator',
moduleAddress: OWNABLE_VALIDATOR_ADDRESS,
description: `The Ownable Validator module is a module that allows you to add multiple ECDSA owners to an account.
The owners can then be used to sign transactions to be executed on the account.`,
moduleData: ''
moduleData: '',
view: 'OwnableValidatorActions'
},
{
name: `Muti-factor Validator`,
type: 1,
type: 'validator',
url: '/mfa-validator',
moduleAddress: MULTI_FACTOR_VALIDATOR_ADDRESS,
description: `The MFA Validator module is a module that allows you to add multi-factor validation to an account. The MFA Validator module is used to validate transactions and other executions on the account.`,
moduleData: ''
},
{
name: 'WebAuthn Validator',
type: 1,
type: 'validator',
url: '/webauthn-validator',
moduleAddress: WEBAUTHN_VALIDATOR_ADDRESS,
description: 'Coming Soon',
moduleData: ''
},
{
name: 'Schedule Orders Executor',
type: 2,
type: 'executor',
url: 'schedule-orders-executor',
moduleAddress: SCHEDULED_ORDERS_EXECUTER_ADDRESS,
description: `The Scheduled Orders module allows users to schedule swaps to be executed at a later time, with an optional recurring schedule. This module is an executor that is installed on an account and can be triggered by an automation service at the pre-specified time(s).`,
moduleData: ''
},
{
name: 'Schedule Transfers Executor',
type: 2,
type: 'executor',
url: '/schedule-transfers-executor',
moduleAddress: SCHEDULED_TRANSFERS_EXECUTER_ADDRESS,
description: `The Scheduled Transfers module allows users to schedule token transfers to occur at a future time, with an optional recurring schedule. It is an executor that is installed on an account and can be triggered by an automation service at the pre-specified time(s).`,
moduleData: ''
Expand Down
7 changes: 7 additions & 0 deletions advanced/wallets/react-wallet-v2/src/data/chainsUtil.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as viemChains from 'viem/chains'
import { COSMOS_MAINNET_CHAINS } from './COSMOSData'
import { EIP155_CHAINS } from './EIP155Data'
import { KADENA_CHAINS } from './KadenaData'
Expand Down Expand Up @@ -27,3 +28,9 @@ export function getChainData(chainId?: string) {
chain => chain.chainId == reference && chain.namespace === namespace
)
}

export function getViemChain(id: number) {
const chains = Object.values(viemChains) as viemChains.Chain[]

return chains.find(x => x.id === id)
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,15 @@ export class SafeSmartAccountLib extends SmartAccountLib {
if (!this.client?.account) {
throw new Error('Client not initialized')
}
await this.setupSafe7579({ to, value, data })
const setUpSafeUserOpHash = await this.setupSafe7579({ to, value, data })
if (setUpSafeUserOpHash) {
const txReceipt = await this.bundlerClient.waitForUserOperationReceipt({
hash: setUpSafeUserOpHash
})
return txReceipt.receipt.transactionHash
}

//This is executed only if safe is already setup and deployed
const txResult = await this.client.sendTransaction({
to,
value,
Expand All @@ -77,8 +84,10 @@ export class SafeSmartAccountLib extends SmartAccountLib {
if (!this.client?.account) {
throw new Error('Client not initialized')
}
await this.setupSafe7579(calls)
const setUpSafeUserOpHash = await this.setupSafe7579(calls)
if (setUpSafeUserOpHash) return setUpSafeUserOpHash

//this execution starts only if safe is already setup and deployed
const userOp = await this.client.prepareUserOperationRequest({
userOperation: {
callData: await this.client.account.encodeCallData(calls)
Expand All @@ -92,6 +101,7 @@ export class SafeSmartAccountLib extends SmartAccountLib {
const userOpHash = await this.bundlerClient.sendUserOperation({
userOperation: userOp
})
console.log({ userOpHash })
return userOpHash
}

Expand Down Expand Up @@ -162,10 +172,8 @@ export class SafeSmartAccountLib extends SmartAccountLib {
const setUpAndExecuteUserOpHash = await this.bundlerClient.sendUserOperation({
userOperation: setUpUserOp
})
const userOpReceipt = await this.bundlerClient.waitForUserOperationReceipt({
hash: setUpAndExecuteUserOpHash
})
console.log({ setupSafetxHash: userOpReceipt.receipt.transactionHash })
console.log('SetUp Safe completed.')
return setUpAndExecuteUserOpHash
}
}

Expand Down Expand Up @@ -240,4 +248,11 @@ export class SafeSmartAccountLib extends SmartAccountLib {
permissions
}
}

async manageModule(calls: Execution[]) {
const userOpHash = await this.sendBatchTransaction(calls)
return await this.bundlerClient.waitForUserOperationReceipt({
hash: userOpHash
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import {
http,
createClient,
HttpTransport,
Address,
encodeFunctionData
Address
} from 'viem'
import { EIP155Wallet } from '../EIP155Lib'
import { JsonRpcProvider } from '@ethersproject/providers'
Expand All @@ -31,7 +30,6 @@ import { PimlicoBundlerActions, pimlicoBundlerActions } from 'permissionless/act
import { PIMLICO_NETWORK_NAMES, UrlConfig, publicRPCUrl } from '@/utils/SmartAccountUtil'
import { Chain } from '@/consts/smartAccounts'
import { EntryPoint } from 'permissionless/types/entrypoint'
import { installModuleAbi, isModuleInstalledAbi } from '@/utils/safe7579AccountUtils/abis/Account'

type SmartAccountLibOptions = {
privateKey: string
Expand Down Expand Up @@ -221,71 +219,6 @@ export abstract class SmartAccountLib implements EIP155Wallet {
return userOpHash
}

async installModule(args: { moduleType: bigint; moduleAddress: Address; moduleInitcode: Hex }) {
if (!this.client?.account) {
throw new Error('Client not initialized')
}
const { moduleType, moduleAddress, moduleInitcode } = args

//check whether module already installed
const isModuleInstalled = await this.checkModuleInstalled({
moduleType,
moduleAddress
})

if (isModuleInstalled) {
throw new Error('Module is already installed.')
}
const installModuleCallData = encodeFunctionData({
abi: installModuleAbi,
functionName: 'installModule',
args: [moduleType, moduleAddress, moduleInitcode]
})

const userOp = await this.client.prepareUserOperationRequest({
userOperation: {
callData: installModuleCallData
},
account: this.client.account
})
const newSignature = await this.client.account.signUserOperation(userOp)

userOp.signature = newSignature
console.log(userOp)
const userOpHash = await this.client.sendUserOperation({
userOperation: userOp,
account: this.client.account
})
const txHash = await this.bundlerClient.waitForUserOperationReceipt({
hash: userOpHash
})
return txHash
}

async checkModuleInstalled(args: {
moduleType: bigint
moduleAddress: Address
}): Promise<boolean> {
if (!this.client?.account || !this.publicClient) {
throw new Error('Client not initialized')
}

const { moduleType, moduleAddress } = args

const isModuleInstalled = await this.publicClient.readContract({
address: this.client.account.address,
abi: isModuleInstalledAbi,
functionName: 'isModuleInstalled',
args: [
moduleType, // ModuleType
moduleAddress, // Module Address
'0x' // Additional Context
]
})
console.log(`isModuleInstalled : ${isModuleInstalled}`)
return isModuleInstalled
}

getAccount() {
if (!this.client?.account) {
throw new Error('Client not initialized')
Expand Down
2 changes: 1 addition & 1 deletion advanced/wallets/react-wallet-v2/src/pages/account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export default function AccountPage() {
<ModulesManagement
accountAddress={accountAddress}
accountType={accountType}
chain={selectedChain}
chainId={chainId}
isDeployed={isAccountDeployed}
/>
</Fragment>
Expand Down
Loading

0 comments on commit 02d2d06

Please sign in to comment.