Unlocking Account Abstraction with Amex Passport
Breaking Down Amex Passport's On-Chain Data Insights

When American Express launched Amex Passport in September 2025, minting NFT “stamps” on Base for international purchases, I knew the on-chain data would tell a story most people would miss.
Users have no idea they’re interacting with Web3. That invisibility is the product’s genius, but it also means the blockchain holds insights Amex isn’t publishing.
I built a Dune dashboard to decode it. Here’s how.
The Architecture Worth Understanding
Before writing queries, you need to grasp what Amex built:
Account Abstraction (ERC-4337) gives each user a smart contract wallet instead of a standard EOA. Amex’s backend controls minting, no seed phrases, no user action required.
Paymaster contracts cover all gas fees. Users pay nothing. Amex funds a contract that validates legitimate mints and reimburses costs through the EntryPoint.
Soulbound tokens have disabled transfers. Stamps can’t be sold, purely commemorative. No speculation, no secondary market noise.
The Contracts
Three addresses matter:
NFT Contract:
0x96cebb59b00109dc8c4de1a9a94d9fad658fee46EntryPoint (v0.7.0):
0x0000000071727de22e5e9d8baf0edac6f37da032Paymaster:
0x5fa66dfe8a3983e55071e8c4631ab43b5f33a4ab
Query 1: Daily Mints and Unique Wallets
The Transfer event (0xddf252ad...) fires on every mint. Key filter: topic1 equals the zero address, that's a mint, not a transfer.
SELECT
varbinary_ltrim(topic2) AS minted_to,
varbinary_to_uint256(topic3) AS token_id
FROM base.logs
WHERE contract_address = 0x96cebb59b00109dc8c4de1a9a94d9fad658fee46
AND topic0 = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
AND topic1 = 0x0000000000000000000000000000000000000000000000000000000000000000
varbinary_ltrim() strips left-padding from addresses. varbinary_to_uint256() converts the token ID. I join this with the TokensMinted event (0x9d89e36e...) to pull IPFS URIs when needed.
The full query aggregates daily mints, unique wallets, cumulative totals, and a 7-day moving average to smooth noise.
Query 2: Wallet Distribution
Are stamps concentrated in whales or spread across users?
WITH wallet_mint_counts AS (
SELECT
varbinary_ltrim(topic2) AS wallet,
COUNT(*) AS stamps_per_wallet
FROM base.logs
WHERE contract_address = 0x96cebb59b00109dc8c4de1a9a94d9fad658fee46
AND topic0 = 0xddf252ad...
AND topic1 = 0x0000...
GROUP BY varbinary_ltrim(topic2)
)
SELECT
stamps_per_wallet,
COUNT(*) AS wallets_with_this_count
FROM wallet_mint_counts
GROUP BY stamps_per_wallet
I bucket wallets by stamp count and calculate the percentage of total wallets and stamps per bucket. The data shows remarkably even distribution, no whale dominance, indicating organic adoption across diverse cardholders.
Query 3: Gas Economics
This reveals Amex’s actual infrastructure costs. The UserOperationEvent from EntryPoint contains everything:
SELECT
varbinary_to_uint256(varbinary_substring(data, 1, 32)) AS nonce,
varbinary_to_uint256(varbinary_substring(data, 33, 32)) > 0 AS success,
varbinary_to_uint256(varbinary_substring(data, 65, 32)) AS actual_gas_cost_wei,
varbinary_to_uint256(varbinary_substring(data, 97, 32)) AS actual_gas_used
FROM base.logs
WHERE contract_address = 0x0000000071727de22e5e9d8baf0edac6f37da032
AND topic0 = 0x49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f
The data field packs non-indexed parameters sequentially in 32-byte chunks. I filter for operations that paymaster_used match Amex's Paymaster address, then join with it prices.usd to convert ETH costs to USD at the minute-level.
The final output: daily sponsored operations, gas costs in ETH and USD, cost-per-stamp, and cumulative spend over time.
Technical Notes
Use DuneSQL’s varbinary functions:
varbinary_ltrim(),varbinary_to_uint256(), andvarbinary_substring()handle hex data cleanly. Don't fight with string casting.Always filter for mints: Transfer events fire for both mints and transfers. Without the zero-address filter, you’ll miscount.
Verify byte offsets: The UserOperationEvent packs data at specific positions (1–32 for nonce, 33–64 for success, etc.). Get these wrong, and you’ll extract garbage. Cross-reference with the contract ABI on BaseScan; this helps too.
Join prices at minute granularity: The
prices.usdtable on Dune provides minute-level pricing. Match ondate_trunc('minute', block_time)for accurate USD conversion.
What the Data Shows
The dashboard reveals what Amex won’t publish: real adoption curves, cost efficiency trends, and wallet concentration metrics. And to be honest, they dont need to. Public blockchains create accountability, even when the company abstracts the technology completely.




