Skip to content

SajalDevX/BlitzUnstake

Repository files navigation

FlashUnstake

Instant ETH Unstaking with EIP-7702

Skip the 17-46 day Ethereum unstaking queue. Get your ETH instantly.

Hackathon Solidity Tests


Hackathon Submission

Zero-Wait Unstaking Using EIP-7702 Hackathon

Quick Start for Judges

# Clone and install
git clone <repo-url>
cd flashunstake
npm install
forge install

# Build contracts
forge build

# Run all tests (38 tests)
forge test -vvv

# Deploy to BSC Testnet
forge script script/DeployHackathon.s.sol --rpc-url $BSC_TESTNET_RPC_URL --broadcast --verify

Submission Requirements

Requirement Value
Testing Contract StakingVault (deployed address in .env)
Testing Token FUST - FlashUnstake Test Token
Chain BSC Testnet (Chain ID: 97)
Lock Time Duration 3600 seconds (1 hour)
EIP-7702 Integration Yes - Delegated execution, session keys, batch ops

Key Innovation: EIP-7702 Delegated Unstaking

Traditional Flow (Multiple Transactions):
┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│  Tx 1:       │    │  Tx 2:       │    │  Tx 3:       │
│  Approve     │───▶│  Stake       │───▶│  Unstake     │
│  Tokens      │    │  Tokens      │    │  (manual)    │
└──────────────┘    └──────────────┘    └──────────────┘
     Gas: ~50k           Gas: ~100k          Gas: ~80k
                                        ↑
                               User must wait 3600s
                               and manually trigger


EIP-7702 Flow (Single Atomic Transaction):
┌─────────────────────────────────────────────────────────────┐
│                    ONE TRANSACTION                           │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌───────────────┐   │
│  │ Approve │─▶│ Stake   │─▶│ Schedule│─▶│ Auto-Unstake  │   │
│  │         │  │         │  │         │  │ at Unlock     │   │
│  └─────────┘  └─────────┘  └─────────┘  └───────────────┘   │
│                                                              │
│  • Batched via EIP-7702 delegation                          │
│  • One signature, one gas payment                            │
│  • Auto-executes at exact unlock timestamp                   │
└─────────────────────────────────────────────────────────────┘

Hackathon Contracts

Contract Purpose Key Features
TestToken.sol Test ERC20 EIP-2612 Permit, Faucet, 100M cap
StakingVault.sol Staking with 3600s lock Multiple positions, EIP-7702 ready
EIP7702UnstakeModule.sol Delegation module Scheduled auto-unstake, batch execution

Test Results

╭──────────────────┬────────┬────────┬─────────╮
│ Test Suite       │ Passed │ Failed │ Skipped │
╞══════════════════╪════════╪════════╪═════════╡
│ FlashUnstakeTest │ 13     │ 0      │ 0       │
├──────────────────┼────────┼────────┼─────────┤
│ HackathonTest    │ 25     │ 0      │ 0       │
╰──────────────────┴────────┴────────┴─────────╯

The Problem

Ethereum staking provides ~4% APY, but unstaking is painful:

Traditional Unstaking Flow:
┌─────────────────────────────────────────────────────────────────────────┐
│                                                                         │
│   User has stETH/rETH                                                   │
│         │                                                               │
│         ▼                                                               │
│   ┌─────────────┐     ┌─────────────┐     ┌─────────────────────────┐  │
│   │ Transaction │     │ Transaction │     │                         │  │
│   │ 1: Approve  │────▶│ 2: Request  │────▶│   WAIT 17-46 DAYS       │  │
│   │   stETH     │     │   Withdraw  │     │   in Exit Queue         │  │
│   └─────────────┘     └─────────────┘     └───────────┬─────────────┘  │
│                                                       │                 │
│                                                       ▼                 │
│                                               Finally get ETH           │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Problems:
  • 17-46 day wait time (142,500+ validators in queue)
  • 2 separate transactions required
  • 2 gas fees to pay
  • No liquidity while waiting
  • Risk of price changes during wait

The Solution: FlashUnstake

FlashUnstake provides instant liquidity for staked ETH using a liquidity pool and EIP-7702 for the best user experience.

