Zokyo Auditing Tutorials
  • ๐Ÿ”Zokyo Auditing Tutorials
  • ๐Ÿ“šTutorials
    • ๐ŸƒTutorial 1: Front-Running
      • ๐Ÿš€Prerequisites
      • ๐Ÿ“˜Understanding Front-Running
      • ๐Ÿ‘“Examples
      • โš’๏ธMitigation Steps
      • ๐ŸฆResource Bank to more front running examples
      • ๐ŸคFront-Running Conclusion
    • ๐ŸงฑTutorial 2: Unsafe Casting
      • ๐Ÿš€Prerequisites
      • ๐Ÿ“˜Understanding Casting
      • ๐Ÿ‘“Examples
      • ๐ŸคUnsafe Casting Conclusion
    • ๐Ÿ‘Tutorial 3: Approvals and Safe Approvals
      • ๐Ÿš€Prerequisites
      • ๐Ÿ“˜Understanding Approvals
      • ๐Ÿ‘“Vulnerability Examples
        • ๐Ÿ”ERC20 Approval Reset Requirement
        • ๐Ÿ˜ดIgnoring Return Values from ERC20 approve() Function: Potential Miscount of Successful Approvals
        • ๐ŸšซImproper use of Open Zeppelins safeApprove() for Non-zero Allowance Increments
        • ๐ŸฅพOmitted Approval for Contract Interactions Within a Protocol
        • ๐Ÿคฆโ€โ™‚๏ธFailing to Reset Token Approvals in Case of Failed Transactions or other actions
        • ๐Ÿ’ญMiscellaneous
        • ERC20 Approve Race Condition Vulnerability
      • โš’๏ธSpot the Vulnerability
      • ๐ŸคApprovals and Safe Approvals Conclusion
    • โ›“๏ธTutorial 4: Block.chainid, DOMAIN_SEPARATOR and EIP-2612 permit
      • ๐Ÿš€Prerequisites
      • ๐Ÿ“˜Understanding Block.chainid and DOMAIN_SEPARATOR
      • ๐Ÿ‘“Examples
      • โš’๏ธGeneral Mitigation Steps
      • ๐ŸคTutorial 4 Conclusion
  • ๐Ÿ’ฐTutorial 5: Fee-On-Transfer Tokens
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“˜Understanding Fee-On-Transfer
    • ๐Ÿ‘“Examples
    • ๐Ÿ“˜Links to more fee-on-transfer vulnerability examples
    • ๐ŸคFee-On-Transfer Tokens: Conclusion
  • ๐ŸŒดTutorial 6: Merkle Trees
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“˜Understanding Merkle Trees
    • ๐Ÿ”ŽVerification within a Merkle Tree:
    • ๐Ÿ“œMerkle Proofs Within Smart Contracts
    • ๐Ÿ–‹๏ธMerkle Proof Solidity Implementation
    • ๐Ÿ›‘Vulnerabilities When Using Merkle Trees
    • ๐Ÿ’€Example Vulnerabilities
    • ๐Ÿง Exercise
    • ๐ŸคMerkle Trees Conclusion
  • ๐ŸŒณTutorial 7: Merkle-Patricia Trees
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“˜Understanding Merkle-Patricia Trees
    • ๐Ÿ“•Understanding Merkle-Patrica Trees pt.2
    • ๐Ÿ”ŽVerification within a Merkle-Patricia Tree
    • ๐Ÿ›‘Vulnerabilities When Using Merkle-Patricia Trees
    • ๐Ÿ’€Example Vulnerability
    • ๐ŸคMerkle-Patricia Trees: Conclusion
  • ๐Ÿ”Tutorial 8: Reentrancy
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“˜Understanding Reentrancy
    • โš’๏ธMitigation
    • ๐Ÿ’€The DAO Hack: An In-depth Examination
    • ๐Ÿ‘“Examples
    • ๐ŸฆResource Bank To More Reentrancy Examples
    • ๐ŸคConclusion: Reflecting on the Reentrancy Vulnerability
  • ๐Ÿ”‚Tutorial 9: Read-Only Reentrancy
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“˜Understanding Read-Only Reentrancy
    • ๐Ÿ”จMitigating Read-Only Reentrancy
    • ๐Ÿ‘“Real World Examples
    • ๐ŸฆResource Bank To More Reentrancy Examples
    • ๐ŸคRead-Only Reentrancy: Conclusion
  • ๐Ÿš†Tutorial 10: ERC20 transfer() and safeTransfer()
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“˜Understanding ERC20 transfer() and safeTransfer()
    • ๐Ÿ‘“Examples
    • ๐ŸคConclusion
  • ๐Ÿ“žTutorial 11: Low level .call(), .transfer() and .send()
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“˜Understanding .call, .transfer, and .send
    • ๐Ÿ›‘Understanding the Vulnerabilities of .transfer and .send
    • ๐Ÿ‘“Examples
    • ๐ŸคLow level .call(), .transfer() and .send() conclusion
  • โ˜Ž๏ธTutorial 12: Delegatecall Vulnerabilities in Precompiled Contracts
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“ณUnderstanding Delegatecall
    • โ›ฐ๏ธEVM, L2s, Bridges, and the Quest for Scalability
    • ๐Ÿ—๏ธUnderstanding Precompiles in the Ethereum Virtual Machine (EVM)
    • ๐Ÿ’ปCustom Precompiles
    • ๐Ÿ’€Potential Vulnerabilities in EVM Implementations: Overlooked DelegateCall in Precompiled Contracts
    • ๐Ÿ‘“Real World Examples
    • ๐ŸคDelegatecall and Precompiles: Conclusion
  • ๐ŸŒŠTutorial 13: Liquid Staking
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“˜Understanding Liquid Staking
    • ๐Ÿ’€Understanding Liquid Staking Vulnerabilities
    • ๐Ÿ›‘Example Vulnerability
    • ๐ŸœExample Vulnerability 2
    • ๐Ÿ•ท๏ธExample Vulnerability 3
    • ๐ŸคLiquid Staking: Conclusion
  • ๐ŸšฟTutorial 14: Slippage
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“˜Understanding Slippage in Automated Market Makers (AMMs)
    • ๐Ÿ’€Understanding the "Lack of Slippage Check" Vulnerability in Automated Market Makers (AMMs) and DEXs
    • ๐Ÿ˜กOn-Chain Slippage Calculations Vulnerability
    • ๐Ÿ“›0 slippage tolerance vulnerability
    • ๐Ÿ‘“Real World Examples
    • ๐ŸฆResource bank to more slippage vulnerabilities
    • ๐ŸคSlippage Conclusion
  • ๐Ÿ“‰Tutorial 15: Oracles
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“˜Understanding Oracles
    • ๐Ÿ“ˆTypes of price feeds
    • ๐Ÿ˜กFlash Loans
    • ๐Ÿ’€Understanding Oracle Vulnerabilities
      • โ›“๏ธThe Danger of Single Oracle Dependence
      • โฌ‡๏ธUsing Deprecated Functions
      • โŒLack of return data validation
      • ๐Ÿ•Inconsistent or Absent Price Data Fetching/Updating Intervals
    • ๐Ÿ”ซDecentralized Exchange (DEX) Price Oracles Vulnerabilities
    • ๐Ÿ›‘Found Vulnerabilities In Oracle Implementations
      • โš–๏ธNewly Registered Assets Skew Consultation Results
      • โšกFlash-Loan Oracle Manipulations
      • โ›“๏ธRelying Only On Chainlink: PriceOracle Does Not Filter Price Feed Outliers
      • โœ๏ธNot Validating Return Data e.g Chainlink: (lastestRoundData)
      • ๐Ÿ—ฏ๏ธChainlink: Using latestAnswer instead of latestRoundData
      • ๐Ÿ˜ญReliance On Fetching Oracle Functionality
      • ๐ŸŽฑWrong Assumption of 18 decimals
      • ๐Ÿง€Stale Prices
      • 0๏ธโƒฃOracle Price Returning 0
      • ๐Ÿ›ถTWAP Oracles
      • ๐Ÿ˜–Wrong Token Order In Return Value
      • ๐Ÿ—๏ธmiscellaneous
    • ๐ŸคOracles: Conclusion
  • ๐Ÿง Tutorial 16: Zero Knowledge (ZK)
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“šTheory
      • ๐Ÿ”ŒCircom
      • ๐Ÿ’ปComputation
      • ๐Ÿ›ค๏ธArithmetic Circuits
      • ๐ŸšงRank-1 Constraint System (R1CS)
      • โž—Quadratic Arithmetic Program
      • โœ๏ธLinear Interactive Proof
      • โœจZK-Snarks
    • ๐Ÿค“Definitions and Essentials
      • ๐Ÿ”‘Key
      • ๐Ÿ˜ŽScalar Field Order
      • ๐ŸŒณIncremental Merkle Tree
      • โœ’๏ธECDSA signature
      • ๐Ÿ“จNon-Interactive Proofs
      • ๐Ÿ๏ธFiat-Shamir transformation (or Fiat-Shamir heuristic)
      • ๐ŸชถPedersen commitment
    • ๐Ÿ’€Common Vulnerabilities in ZK Code
      • โ›“๏ธUnder-constrained Circuits
      • โ—Nondeterministic Circuits
      • ๐ŸŒŠArithmetic Over/Under Flows
      • ๐Ÿ‚Mismatching Bit Lengths
      • ๐ŸŒช๏ธUnused Public Inputs Optimized Out
      • ๐ŸฅถFrozen Heart: Forging of Zero Knowledge Proofs
      • ๐ŸšฐTrusted Setup Leak
      • โ›”Assigned but not Constrained
    • ๐Ÿ›Bugs In The Wild
      • ๐ŸŒณDark Forest v0.3: Missing Bit Length Check
      • ๐Ÿ”ขBigInt: Missing Bit Length Check
      • ๐Ÿš“Circom-Pairing: Missing Output Check Constraint
      • ๐ŸนSemaphore: Missing Smart Contract Range Check
      • ๐Ÿ”ซZk-Kit: Missing Smart Contract Range Check
      • ๐Ÿค–Aztec 2.0: Missing Bit Length Check / Nondeterministic Nullifier
      • โธ๏ธAztec Plonk Verifier: 0 Bug
      • ๐Ÿช‚0xPARC StealthDrop: Nondeterministic Nullifier
      • ๐Ÿ˜จa16z ZkDrops: Missing Nullifier Range Check
      • ๐ŸคซMACI 1.0: Under-constrained Circuit
      • โ„๏ธBulletproofs Paper: Frozen Heart
      • ๐Ÿ”๏ธPlonK: Frozen Heart
      • ๐Ÿ’คZcash: Trusted Setup Leak
      • ๐Ÿšจ14. MiMC Hash: Assigned but not Constrained
      • ๐Ÿš”PSE & Scroll zkEVM: Missing Overflow Constraint
      • โžก๏ธPSE & Scroll zkEVM: Missing Constraint
      • ๐ŸคจDusk Network: Missing Blinding Factors
      • ๐ŸŒƒEY Nightfall: Missing Nullifier Range Check
      • ๐ŸŽ†Summa: Unconstrained Constants Assignemnt
      • ๐Ÿ“ŒPolygon zkEVM: Missing Remainder Constraint
    • ๐Ÿ’ฟZK Security Resources
  • ๐ŸคTutorial 17 DEX's (Decentralized Exchanges)
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“šUnderstanding Decentralized Exchanges
    • ๐Ÿ’€Common Vulnerabilities in DEX Code
      • ๐Ÿ”ŽThe "Lack of Slippage Check" Vulnerability in Automated Market Makers (AMMs) a
      • ๐Ÿ˜กOn-Chain Slippage Calculations Vulnerability
      • ๐Ÿ“›Slippage tolerance vulnerability
      • ๐Ÿ˜ตHow Pool Implementation Mismatches Pose a Security Risk to Decentralized Exchanges (DEXs)
      • ๐ŸŠโ€โ™‚๏ธVulnerabilities in Initial Pool Creation - Liquidity Manipulation Attacks
      • ๐Ÿ›‘Vulnerabilities In Oracle Implementations
        • โš–๏ธNewly Registered Assets Skew Consultation Results
        • โšกFlash-Loan Oracle Manipulations
        • โ›“๏ธRelying Only On Chainlink: PriceOracle Does Not Filter Price Feed Outliers
        • โœ๏ธNot Validating Return Data e.g Chainlink: (lastestRoundData)
        • ๐Ÿ—ฏ๏ธChainlink: Using latestAnswer instead of latestRoundData
        • ๐Ÿ˜ญReliance On Fetching Oracle Functionality
        • ๐ŸŽฑWrong Assumption of 18 decimals
        • ๐Ÿง€Stale Prices
        • 0๏ธโƒฃOracle Price Returning 0
        • ๐Ÿ›ถTWAP Oracles
        • ๐Ÿ˜–Wrong Token Order In Return Value
        • ๐Ÿ—๏ธmiscellaneous
      • ๐ŸฅถMinting and Burning Liquidity Pool Tokens
      • ๐ŸŽซMissing Checks
      • ๐Ÿ”ž18 Decimal Assumption
        • ๐Ÿ“ŒUnderstanding ERC20 Decimals
        • ๐Ÿ’€Examples Of Vulnerabilities To Do With Assuming 18 Decimals
      • ๐Ÿ›ฃ๏ธIncorrect Swap Path
      • The Importance of Deadline Checks in Swaps
    • ๐ŸคConclusion
  • ๐Ÿค–Tutorial 18: Proxies
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“ฅEthereum Storage and Memory
    • ๐Ÿ“ฒEthereum Calls and Delegate Calls
    • ๐Ÿ’ชUpgradability Patterns in Ethereum: Enhancing Smart Contracts Over Time
    • ๐Ÿ”Proxy Upgrade Pattern in Ethereum
    • ๐ŸŒ€Exploring the Landscape of Ethereum Proxies
      • ๐ŸชžTransparent Proxies
      • โฌ†๏ธUUPS Proxies
      • ๐Ÿ’กBeacon Proxies
      • ๐Ÿ’ŽDiamond Proxies
  • ๐Ÿ”žTutorial 19: 18 Decimal Assumption
    • ๐Ÿš€Prerequisites
    • ๐Ÿ“ŒUnderstanding ERC20 Decimals
    • ๐Ÿ’€Examples Of Vulnerabilities To Do With Assuming 18 Decimals
    • ๐ŸคConclusion
  • โž—Tutorial 20: Arithmetic
    • ๐Ÿš€Prerequisites
    • ๐Ÿ•ณ๏ธArithmetic pitfall 1: Division by 0
    • ๐Ÿ”ชArithmetic pitfall 2: Precision Loss Due To Rounding
    • ๐ŸฅธArithmetic pitfall 3: Erroneous Calculations
    • ๐ŸคConclusion
  • ๐Ÿ”Tutorial 21: Unbounded Loops
    • ๐Ÿš€Prerequisites
    • โ›ฝGas Limit Vulnerability
    • ๐Ÿ“จTransaction Failures Within Loops
    • ๐ŸคConclusion
  • ๐Ÿ“”Tutorial 22: `isContract`
    • ๐Ÿš€Prerequisites
    • ๐Ÿ’€Understanding the 'isContract()` vulnerability
    • ๐ŸคConclusion
  • ๐Ÿ’ตTutorial 23: Staking
    • ๐Ÿš€Prerequisites
    • ๐Ÿ’€First Depositor Inflation Attack in Staking Contracts
    • ๐ŸŒช๏ธFront-Running Rebase Attack (Stepwise Jump in Rewards)
    • โ™จ๏ธRugability of a Poorly Implemented recoverERC20 Function in Staking Contracts
    • ๐Ÿ˜ General Considerations for ERC777 Reentrancy Vulnerabilities
    • ๐ŸฅVulnerability: _lpToken and Reward Token Confusion in Staking Contracts
    • ๐ŸŒŠSlippage Checks
    • ๐ŸŒฝThe Harvest Functionality in Vaults: Issues and Best Practices
  • โ›“๏ธTutorial 24: Chain Re-org Vulnerability
    • ๐Ÿš€Prerequisites
    • โ™ป๏ธChain Reorganization (Re-org) Vulnerability
    • ๐Ÿง‘โ€โš–๏ธChain Re-org Vulnerability in Governance Voting Mechanisms
  • ๐ŸŒ‰Tutorial 25: Cross Chain Bridges Vulnerabilities
    • ๐Ÿš€Prerequisites
    • โ™ป๏ธERC777 Bridge Vulnerability: Reentrancy Attack in Token Accounting
      • ๐Ÿ›‘Vulnerability: Withdrawals Can Be Locked Forever If Recipient Is a Contract
    • ๐Ÿ‘›The Dangers of Not Using SafeERC20 for Token Transfers
    • Uninitialized Variable Vulnerability in Upgradeable Smart Contracts
    • Unsafe External Calls and Their Vulnerabilities
    • Signature Replay Attacks in Cross-Chain Protocols
  • ๐ŸšฐTutorial 26: Integer Underflow and Overflow Vulnerabilities in Solidity (Before 0.8.0)
    • ๐Ÿš€Prerequisites
    • ๐Ÿ’€Understanding Integer Underflow and Overflow Vulnerabilities
    • ๐ŸคConclusion
  • ๐ŸฅTutorial 27: OpenZeppelin Vulnerabilities
    • ๐Ÿš€Prerequisites
    • ๐Ÿ›ฃ๏ธA Guide on Vulnerability Awareness and Management
      • ๐ŸคConclusion
  • ๐Ÿ–Š๏ธTutorial 28: Signature Vulnerabilities / Replays
    • ๐Ÿš€Prerequisites
    • ๐Ÿ”Reusing EIP-712 Signatures in Private Sales
    • ๐Ÿ”Replay Attacks on Failed Transactions
    • ๐Ÿ“ƒImproper Token Validation in Permit Signature
  • ๐ŸคTutorial 29: Solmate Vulnerabilities
    • ๐Ÿ”Lack of Code Size Check in Token Transfer Functions in Solmate
  • ๐ŸงฑTutorial 30: Inconsistent block lengths across chains
    • ๐Ÿ•›Incorrect Assumptions about Block Number in Multi-Chain Deployments
  • ๐Ÿ’‰Tutorial 31: NFT JSON and XSS injection
    • ๐Ÿ“œVulnerability: JSON Injection in tokenURI Functions
    • ๐Ÿ“Cross-Site Scripting (XSS) Vulnerability via SVG Construction in Smart Contracts
  • ๐ŸƒTutorial 32: Merkle Leafs
    • ๐Ÿ–ฅ๏ธMisuse of Merkle Leaf Nodes
  • 0๏ธTutorial 33: Layer 0
    • ๐Ÿ“ฉLack of Force Resume in LayerZero Integrations
    • โ›ฝLayerZero-Specific Vulnerabilities in Airdropped Gas and Failure Handling
    • ๐Ÿ”“Understanding the Vulnerability of Blocking LayerZero Channels
    • ๐Ÿ–Š๏ธCopy of Understanding the Vulnerability of Blocking LayerZero Channels
  • โ™ป๏ธTutorial 34: Forgetting to Update the Global State in Smart Contracts
  • โ€ผ๏ธTutorial 35: Wrong Function Signature
  • ๐Ÿ›‘Tutorial 36: Handling Edge Cases of Banned Addresses in DeFi
  • Tutorial 37: initializer and onlyInitializing
  • โž—Tutorial 38: Eigen Layer
    • ๐Ÿ“ฉDenial of Service in NodeDelegator Due to EigenLayer's maxPerDeposit Check
    • ๐Ÿ“ˆIncorrect Share Issuance Due to Strategy Updates in EigenLayer Integrations
    • ๐Ÿ”nonReentrant Vulnerability in EigenLayer Withdrawals
  • โšซTutorial 39: Wormhole
    • ๐Ÿ“ฉProposal Execution Failure Due to Guardian Set Change
  • ๐Ÿ’ผTutorial 40: Uniswap V3
    • ๐Ÿ“ฉUnderstanding and Mitigating Partial Swaps in Uniswap V3
    • ๐ŸŒŠUnderflow Vulnerability in Uniswap V3 Position Fee Growth Calculations
    • โž—Handling Decimal Discrepancies in Uniswap V3 Price Calculations
  • ๐Ÿ”ขTutorial 41: Multiple Token Addresses in Proxied Tokens
    • ๐Ÿ”“Understanding Vulnerabilities Arising from Tokens with Multiple Entry Points
  • ๐Ÿค–Tutorial 42: abiDecoder v2
    • ๐ŸฅฅVulnerabilities from Manipulated Token Interactions Using ABI Decoding
  • โ“Tutorial 43: On-Chain Randomness
    • Vulnerabilities in On-Chain Randomness and How It Can Be Exploited
  • ๐Ÿ˜–Tutorial 44: Weird ERC20 Tokens
    • Weird Token List
  • ๐Ÿ”จTutorial 45: Hardcoded stable coin values
  • โค๏ธTutorial 46: The Risks of Chainlink Heartbeat Discrepancies in Smart Contracts
  • ๐Ÿ‘ฃTutorial 47: The Risk of Forgetting a Withdrawal Mechanism in Smart Contracts
  • ๐Ÿ’ปTutorial 48: Governance and Voting
    • Flash Loan Voting Exploit
    • Exploiting Self-Delegation
    • ๐Ÿ’ฐMissing payable Keyword in Governance Execute Function
    • ๐Ÿ‘ŠVoting Multiple Times by Shifting Delegation
    • ๐Ÿ‘Missing Duplicate Veto Check
  • ๐Ÿ“•Tutorial 49: Not Conforming To EIP standards
    • ๐Ÿ’ŽUnderstanding EIP-2981: NFT Royalty Standard
    • ๐Ÿ‘Improper Implementation of EIP-2612 Permit Standard
    • ๐Ÿ”Vulnerabilities of Missing EIP-155 Replay Attack Protection
    • โžก๏ธVulnerabilities Due to Missing EIP-1967 in Proxy Contracts
    • ๐Ÿ”“Vulnerability of Design Preventing EIP-165 Extensibility
    • ๐ŸŽŸ๏ธThe Dangers of Not Properly Implementing ERC-4626 in Yield Vaults
    • ๐Ÿ”EIP-712 Implementation and Replay Attacks
  • โณTutorial 50: Vesting
    • ๐Ÿš”Vulnerability of Allowing Unauthorized Withdrawals in Vesting Contracts
    • ๐Ÿ‘ŠVulnerability of Unbounded Timelock Loops in Vesting Contracts
    • โฌ†๏ธVulnerability of Incorrect Linear Vesting Calculations
    • โ›ณMissing hasStarted Modifier
    • ๐Ÿ”“Vulnerability in Bond Depositor's Vesting Period Reset
  • โ›ฝTutorial 51: Ethereum's 63/64 Gas Rule
    • ๐Ÿ›ข๏ธAbusing Ethereum's 63/64 Gas Rule to Manipulate Contract Behavior
  • ๐Ÿ“ฉTutorial 52: NPM Dependency Confusion and Unclaimed Packages
    • ๐Ÿ’ŽExploiting Unclaimed NPM Packages and Scopes
  • ๐ŸŽˆTutorial 53: Airdrops
    • ๐Ÿ›„Claiming on Behalf of Other Users
    • ๐ŸงฒRepeated Airdrop Claims Vulnerability
    • ๐ŸƒAirdrop Vulnerability โ€“ Merkle Leaves and Parent Node Hash Collisions
  • ๐ŸŽฏTutorial 54: Precision
    • ๐ŸŽVulnerabilities Due to Insufficient Precision in Reward Calculations
    • Min-Shares: Fixed Minimum Share Values for Tokens with Low Decimal Precision
    • Vulnerability Due to Incorrect Rounding When the Numerator is Not a Multiple of the Denominator
    • Vulnerability from Small Deposits Being Rounded Down to Zero Shares in Smart Contracts
    • Precision Loss During Withdrawals from Vaults Can Block Token Transfers Due to Value < Amount
    • 18 Decimal Assumption Scaling: Loss of Precision in Asset Conversion Due to Incorrect Scaling
  • Tutorial 55: AssetIn == AssetOut, FromToken == ToToken
    • ๐Ÿ–ผ๏ธVulnerability: Missing fromToken != toToken Check
  • ๐ŸšฟTutorial 56: Vulnerabilities Related to LP Tokens Being the Same as Reward Tokens
    • ๐Ÿ–ผ๏ธVulnerabilities Caused by LP Tokens Being the Same as Reward Tokens
  • Tutorial 57: Unsanitized SWAP Paths and Arbitrary Contract Call Vulnerabilities
    • ๐Ÿ“ฒArbitrary Contract Calls from Unsanitized Paths
  • Tutorial 58: The Risk of Infinite Approvals and Arbitrary Contract Calls
    • ๐ŸชฃExploiting Infinite Approvals and Arbitrary Contract Calls
  • Tutorial 59: Low-Level Calls in Solidity Returning True for Non-Existent Contracts
    • Low-Level Calls Returning True for Non-Existent Contracts
  • 0๏ธโƒฃTutorial 60: The Impact of PUSH0 and the Shanghai Hardfork on Cross-Chain Deployments > 0.8.20
    • PUSH0 and Cross-Chain Compatibility Challenges
  • ๐ŸTutorial 61: Vyper Vulnerable Versions
    • Vyper and the EVM
  • โŒจ๏ธTutorial 62: Typos in Smart Contracts โ€” The Silent Threat Leading to Interface Mismatch
    • Vyper and the EVM
  • โ˜๏ธTutorial 63: Balance Check Using ==
    • The Vulnerability: == Balance Check
  • ๐Ÿ’Tutorial 64: Equal Royalties for Unequal NFTs
    • Understanding the Problem: Equal Royalties for Unequal NFTs
  • ๐Ÿ–ผ๏ธTutorial 65: ERC721 and NFTs
    • The Risk of Using transferFrom Instead of safeTransferFrom in ERC721 Projects
    • โ„๏ธWhy _safeMint Should Be Used Instead of _mint in ERC721 Projects
    • The Importance of Validating Token Types in Smart Contracts
    • ๐Ÿ“ฌImplementing ERC721TokenReceiver to Handle ERC721 Safe Transfers
    • NFT Implementation Deviating from ERC721 Standard in Transfer Functions
    • NFT Approval Persistence after Transfer
    • ๐ŸŽฎGameable NFT Launches through Pseudo-Randomness
    • 2๏ธโƒฃProtecting Buyers from Losing Funds Due to Claimed NFT Rewards on Secondary Markets
    • โ™ป๏ธPreventing Reentrancy When Using SafeERC721
    • ๐Ÿ–Š๏ธPreventing Re-use of EIP-712 Signatures in NFT Private Sales
  • 2๏ธโƒฃTutorial 66: Vulnerability Arising from NFTs Supporting Both ERC721 and ERC1155 Standards
  • ๐Ÿ“ทTutorial 67: ERC1155 Vulnerabilities
    • โ™ป๏ธPreventing Reentrancy in OpenZeppelin's SafeERC1155
    • ๐Ÿ›ซVulnerabilities in OpenZeppelin's ERC1155Supply Contract
    • Understanding Incorrect Token Owner Enumeration in ERC1155Enumerable
    • Avoiding Breaking ERC1155 Composability with Improper safeTransferFrom Implementation
    • ๐Ÿ’Ensuring Compatibility with EIP-2981 in ERC1155 Contracts
  • ๐ŸชŸInformational Vulnerabilities
  • โ›ฝGas Efficiency
  • ๐Ÿ’ปAutomation Tools
  • ๐Ÿ”œOut Of Gas (Coming Soon)
  • ๐Ÿ”œDEX Aggregators (Coming Soon)
  • ๐Ÿ”œBribes (Coming Soon)
  • ๐Ÿ”œUnderstanding Compiled Bytecode (coming soon)
  • ๐Ÿ”œDeployment Mistakes (coming soon)
  • ๐Ÿ”œOptimistic Roll-ups (coming soon)
  • ๐Ÿ”œTypos (coming soon)
  • ๐Ÿ”œTry-Catch (coming soon)
  • ๐Ÿ”œNFT Market-place (coming soon)
  • ๐Ÿ”œUpgrade-able Contracts (coming soon)
