11import { verifyTypedData } from "src/auth/verify-typed-data.js" ;
2+ import { toWei } from "src/utils/units.js" ;
23import { beforeAll , describe , expect , it } from "vitest" ;
34import { TEST_CLIENT } from "../../test/src/test-clients.js" ;
45import { TEST_ACCOUNT_B } from "../../test/src/test-wallets.js" ;
@@ -8,6 +9,9 @@ import { baseSepolia } from "../chains/chain-definitions/base-sepolia.js";
89import { sepolia } from "../chains/chain-definitions/sepolia.js" ;
910import { getContract } from "../contract/contract.js" ;
1011import { 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" ;
1115import { setApprovalForAll } from "../extensions/erc1155/__generated__/IERC1155/write/setApprovalForAll.js" ;
1216import { claimTo } from "../extensions/erc1155/drops/write/claimTo.js" ;
1317import { getAllActiveSigners } from "../extensions/erc4337/__generated__/IAccountPermissions/read/getAllActiveSigners.js" ;
@@ -217,7 +221,7 @@ describe.runIf(
217221 ) . rejects . toThrow ( ) ;
218222 } ) ;
219223
220- it ( "should send a session key tx" , async ( ) => {
224+ it ( "should send a basic session key tx" , async ( ) => {
221225 const sessionKeyAccountAddress = process . env
222226 . ENGINE_CLOUD_WALLET_ADDRESS_EOA as string ;
223227 const personalAccount = await generateAccount ( {
@@ -272,5 +276,117 @@ describe.runIf(
272276 } ) ;
273277 expect ( tx ) . toBeDefined ( ) ;
274278 } ) ;
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+ } ) ;
275391 } ,
276392) ;
0 commit comments