FlashUnstake Flow:
┌─────────────────────────────────────────────────────────────────────────┐
│                                                                         │
│   User has stETH/rETH                                                   │
│         │                                                               │
│         ▼                                                               │
│   ┌─────────────────────────────────────────────────────────────────┐  │
│   │                  ONE EIP-7702 TRANSACTION                        │  │
│   │                                                                  │  │
│   │   ┌──────────┐    ┌──────────┐    ┌──────────┐                  │  │
│   │   │ Approve  │───▶│ Swap LST │───▶│ Receive  │                  │  │
│   │   │  stETH   │    │ for ETH  │    │   ETH    │                  │  │
│   │   └──────────┘    └──────────┘    └──────────┘                  │  │
│   │                                                                  │  │
│   │              All atomic. All in ~12 seconds.                     │  │
│   └─────────────────────────────────────────────────────────────────┘  │
│                                                                         │
│   ✓ Instant (no queue)                                                  │
│   ✓ One transaction (not two)                                          │
│   ✓ One signature                                                       │
│   ✓ Optional: Zero gas (paymaster sponsored)                           │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

How It Works

Architecture Overview

┌─────────────────────────────────────────────────────────────────────────────┐
│                           FlashUnstake Protocol                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌──────────────────┐    ┌──────────────────┐    ┌──────────────────┐       │
│  │                  │    │                  │    │                  │       │
│  │   FlashUnstake   │    │   Delegator      │    │   Paymaster      │       │
│  │   (Core Pool)    │    │   (EIP-7702)     │    │   (Gas Sponsor)  │       │
│  │                  │    │                  │    │                  │       │
│  └────────┬─────────┘    └────────┬─────────┘    └────────┬─────────┘       │
│           │                       │                       │                  │
│           │                       │                       │                  │
│  ┌────────▼─────────┐    ┌────────▼─────────┐    ┌────────▼─────────┐       │
│  │ • Liquidity Pool │    │ • Batch Calls    │    │ • Sponsor Gas    │       │
│  │ • Instant Swaps  │    │ • One-Click      │    │ • User Deposits  │       │
│  │ • LP Shares      │    │ • Session Keys   │    │ • Whitelisting   │       │
│  │ • Exit Queue NFT │    │ • ERC-4337       │    │ • Limits         │       │
│  └──────────────────┘    └──────────────────┘    └──────────────────┘       │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Transaction Flow with EIP-7702

┌─────────────────────────────────────────────────────────────────────────────┐
│                         EIP-7702 Transaction Flow                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  User's EOA                                                                  │
│      │                                                                       │
│      │ 1. Sign EIP-7702 Authorization                                        │
│      │    (Delegate EOA to FlashUnstakeDelegator contract)                   │
│      │                                                                       │
│      ▼                                                                       │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                    Type 0x04 Transaction                             │    │
│  │  ┌─────────────────────────────────────────────────────────────┐    │    │
│  │  │  Authorization List:                                         │    │    │
│  │  │  • chainId: 97 (BSC Testnet)                                │    │    │
│  │  │  • address: FlashUnstakeDelegator                           │    │    │
│  │  │  • nonce: 0                                                  │    │    │
│  │  │  • signature: [v, r, s]                                      │    │    │
│  │  └─────────────────────────────────────────────────────────────┘    │    │
│  │                                                                      │    │
│  │  Calldata: oneClickUnstake(flashUnstake, stETH, amount, minOut)     │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│      │                                                                       │
│      │ 2. EOA temporarily becomes smart contract                             │
│      │                                                                       │
│      ▼                                                                       │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │  Batched Execution (Atomic):                                         │    │
│  │                                                                      │    │
│  │  Step A: stETH.approve(flashUnstake, amount)                        │    │
│  │                          │                                           │    │
│  │                          ▼                                           │    │
│  │  Step B: flashUnstake.instantUnstakeStETH(amount, minOut)           │    │
│  │                          │                                           │    │
│  │                          ▼                                           │    │
│  │  Step C: ETH sent to user's EOA                                     │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│      │                                                                       │
│      │ 3. Delegation ends, EOA returns to normal                             │
│      ▼                                                                       │
│                                                                              │
│  User receives ETH instantly!                                                │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Liquidity Pool Mechanism