Powered by GitBook
On this page
  • Example vulnerabilities of DEXs that didnt migitage this issue
  • First user can steal everyone else's tokens
  • Impact
  • Proof of Concept
  • Recommended Mitigation Steps
  • Bunni Bug Report - The first deposit into a new pool can be frontrun
  • Early user can break addLiquidity
  • The first lp provider can destroy the pool
  • Vulnerable Pool initial rate.
  • The value of LP token can be manipulated by the first minister, which allows the attacker to dilute future liquidity providers' share
  • createRJLaunchEvent() can be called by anyone with 1 Wei of _token and stop others from creating RJLaunchEvent with the same token anymore
  • Uninitialized RocketJoeStaking.lastRewardTimestamp can inflate rJoe supply
  1. Tutorial 17 DEX's (Decentralized Exchanges)
  2. Common Vulnerabilities in DEX Code

Vulnerabilities in Initial Pool Creation - Liquidity Manipulation Attacks

PreviousHow Pool Implementation Mismatches Pose a Security Risk to Decentralized Exchanges (DEXs)NextVulnerabilities In Oracle Implementations

Last updated 1 year ago

Deciphering Initial Liquidity Vulnerabilities and Uniswap's Countermeasure

Introduction

The Decentralized Exchange (DEX) landscape relies heavily on liquidity pools, and the initialization phase of these pools is critically vulnerable to exploitation. Uniswap V2 deploys a mechanism to mitigate this risk, one that centers around the burning of initial liquidity pool shares. This article seeks to elaborate and clarify this strategy in depth.

