π 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_sendTransactionvia 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β
| Command | Opcode | Description | Uniswap | PancakeSwap |
|---|---|---|---|---|
| V2_SWAP_EXACT_IN | 0x08 | Uniswap V2 exact input | β | β |
| V2_SWAP_EXACT_OUT | 0x09 | Uniswap V2 exact output | β | β |
| V3_SWAP_EXACT_IN | 0x00 | Uniswap V3 exact input | β | β |
| V3_SWAP_EXACT_OUT | 0x01 | Uniswap V3 exact output | β | β |
| V4_SWAP | 0x10 | Uniswap V4 with hooks | β | β |
| INFI_SWAP | 0x10 | PancakeSwap Infinity CL | β | β |
| WRAP_ETH | 0x0b | Wrap native token | β | β |
| UNWRAP_WETH | 0x0c | Unwrap WETH | β | β |
| PERMIT2_PERMIT | 0x0a | Gasless approval | β | β |
| SWEEP | 0x04 | Collect tokens | β | β |
| TRANSFER | 0x05 | Transfer tokens | β | β |
| PAY_PORTION | 0x06 | Pay 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β
| Protocol | Network(s) | Function Selectors | Features |
|---|---|---|---|
| Uniswap V2 | ETH, BSC | 0x38ed1739 (swapExactTokensForTokens)0x7ff36ab5 (swapExactETHForTokens)0x18cbafe5 (swapExactTokensForETH) | - Full path decoding - Multi-hop support - Slippage calculation |
| Uniswap V3 | ETH, OPT, BASE | 0x414bf389 (exactInputSingle)0xc04b8d59 (exactInput) | - Fee tier display - Encoded path parsing - Pool identification |
| Uniswap V4 | ETH, OPT, BASE | 0x24856bc3 (UR cmd 0x10) | - Hook support - Actions decoding - Advanced routing |
| Universal Router | ETH, OPT, BASE, BSC | 0x24856bc3 (execute)0x3593564c (execute) | - Multi-command bundles - Permit2 integration - Recursive multicall |
| PancakeSwap V2 | BSC | 0x38ed1739 | - Similar to Uniswap V2 |
| PancakeSwap V3 | BSC | 0x414bf3890xc04b8d59 | - Similar to Uniswap V3 |
| PancakeSwap Infinity | BSC | 0x3593564c (UR cmd 0x10) | - Heuristic decoding - CL swaps - Native + ERC-20 inputs |
| Velodrome | Optimism | Custom | - Stable/volatile pools - Gauge integration |
| Aerodrome | Base | Custom | - Similar to Velodrome |
| ERC-20 | All networks | 0x095ea7b3 (approve)0xa9059cbb (transfer)0x39509351 (increaseAllowance)0xa457c2d7 (decreaseAllowance)0xd505accf (permit EIP-2612) | - Token metadata - Unlimited approval detection - Deadline display |
| WETH | All networks | 0xd0e30db0 (deposit/wrap)0x2e1a7d4d (withdraw/unwrap) | - Native β Wrapped conversion |
| Permit2 | All networks | 0x30f28b7a (permit) | - Single token approvals - Batch approvals - Unlimited detection - Expiration display |
Network Support Matrixβ
| Network | Chain ID | DEXes Supported | Status |
|---|---|---|---|
| SuperSeed | 5330 | Bebop (JAM), Uniswap V2/V3 (via Universal Router) | β Active |
| Ethereum | 1 | Uniswap V2/V3/V4, Universal Router, 1inch | β Active |
| Optimism | 10 | Uniswap V3, Universal Router, Velodrome | β Active |
| Base | 8453 | Uniswap V3, Universal Router, Aerodrome | β Active |
| BNB Chain | 56 | PancakeSwap V2/V3/Infinity, Universal Router | β Active |
| Arbitrum One | 42161 | Uniswap V2/V3, Universal Router | β Active |
| Shardeum | 8118 | Limited 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+