1
1
import { verifyTypedData } from "src/auth/verify-typed-data.js" ;
2
+ import { toWei } from "src/utils/units.js" ;
2
3
import { beforeAll , describe , expect , it } from "vitest" ;
3
4
import { TEST_CLIENT } from "../../test/src/test-clients.js" ;
4
5
import { TEST_ACCOUNT_B } from "../../test/src/test-wallets.js" ;
@@ -8,6 +9,9 @@ import { baseSepolia } from "../chains/chain-definitions/base-sepolia.js";
8
9
import { sepolia } from "../chains/chain-definitions/sepolia.js" ;
9
10
import { getContract } from "../contract/contract.js" ;
10
11
import { setContractURI } from "../extensions/common/__generated__/IContractMetadata/write/setContractURI.js" ;
12
+ import { claimTo as claimToERC20 } from "../extensions/erc20/drops/write/claimTo.js" ;
13
+ import { getBalance } from "../extensions/erc20/read/getBalance.js" ;
14
+ import { transfer } from "../extensions/erc20/write/transfer.js" ;
11
15
import { setApprovalForAll } from "../extensions/erc1155/__generated__/IERC1155/write/setApprovalForAll.js" ;
12
16
import { claimTo } from "../extensions/erc1155/drops/write/claimTo.js" ;
13
17
import { getAllActiveSigners } from "../extensions/erc4337/__generated__/IAccountPermissions/read/getAllActiveSigners.js" ;
@@ -217,7 +221,7 @@ describe.runIf(
217
221
) . rejects . toThrow ( ) ;
218
222
} ) ;
219
223
220
- it ( "should send a session key tx" , async ( ) => {
224
+ it ( "should send a basic session key tx" , async ( ) => {
221
225
const sessionKeyAccountAddress = process . env
222
226
. ENGINE_CLOUD_WALLET_ADDRESS_EOA as string ;
223
227
const personalAccount = await generateAccount ( {
@@ -272,5 +276,117 @@ describe.runIf(
272
276
} ) ;
273
277
expect ( tx ) . toBeDefined ( ) ;
274
278
} ) ;
279
+
280
+ it ( "should send a session key tx with ERC20 claiming and transfer" , async ( ) => {
281
+ // The EOA is the session key signer, ie, it has session key permissions on the generated smart account
282
+ const sessionKeyAccountAddress = process . env
283
+ . ENGINE_CLOUD_WALLET_ADDRESS_EOA as string ;
284
+ const personalAccount = await generateAccount ( {
285
+ client : TEST_CLIENT ,
286
+ } ) ;
287
+ const smart = smartWallet ( {
288
+ chain : arbitrumSepolia ,
289
+ sessionKey : {
290
+ address : sessionKeyAccountAddress ,
291
+ permissions : {
292
+ approvedTargets : "*" ,
293
+ } ,
294
+ } ,
295
+ sponsorGas : true ,
296
+ } ) ;
297
+ const smartAccount = await smart . connect ( {
298
+ client : TEST_CLIENT ,
299
+ personalAccount,
300
+ } ) ;
301
+ expect ( smartAccount . address ) . toBeDefined ( ) ;
302
+
303
+ const signers = await getAllActiveSigners ( {
304
+ contract : getContract ( {
305
+ address : smartAccount . address ,
306
+ chain : arbitrumSepolia ,
307
+ client : TEST_CLIENT ,
308
+ } ) ,
309
+ } ) ;
310
+ expect ( signers . map ( ( s ) => s . signer ) ) . toContain ( sessionKeyAccountAddress ) ;
311
+
312
+ const serverWallet = Engine . serverWallet ( {
313
+ address : sessionKeyAccountAddress ,
314
+ chain : arbitrumSepolia ,
315
+ client : TEST_CLIENT ,
316
+ executionOptions : {
317
+ entrypointVersion : "0.6" ,
318
+ signerAddress : sessionKeyAccountAddress ,
319
+ smartAccountAddress : smartAccount . address ,
320
+ type : "ERC4337" ,
321
+ } ,
322
+ vaultAccessToken : process . env . VAULT_TOKEN as string ,
323
+ } ) ;
324
+
325
+ // Get the ERC20 contract
326
+ const erc20Contract = getContract ( {
327
+ // this ERC20 on arbitrumSepolia has infinite free public claim phase
328
+ address : "0xd4d3D9261e2da56c4cC618a06dD5BDcB1A7a21d7" ,
329
+ chain : arbitrumSepolia ,
330
+ client : TEST_CLIENT ,
331
+ } ) ;
332
+
333
+ // Check initial signer balance
334
+ const initialSignerBalance = await getBalance ( {
335
+ address : sessionKeyAccountAddress ,
336
+ contract : erc20Contract ,
337
+ } ) ;
338
+
339
+ // Claim 10 tokens to the smart account
340
+ const claimTx = claimToERC20 ( {
341
+ contract : erc20Contract ,
342
+ to : smartAccount . address ,
343
+ quantity : "10" ,
344
+ } ) ;
345
+
346
+ const claimResult = await sendTransaction ( {
347
+ account : serverWallet ,
348
+ transaction : claimTx ,
349
+ } ) ;
350
+ expect ( claimResult ) . toBeDefined ( ) ;
351
+
352
+ // Check balance after claim
353
+ const balanceAfterClaim = await getBalance ( {
354
+ address : smartAccount . address ,
355
+ contract : erc20Contract ,
356
+ } ) ;
357
+
358
+ // Verify the smart account now has 10 tokens (since it started with 0)
359
+ expect ( balanceAfterClaim . value ) . toBe ( toWei ( "10" ) ) ;
360
+
361
+ // Transfer tokens from smart account to signer
362
+ const transferTx = transfer ( {
363
+ contract : erc20Contract ,
364
+ to : sessionKeyAccountAddress ,
365
+ amount : "10" ,
366
+ } ) ;
367
+
368
+ const transferResult = await sendTransaction ( {
369
+ account : serverWallet ,
370
+ transaction : transferTx ,
371
+ } ) ;
372
+ expect ( transferResult ) . toBeDefined ( ) ;
373
+
374
+ // Check final balances
375
+ const finalSmartAccountBalance = await getBalance ( {
376
+ address : smartAccount . address ,
377
+ contract : erc20Contract ,
378
+ } ) ;
379
+ const finalSignerBalance = await getBalance ( {
380
+ address : sessionKeyAccountAddress ,
381
+ contract : erc20Contract ,
382
+ } ) ;
383
+ // Verify the transfer worked correctly
384
+ // Smart account should be back to 0 balance
385
+ expect ( finalSmartAccountBalance . value ) . toBe ( 0n ) ;
386
+ // Signer should have gained 10 tokens
387
+ expect (
388
+ BigInt ( finalSignerBalance . value ) - BigInt ( initialSignerBalance . value ) ,
389
+ ) . toBe ( toWei ( "10" ) ) ;
390
+ } ) ;
275
391
} ,
276
392
) ;
0 commit comments