How Liquidity Pools Generally Work

  1. Initial Liquidity: When a liquidity pool is first created, it has zero assets and zero pool shares (liquidity tokens).

  2. First Deposit: The first liquidity provider sets the initial value of these pool shares by depositing assets into the pool. In return, they get an equivalent number of pool shares (often calculated as the geometric mean of the deposited amounts).

  3. Subsequent Deposits: Future liquidity providers deposit assets and receive pool shares based on the current value set by the pool.

Problem Statement: Initializing Liquidity Token Supply

When someone wants to become a liquidity provider (LP) by depositing tokens into an existing Uniswap pair (or forked DEX), the formula to calculate how many liquidity tokens (also known as pool shares) they receive involves dividing the amount deposited by the starting amount of tokens already in the pool.

However, this formula doesn't work if the person is the first to deposit because the starting amount of tokens would be zero, causing a division by zero problem.

2. Uniswap V1's Approach

In Uniswap V1, the initial supply of liquidity tokens was set to be equal to the amount of ETH deposited. While this was an acceptable approximation, it had limitations:

  1. The value of one liquidity token would depend on how liquidity was initially added, which can be arbitrary.

  2. Uniswap V2 allows for arbitrary pairs, not just those involving ETH, making the V1 approach less applicable.

3. Uniswap V2's Solution: The Geometric Mean

