AWS Database Blog

Build Account Abstraction Wallets with Alchemy and AWS: Part 2

In Part 1 of this series, we introduced the Account Abstraction (AA) concept and explained how it overcomes some of the user experience challenges of Externally Owned Account (EOA) wallets. We also covered how you can apply AA in the context of different use cases, such as marketing campaigns and enabling user onboarding at scale.

In this post, we introduce the technical core concepts of AA. We then walk you through a solution built on AWS using the Alchemy Account Kit SDK and other services provided by Alchemy. Finally, we deep dive into the components of Account Kit used for the solution, namely the AA-SDK, Bundler, and the Gas Manager API.

How Account Abstraction works

Ethereum Improvement Proposal (EIP) 4337 explains how Account Abstraction can be achieved on Ethereum without requiring any updates to the Ethereum protocol. The primary difference between AA wallets and EOAs is that every AA wallet is a smart contract. From Vitalik Buterin’s post, The road to account abstraction, this “[…] allows us to use smart contract logic to specify not just the effects of the transaction, but also the fee payment and validation logic. This allows many important security benefits, such as multi-signature and smart recovery wallets, being able to change keys without changing wallets, and quantum-safety.”

As pointed out earlier, AA on Ethereum does not require any changes to the Ethereum protocol. This has two benefits. First, no potentially destabilizing updates are required at the protocol level, removing any impact to other parts of the protocol. Second, AA development can proceed independently of protocol development. The following diagram depicts the general transaction flow for a transaction submitted from an AA wallet. This type of transaction is referred to as a UserOperation. Refer to Part 1 for additional information on the traditional EOA wallet transaction flow.

User Operation Flow

A UserOperation gets processed by the network through the following steps:

  1. Users authorize transactions using their smart contract wallets by signing these with their private key. This creates a UserOperation.
  2. The UserOperation is sent to a bundler, which is an off-chain entity that can process batches of UserOperations.
  3. A bundler simulates these UserOperations, and evaluates if the signature submitted in the UserOperation corresponds to the address in the associated smart contract wallet.
  4. After validating a batch of UserOperations, the bundler batches up one to several UserOperations into a single bundled transaction, which then gets submitted to the Ethereum blockchain and, ultimately, gets included in an Ethereum block.

For additional information and a technical deep dive on AA wallets, refer to Understanding Account Abstraction.

Solution overview

The following architecture diagram illustrates the solution we will be walking through.

Solution Architecture Diagram

A deployable AWS Cloud Development Kit (AWS CDK) repository of the AWS components is available in the public web3-workshop GitHub repository. The architecture covered in this post consists of Steps 1 and 4 of the first module of the Build Web3 workshop. For instructions on deploying the solution, refer to the README or follow the instructions in the Build Web3 workshop.

An Account Abstraction solution built on AWS consists of the following building blocks (as numbered in the preceding diagram):

  1. Amazon API Gateway, a fully managed service to create, publish, maintain, monitor, and secure APIs at scale. API Gateway is used in this solution to expose all required functionality as a well-defined REST interface, validating JSON Web Token (JWT) tokens against the Amazon Cognito user pool, and translating authenticated calls to Lambda function invokes internally.
  2. Amazon Cognito, a fully managed identity and access management service for web and mobile applications. With Amazon Cognito, developers can choose the authentication mechanism they want to use, for example, an email and password, or a social login. Upon successful login, users receive a JWT token containing various metadata about the user, including their AA wallet address. The AA wallet address is available even before the user ever interacts with it. This is because AA wallet addresses are deterministically calculated.
  3. AWS Step Functions, a serverless workflow orchestration service. A Step Functions-based express workflow is the main serverless orchestration service used in this solution. It is triggered during the JWT generation after a user has successfully logged in via Amazon Cognito. The Step Functions workflow checks if the user already has a key associated via a lookup on the associated Amazon DynamoDB table. If no key exists yet, the workflow invokes the Key Management AWS Lambda function to generate a new key.
  4. Key Management, UserOperation Signing, and Blockchain Lambda functions:
    1. The Key Management function is responsible for interacting with AWS KMS to obtain new private keys generated in a secure fashion by calling generate-data-key-pair-without-plaintext. The key is then stored in the associated DynamoDB table.
    2. The UserOperation Signer function is responsible for creating signatures on the submitted UserOperations. To do so, the function has permission to decrypt certain private keys via AWS KMS. The private keys are then used to create a signature on the submitted hash of the UserOperation.
    3. The Blockchain Handler function uses the Alchemy AA-SDK. It assembles the UserOperation, gets the hash signed via the UserOperation Signer Lambda, and interacts with Alchemy’s Account Abstraction APIs via the Alchemy AA-SDK.
  5. AWS Key Management Service (AWS KMS), a fully managed key management service. With AWS KMS, it is straightforward to create and control cryptographic keys that are used by your application. In this solution, when a user logs in for the first time, a KMS data key pair is created for them using the secp256k1 curve. This key pair is encrypted and can only be decrypted via the associated key residing on AWS KMS.
  6. Amazon DynamoDB, a fully managed, serverless, key-value NoSQL database designed to run high-performance applications at any scale. In this solution, DynamoDB is used to store users’ encrypted private keys of their data key pair. During user login, DynamoDB is checked to verify if a unique user ID (also known as a sub) already exists. If it does, the existing key material is returned. If the sub doesn’t exist, a new key is created in AWS KMS, and the returned encrypted private key is stored in DynamoDB along with the user ID.
  7. An Amazon Managed Blockchain Ethereum node, which is a fully managed RPC node. AA wallets require access to the blockchain—for example, to get the deterministically calculated wallet address, calculated via the eth_call API, or to get the current network gas fees using eth_gasPrice. A Managed Blockchain Goerli Ethereum node is used in this solution for blockchain access, handling JSON Remote Procedure Call (RPC) requests to Ethereum. For additional information on how to deploy a Managed Blockchain Ethereum RPC node, refer to How to deploy an Ethereum node on AWS.
  8. Alchemy Account Kit, a framework to embed smart accounts in your Web3 apps, unlocking powerful features like gas sponsorship, batched transactions, and more. The Alchemy AA-SDK makes it straightforward to integrate and deploy smart accounts, send user operations, and sponsor gas with just a few lines of code.

