-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: redeem manager TransferError test added
- Loading branch information
1 parent
76d9173
commit 54ca475
Showing
2 changed files
with
173 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity 0.8.20; | ||
|
||
import "forge-std/Test.sol"; | ||
import "../src/RedeemManager.1.sol"; | ||
import "./mocks/MockERC20.sol"; | ||
import "../src/Allowlist.1.sol"; | ||
|
||
import "./utils/LibImplementationUnbricker.sol"; | ||
|
||
interface IRedeemManagerV1Mock { | ||
|
||
/// @notice Thrown when a transfer error occured with LsETH | ||
error TransferError(); | ||
|
||
} | ||
|
||
contract RedeemManagerV1Mock is RedeemManagerV1 { | ||
// Error we are testing for | ||
function redeem(uint256 _lsETHAmount) external onlyRedeemerOrRiver { | ||
if (!_castedRiver().transferFrom(msg.sender, address(this), _lsETHAmount)) { | ||
revert TransferError(); | ||
} | ||
} | ||
} | ||
|
||
contract RiverMock is MockERC20 { | ||
mapping(address => uint256) internal balances; | ||
mapping(address => mapping(address => uint256)) internal approvals; | ||
address internal allowlist; | ||
uint256 internal rate = 1e18; | ||
uint256 internal _totalSupply; | ||
|
||
constructor(address _allowlist) MockERC20("Mock River", "MRIV", 18) { | ||
allowlist = _allowlist; | ||
} | ||
|
||
function approve(address to, uint256 amount) public virtual override returns(bool) { | ||
approvals[msg.sender][to] = amount; | ||
return true; | ||
} | ||
|
||
error ApprovedAmountTooLow(); | ||
|
||
function transferFrom(address from, address to, uint256 amount) public override returns (bool) { | ||
if (transferFromFail) { | ||
return false; | ||
} | ||
if (approvals[from][msg.sender] < amount) { | ||
revert ApprovedAmountTooLow(); | ||
} | ||
if (approvals[from][msg.sender] != type(uint256).max) { | ||
approvals[from][msg.sender] -= amount; | ||
} | ||
balances[from] -= amount; | ||
balances[to] += amount; | ||
return true; | ||
} | ||
|
||
function balanceOf(address account) public view virtual override returns (uint256) { | ||
return balances[account]; | ||
} | ||
|
||
/// @notice Sets the balance of the given account and updates totalSupply | ||
/// @param account The account to set the balance of | ||
/// @param amount Amount to set as balance | ||
function sudoDeal(address account, uint256 amount) external { | ||
if (amount > balances[account]) { | ||
_totalSupply += amount - balances[account]; | ||
} else { | ||
_totalSupply -= balances[account] - amount; | ||
} | ||
balances[account] = amount; | ||
} | ||
|
||
function sudoSetRate(uint256 newRate) external { | ||
rate = newRate; | ||
} | ||
|
||
function getAllowlist() external view returns (address) { | ||
return allowlist; | ||
} | ||
|
||
function sudoReportWithdraw(address redeemManager, uint256 lsETHAmount) external payable { | ||
RedeemManagerV1(redeemManager).reportWithdraw{value: msg.value}(lsETHAmount); | ||
} | ||
|
||
function totalSupply() public view virtual override returns (uint256) { | ||
return _totalSupply; | ||
} | ||
|
||
function totalUnderlyingSupply() external view returns (uint256) { | ||
return (_totalSupply * rate) / 1e18; | ||
} | ||
|
||
function underlyingBalanceFromShares(uint256 shares) external view returns (uint256) { | ||
return (shares * rate) / 1e18; | ||
} | ||
|
||
function pullExceedingEth(address redeemManager, uint256 amount) external { | ||
RedeemManagerV1(redeemManager).pullExceedingEth(amount); | ||
} | ||
|
||
fallback() external payable {} | ||
receive() external payable {} | ||
} | ||
|
||
contract RedeemManagerTest is Test { | ||
RedeemManagerV1Mock internal redeemManager; | ||
AllowlistV1 internal allowlist; | ||
RiverMock internal river; | ||
// UserFactory internal uf = new UserFactory(); | ||
address internal allowlistAdmin; | ||
address internal allowlistAllower; | ||
address internal allowlistDenier; | ||
address public mockRiverAddress; | ||
|
||
function setUp() external { | ||
allowlistAdmin = makeAddr("allowlistAdmin"); | ||
allowlistAllower = makeAddr("allowlistAllower"); | ||
allowlistDenier = makeAddr("allowlistDenier"); | ||
redeemManager = new RedeemManagerV1Mock(); | ||
LibImplementationUnbricker.unbrick(vm, address(redeemManager)); | ||
allowlist = new AllowlistV1(); | ||
LibImplementationUnbricker.unbrick(vm, address(allowlist)); | ||
allowlist.initAllowlistV1(allowlistAdmin, allowlistAllower); | ||
allowlist.initAllowlistV1_1(allowlistDenier); | ||
river = new RiverMock(address(allowlist)); | ||
|
||
redeemManager.initializeRedeemManagerV1(address(river)); | ||
} | ||
|
||
function testTransferError() public { | ||
// Set up the mock to fail the transferFrom function | ||
river.setTransferFromFail(true); | ||
|
||
// Expect the TransferError revert | ||
vm.expectRevert(IRedeemManagerV1Mock.TransferError.selector); | ||
|
||
// Call the function that triggers the transferFrom | ||
vm.prank(address(river)); | ||
redeemManager.redeem(100 ether); | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// MockERC20.sol | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity 0.8.20; | ||
|
||
// import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; | ||
|
||
contract MockERC20 is ERC20 { | ||
bool transferFromFail; | ||
|
||
constructor(string memory name, string memory symbol, uint8 decimals) ERC20(name, symbol) { | ||
// No need to set decimals here, OpenZeppelin's ERC20 defaults to 18 decimals | ||
} | ||
|
||
function setTransferFromFail(bool _fail) external { | ||
transferFromFail = _fail; | ||
} | ||
|
||
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { | ||
if (transferFromFail) { | ||
return false; | ||
} | ||
return super.transferFrom(sender, recipient, amount); | ||
} | ||
|
||
function mint(address to, uint256 amount) external { | ||
_mint(to, amount); | ||
} | ||
} |