To solve this problem, Uniswap V2 uses the geometric mean of the amounts deposited as the number of liquidity tokens minted for the first depositor. The formula used is the square root of the product of the amounts deposited of each token (root(xร—y)โ€‹root(xร—y)โ€‹root(xร—y)โ€‹).

Advantages:

  1. It ensures the value of one liquidity pool share doesn't depend on how liquidity was initially added.

  2. It minimizes rounding errors.

4. Risk of Share Value Growth

Over time, the value of a liquidity pool share could grow either by accumulating trading fees or through direct donations. If it grows too much, small liquidity providers could find it too costly to join the pool.

5. Mitigation: Burning Initial Shares

To prevent this risk, Uniswap V2 burns the first 1ร—10โˆ’151ร—10โˆ’151ร—10โˆ’151ร—10โˆ’151ร—10โˆ’151ร—10โˆ’15 (0.000000000000001) pool shares, sending them to a zero address instead of the first depositor. This acts as a safety net against an attacker who might want to raise the value of a liquidity pool share significantly. They would need to donate a prohibitively large amount to accomplish that.

How an Attacker Can Raise the Value of Liquidity Pool Shares: A Detailed Explanation with Visualization

The Setup:

Let's say an attacker aims to manipulate a liquidity pool for a token pair ABC/XYZ to make it infeasible for smaller investors to participate. The attacker's strategy is to make 1 liquidity pool share extremely valuable by contributing a large amount of one token (or both) and a very small amount of the other.

