From 2ab8bc312d8deecee0356664bf9454fb78af5e1c Mon Sep 17 00:00:00 2001 From: Uncle Fatso Date: Thu, 9 Oct 2025 12:48:53 +0300 Subject: [PATCH] redemtion functionality finalized; mainnet tests added Signed-off-by: Uncle Fatso --- src/Treasury.sol | 32 ++++------- test/treasury/TreasuryRedemption.t.sol | 74 ++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 test/treasury/TreasuryRedemption.t.sol diff --git a/src/Treasury.sol b/src/Treasury.sol index 6e90b8e..40f31e3 100644 --- a/src/Treasury.sol +++ b/src/Treasury.sol @@ -223,51 +223,39 @@ contract GhostTreasury is GhostAccessControlled, ITreasury { function redeemReserve( address router, // could be an issue - uint256 amount, - uint256 slippage + uint256 amount ) external onlyGovernor { address weth = IUniswapV2Router01(router).WETH(); address pair = IUniswapV2Factory(IUniswapV2Router01(router).factory()).getPair(ftso, weth); - IERC20(weth).approve(router, amount + 1); + IERC20(weth).approve(router, amount); (uint256 reserve0, uint256 reserve1,) = IUniswapV2Pair(pair).getReserves(); - address[] memory path; - if (ftso < weth) { - path[0] = ftso; - path[1] = weth; + address[] memory path = new address[](2); + path[0] = weth; + path[1] = ftso; + if (ftso < weth) { reserve0 = reserve1 ^ reserve0; reserve1 = reserve1 ^ reserve0; reserve0 = reserve1 ^ reserve0; - } else { - path[0] = weth; - path[1] = ftso; } uint256 amountIn = _quantityToBeSwapped(amount, reserve0); uint256[] memory amounts = IUniswapV2Router02(router).getAmountsOut(amountIn, path); IUniswapV2Router02(router).swapExactTokensForTokens( amountIn, - amounts[0], + amounts[1], path, address(this), block.timestamp ); amountIn = amount - amountIn; - IERC20(ftso).approve(router, amountIn + 1); - IUniswapV2Router02(router).addLiquidity( - path[0], - path[1], - amountIn, - amounts[0], - amountIn * (1e7 - slippage) / 1e7, - amounts[0] * (1e7 - slippage) / 1e7, - address(this), - block.timestamp - ); + IERC20(weth).transfer(pair, amountIn); + IERC20(ftso).transfer(pair, amounts[1]); + IUniswapV2Pair(pair).mint(address(this)); } function indexInRegistry( diff --git a/test/treasury/TreasuryRedemption.t.sol b/test/treasury/TreasuryRedemption.t.sol new file mode 100644 index 0000000..1e46371 --- /dev/null +++ b/test/treasury/TreasuryRedemption.t.sol @@ -0,0 +1,74 @@ +pragma solidity 0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {StdChains} from "forge-std/StdChains.sol"; + +import "../../src/GhostAuthority.sol"; +import "../../src/Treasury.sol"; +import "../../src/StandardBondingCalculator.sol"; + +import "@uniswap-v2-periphery-1.1.0-beta.0/interfaces/IWETH.sol"; + +contract GhostTreasuryRedemptionTest is Test { + address public constant owner = 0x0000000000000000000000000000000000000001; + address public constant governor = 0x0000000000000000000000000000000000000002; + address public constant guardian = 0x0000000000000000000000000000000000000003; + + uint256 public constant amount = 69 * 1e18; + address public constant usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address public constant pair = 0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc; + address public constant router = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D; + address public constant weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + + GhostTreasury treasury; + GhostAuthority authority; + GhostBondingCalculator calculator; + + function setUp() public { + vm.startPrank(owner); + authority = new GhostAuthority( + governor, + guardian, + owner, + owner + ); + treasury = new GhostTreasury(usdc, 69, address(authority)); + calculator = new GhostBondingCalculator(usdc, 4000, 1); + vm.stopPrank(); + + vm.startPrank(governor); + treasury.enable(ITreasury.STATUS.RESERVETOKEN, weth, address(calculator)); + treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, pair, address(calculator)); + vm.stopPrank(); + } + + function test_mainnet_redemptionWorksCorrectly() public { + vm.deal(owner, amount); + vm.startPrank(owner); + IWETH(weth).deposit{value: amount}(); + IERC20(weth).transfer(address(treasury), amount); + assertEq(IERC20(weth).balanceOf(address(treasury)), amount); + vm.stopPrank(); + + assertEq(treasury.totalReserves(), 0); + + vm.prank(governor); + treasury.auditReserves(); + + uint256 prevTotalReserves = treasury.totalReserves(); + assertEq(prevTotalReserves > 0, true); + assertEq(IERC20(pair).balanceOf(address(treasury)), 0); + assertEq(IERC20(pair).balanceOf(address(treasury)), 0); + + vm.prank(governor); + treasury.redeemReserve(router, amount); + + assertEq(IERC20(usdc).balanceOf(address(treasury)), 0); + assertEq(IERC20(weth).balanceOf(address(treasury)), 0); + assertEq(IERC20(pair).balanceOf(address(treasury)) > 0, true); + + vm.prank(governor); + treasury.auditReserves(); + assertEq(treasury.totalReserves() > prevTotalReserves, true); + } +}