This walkthrough explores two approaches to account abstraction with Para and Alchemy: EIP-7702 temporary account upgrades versus traditional smart wallet accounts. Both approaches enable gas sponsorship and advanced transaction capabilities, but work differently under the hood.
Understanding the Approaches
Traditional Smart Wallet Accounts
Traditional smart wallet accounts involve:
EOA as signer/owner - Para wallet acts as the signer for a deployed smart contract
Smart contract deployment - A separate smart contract wallet is deployed on-chain
Smart contract receives benefits - Gas sponsorship goes to the smart contract, not the EOA
Persistent deployment - The smart contract remains deployed after use
EIP-7702 Temporary Upgrades
EIP-7702 enables:
EOA receives benefits directly - Para wallet itself receives gas sponsorship and smart contract capabilities
No permanent deployment - Temporarily borrows bytecode from a pre-deployed smart contract
EOA transformation - The EOA itself becomes a smart account temporarily
Simplified architecture - No need to manage separate smart contract addresses
Key Differences
Feature Smart Wallet Account EIP-7702 Contract Deployment Required per user Uses pre-deployed contract Gas Sponsorship Target Smart contract address EOA address directly Transaction Complexity Higher (userOps) Lower (standard transactions) Signature Recovery Expects 27/28 v-bytes Expects 0/1 v-bytes Persistence Permanent deployment Temporary upgrade
Para Wallet Integration
Para wallets work as EOAs (Externally Owned Accounts) that can sign for both approaches:
Active user sessions - Authenticated users with live Para embedded wallets
Pregenerated wallets - Server-side Para instances with loaded user shares
Since Para provides raw signing capabilities, it can facilitate signatures for both smart wallet accounts and EIP-7702 operations.
Implementation: Smart Wallet Accounts
Setup Para Client
Pregenerated Wallet Active Session import { Para , Environment } from "@getpara/server-sdk" ;
import { createParaAccount , createParaViemClient } from "@getpara/viem" ;
// Initialize Para with pregenerated wallet
const para = new Para ( Environment . BETA , process . env . PARA_API_KEY ! );
// Load user share for pregenerated wallet
const userShare = await getUserShareFromDatabase ( email );
await para . setUserShare ( userShare );
// Create Para account with custom signing
const viemParaAccount = createParaAccount ( para );
viemParaAccount . signMessage = async ({ message }) =>
customSignMessage ( para , message );
Create Alchemy Modular Account Client
import { customSignMessage } from "./signature-utils" ;
// Create Viem client with Para integration
const viemClient = createParaViemClient ( para , {
account: viemParaAccount ,
chain: arbitrumSepolia ,
transport: http ( rpcUrl )
});
// Create wallet client signer
const walletClientSigner = new WalletClientSigner ( viemClient , "para" );
// Create Alchemy modular account client
const alchemyClient = await createModularAccountAlchemyClient ({
transport: alchemy ({ rpcUrl: rpcUrl }),
chain: arbitrumSepolia ,
signer: walletClientSigner ,
policyId: alchemyGasPolicyId // For gas sponsorship
});
Execute Smart Wallet Transactions
// Prepare batch user operations
const uoCallData = await alchemyClient . buildUserOperation ({
calls: [
{
target: "0x1234567890123456789012345678901234567890" ,
data: "0x" ,
value: parseEther ( "0.001" )
}
]
});
// Send user operation
const { hash : uoHash } = await alchemyClient . sendUserOperation ( uoCallData );
// Wait for confirmation
const txHash = await alchemyClient . waitForUserOperationTransaction ({
hash: uoHash
});
console . log ( `Smart wallet transaction: ${ txHash } ` );
Implementation: EIP-7702
Setup Para Client
Pregenerated Wallet Active Session import { Para , Environment } from "@getpara/server-sdk" ;
import { createParaAccount , createParaViemClient } from "@getpara/viem" ;
// Initialize Para with pregenerated wallet
const para = new Para ( Environment . BETA , process . env . PARA_API_KEY ! );
// Load user share for pregenerated wallet
const userShare = await getUserShareFromDatabase ( email );
await para . setUserShare ( userShare );
// Create Para account with custom signing
const viemParaAccount = createParaAccount ( para );
viemParaAccount . signMessage = async ({ message }) =>
customSignMessage ( para , message );
Create EIP-7702 Client
// Create Viem client
const viemClient = createParaViemClient ( para , {
account: viemParaAccount ,
chain: arbitrumSepolia ,
transport: http ( rpcUrl )
});
const walletClientSigner = new WalletClientSigner ( viemClient , "para" );
// Create EIP-7702 client - note the "mode" parameter
const alchemyClient = await createModularAccountV2Client ({
mode: "7702" , // This is the key difference
transport: alchemy ({ rpcUrl: rpcUrl }),
chain: arbitrumSepolia ,
signer: walletClientSigner ,
policyId: alchemyGasPolicyId
});
Execute EIP-7702 Transactions
// EIP-7702 transactions are simpler
const txHash = await alchemyClient . sendTransaction ({
calls: [
{
target: "0x1234567890123456789012345678901234567890" ,
data: "0x" ,
value: parseEther ( "0.001" )
}
]
});
console . log ( `EIP-7702 transaction: ${ txHash } ` );
Signature Compatibility
Para’s MPC signatures use 0/1 v-byte recovery, but smart wallet accounts expect 27/28. You need custom signing utilities:
Custom Signature Utils
// signature-utils.ts
const V_OFFSET_FOR_ETHEREUM = 27 ;
export async function customSignMessage ( para : Para , message : string | Uint8Array ) {
const messageToSign = typeof message === "string" ? message : toHex ( message );
const signature = await para . signMessage ( messageToSign );
// Parse signature components
const r = signature . slice ( 0 , 64 );
const s = signature . slice ( 64 , 128 );
let v = parseInt ( signature . slice ( 128 , 130 ), 16 );
// Adjust v-byte for smart wallet compatibility
if ( v < 27 ) {
v += V_OFFSET_FOR_ETHEREUM ;
}
return `0x ${ r }${ s }${ v . toString ( 16 ). padStart ( 2 , "0" ) } ` ;
}
export async function customSignAuthorization ( para : Para , authorization : any ) {
const signature = await para . signMessage ( serializeAuthorization ( authorization ));
// Parse v-byte
const v = parseInt ( signature . slice ( 128 , 130 ), 16 );
// EIP-7702 requires v-byte of 0 or 1
if ( v !== 0 && v !== 1 ) {
throw new Error ( `Invalid v value for EIP-7702: ${ v } . Expected 0 or 1` );
}
return `0x ${ signature } ` ;
}
Apply Custom Signing
// Override Para account signing methods
viemParaAccount . signMessage = async ({ message }) =>
customSignMessage ( para , message );
viemParaAccount . signTransaction = async ( transaction ) =>
customSignTransaction ( para , transaction );
Transaction Construction Best Practices
Para signs raw bytes without transaction validation. Ensure proper transaction construction:
Type Safety
// Ensure proper types before signing
const calls = [
{
target: getAddress ( "0x1234567890123456789012345678901234567890" ), // Proper address format
data: "0x" as Hex , // Proper hex format
value: parseEther ( "0.001" ) // Proper bigint value
}
];
Error Handling
try {
const txHash = await alchemyClient . sendTransaction ({ calls });
console . log ( `Transaction successful: ${ txHash } ` );
} catch ( error ) {
if ( error . message . includes ( "signature verification failed" )) {
console . error ( "Signature issue - check v-byte adjustment" );
} else if ( error . message . includes ( "invalid transaction" )) {
console . error ( "Transaction construction issue - check types and values" );
}
throw error ;
}
Choosing the Right Approach
Use Smart Wallet Accounts When:
You need persistent smart contract functionality
Your application requires complex access control
You want to leverage established userOp infrastructure
Gas sponsorship policies are account-specific
Use EIP-7702 When:
You want simpler transaction flows
Gas sponsorship should go directly to EOAs
You prefer avoiding permanent contract deployments
Your use case fits temporary smart account capabilities
Important Considerations
Signature Recovery
Smart Wallet Accounts : Expect 27/28 v-byte recovery (legacy Ethereum format)
EIP-7702 : Expects 0/1 v-byte recovery (modern format)
Para Default : Produces 0/1 v-byte signatures (requires adjustment for smart wallets)
Network Support
EIP-7702 requires network support for the new transaction type
Smart wallet accounts work on any EVM-compatible network
Check Alchemy’s documentation for current EIP-7702 network availability
Both approaches support Alchemy’s gas sponsorship policies
EIP-7702 sponsors the EOA directly
Smart wallet accounts sponsor the smart contract address
Additional Resources
For more detailed information about EIP-7702 implementation with Alchemy, see the Alchemy Modular Account v2 EIP-7702 documentation .
Next Steps