Let’s dive into the components of Account Kit used in our solution.

AA-SDK

The AA-SDK is a type-safe and performant TypeScript library built on top of viem to provide methods for sending user operations, sponsoring gas, and deploying smart accounts. It handles all the complexity of ERC-4337 under the hood to make account abstraction simple.

You can interact with Alchemy’s Bundler and Gas Manager through the AA-SDK. Let’s explore how to use the AA-SDK by walking through its primary touchpoints.

Creating a Provider & Integrating a Smart Account Implementation

The first step in utilizing the AA-SDK is setting up a provider. This provider acts as the gateway to interact with the blockchain, sending UserOperations (UOs) and managing smart accounts.

The provider is connected to the LightAccount smart account implementation (Alchemy’s gas-optimized smart account implementation). This defines the interface for your smart account (AA Wallet) that you will be controlling through the ‘provider’. Remember to replace the placeholders with your actual Alchemy API key (obtainable from the Alchemy dashboard) and private key.

import { createLightAccountAlchemyClient } from "@alchemy/aa-alchemy";
import { LocalAccountSigner, sepolia, type Hex } from "@alchemy/aa-core";

const chain = sepolia;

// The private key of your EOA that will be the signer of Light Account
const PRIVATE_KEY = "0xYourEOAPrivateKey" as Hex;
const signer = LocalAccountSigner.privateKeyToAccountSigner(PRIVATE_KEY);

// Create a provider to send user operations from your smart account
const provider = await createLightAccountAlchemyClient({
  // get your Alchemy API key at https://dashboard.alchemy.com
  apiKey: "ALCHEMY_API_KEY",
  chain,
  signer,
});

// Fund your account address with ETH to send for the user operations
// (e.g. Get Sepolia ETH at https://sepoliafaucet.com)
console.log(provider.getAddress()); // Log the smart account address

This will log your smart account address to console. Fund your account address with SepoliaETH for sending UOs through it.

Sending UserOperations

At this point you are ready to send UOs. UOs are akin to transactions sent from your smart account (AA Wallet). Here’s how to send a simple UO:

// Send a user operation from your smart account
const { hash: uoHash } = await provider.sendUserOperation({
  uo: {
    target: "0xTargetAddress", // The desired target contract address
    data: "0xCallData", // The desired call data
    value: 0n, // (Optional) value to send the target contract address
  },
});

console.log(uoHash); // Log the user operation hash

The ‘data’ field in UO allows you to define your intended action. It can be empty for simple value transfers or detailed for contract calls. Further guidance on constructing call data is available here.

Upon executing the above code, UOs are sent to the Alchemy Bundler for processing and a `UserOperationHash` is logged, allowing you to track your UO’s status on platforms like Jiffyscan.

Batching UserOperations

Batching multiple UOs into a single `UserOperation` is an effective strategy to reduce gas costs and facilitate complex operations. For instance, in a Web3 game, players can execute several on-chain actions with a single UO without having to approve UOs for each action, enhancing user experience. Here’s how to batch UOs:

const { hash: uoHash } = await provider.sendUserOperation({
  uo: [
    {
      target: "0x...",
      data: "0xcallDataTransacation1",
    },
    {
      target: "0x...",
      data: "0xcallDataTransacation2",
    },
  ],
});

These UOs are executed sequentially as they appear in the array. Note, however, that not every smart account implementation supports batching. Both the LightAccount and ModularAccount implementations from Alchemy do support this feature.

Learn more about batching UOs on Account Kit docs.

Gas Manager

A Paymaster is an onchain contract that allows an entity to sponsor the gas fees for another entity. It can be used by dapps to abstract away the concept of gas from their users. This significantly enhances the UX of dapps and can help onboard the next wave of Web3 users.

