ERC4337 Smart Account Wallets

Crypto for consumers

Polystream integrates ERC-4337 Account Abstraction to provide a seamless user experience by abstracting away complex blockchain interactions. This architecture allows users to interact with DeFi protocols without managing gas fees directly or dealing with the traditional complications of cryptocurrency wallets.

Polystream's ERC-4337 integration is enabled by leveraging Biconomy’s Nexus Smart Accounts.


Smart Account Architecture

1. EntryPoint Contract

The EntryPoint.sol contract is the central hub through which all user operations are processed:

// Core contract that validates and executes UserOperations
contract EntryPoint {
    function handleOps(UserOperation[] calldata ops, address payable beneficiary) external;
    function handleAggregatedOps(...) external;
    function simulateValidation(UserOperation calldata userOp) external;
    // Additional functionality...
}
  • Validates signatures and transaction parameters

  • Executes batched user operations

  • Manages gas refunds and paymaster interactions

  • Provides simulation capabilities for off-chain validation

2. Bundler

Bundlers are a critical component of the ERC-4337 infrastructure that collect "UserOperation" objects from users and submit them to the EntryPoint contract:

While the bundler itself is typically an off-chain service, your codebase integrates with bundlers through:

  • UserOperation creation and signing in client-side code

  • Verification and validation mechanisms in the smart contracts

  • Tests for bundler compatibility

The core bundler interaction happens through the SendUserOp interface which is referenced in the AASigner class:

export class AASigner extends Signer {
  // ...
  constructor(
    readonly signer: Signer,
    readonly entryPointAddress: string,
    readonly sendUserOp: SendUserOp, // Function to send UserOperations to a bundler
    readonly accountFactoryAddress: string,
    readonly index = 0,
    readonly provider = signer.provider
  ) {
    // ...
  }
  // ...
}

3. Factory Contract

The SimpleAccountFactory.sol contract deploys new smart accounts when needed:

// Creates new SimpleAccount instances
contract SimpleAccountFactory {
    function createAccount(address owner, uint256 salt) public returns (SimpleAccount);
    function getAddress(address owner, uint256 salt) public view returns (address);
    // Additional functionality...
}
  • Deterministic account creation with CREATE2

  • Address calculation for counterfactual accounts

  • Batched account creation

4. Paymaster

The optional VerifyingPaymaster.sol contract can sponsor gas fees for users:

// Sponsors gas fees for users
contract VerifyingPaymaster {
    function validatePaymasterUserOp(
        UserOperation calldata userOp,
        bytes32 userOpHash,
        uint256 maxCost
    ) external returns (bytes memory context, uint256 validationData);
    
    function postOp(
        PostOpMode mode,
        bytes calldata context,
        uint256 actualGasCost
    ) external;
    // Additional functionality...
}
  • Validates operations it's willing to sponsor

  • Implements post-operation logic for accounting

  • Defines payment criteria and limitations


User Operation Structure

The UserOperation.ts structure is the fundamental data type in ERC-4337:

class UserOperation {
  constructor(params) {
    this.sender = getAddress(params.sender);          // Smart Account address
    this.nonce = params.nonce;                        // Unique nonce for operation
    this.factory = params.factory ?? undefined;       // Factory for counterfactual accounts
    this.factoryData = params.factoryData ?? '0x';    // Init data for account creation
    this.callData = params.callData ?? '0x';          // The operation data
    this.verificationGas = params.verificationGas;    // Gas for signature verification
    this.callGas = params.callGas;                    // Gas for the main call
    this.preVerificationGas = params.preVerificationGas; // Gas for pre-verification
    this.maxPriorityFee = params.maxPriorityFee;      // Max priority fee (EIP-1559)
    this.maxFeePerGas = params.maxFeePerGas;          // Max fee per gas (EIP-1559)
    this.paymaster = params.paymaster ?? undefined;   // Paymaster contract (optional)
    this.paymasterData = params.paymasterData ?? '0x'; // Paymaster verification data
    this.signature = params.signature ?? '0x';        // Account signature
    // Additional fields...
  }
}

Polystream implements sponsored transactions through paymasters, allowing users to execute transactions without holding ETH. This creates a "Web2-like" experience where users don't need to understand gas or acquire ETH to use the platform.

The PaymasterFlow implementation is referenced in several test files, showing how transactions can be sponsored:

// From account-abstraction/test/entrypoint.test.ts
describe('with paymaster (account with no eth)', () => {
  let testPaymasterAcceptAll: TestPaymasterAcceptAll
  let testPaymasterWithPostOp: TestPaymasterWithPostOp
  // ...
  
  beforeEach(async () => {
    testPaymasterAcceptAll = await new TestPaymasterAcceptAll__factory(ethersSigner).deploy(entryPoint.address)
    testPaymasterWithPostOp = await new TestPaymasterWithPostOp__factory(ethersSigner).deploy(entryPoint.address)
    await testPaymasterAcceptAll.addStake(globalUnstakeDelaySec, { value: paymasterStake })
    // ...
  })
  // ...
})

Paymasters can sponsor gas fees and can implement different payment models:

  1. Free transactions: Subsidizing user operations as a business expense

  2. Token payments: Users pay in ERC-20 tokens instead of ETH

  3. Subscription models: Users with active subscriptions get free transactions


Dealing with popups and signing for every transaction is one of the worst parts of crypto UX.

Thanks to ERC4337, you won't need to sign endless transaction prompts:

  • Set up once with a single approval

  • No more constant wallet connection requests

  • No more confusing technical permissions

  • No more gas fee surprises

If interaction is needed, you'll only see one final confirmation - not dozens of confusing approval requests.

Last updated