┌─────────────────────────────────────────────────────────────────────────────┐
│                           Liquidity Pool Flow                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   LIQUIDITY PROVIDERS                      UNSTAKERS                         │
│   ──────────────────                       ─────────                         │
│                                                                              │
│   ┌─────────────┐                          ┌─────────────┐                   │
│   │             │                          │             │                   │
│   │  LP deposits│                          │ User has    │                   │
│   │  ETH        │                          │ stETH/rETH  │                   │
│   │             │                          │             │                   │
│   └──────┬──────┘                          └──────┬──────┘                   │
│          │                                        │                          │
│          ▼                                        ▼                          │
│   ┌─────────────────────────────────────────────────────────────────┐       │
│   │                                                                  │       │
│   │                    FlashUnstake Pool                             │       │
│   │                                                                  │       │
│   │   ┌─────────────────────────────────────────────────────────┐   │       │
│   │   │                                                          │   │       │
│   │   │   ETH Liquidity Pool          LST Holdings               │   │       │
│   │   │   ════════════════            ════════════               │   │       │
│   │   │                                                          │   │       │
│   │   │   100 ETH ◄──────────────────► 50 stETH                  │   │       │
│   │   │                                 30 rETH                   │   │       │
│   │   │                                                          │   │       │
│   │   └─────────────────────────────────────────────────────────┘   │       │
│   │                                                                  │       │
│   │   LP Share Tokens (tracks proportional ownership)                │       │
│   │                                                                  │       │
│   └─────────────────────────────────────────────────────────────────┘       │
│          │                                        │                          │
│          │                                        │                          │
│          ▼                                        ▼                          │
│   ┌─────────────┐                          ┌─────────────┐                   │
│   │             │                          │             │                   │
│   │ Earn fees   │                          │ Receive ETH │                   │
│   │ from swaps  │                          │ instantly   │                   │
│   │ (~7-9% APY) │                          │ (0.5% fee)  │                   │
│   │             │                          │             │                   │
│   └─────────────┘                          └─────────────┘                   │
│                                                                              │
│   Meanwhile, protocol queues LSTs through Lido/RocketPool                    │
│   withdrawal queues in the background to replenish ETH                       │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Features

1. Instant Unstaking

  • Convert stETH or rETH to ETH in seconds, not weeks
  • 0.5% fee (vs waiting 17-46 days)

2. EIP-7702 Integration

  • Batched Transactions: Approve + unstake in one tx
  • Single Signature: Better UX than multi-tx flows
  • Gas Sponsorship: Optional gasless transactions
  • Session Keys: Delegated access for automation

3. Liquidity Pool

  • LPs provide ETH and earn yield
  • ~7-9% APY (staking rewards + swap fees)
  • Protocol handles exit queue in background

4. Exit Position NFTs

  • Tradeable NFT representing queue position
  • Secondary market for exit positions
  • Buyers get discounted ETH, sellers get instant liquidity

Project Structure

flashunstake/
├── contracts/
│   ├── FlashUnstake.sol           # Main protocol (liquidity pool, swaps)
│   ├── FlashUnstakeDelegator.sol  # EIP-7702 delegation, session keys
│   ├── FlashUnstakePaymaster.sol  # ERC-4337 gas sponsorship
│   └── interfaces/                 # External protocol interfaces
├── frontend/
│   ├── src/
│   │   ├── App.jsx                # React frontend (550+ lines)
│   │   ├── index.css              # Tailwind + animations
│   │   └── main.jsx               # Entry point
│   ├── package.json
│   └── vite.config.js
├── script/
│   └── Deploy.s.sol               # Foundry deployment script
├── scripts/
│   └── test-eip7702.ts            # TypeScript integration tests
├── test/
│   └── FlashUnstake.t.sol         # Solidity unit tests
├── lib/                            # Dependencies (forge-std, openzeppelin)
├── foundry.toml                    # Foundry configuration
├── package.json                    # NPM configuration
└── README.md

Getting Started

Prerequisites

Installation

# Clone the repository
git clone https://github.com/flashunstake/flashunstake
cd flashunstake