Gas Manager is Alchemy’s implementation of a Paymaster. You can use the Gas Manager to sponsor UOs through AA-SDK by following the steps below:

  1. Sign up for an Alchemy account: To access the Gas Manager, you’ll need an Alchemy account. Sign up here and navigate to the Gas Manager tab.
    Gas Manager UI
  2. Create a new gas policy: A gas policy is a set of rules that define which UOs are eligible for gas sponsorship. You can control which operations are eligible for sponsorship by defining rules:- Spending rules: limit the amount of money or the number of UOs that can be sponsored by a policy.- Allowlist: restrict wallet addresses that are eligible for sponsorship. The policy will only sponsor gas for UOs that were sent by addresses on this list.

    Blocklist: ban certain addresses from receiving sponsorship under this policy

    Policy duration: define the duration of your policy and the sponsorship expiry period. This is the period for which the Gas Manager signature (paymaster data) will remain valid once it is generated.

    Create Policy UI

    Ensure that the Gas Policy is linked to the specific Alchemy App whose API key you are using for provider creation. A Gas Policy can only be associated with one Alchemy App and it will only accept requests sent through the API key of associated app.

    To learn more about policy configuration, refer to the Alchemy guide on setting up a gas policyz.

  3. Link the Gas Policy to your Provider in AA-SDK: Next, you must link your gas policy to your provider in AA-SDK, this will ensure any eligible UOs sent through your provider receive gas sponsorship.
    1. Find your Policy ID located at the top of the policy page in the Gas Manager dashboard.
      Create Policy
    2. Create a provider that uses your policy:
      // Client with the Gas Manager to sponsor gas.
              // Find your Gas Manager policy id at: dashboard.alchemy.com/gas-manager/policy/create
              const provider = await createLightAccountAlchemyClient({
                // get your Alchemy API key at https://dashboard.alchemy.com
                apiKey: "ALCHEMY_API_KEY",
                chain,
                signer,
                gasManagerConfig: {
                  policyId: "YourGasManagerPolicyId",
                },
              });
  4. Send sponsored UOs: Now, you’re ready to send sponsored UOs, which means Gas Manager will cover the cost of any eligible UO sent using your provider.
    // Since provider is already linked to gas policy 
        // any eligible UOs sent using this provider will receive gas sponsorship
        const { hash } = await provider.sendUserOperation({
          target: "0xTargetAddress",
          data: "0xCallData",
          value: 0n, // value in bigint or leave undefined
        });

Bundler

Bundler is a network participant in the ERC-4337 standard that collects and submits UserOperations (UOs) to the blockchain, handling the associated gas fees, in exchange for payment during UO processing, either directly from the user’s AA wallet or from a paymaster.

Alchemy’s implementation of a Bundler is called Rundler. It is written in Rust and designed to achieve high performance and reliability. When you send a UO through AA-SDK, it is received by Rundler and submitted on-chain after passing certain checks.

The following are Rundler’s functionality and features:

  • ERC-4337 specification compliance – Rundler is designed to fully comply with the ERC-4337 specification, ensuring compatibility with the latest protocols and on-chain components.
  • Modular architecture – Its modular design allows various components to run either as an integrated binary or a distributed system. This flexibility is key in adapting to different deployment needs.
  • Separate mempool – Rundler maintains its own mempool, a collection of pending user operations awaiting inclusion in a bundle. This ensures better control and prioritization of UOs.
  • Mempool management – Rundler’s mempool validates and simulates UOs as per the ERC-4337 specification. It maintains these operations in memory until they are mined on-chain, handling chain reorgs effectively through a cache of mined user operations.
  • Chain support and extendibility – Rundler is built to support various EVM-compatible chains, with an architecture that can be extended and adapted to specific network requirements.
  • Event listening – Rundler listens for various blockchain events, including new block confirmations and changes in gas prices. This responsiveness ensures that it remains synchronized with the latest state of the blockchain and adjusts its operations accordingly.

To learn more about the inner workings of Rundler and inspect its source code, check out the Rundler GitHub repository.

Conclusion

In this post, we introduced how Account Abstraction works, and we walked through the AA wallet reference architecture that is used in the AWS Build Web3 workshop. We closed the post with a high-level introduction to the Alchemy Account Kit framework.

You can deploy the provided AA wallet CDK repository into your AWS account, configure your Alchemy Account Kit framework, and build your next Web3 app using AA smart wallets!


About the Authors

Emile Baizel is a Senior Blockchain Architect at AWS. He has been working with blockchain technology since 2018, when he participated in his first Ethereum hackathon. He didn’t win, but he got hooked. He specializes in blockchain node infrastructure, digital custody and wallets, and smart contract security.

David-Paul Dornseifer is a Blockchain Development Architect at AWS. He focuses on helping customers design, develop, and scale end-to-end blockchain solutions. His primary focus is on digital asset custody and key management solutions.