@@ -12,16 +12,26 @@ import {
12
12
WalletGrantPermissionsParameters ,
13
13
createWalletClient ,
14
14
encodeFunctionData ,
15
+ getAddress ,
15
16
http ,
17
+ parseAbi ,
16
18
type WalletGrantPermissionsReturnType
17
19
} from 'viem'
18
20
import { MultiKeySigner } from 'viem/_types/experimental/erc7715/types/signer'
19
21
import { ModuleType } from 'permissionless/actions/erc7579'
20
22
import { MOCK_VALIDATOR_ADDRESSES } from './builders/SmartSessionUtil'
21
23
import { Permission } from '@/data/EIP7715Data'
22
24
import { getSmartSessionContext } from './builders/ContextBuilderUtil'
23
- const { SMART_SESSIONS_ADDRESS , getAccount } =
24
- require ( '@rhinestone/module-sdk' ) as typeof import ( '@rhinestone/module-sdk' )
25
+ import { readContract } from 'viem/actions'
26
+ import { Execution , Module } from '@rhinestone/module-sdk'
27
+
28
+ const {
29
+ SMART_SESSIONS_ADDRESS ,
30
+ REGISTRY_ADDRESS ,
31
+ getTrustAttestersAction,
32
+ getAccount,
33
+ getSmartSessionsValidator
34
+ } = require ( '@rhinestone/module-sdk' ) as typeof import ( '@rhinestone/module-sdk' )
25
35
export class SafeSmartAccountLib extends SmartAccountLib {
26
36
protected ERC_7579_LAUNCHPAD_ADDRESS : Address = '0xEBe001b3D534B9B6E2500FB78E67a1A137f561CE'
27
37
protected SAFE_4337_MODULE_ADDRESS : Address = '0x3Fdb5BC686e861480ef99A6E3FaAe03c0b9F32e2'
@@ -102,21 +112,22 @@ export class SafeSmartAccountLib extends SmartAccountLib {
102
112
/**
103
113
* Check Safe7579 Account is ready for processing this RPC request
104
114
* - Check Account is deployed
115
+ * - Check SmartSession Attesters are trusted
105
116
* - Check Permission Validator & Mock Validator modules are installed
106
- * If not, Deploy and installed all necessary module for processing this RPC request
117
+ * If not, Deploy and installed all necessary module and enable trusted attester if not trusted for processing this RPC request
107
118
* @returns
108
119
*/
109
120
private async ensureAccountReadyForGrantPermissions ( ) : Promise < void > {
110
121
if ( ! this . client ?. account ) {
111
122
throw new Error ( 'Client not initialized' )
112
123
}
113
124
try {
114
- const isAccountDeployed = await isSmartAccountDeployed (
115
- this . publicClient ,
116
- this . client . account . address
117
- )
118
- // TODO: check if account trust the attesters of the module
119
- await this . trustAttesters ( )
125
+ const setUpSmartAccountForSmartSession : Execution [ ] = [ ]
126
+
127
+ const [ isAccountDeployed , doesSmartAccountTrustSmartSessionAttesters ] = await Promise . all ( [
128
+ isSmartAccountDeployed ( this . publicClient , this . client . account . address ) ,
129
+ this . isSmartAccountTrustSmartSessionAttesters ( )
130
+ ] )
120
131
121
132
let smartSessionValidatorInstalled = false
122
133
let mockValidatorInstalled = false
@@ -130,36 +141,64 @@ export class SafeSmartAccountLib extends SmartAccountLib {
130
141
}
131
142
console . log ( { smartSessionValidatorInstalled, mockValidatorInstalled } )
132
143
133
- if ( isAccountDeployed && smartSessionValidatorInstalled && mockValidatorInstalled ) {
144
+ if (
145
+ isAccountDeployed &&
146
+ smartSessionValidatorInstalled &&
147
+ mockValidatorInstalled &&
148
+ doesSmartAccountTrustSmartSessionAttesters
149
+ ) {
134
150
console . log ( 'Account is already set up with required modules' )
135
151
return
136
152
}
137
153
138
154
console . log ( 'Setting up the Account with required modules' )
139
155
140
- const installModules : {
141
- address : Address
142
- type : ModuleType
143
- context : Hex
144
- } [ ] = [ ]
145
-
146
156
if ( ! isAccountDeployed || ! smartSessionValidatorInstalled ) {
147
- installModules . push ( {
148
- address : SMART_SESSIONS_ADDRESS ,
149
- type : 'validator' ,
150
- context : '0x'
151
- } )
157
+ const smartSessionValidator : Module = {
158
+ module : SMART_SESSIONS_ADDRESS ,
159
+ type : 'validator'
160
+ }
161
+ const installSmartSessionValidatorAction = this . getInstallModuleAction (
162
+ this . client . account . address ,
163
+ smartSessionValidator
164
+ )
165
+ setUpSmartAccountForSmartSession . push ( installSmartSessionValidatorAction )
152
166
}
153
167
154
168
if ( ! isAccountDeployed || ! mockValidatorInstalled ) {
155
- installModules . push ( {
156
- address : MOCK_VALIDATOR_ADDRESSES [ this . chain . id ] ,
157
- type : 'validator' ,
158
- context : '0x'
169
+ const mockSignatureValidator : Module = {
170
+ module : MOCK_VALIDATOR_ADDRESSES [ this . chain . id ] ,
171
+ type : 'validator'
172
+ }
173
+ const installMockSignatureValidatorAction = this . getInstallModuleAction (
174
+ this . client . account . address ,
175
+ mockSignatureValidator
176
+ )
177
+ setUpSmartAccountForSmartSession . push ( installMockSignatureValidatorAction )
178
+ }
179
+
180
+ if ( ! doesSmartAccountTrustSmartSessionAttesters ) {
181
+ console . log ( 'Smart Account do not trusted the attesters of the smartsessions module' )
182
+ console . log ( 'Enable trusting the attesters of the smartsessions module' )
183
+ const trustAttestersAction = getTrustAttestersAction ( {
184
+ attesters : [ '0xA4C777199658a41688E9488c4EcbD7a2925Cc23A' ] ,
185
+ threshold : 1
159
186
} )
187
+ setUpSmartAccountForSmartSession . push ( trustAttestersAction )
160
188
}
161
189
162
- await this . installModules ( installModules )
190
+ console . log ( 'Setting up the Account with Executions' , { setUpSmartAccountForSmartSession } )
191
+ const userOpHash = await this . sendBatchTransaction (
192
+ setUpSmartAccountForSmartSession . map ( action => {
193
+ return {
194
+ to : action . target ,
195
+ value : action . value . valueOf ( ) ,
196
+ data : action . callData
197
+ }
198
+ } )
199
+ )
200
+ const receipt = await this . bundlerClient . waitForUserOperationReceipt ( { hash : userOpHash } )
201
+ console . log ( `Account setup receipt:` , receipt )
163
202
console . log ( 'Account setup completed' )
164
203
} catch ( error ) {
165
204
console . error ( `Error ensuring account is ready for grant permissions: ${ error } ` )
@@ -179,52 +218,82 @@ export class SafeSmartAccountLib extends SmartAccountLib {
179
218
} )
180
219
}
181
220
182
- private async installModules (
183
- modules : {
184
- address : Address
185
- type : ModuleType
186
- context : Hex
187
- } [ ]
188
- ) : Promise < void > {
189
- if ( ! this . client ?. account ) {
190
- throw new Error ( 'Client not initialized' )
191
- }
192
- const userOpHash = await this . client . installModules ( {
193
- account : this . client . account ,
194
- modules : modules
195
- } )
196
- const receipt = await this . bundlerClient . waitForUserOperationReceipt ( { hash : userOpHash } )
197
- console . log ( `Module installation receipt:` , receipt )
198
- }
199
-
200
- private async trustAttesters ( ) : Promise < void > {
201
- if ( ! this . client ?. account ) {
202
- throw new Error ( 'Client not initialized' )
203
- }
204
- const trustAttestersAction = {
205
- to : '0x000000000069E2a187AEFFb852bF3cCdC95151B2' as Address , // mock-registry
221
+ private getInstallModuleAction ( accountAddress : Address , module : Module ) : Execution {
222
+ return {
223
+ target : accountAddress ,
206
224
value : BigInt ( 0 ) ,
207
- data : encodeFunctionData ( {
225
+ callData : encodeFunctionData ( {
208
226
abi : [
209
227
{
210
- inputs : [
211
- { type : 'uint8' , name : 'threshold' } ,
212
- { type : 'address[]' , name : 'attesters' }
213
- ] ,
214
- name : 'trustAttesters' ,
228
+ name : 'installModule' ,
215
229
type : 'function' ,
216
230
stateMutability : 'nonpayable' ,
231
+ inputs : [
232
+ {
233
+ type : 'uint256' ,
234
+ name : 'moduleTypeId'
235
+ } ,
236
+ {
237
+ type : 'address' ,
238
+ name : 'module'
239
+ } ,
240
+ {
241
+ type : 'bytes' ,
242
+ name : 'initData'
243
+ }
244
+ ] ,
217
245
outputs : [ ]
218
246
}
219
247
] ,
220
- functionName : 'trustAttesters' ,
221
- args : [ 1 , [ '0xA4C777199658a41688E9488c4EcbD7a2925Cc23A' ] ]
248
+ functionName : 'installModule' ,
249
+ args : [
250
+ this . parseModuleTypeId ( module . type ) ,
251
+ getAddress ( module . module ) ,
252
+ module . initData || '0x'
253
+ ]
222
254
} )
223
255
}
256
+ }
224
257
225
- const userOpHash = await this . sendTransaction ( trustAttestersAction )
226
- console . log ( `Trust Attesters userOpHash:` , userOpHash )
227
- // const receipt = await this.bundlerClient.waitForUserOperationReceipt({ hash: userOpHash })
228
- // console.log(`Trust Attesters receipt:`, receipt)
258
+ private async isSmartAccountTrustSmartSessionAttesters ( ) : Promise < boolean > {
259
+ if ( ! this . client ?. account ) {
260
+ throw new Error ( 'Client not initialized' )
261
+ }
262
+
263
+ const TRUSTED_SMART_SESSIONS_ATTERSTER_ADDRESS = '0xA4C777199658a41688E9488c4EcbD7a2925Cc23A'
264
+ const attesters = await readContract ( this . publicClient , {
265
+ address : REGISTRY_ADDRESS ,
266
+ abi : parseAbi ( [
267
+ 'function findTrustedAttesters(address smartAccount) view returns (address[])'
268
+ ] ) ,
269
+ functionName : 'findTrustedAttesters' ,
270
+ args : [ this . client . account . address ]
271
+ } )
272
+
273
+ if ( attesters . length > 0 ) {
274
+ return Boolean (
275
+ attesters . find (
276
+ ( attester : Address ) =>
277
+ attester . toLowerCase ( ) === TRUSTED_SMART_SESSIONS_ATTERSTER_ADDRESS . toLowerCase ( )
278
+ )
279
+ )
280
+ }
281
+
282
+ return false
283
+ }
284
+
285
+ private parseModuleTypeId ( type : ModuleType ) : bigint {
286
+ switch ( type ) {
287
+ case 'validator' :
288
+ return BigInt ( 1 )
289
+ case 'executor' :
290
+ return BigInt ( 2 )
291
+ case 'fallback' :
292
+ return BigInt ( 3 )
293
+ case 'hook' :
294
+ return BigInt ( 4 )
295
+ default :
296
+ throw new Error ( 'Invalid module type' )
297
+ }
229
298
}
230
299
}
0 commit comments