# Install Foundry (if not already installed)
curl -L https://foundry.paradigm.xyz | bash
foundryup

# Install Foundry dependencies
forge install

# Install Node.js dependencies
npm install

# Install frontend dependencies
cd frontend && npm install && cd ..

Environment Setup

# Copy environment template
cp .env.example .env

# Edit .env with your values:
# PRIVATE_KEY=your_private_key
# BSC_TESTNET_RPC_URL=https://data-seed-prebsc-1-s1.binance.org:8545
# BSCSCAN_API_KEY=your_api_key

Build Contracts

# Compile all contracts
forge build

# Run tests
forge test -vvv

# Run tests with gas report
forge test --gas-report

Run Frontend

cd frontend
npm run dev

# Opens at http://localhost:3000

Deploy Contracts

# Deploy to BSC Testnet
forge script script/Deploy.s.sol --rpc-url $BSC_TESTNET_RPC_URL --broadcast --verify

# After deployment, update .env with contract addresses:
# FLASH_UNSTAKE_ADDRESS=0x...
# DELEGATOR_ADDRESS=0x...
# PAYMASTER_ADDRESS=0x...

Run Integration Tests

# TypeScript integration tests for EIP-7702
npx tsx scripts/test-eip7702.ts

Smart Contract Overview

FlashUnstake.sol (Main Protocol)

Function Description
provideLiquidity() Deposit ETH, receive LP shares
withdrawLiquidity(shares) Burn shares, receive ETH
instantUnstakeStETH(amount, minOut) Swap stETH for ETH
instantUnstakeRETH(amount, minOut) Swap rETH for ETH
batchedInstantUnstake(...) Multi-token unstake with EIP-7702

FlashUnstakeDelegator.sol (EIP-7702)

Function Description
executeBatch(calls) Execute multiple calls atomically
oneClickUnstake(...) Approve + unstake in one call
createSessionKey(...) Create limited-access session key
validateUserOp(...) ERC-4337 account validation

FlashUnstakePaymaster.sol (Gas Sponsorship)

Function Description
validatePaymasterUserOp(...) Validate and sponsor user ops
deposit(user) Deposit ETH for user
setWhitelistedTarget(...) Whitelist contracts for sponsorship

Economics

Parameter Value
Instant Unstake Fee 0.5%
LP Fee Share 80%
Protocol Fee 20%
Minimum Unstake 0.01 ETH
Supported LSTs stETH, rETH
Target LP APY 7-9%

Comparison

Feature Traditional Unstaking FlashUnstake
Wait Time 17-46 days ~12 seconds
Transactions 2 (approve + request) 1 (EIP-7702)
Signatures 2 1
Gas Cost ~100k total ~60k
Failure Mode Can fail partially Atomic (all or nothing)
Gas Sponsorship No Yes (Paymaster)

Security Considerations

For Users

  • Only delegate to verified FlashUnstakeDelegator contracts
  • Review authorization before signing
  • Session keys have limited scope and expiration
  • Revoke delegations when not needed

For Protocol

  • ReentrancyGuard on all state-changing functions
  • Ownable for admin functions
  • OpenZeppelin battle-tested libraries
  • Slippage protection on all swaps

EIP-7702 Specific

  • Authorization is chain-specific (prevents cross-chain replay)
  • Nonce prevents authorization replay
  • Delegation can be revoked anytime

Contract Addresses (BSC Testnet)

Contract Address
stETH 0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af
rETH 0x178E141a0E3b34152f73Ff610437A7bf9B83267A
Lido Withdrawal Queue 0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1
ERC-4337 EntryPoint 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789
FlashUnstake Deploy to get address
FlashUnstakeDelegator Deploy to get address
FlashUnstakePaymaster Deploy to get address

BSC Testnet Details:


Development

Running Tests

# All tests
forge test

# Verbose output
forge test -vvv

# Specific test
forge test --match-test testInstantUnstakeStETH

# Gas report
forge test --gas-report

# Coverage
forge coverage

Linting

# Solidity linting
forge fmt

# TypeScript linting
npm run lint

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see LICENSE file for details.


Links


Built for the EIP-7702 Hackathon

"Unstake Instantly. Final Block. Zero Wait."

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published