The Attack:

  1. Initial Deposit: The attacker deposits 1 ABC and 1,000,000 XYZ tokens into the pool, receiving 1ร—1,000,0001ร—1,000,000โ€‹1ร—1,000,0001ร—1,000,000โ€‹1ร—1,000,0001ร—1,000,000โ€‹ = 1000 liquidity pool shares.

  2. Manipulated Value: At this point, 1 liquidity pool share is representative of 1100010001โ€‹1100010001โ€‹1100010001โ€‹ ABC and 1,000,000100010001,000,000โ€‹1,000,000100010001,000,000โ€‹1,000,000100010001,000,000โ€‹ = 1000 XYZ.

  3. Small Investor Deterrence: A small investor who can only afford to deposit 1 XYZ will receive far less than 1 pool share, making it practically impossible for them to participate.

Visualization:

Imagine each liquidity pool share as a "block" that represents a proportional slice of the total pool assets. In a well-balanced pool, these blocks are relatively small and easily divisible:

yamlCopy codeNormal Pool:
Blocks: โ–กโ–กโ–กโ–กโ–กโ–ก

In our attack scenario, the attacker has made each block (pool share) represent a large amount of the pool's assets:

yamlCopy codeManipulated Pool:
Blocks: โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ

The size of each block (or the value of each liquidity pool share) is now so large that a small investor can only afford a tiny sliver, represented by a small fraction of a block:

