CollateralPool is the core vault contract of the BankX protocol. It accepts WETH as collateral, mints and burns XSD, tracks per-user interest, and handles the buyback-and-burn mechanism. All minting and redeeming is subject to the current global_collateral_ratio reported by the PIDController. The contract implements ReentrancyGuard and a block-delay anti-flash-loan mechanism.
Key Concepts
collat_XSD — Running total of XSD that has been minted through this pool and is currently outstanding. Used for collateralisation accounting.
mintMapping — Per-address MintInfo struct tracking accumulated interest, weighted-average rate, last interaction time, and principal XSD amount.
Redemption staging. Redemptions are split into two steps: a redeem call (burns XSD, queues collateral and BankX) and collectRedemption() (transfers queued assets) separated by block_delay blocks.
block_delay — Default: 2 blocks. Prevents flash loans that mint XSD, manipulate prices, then redeem in the same transaction.
blockDelay modifier — Requires that pid_controller.lastPriceCheck(msg.sender).pricecheck == true AND the last price check block + block_delay <= block.number. After each call with this modifier, pricecheck is reset to false, requiring a new priceCheck() call before the next action.
Pause flags.mint_paused, redeem_paused, buyback_paused are owner-controlled.
nonReentrant on all mint/redeem/collect. All state-changing user functions in CollateralPool carry OpenZeppelin's nonReentrant guard.
Two-step redemption prevents flash loans. XSD is burned in the redeem call. Collateral and BankX are only transferred block_delay blocks later via collectRedemption(). An attacker cannot mint, manipulate, and redeem in a single transaction.
bucket3 redemption block. If pid_controller.bucket3() == true, all redeem functions and collectRedemption() revert. Redemptions resume only when the collateral deficit is resolved.
blockDelay requires a prior priceCheck(). Fractional minting, algorithmic minting, and all redeems require the caller to have a valid priceCheck recorded in the PID Controller within the last block_delay blocks.
Overredemption guard.XSD_amount <= mintMapping[msg.sender].amount ensures a user cannot redeem more XSD than they personally minted, preventing draining the pool via fabricated redemptions.
receive() restricted to WETH. The fallback receive() function only accepts ETH from the WETH contract. Direct ETH sends revert.
Integration Guide
ICollateralPool pool = ICollateralPool(payable(COLLATERAL_POOL_ADDRESS));// Step 1: Call priceCheck() on PID Controller to satisfy blockDelay modifierIPIDController(PID_ADDRESS).priceCheck();// Step 2a: 1:1 mint (CR = 100%)pool.mint1t1XSD{value: ethAmount}(XSD_amount, block.timestamp + 300);// Step 2b: Fractional mint (0 < CR < 100%)IERC20(BANKX_ADDRESS).approve(COLLATERAL_POOL_ADDRESS, bankx_amount);pool.mintFractionalXSD{value: ethAmount}(XSD_amount, bankx_amount, block.timestamp + 300);// Step 3: Fractional redeemIERC20(XSD_ADDRESS).approve(COLLATERAL_POOL_ADDRESS, XSD_amount);pool.redeemFractionalXSD(XSD_amount, bankx_min, collateral_min, block.timestamp + 300);// Step 4: Wait block_delay blocks, then collect// (Must call priceCheck() again before collectRedemption)IPIDController(PID_ADDRESS).priceCheck();pool.collectRedemption();