Secure, Sovereign Transaction Signing with Hardware Wallet Integration
Demo project showcasing human-readable transaction signing using ERC-7730 standard, Ledger hardware wallet integration, and Web3 infrastructure for the Protocol Labs "Secure, Sovereign Systems" track.
- ✅ ERC-7730 Human-Readable Descriptors - Transform raw calldata into understandable transaction previews
- ✅ Smart Contract Decoder - Automatic ABI-based transaction parsing with ethers.js
- ✅ Ledger Hardware Wallet Integration - Real device signing via WebUSB
- ✅ Interactive UI Simulation - Visual Ledger Nano X simulator for testing without hardware
- ✅ DeFi Router Contract - Production-ready swap and liquidity management functions
- ✅ Hardhat 3 Development Environment - Modern smart contract tooling with mainnet forking
- ✅ Digital Asset Dashboard - MultiBaAS-powered portfolio tracking and governance interface
- Frontend: Next.js 14, TypeScript, Tailwind CSS
- Smart Contracts: Solidity 0.8.24, Hardhat 3, OpenZeppelin
- Web3: ethers.js v6, MetaMask integration
- Hardware: @ledgerhq/hw-transport-webusb, @ledgerhq/hw-app-eth
- API Integration: MultiBaAS REST API, axios
- Architecture: React hooks, centralized state management, service layer pattern
node >= 18.x
npm or yarn# Clone repository
git clone https://github.com/robdgs/erc-7730Humanizer.git
cd erc-7730Humanizer
# Install all dependencies (root + hardhat + frontend)
npm run setup1. Start local blockchain
npm run node
# Hardhat node running on http://localhost:85452. Deploy contracts (in new terminal)
npm run deploy
# DemoRouter deployed with address saved to deployments/3. Generate ERC-7730 descriptor
npm run generate-descriptor
# Creates hardhat/descriptors/DemoRouter.json
# Copies to frontend/public/descriptors/4. Start frontend
npm run dev
# Next.js running on http://localhost:3000erc-7730Humanizer/
├── erc7730-descriptors/
│ └── DemoRouter.erc7730.json # ERC-7730 schema-compliant descriptor
├── frontend/
│ ├── app/
│ │ ├── page.tsx # Landing page with two paths
│ │ ├── create/
│ │ │ └── page.tsx # Descriptor generator
│ │ ├── dashboard/
│ │ │ └── page.tsx # Digital asset dashboard
│ │ └── sign/
│ │ └── page.tsx # Hardware signing page
│ ├── core/ # Business logic layer
│ │ ├── wallet.ts # Centralized wallet manager
│ │ └── erc7730/ # ERC-7730 utilities
│ │ ├── index.ts # Public exports
│ │ ├── types.ts # Type definitions
│ │ ├── parser.ts # Descriptor parser
│ │ └── formatter.ts # Human-readable formatter
│ ├── hooks/ # React hooks
│ │ ├── useWallet.ts # Wallet connection hook
│ │ └── useDashboard.ts # Dashboard data hook
│ ├── services/ # Unified data layer
│ │ ├── portfolio.ts # Token balances (real + mock)
│ │ ├── governance.ts # DAO voting (real + mock)
│ │ └── vesting.ts # Claimable tokens (real + mock)
│ ├── components/
│ │ ├── wallet/ # Wallet components
│ │ │ ├── ConnectButton.tsx # Wallet connection button
│ │ │ └── AddressDisplay.tsx # Address display
│ │ ├── signing/ # Signing flow
│ │ │ ├── SigningModal.tsx # Unified signing modal
│ │ │ └── TransactionPreview.tsx # Transaction preview
│ │ ├── CalldataDecoder.tsx # Transaction decoder component
│ │ ├── LedgerSimulator.tsx # Visual Ledger device UI
│ │ ├── LedgerSigner.tsx # Real Ledger WebUSB integration
│ │ ├── PortfolioCard.tsx # Portfolio overview component
│ │ ├── TokenTable.tsx # Token holdings table
│ │ ├── DAOVotes.tsx # Governance proposals component
│ │ └── VestingTimeline.tsx # Vesting schedule visualizer
│ ├── lib/
│ │ ├── decoder.ts # ABI decoder utilities
│ │ └── multibaas/ # MultiBaAS API clients
│ │ ├── client.ts # API client configuration
│ │ ├── portfolio.ts # Portfolio fetching
│ │ ├── governance.ts # DAO voting
│ │ └── events.ts # Claimable tokens & vesting
│ └── public/
│ └── descriptors/
│ └── DemoRouter.json # Generated descriptor (runtime)
├── hardhat/
│ ├── contracts/
│ │ └── DemoRouter.sol # DeFi router contract
│ ├── scripts/
│ │ ├── deploy.ts # Deployment script
│ │ ├── generate-descriptor.ts # ERC-7730 generator
│ │ └── validate-descriptor.ts # Schema validator
│ ├── descriptors/
│ │ └── DemoRouter.json # Generated descriptor
│ └── deployments/
│ └── DemoRouter.json # Deployment artifacts
└── package.json # Root scripts
The project follows a clean architecture with clear separation of concerns:
User Interface (React Components)
↓
Hooks Layer (useWallet, useDashboard)
↓
Services Layer (portfolio, governance, vesting)
↓
Core Layer (wallet manager, ERC-7730 utilities)
↓
External APIs (MultiBaAS, Web3 Providers)
1. Centralized Wallet Management (core/wallet.ts)
// Single WalletManager instance
const walletManager = WalletManager.getInstance();
// React hook for components
const { address, provider, connect, isConnected } = useWallet();Features:
- Singleton pattern for consistent state
- Automatic reconnection on page load
- Account change listeners
- Network switching support
2. Unified Services (services/)
All services follow the same pattern:
// Automatic fallback to mock data
async function getPortfolio(
address: string,
provider?: Provider,
forceMock?: boolean
): Promise<Portfolio>;Services:
portfolio.ts- Token balances with Web3 providergovernance.ts- DAO proposals and voting powervesting.ts- Claimable tokens and schedules
3. ERC-7730 Utilities (core/erc7730/)
Modular implementation:
parser.ts- Descriptor loading and validationformatter.ts- Human-readable formattingtypes.ts- Shared TypeScript definitions
4. Reusable Components
SigningModal- Universal transaction signing flowConnectButton- Wallet connection UIAddressDisplay- Formatted address display
1. User clicks "Vote For" button
↓
2. Component calls useDashboard hook
↓
3. Hook calls getDaoVotes service
↓
4. Service fetches from Web3/MultiBaAS (or mock)
↓
5. Data returns through hook to component
↓
6. Component opens SigningModal
↓
7. Modal loads ERC-7730 descriptor
↓
8. User approves in Ledger simulator
↓
9. Signed transaction returned
ERC-7730 provides a standardized way to describe smart contract functions in human-readable format.
Example Descriptor Structure:
{
"context": {
"contract": {
"abi": [...],
"deployments": [{"chainId": 1, "address": "0x..."}]
}
},
"messages": {
"swapExactTokensForTokens": {
"intent": "Swap tokens",
"fields": [
{
"path": "params.tokenIn",
"label": "Token In",
"format": "tokenAddress"
},
{
"path": "params.amountIn",
"label": "Amount In",
"format": "tokenAmount"
}
]
}
},
"display": {
"formats": {
"tokenAmount": {
"type": "amount",
"denomination": "wei"
}
}
}
}Raw Calldata (0x1760feec...)
↓
ABI Parser (ethers.Interface)
↓
Function Name + Parameters
↓
ERC-7730 Formatter
↓
Human-Readable Display
Example:
Raw: 0x1760feec000000000000000000000000a0b86991c...
Decoded:
Intent: Swap tokens
Function: swapExactTokensForTokens()
Fields:
• Token In: USDC (0xA0b8...eB48)
• Token Out: DAI (0x6B17...1d0F)
• Amount In: 1,000,000.0
• Minimum Out: 990,000.0
• Recipient: 0x742d...5f00
• Deadline: Nov 22, 2025, 3:45 PM
Simulation Mode (Default)
- Visual Ledger Nano X UI
- Navigate transaction fields
- Approve/Reject buttons
- No hardware required
Real Device Mode (WebUSB)
import TransportWebUSB from "@ledgerhq/hw-transport-webusb";
import Eth from "@ledgerhq/hw-app-eth";
// Connect to Ledger
const transport = await TransportWebUSB.create();
const eth = new Eth(transport);
// Get address
const { address } = await eth.getAddress("44'/60'/0'/0/0");
// Sign transaction
const signature = await eth.signTransaction("44'/60'/0'/0/0", serializedTx);Requirements for Real Device:
- Ledger Nano S/X/S Plus
- Ethereum app installed
- Chrome/Edge browser (WebUSB support)
- HTTPS connection
Production-ready DeFi router with complex parameter structures:
Functions:
swapExactTokensForTokens(SwapParams)- Token swap with slippage protectionaddLiquidity(LiquidityParams)- Add liquidity to poolsremoveLiquidity(...)- Remove liquidity with minimum amountssimpleTransfer(...)- Basic token transfer
Struct Parameters:
struct SwapParams {
address tokenIn;
address tokenOut;
uint256 amountIn;
uint256 minAmountOut;
address recipient;
uint256 deadline;
}Events:
TokenSwap- Emitted on successful swapsLiquidityAdded- Emitted when adding liquidityLiquidityRemoved- Emitted when removing liquidity
Clean Landing with Two Paths:
- Quick Decode: Paste calldata and see human-readable preview
- Asset Dashboard: Full portfolio management interface
Features:
- Visual card navigation
- Tech stack overview
- GitHub/demo links
- Modern terminal aesthetic
Automated ERC-7730 Generator:
- Paste your contract's ABI JSON
- Click "Generate ERC-7730 JSON"
- Auto-detects formats:
- Addresses →
addressortokenformat - Amounts →
amountformat (wei) - Timestamps →
dateformat
- Addresses →
- Download or copy generated descriptor
- Use with Ledger for human-readable signing
Example Use Case:
Input: Contract ABI from Etherscan
Output: Complete ERC-7730 descriptor with:
✓ All functions included
✓ Smart format detection
✓ Ready for hardware wallets
Features:
- Wallet Connection: MetaMask integration with automatic reconnection
- Portfolio Overview: Total value and token holdings
- Token Management: View balances with Stake/Swap actions
- DAO Governance: Active proposals with voting interface
- Vesting Timeline: Track claimable tokens and vesting schedules
- Mock Mode Toggle: Test with sample data or connect real wallet
- ERC-7730 Integration: All actions flow through Ledger-style signing
Usage:
- Connect MetaMask wallet
- Portfolio loads automatically
- View token balances, DAO votes, and vesting schedules
- Click action buttons (Vote/Claim/Stake/Swap)
- Review transaction in signing modal with ERC-7730 preview
- Approve with Ledger simulator
- Receive signed transaction
- Input calldata
- Decode with ERC-7730
- Connect Ledger (optional)
- Simulate/Sign transaction
- Export signature
MultiBaAS powers the Digital Asset Dashboard, providing:
- Portfolio Tracking: Real-time token balances and valuations
- DAO Governance: Proposal tracking and voting power calculation
- Event Monitoring: Claimable airdrops and vesting schedules
User Address Input
↓
MultiBaAS API Client (axios)
↓
┌──────────────┬──────────────┬──────────────┐
│ Portfolio │ Governance │ Events │
│ Service │ Service │ Service │
└──────────────┴──────────────┴──────────────┘
↓ ↓ ↓
Token Data DAO Proposals Claimable
Balances Voting Power Vesting
↓ ↓ ↓
Dashboard Components (React)
↓
ERC-7730 Descriptor Loading
↓
Ledger Simulator Integration
1. Portfolio Service (multibaas/portfolio.ts)
getPortfolio(address: string): Promise<Portfolio>
getTokenBalances(address: string): Promise<TokenBalance[]>Returns:
- Total portfolio value (USD)
- Token holdings with balances
- Token metadata (symbol, decimals)
2. Governance Service (multibaas/governance.ts)
getDaoVotes(address: string): Promise<UserVotes>
getActiveProposals(address: string): Promise<DAOProposal[]>
encodeVote(proposalId: string, support: boolean): Promise<string>Returns:
- User voting power
- Active/passed/rejected proposals
- Vote counts (for/against)
3. Events Service (multibaas/events.ts)
getClaimable(address: string): Promise<ClaimableEvents>
getVestingSchedules(address: string): Promise<ClaimableToken[]>
encodeClaim(token: string, amount: string): Promise<string>Returns:
- Claimable airdrops
- Vesting schedules with progress
- Cliff periods and intervals
# frontend/.env
NEXT_PUBLIC_MULTIBAAS_API=https://api.multibaas.com
MULTIBAAS_API_KEY=your_api_key_hereThe dashboard uses mock data by default for demonstration. To connect to real MultiBaAS:
- Sign up at https://www.curvegrid.com/multibaas/
- Get your API key
- Update
.envfile - Replace mock implementations with actual API calls
1. User clicks "Vote For" on proposal
↓
2. App calls getDaoVotes() to get proposal data
↓
3. App loads ERC-7730 descriptor (mock vote contract)
↓
4. LedgerSimulator shows:
- Intent: "Vote FOR proposal"
- Proposal ID: 0x1
- Proposal: "Increase Treasury Allocation"
- Vote: FOR
↓
5. User navigates fields with ◀ ▶ buttons
↓
6. User clicks ✓ Approve or ✗ Reject
↓
7. Transaction signed (mock signature)
↓
8. Success notification
1. User clicks "Claim" on vesting schedule
↓
2. App calls getClaimable() to get token data
↓
3. App loads ERC-7730 descriptor (mock vesting contract)
↓
4. LedgerSimulator shows:
- Intent: "Claim DAI tokens"
- Token: DAI
- Amount: 1500.0
- Token Address: 0x6B17...
↓
5. User reviews and approves
↓
6. Transaction signed
Current Problem: Users sign transactions blindly, seeing only raw hex data. This leads to:
- Phishing attacks
- Approval exploits
- Loss of funds
ERC-7730 Solution:
- Clear intent display ("Swap tokens")
- Formatted amounts (1,000.0 USDC)
- Address labels (USDC contract)
- Timestamp conversion
- Hardware wallet verification
Centralized Wallet Management:
- Single
WalletManagerclass incore/wallet.ts - React hook
useWallet()for components - Automatic reconnection on page refresh
- Account change listeners built-in
Unified Data Services:
- Automatic fallback to mock data on errors
- Single service function per feature (
getPortfolio,getDaoVotes,getVestingSchedules) - Real Web3 integration with mock testing support
Integrated Signing Flow:
SigningModalcomponent used across all pages- Three-step flow: preview → ledger → signed
- Dashboard actions automatically trigger modal
- Reusable across Vote/Claim/Stake/Swap actions
1. Context
- Contract ABI
- Deployment addresses
- Chain IDs
2. Metadata
- Owner information
- Constants (token addresses)
- Update timestamps
3. Display
- Format definitions (amount, address, date)
- Nested structures
- Field mappings
4. Messages
- Per-function intent
- Field labels
- Formatting rules
| Type | Description | Example |
|---|---|---|
amount |
Token amounts in wei | 1000000000000000000 → 1.0 |
address |
Ethereum addresses | 0xA0b8...eB48 → USDC |
date |
Unix timestamps | 1700000000 → Nov 15, 2023 |
tokenAmount |
Token-specific formatting | Uses token decimals |
cd hardhat
npm run test1. Generate test calldata
cd hardhat
node test-import.mjs2. Test decoder
- Open http://localhost:3000
- Paste calldata
- Verify human-readable output
3. Test Ledger simulation
- Navigate to http://localhost:3000/sign
- Decode transaction
- Click "Sign with Ledger"
- Use navigation buttons
- Approve/Reject
4. Test real Ledger (optional)
- Enable "Use real Ledger device"
- Connect Ledger via USB
- Unlock device
- Open Ethereum app
- Click "Connect Ledger Device"
1. Configure environment variables
cd hardhat
cp .env.example .env
# Edit .env and add your private key and RPC URLs2. Deploy to Arbitrum Sepolia (Testnet)
npm run deploy:arbitrum-sepolia3. Deploy to Arbitrum One (Mainnet)
npm run deploy:arbitrum4. Update descriptor with real addresses
npm run generate-descriptor5. Deploy frontend
cd frontend
npm run build
npm run startVercel Deployment:
vercel deploy| Network | Chain ID | RPC URL |
|---|---|---|
| Localhost | 31337 | http://127.0.0.1:8545 |
| Arbitrum One | 42161 | https://arb1.arbitrum.io/rpc |
| Arbitrum Sepolia | 421614 | https://sepolia-rollup.arbitrum.io/rpc |
// hardhat/hardhat.config.ts
networks: {
hardhat: {
forking: {
url: process.env.MAINNET_RPC_URL,
blockNumber: 18500000
}
},
localhost: {
url: "http://127.0.0.1:8545"
}
}# hardhat/.env
ARBITRUM_RPC_URL=https://arb1.arbitrum.io/rpc
ARBITRUM_SEPOLIA_RPC_URL=https://sepolia-rollup.arbitrum.io/rpc
MAINNET_RPC_URL=https://eth.llamarpc.com
PRIVATE_KEY=your_private_key_without_0x_prefix
ARBISCAN_API_KEY=your_arbiscan_api_key
# frontend/.env
NEXT_PUBLIC_MULTIBAAS_API=https://api.multibaas.com
MULTIBAAS_API_KEY=your_multibaas_api_key1. Secure, Sovereign Systems (Protocol Labs + Ledger)
- ERC-7730 human-readable transaction signing
- Ledger hardware wallet integration
- Clear signing for complex DeFi operations
2. Best Digital Asset Dashboard (MultiBaAS)
- Comprehensive portfolio tracking
- DAO governance interface
- Vesting schedule visualization
- Integrated transaction signing flow
- ERC-7730 Implementation - Full schema compliance with nested structures
- Ledger Integration - WebUSB connection with fallback simulation
- DeFi Use Case - Production-ready router with complex parameters
- Developer Experience - Automated descriptor generation from ABI
- Descriptor Generator - Visual tool for creating ERC-7730 descriptors in browser
- Unified Architecture - Centralized wallet management with React hooks
- MultiBaAS Dashboard - Unified interface for portfolio, governance, and vesting
- Seamless UX - Every dashboard action flows through ERC-7730 + Ledger signing
Standard Transaction Signing:
- Deploy DemoRouter contract
- Generate ERC-7730 descriptor (or use
/createpage) - Encode transaction calldata
- Decode with human-readable labels
- Sign with Ledger (simulated or real)
- Export signed transaction
Descriptor Creation Flow:
- Navigate to
/createpage - Paste contract ABI JSON (or load example)
- Click generate
- Review auto-detected formats
- Download JSON descriptor
- Use with signing flow
Dashboard Transaction Flow:
- Connect MetaMask wallet (or use mock mode)
- Portfolio/governance/vesting data loads automatically
- View tokens, proposals, vesting schedules
- Click action (Vote/Claim/Stake/Swap)
- Signing modal opens with ERC-7730 preview
- Review transaction details in Ledger-style UI
- Approve transaction
- Receive signed payload
For Ledger Track:
- ✅ Full ERC-7730 standard implementation
- ✅ Real hardware wallet support (WebUSB)
- ✅ Complex struct parameter handling
- ✅ Production-ready DeFi use case
- ✅ Beautiful UI/UX with Ledger-style simulator
- ✅ Browser-based descriptor generator tool
For MultiBaAS Track:
- ✅ Comprehensive dashboard with 3 data sources (portfolio, governance, events)
- ✅ Real-time data aggregation and display
- ✅ Interactive components with rich visualizations
- ✅ Action-oriented UX (Vote, Claim, Stake, Swap)
- ✅ Integrated signing flow for all operations
- ✅ Vesting timeline with progress tracking
- ✅ DAO proposal voting interface
- ✅ Unified architecture with centralized state management
This project uniquely combines:
- Data aggregation (MultiBaAS)
- Transaction preparation (ERC-7730 encoding)
- Secure signing (Ledger hardware wallet)
Creating a complete sovereign asset management experience where users can:
- See what they own
- Decide what to do
- Sign transactions with full clarity
- Maintain custody throughout
Contributions welcome! Areas for improvement:
- Additional format types (NFT, ENS)
- Multi-chain descriptor registry
- Browser extension integration
- Mobile wallet support
- Real-time descriptor validation
- Enhanced auto-detection for complex types
The project follows a clean architecture pattern:
- Core: Business logic and utilities (
core/) - Hooks: React state management (
hooks/) - Services: Data fetching with fallbacks (
services/) - Components: Reusable UI components
- Pages: Route-level components (
app/)
See REFACTOR.md for detailed architecture documentation.
MIT License - see LICENSE file
- Ledger - Hardware wallet security standards
- Hardhat Team - Smart contract development tools
- MultiBaAS by Curvegrid - Enterprise blockchain infrastructure
Last updated: November 2025