mathematicaCopy codeSmall Investor's Share:
Block:  โ–ˆโ–ˆโ–ˆโ–ˆโ–ก (The small square represents what a small investor can afford)

Counter-Measure: Uniswap V2's Initial Share Burning

To deter this kind of manipulation, Uniswap V2 burns the first 1ร—10โˆ’151ร—10โˆ’151ร—10โˆ’151ร—10โˆ’151ร—10โˆ’151ร—10โˆ’15 (0.000000000000001) pool shares. If the attacker wants to raise the value of 1 liquidity pool share to, say, $100, they would need to contribute assets worth $100,000. This creates a prohibitively high cost for the attacker.

vbnetCopy codeWith Uniswap V2's Mechanism:
Initial Blocks Burned: (tiny pieces removed from the initial blocks)

Summary:

Uniswap V2's mechanism of burning initial liquidity pool shares serves as a protective barrier against this type of manipulation. It keeps the door open for small investors while putting up a prohibitively expensive wall for malicious actors aiming to distort the pool's economics.

Example vulnerabilities of DEXs that didnt migitage this issue

Impact

A user who joins the systems first (stakes first) can steal everybody's tokens by sending tokens to the system externally. This attack is possible because you enable staking a small amount of tokens.

Proof of Concept

See the following attack:

  1. the first user (user A) who enters the system stake 1 token

  2. another user (user B) is about to stake X tokens

  3. user A frontrun and transfer X tokens to the system via ERC20.transfer

  4. user B stakes X tokens, and the shares he receives is: shares = (_amount * totalStakeShares_) / (totalTokenBalanceStakers() - _amount); shares = (X * 1) / (X + 1 + X - X) = X/(X+1) = 0 meaning all the tokens he staked got him no shares, and those tokens are now a part of the single share that user A holds

  5. user A can now redeem his shares and get the 1 token he staked, the X tokens user B staked, and the X tokens he ERC20.transfer to the system because all the money in the system is in a single share that user A holds.

