Last active
May 15, 2023 05:33
-
-
Save carlitox477/a5bd6345b4854da91fe5f80217a18aed to your computer and use it in GitHub Desktop.
POC_wxETHUnhandleRoundingDown.t.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: Unlicense | |
pragma solidity >=0.8.0; | |
import {DSTest} from "ds-test/test.sol"; | |
import {Utilities} from "./utils/Utilities.sol"; | |
import {MockErc20} from "./mocks/MockERC20.sol"; | |
import {console} from "./utils/Console.sol"; | |
import {Vm} from "forge-std/Vm.sol"; | |
import {ICurveFactory} from "src/interfaces/ICurveFactory.sol"; | |
import {ICurvePool} from "src/interfaces/ICurvePool.sol"; | |
import {xETH as xETH_contract} from "src/xETH.sol"; | |
import {WrappedXETH} from "src/wxETH.sol"; | |
contract POC_wxETHUnhandleRoundingDown is DSTest { | |
Vm internal immutable vm = Vm(HEVM_ADDRESS); | |
Utilities internal utils; | |
address payable[] internal users; | |
address public owner; | |
address public testUser; | |
xETH_contract internal xETH; | |
WrappedXETH internal wxETH; | |
uint256 TIME_PER_BLOCK = 12; // seconds | |
uint256 DRIP_AMOUNT = 70 ether; | |
uint256 DRIP_DURATION = 1 weeks; // 1 year | |
uint256 DRIP_RATE = DRIP_AMOUNT / (DRIP_DURATION / TIME_PER_BLOCK); | |
uint256 TIME_FOR_SECOND_DEPOSIT = 15 minutes; | |
function setUp() public { | |
utils = new Utilities(); | |
users = utils.createUsers(5); | |
owner = users[0]; | |
testUser = users[1]; | |
vm.startPrank(owner); | |
xETH = new xETH_contract(); | |
xETH.setAMO(owner); | |
xETH.mintShares(10000 ether); | |
wxETH = new WrappedXETH(address(xETH)); | |
vm.stopPrank(); | |
vm.label(address(xETH), "xETH"); | |
vm.label(address(wxETH), "wxETH"); | |
vm.label(owner, "owner"); | |
vm.label(testUser, "test_user"); | |
} | |
function testPOCUnfairRewardDistribution() public { | |
address ALICE = users[1]; | |
address BOB = users[2]; | |
//@audit notice that it is just 1 wei | |
uint256 ALICE_STAKE = 1; | |
// The owner configure drip and lock funds | |
vm.startPrank(owner); | |
{ | |
wxETH.setDripRate(DRIP_RATE); | |
xETH.approve(address(wxETH), DRIP_AMOUNT); | |
wxETH.addLockedFunds(DRIP_AMOUNT); | |
wxETH.startDrip(); | |
assertTrue(wxETH.dripEnabled()); | |
} | |
vm.stopPrank(); | |
{ | |
// Owner funds Alice | |
vm.prank(owner); | |
xETH.transfer(ALICE, ALICE_STAKE); | |
// Alice now stakes her xETH | |
vm.startPrank(ALICE); | |
{ | |
xETH.approve(address(wxETH), ALICE_STAKE); | |
wxETH.stake(ALICE_STAKE); | |
} | |
vm.stopPrank(); | |
} | |
// Some blocks pass | |
vm.roll(block.number + TIME_FOR_SECOND_DEPOSIT / TIME_PER_BLOCK); | |
wxETH.accrueDrip(); | |
// console.log("Exchange rate: %s", wxETH.exchangeRate()/1e18); | |
// if xETHAmount * BASE_UNIT < wxETH.exchangeRate() then deposit is zero | |
// if xETHAmount < wxETH.exchangeRate()/BASE_UNIT then deposit is zero | |
uint256 minAmountToDeposit = wxETH.exchangeRate()/1e18; | |
console.log("Min amount to deposit to get a single share: %d wei",wxETH.exchangeRate()/1e18); | |
{ | |
// Bob tries to deposit 50 xETH | |
uint256 amountToDeposit = minAmountToDeposit - 1; | |
vm.prank(owner); | |
xETH.transfer(BOB, amountToDeposit); | |
// Bob now stakes his xETH | |
vm.startPrank(BOB); | |
{ | |
console.log("Bob xETH before staking: %d", xETH.balanceOf(BOB)); | |
xETH.approve(address(wxETH), amountToDeposit); | |
wxETH.stake(amountToDeposit); | |
// Bob balance now is zero | |
console.log("Bob wxETH after staking balance",wxETH.balanceOf(BOB)); | |
// wxETH.unstake(wxETH.balanceOf(BOB)); | |
// console.log("Bob xETH after unstaking: %d wei", xETH.balanceOf(BOB)); | |
} | |
vm.stopPrank(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment