Skip to main content

πŸ” Transaction Decoding System

SuperSafe Wallet implements a professional-grade transaction decoding system that transforms raw blockchain transactions into human-readable, user-friendly information. The system supports major DEX protocols (Uniswap V2/V3/V4, PancakeSwap Infinity, Velodrome, Aerodrome) on multiple EVM networks with a strict 'no alternatives' security policy.

Executive Summary​

Key Features​

  • βœ… Multi-Protocol Support - Uniswap, PancakeSwap, Velodrome, Aerodrome, and more
  • βœ… Multi-Network - Currently supports 7 active networks (SuperSeed, Ethereum, Optimism, Base, BNB Chain, Arbitrum, Shardeum)
  • βœ… Strict Security - No fallbacks for critical parameters
  • βœ… Token Metadata - Multi-layer lookup with caching
  • βœ… Universal Router - Full command decoding and execution tracking
  • βœ… Permit2 Support - Gasless approvals with unlimited detection
  • βœ… Recursive Multicall - Batch operation breakdown

System Metrics​

Transaction Types Supported: 20+ types
DEX Protocols: 7 major protocols
Networks: 7 active EVM networks
Token Cache: LRU 1000 entries
Decode Success Rate: 95%+ (production)
Average Decode Time: <100ms

Transaction Flow​

Complete Transaction Lifecycle​

sequenceDiagram
participant dApp
participant Content as Content Script
participant Provider as ProviderStreamHandler
participant Decoder as TransactionDecoder
participant TMS as TokenMetadataService
participant RPC as Blockchain RPC
participant Popup
participant User

dApp->>Content: eth_sendTransaction(txParams)
Content->>Provider: Forward via stream
Provider->>Provider: Validate network
Provider->>Decoder: buildTransactionModalRequest(tx, context)

Note over Decoder: Route to appropriate decoder

alt Universal Router
Decoder->>Decoder: Detect UR selector
Decoder->>UniversalRouterDecoder: decode()
else Standard Transaction
Decoder->>Decoder: Decode based on selector
end

Decoder->>TMS: Fetch token metadata

alt Tokens in Cache
TMS-->>Decoder: Return cached metadata
else Tokens not cached
TMS->>RPC: Fetch symbol, decimals, name
RPC-->>TMS: Return metadata
TMS->>TMS: Cache for future use
TMS-->>Decoder: Return metadata
end

Decoder->>Decoder: Format amounts with correct decimals
Decoder->>Decoder: Build user-friendly structure

alt Decode Success
Decoder-->>Provider: Return decoded transaction
Provider->>Popup: Create confirmation popup
Popup->>User: Display human-readable details

alt User Approves
User->>Popup: Click "Confirm"
Popup->>Provider: User approved
Provider->>Provider: Sign transaction
Provider->>RPC: Broadcast transaction
RPC-->>Provider: Return txHash
Provider->>dApp: Return txHash
else User Rejects
User->>Popup: Click "Cancel"
Popup->>Provider: User rejected
Provider->>dApp: Return error 4001
end
else Decode Failure
Decoder-->>Provider: Throw error
Provider->>dApp: Return error -32603
Note over dApp,User: Transaction rejected for safety
end

Transaction Request Lifecycle​

Phase 1: Request Reception

  • dApp initiates eth_sendTransaction via injected provider
  • Content script forwards request to background via stream
  • ProviderStreamHandler receives and validates request

Phase 2: Network Validation

  • Validate current network matches transaction chainId
  • Check if dApp supports current network
  • Ensure network is supported by wallet

Phase 3: Transaction Decoding

  • Extract function selector from transaction data
  • Route to appropriate decoder (Universal Router, ERC-20, etc.)
  • Fetch token metadata for all involved tokens
  • Format amounts with correct decimals
  • Build human-readable transaction structure

Phase 4: User Confirmation

  • Create popup with decoded transaction details
  • Display origin, network, amounts, tokens, risks
  • Wait for user approval or rejection

Phase 5: Execution

  • Sign transaction with private key (background only)
  • Broadcast to blockchain via RPC
  • Return transaction hash to dApp

Phase 6: Cleanup

  • Close popup
  • Update transaction history
  • Clean up pending request state

Universal Router Support​

Overview​

Universal Router is a smart contract pattern used by Uniswap and PancakeSwap to bundle multiple operations into a single transaction. It uses a command-based system where each command represents an operation.

Command Structure​

Transaction Format:

{
to: "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD", // Universal Router address
data: "0x3593564c" + "000000..." // Selector + ABI-encoded (commands, inputs, deadline)
}

Decoded Structure:

{
commands: "0x0b00", // Hex string of command bytes
inputs: [
"0x000000...", // Input for first command
"0x000000..." // Input for second command
],
deadline: 1730000000 // Unix timestamp
}

Supported Commands​

CommandOpcodeDescriptionUniswapPancakeSwap
V2_SWAP_EXACT_IN0x08Uniswap V2 exact inputβœ…βœ…
V2_SWAP_EXACT_OUT0x09Uniswap V2 exact outputβœ…βœ…
V3_SWAP_EXACT_IN0x00Uniswap V3 exact inputβœ…βœ…
V3_SWAP_EXACT_OUT0x01Uniswap V3 exact outputβœ…βœ…
V4_SWAP0x10Uniswap V4 with hooksβœ…βŒ
INFI_SWAP0x10PancakeSwap Infinity CLβŒβœ…
WRAP_ETH0x0bWrap native tokenβœ…βœ…
UNWRAP_WETH0x0cUnwrap WETHβœ…βœ…
PERMIT2_PERMIT0x0aGasless approvalβœ…βœ…
SWEEP0x04Collect tokensβœ…βœ…
TRANSFER0x05Transfer tokensβœ…βœ…
PAY_PORTION0x06Pay portion of balanceβœ…βœ…

Context-Aware Opcode Interpretation​

Challenge: Opcode 0x10 is overloaded - it means V4_SWAP for Uniswap and INFI_SWAP for PancakeSwap.

Solution: Router address detection

// Detect PancakeSwap by router address
const PANCAKE_ROUTERS = [
'0x13f4EA83D0bd40E75C8222255bc855a974568Dd4', // PancakeSwap UR (Base)
'0xd9C500DfF816a1Da21A48A732d3498Bf09dc9AEB' // PancakeSwap UR (BSC)
];

const isPancakeSwap = PANCAKE_ROUTERS.includes(to.toLowerCase());

if (opcode === 0x10) {
if (isPancakeSwap) {
return 'INFI_SWAP'; // PancakeSwap Infinity
} else {
return 'V4_SWAP'; // Uniswap V4
}
}

Token Metadata System​

Overview​

The TokenMetadataService is the central authority for all token information (symbol, decimals, name). It implements a strict "no fallbacks" policy to ensure user safety.

Architecture​

flowchart LR
Decoder[Transaction Decoder] --> TMS[TokenMetadataService]
TMS --> Cache{Check Cache}
Cache -->|Hit| ReturnCached[Return Cached<br/>Metadata]
Cache -->|Miss| CheckBebop{Check Bebop<br/>Database}
CheckBebop -->|Found| UpdateCache1[Update Cache]
CheckBebop -->|Not Found| OnChainRPC[On-Chain RPC<br/>Calls]
OnChainRPC -->|Success| UpdateCache2[Update Cache]
OnChainRPC -->|Failure| ThrowError[Throw Error<br/>NO FALLBACK]
UpdateCache1 --> ReturnCached
UpdateCache2 --> ReturnCached
ThrowError --> RejectTx[Reject Transaction]

Multi-Layer Lookup Strategy​

Layer 1: LRU Cache (Fastest)

  • Capacity: 1000 entries
  • Key: chainId + address (lowercase)
  • Eviction: Least Recently Used
  • Hit Rate: ~90% for active trading
  • Latency: <1ms

Layer 2: BebopTokenService (Fast)

  • Source: Local token database
  • Coverage: Major tokens on supported networks
  • Latency: ~5ms
  • Fallback: On-chain RPC if not found

Layer 3: On-Chain RPC (Slow)

  • Method: Direct smart contract calls
  • Functions: token.symbol(), token.decimals(), token.name()
  • Latency: 50-500ms depending on RPC
  • Validation: Strict type and range checks

Strict Validation​

No Fallbacks Policy:

// βœ… CORRECT - Throws error if metadata unavailable
if (!symbol || !decimals || decimals < 0 || decimals > 18) {
throw new Error(
`Cannot fetch token metadata for ${address} on chain ${chainId}. ` +
`This token may not be a valid ERC-20, or RPC is unavailable.`
);
}

// ❌ NEVER DO THIS - Dangerous fallback
const decimals = metadata?.decimals || 18; // WRONG!
const symbol = metadata?.symbol || 'Unknown'; // WRONG!

Supported Protocols​

Protocol Support Matrix​