In general, since there is only a single share, for any user who is going to stake X tokens, if the system has X+1 tokens in its balance, the user won't get any shares and all the money will go to the attacker.

Recommended Mitigation Steps

Force users to stake at least some amount in the system (Uniswap forces users to pay at least 1e18) That way the amount the attacker will need to ERC20.transfer to the system will be at least X*1e18 instead of X which is unrealistic

Similar to issue above

Code4rena High bug bounty payout

uint256 totalLiquidityUnits = totalSupply;
if (totalLiquidityUnits == 0)
    liquidity = nativeDeposit; // TODO: Contact ThorChain on proper approach

In the current implementation, the first liquidity takes the nativeDeposit amount and uses it directly.

However, since this number (totalLiquidityUnits) will later be used for computing the liquidity issued for future addLiquidity using calculateLiquidityUnits.

A malicious user can add liquidity with only 1 wei USDV and making it nearly impossible for future users to add liquidity to the pool.

Recommendation

Uni v2 solved this problem by sending the first 1000 tokens to the zero address.

The same should work here, i.e., on first mint (totalLiquidityUnits == 0), lock some of the first minter's tokens by minting ~1% of the initial amount to the zero address instead of to the first minter.

First lp provider received liquidity amount same as the nativeDeposit amount and decides the rate. If the first lp sets the pool's rate to an extreme value no one can deposit to the pool afterward. (please refer to the proof of concept section)

