Skip to content
K

Karma Wallet

Karma Wallet turns leftover gas fee “dust” into au

Created on 30th June 2025

•

K

Karma Wallet

Karma Wallet turns leftover gas fee “dust” into au

The problem Karma Wallet solves

Gas fees are a necessary part of using the blockchain, but they’re often odd amounts that leave “dust” in the wallet. Karma Wallet turns these small amounts into meaningful contributions:

Support open-source projects without actively thinking about it.
Fund community initiatives in a passive, automated way.
Gamify generosity by making every transaction part of a bigger giving story.
Instead of letting your micro-ETH fragments sit idle, they get converted into micro-donations.

Challenges I ran into

⚙️ How It Works — Detailed UserOperation Flow

Karma Wallet is built on ERC-4337 and works within the UserOperation lifecycle. Here’s the exact flow:

1️⃣ Transaction Initiation

  • User interacts with a dApp via Karma Wallet.
  • The wallet constructs a UserOperation with:
    • sender = Karma Wallet smart account address.
    • callData = Encoded function call to the target dApp contract.
    • value = Transaction value.
    • maxFeePerGas = Current gas settings.
    • maxPriorityFeePerGas = Current gas settings.
    • paymasterAndData = Empty bytes.
    • signature = Empty bytes.

2️⃣ UserOperation is signed and sent to Bundler

  • The wallet sends the UserOperation to the Bundler.
  • The Bundler processes the UserOperation and sends it to the EntryPoint.
  • The EntryPoint processes the UserOperation and sends it to the Account Abstraction smart contract.

3️⃣ Account Abstraction Smart Contract

function execute(address dest, uint256 value, bytes calldata func) external {
    _requireFromEntryPointOrOwner();

    uint256 gasPre = gasleft();
    _call(dest, value, func);
    uint256 gasPost = gasleft();

    uint256 gasUsed = gasPre - gasPost;
    uint256 balance = address(this).balance;

    uint256 tip = _calculateTip(gasUsed);

    if (tip < balance) {
        _jar.deposit{value: tip}(gasUsed, tip);
    }
}

function _calculateTip(uint256 gasUsed) internal view returns (uint256) {
    uint256 ethPriceUSD = _oracleAdaptor.getLatestEthPriceInUsd();

    uint256 gasCostInWei = gasUsed * tx.gasprice;
    uint256 gasCostInUSD = (gasCostInWei * ethPriceUSD) / 1e18;

    uint256 tipInUSD = 0;
    uint256 roundingMultipleUSD = 1e16; // $0.01 in 18-decimal USD
    if (gasCostInUSD > 0) {
        uint256 remainder = gasCostInUSD % roundingMultipleUSD;
        if (remainder > 0) {
            tipInUSD = roundingMultipleUSD - remainder;
        }
    }

    uint256 tipInWei = (tipInUSD * 1e18) / ethPriceUSD;
    return tipInWei;
}

  • The Account Abstraction smart contract processes the UserOperation and sends it to the EntryPoint.
  • gasPre and gasPost measure the gas consumed during the call.
  • _calculateTip(gasUsed) converts gas used into USD value and determines the rounded-up tip.
  • If the wallet has enough ETH to cover the tip, it’s sent to the _jar contract.

Cheer Project

Cheering for a project means supporting a project you like with as little as 0.0025 ETH. Right now, you can Cheer using ETH on Arbitrum, Optimism and Base.

Discussion

Builders also viewed

See more projects on Devfolio