ProtocolNetwork(s)Function SelectorsFeatures
Uniswap V2ETH, BSC0x38ed1739 (swapExactTokensForTokens)
0x7ff36ab5 (swapExactETHForTokens)
0x18cbafe5 (swapExactTokensForETH)
- Full path decoding
- Multi-hop support
- Slippage calculation
Uniswap V3ETH, OPT, BASE0x414bf389 (exactInputSingle)
0xc04b8d59 (exactInput)
- Fee tier display
- Encoded path parsing
- Pool identification
Uniswap V4ETH, OPT, BASE0x24856bc3 (UR cmd 0x10)- Hook support
- Actions decoding
- Advanced routing
Universal RouterETH, OPT, BASE, BSC0x24856bc3 (execute)
0x3593564c (execute)
- Multi-command bundles
- Permit2 integration
- Recursive multicall
PancakeSwap V2BSC0x38ed1739- Similar to Uniswap V2
PancakeSwap V3BSC0x414bf389
0xc04b8d59
- Similar to Uniswap V3
PancakeSwap InfinityBSC0x3593564c (UR cmd 0x10)- Heuristic decoding
- CL swaps
- Native + ERC-20 inputs
VelodromeOptimismCustom- Stable/volatile pools
- Gauge integration
AerodromeBaseCustom- Similar to Velodrome
ERC-20All networks0x095ea7b3 (approve)
0xa9059cbb (transfer)
0x39509351 (increaseAllowance)
0xa457c2d7 (decreaseAllowance)
0xd505accf (permit EIP-2612)
- Token metadata
- Unlimited approval detection
- Deadline display
WETHAll networks0xd0e30db0 (deposit/wrap)
0x2e1a7d4d (withdraw/unwrap)
- Native ↔ Wrapped conversion
Permit2All networks0x30f28b7a (permit)- Single token approvals
- Batch approvals
- Unlimited detection
- Expiration display

Network Support Matrix​

NetworkChain IDDEXes SupportedStatus
SuperSeed5330Bebop (JAM), Uniswap V2/V3 (via Universal Router)βœ… Active
Ethereum1Uniswap V2/V3/V4, Universal Router, 1inchβœ… Active
Optimism10Uniswap V3, Universal Router, Velodromeβœ… Active
Base8453Uniswap V3, Universal Router, Aerodromeβœ… Active
BNB Chain56PancakeSwap V2/V3/Infinity, Universal Routerβœ… Active
Arbitrum One42161Uniswap V2/V3, Universal Routerβœ… Active
Shardeum8118Limited DEX support (transaction decoding available)βœ… Active

Security Model​

"No Fallbacks" Policy​

Core Principle: Never use default or guessed values for critical transaction parameters in signing contexts.

Rationale:

  • Better to show an error than incorrect amounts/tokens to user
  • Prevents user from signing transactions with wrong information
  • Eliminates risk of signing on wrong network or with wrong tokens
  • Maintains user trust through transparency

Anti-Patterns to Avoid​

1. Defaulting to 18 Decimals

// ❌ WRONG - Could display 1000x incorrect amount
const decimals = token.decimals || 18;
const formatted = ethers.formatUnits(amount, decimals);

// βœ… CORRECT - Throws error if decimals unavailable
const metadata = await tokenMetadataService.getTokenMetadata(token, chainId, provider);
const formatted = ethers.formatUnits(amount, metadata.decimals);

2. Using "Unknown" as Symbol

// ❌ WRONG - Confuses user
const symbol = token.symbol || 'Unknown';
const display = `${amount} ${symbol}`; // "0.5 Unknown" is meaningless

// βœ… CORRECT - Don't display if unknown
if (!token.symbol) {
throw new Error(`Cannot resolve token at ${token.address}`);
}
const display = `${amount} ${token.symbol}`;

Attack Prevention​

Phishing Protection:

  • Always display origin (dApp URL) in confirmation popup
  • Show network name and chainId
  • Highlight mismatches between expected and actual networks

Network Mismatch Protection:

  • Validate transaction chainId matches wallet's current network
  • Reject if dApp declares supported networks and current network not in list
  • Clear error messages for network mismatches

Unlimited Approval Detection:

// Detect MAX_UINT256 or MAX_UINT160 approvals
const MAX_UINT256 = BigInt('2') ** BigInt('256') - BigInt('1');
const MAX_UINT160 = BigInt('2') ** BigInt('160') - BigInt('1');

if (amount >= MAX_UINT256 * BigInt('99') / BigInt('100') ||
amount >= MAX_UINT160 * BigInt('99') / BigInt('100')) {
// Show prominent warning
badges.push('⚠️ UNLIMITED APPROVAL');
risks.push('This grants unlimited access to your tokens');
}

Document Status: βœ… Complete and Current
Last Updated: November 15, 2025
Version: 3.0.0+