A malicious attacker can DOS the system by back-running the setTokenSupport and setting the pools' price to the extreme.

Pool is created in function createPoolADD. The price (rate) of the token is determined in this function. Since the address is deterministic, the attacker can front-run the createPoolADD transaction and sends tokens to Pool's address. This would make the pool start with an extreme price and create a huge arbitrage space.

I assume pools would be created by the deployer rather than DAO at the early stage of the protocol. If the deployer calls createPoolADD and addCuratedPool at the same time then an attacker/arbitrager could actually get (huge) profit by doing this.

Assume that the deployer wants to create a BNB pool at an initial rate of 10000:300 and then make it a curated pool. An arbitrager can send 2700 BNB to the (precomputed) pool address and make iBNB 10x cheaper. The arbitrager can mint the synth at a 10x cheaper price before the price becomes normal.

However, if a user first directly transfers Joe tokens to the contract before the first updatePool call, the block.timestamp - lastRewardTimestamp = block.timestamp will be a large timestamp value and lots of rJoe will be minted (but not distributed to users). Even though they are not distributed to the users, inflating the rJoe total supply might not be desired.

๐Ÿค
๐Ÿ’€
๐ŸŠโ€โ™‚๏ธ
Book an audit with Zokyo
First user can steal everyone else's tokens
Bunni Bug Report - The first deposit into a new pool can be frontrun
Early user can break addLiquidity
https://github.com/code-423n4/2021-11-vader/blob/429970427b4dc65e37808d7116b9de27e395ce0c/contracts/dex/pool/BasePool.sol#L161-L163
The first lp provider can destroy the pool
Vulnerable Pool initial rate.
The value of LP token can be manipulated by the first minister, which allows the attacker to dilute future liquidity providers' share
createRJLaunchEvent() can be called by anyone with 1 Wei of _token and stop others from creating RJLaunchEvent with the same token anymore
Uninitialized RocketJoeStaking.lastRewardTimestamp can inflate rJoe supply