chore: sync submodule state (parent ref update)
Made-with: Cursor
This commit is contained in:
74
test/treasury/CcipBridgeAdapter138.t.sol
Normal file
74
test/treasury/CcipBridgeAdapter138.t.sol
Normal file
@@ -0,0 +1,74 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Test} from "forge-std/Test.sol";
|
||||
import {CcipBridgeAdapter138} from "../../contracts/treasury/CcipBridgeAdapter138.sol";
|
||||
|
||||
contract MockWETH9 {
|
||||
mapping(address => uint256) public balanceOf;
|
||||
function mint(address to, uint256 amount) external {
|
||||
balanceOf[to] += amount;
|
||||
}
|
||||
function transferFrom(address from, address to, uint256 amount) external returns (bool) {
|
||||
balanceOf[from] -= amount;
|
||||
balanceOf[to] += amount;
|
||||
return true;
|
||||
}
|
||||
function approve(address, uint256) external pure returns (bool) { return true; }
|
||||
}
|
||||
|
||||
contract MockBridge {
|
||||
function sendCrossChain(uint64, address, uint256) external payable returns (bytes32) {
|
||||
return keccak256("mock");
|
||||
}
|
||||
}
|
||||
|
||||
contract CcipBridgeAdapter138Test is Test {
|
||||
CcipBridgeAdapter138 public adapter;
|
||||
MockWETH9 public weth9;
|
||||
MockBridge public bridge;
|
||||
address public executor;
|
||||
address public receiverMainnet;
|
||||
address public admin;
|
||||
|
||||
function setUp() public {
|
||||
admin = address(1);
|
||||
executor = address(2);
|
||||
receiverMainnet = address(3);
|
||||
weth9 = new MockWETH9();
|
||||
bridge = new MockBridge();
|
||||
adapter = new CcipBridgeAdapter138(
|
||||
address(weth9),
|
||||
address(bridge),
|
||||
receiverMainnet,
|
||||
admin
|
||||
);
|
||||
vm.prank(admin);
|
||||
adapter.setStrategyExecutor(executor);
|
||||
}
|
||||
|
||||
function test_sendWeth9_revert_exportsDisabled() public {
|
||||
weth9.mint(executor, 10e18);
|
||||
vm.prank(executor);
|
||||
vm.expectRevert(CcipBridgeAdapter138.ExportsDisabled.selector);
|
||||
adapter.sendWeth9ToMainnet(10e18, 0, block.timestamp + 3600);
|
||||
}
|
||||
|
||||
function test_sendWeth9_revert_onlyExecutor() public {
|
||||
vm.prank(admin);
|
||||
adapter.setExportsEnabled(true);
|
||||
weth9.mint(admin, 10e18);
|
||||
vm.prank(admin);
|
||||
vm.expectRevert(CcipBridgeAdapter138.OnlyExecutor.selector);
|
||||
adapter.sendWeth9ToMainnet(10e18, 0, block.timestamp + 3600);
|
||||
}
|
||||
|
||||
function test_sendWeth9_success() public {
|
||||
vm.prank(admin);
|
||||
adapter.setExportsEnabled(true);
|
||||
weth9.mint(executor, 10e18);
|
||||
vm.prank(executor);
|
||||
bytes32 id = adapter.sendWeth9ToMainnet{value: 0}(10e18, 0, block.timestamp + 3600);
|
||||
assertEq(id, keccak256("mock"));
|
||||
}
|
||||
}
|
||||
52
test/treasury/ReceiverExecutorMainnet.t.sol
Normal file
52
test/treasury/ReceiverExecutorMainnet.t.sol
Normal file
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Test} from "forge-std/Test.sol";
|
||||
import {ReceiverExecutorMainnet} from "../../contracts/treasury/ReceiverExecutorMainnet.sol";
|
||||
|
||||
contract ReceiverExecutorMainnetTest is Test {
|
||||
ReceiverExecutorMainnet public receiver;
|
||||
address public admin;
|
||||
address public keeper;
|
||||
address public bridge;
|
||||
|
||||
function setUp() public {
|
||||
admin = address(1);
|
||||
keeper = address(2);
|
||||
bridge = address(0x99);
|
||||
receiver = new ReceiverExecutorMainnet(admin);
|
||||
vm.startPrank(admin);
|
||||
receiver.grantRole(receiver.KEEPER_ROLE(), keeper);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function test_expectedWeth9Source_defaultZero() public view {
|
||||
assertEq(receiver.getExpectedWeth9Source(), address(0));
|
||||
assertEq(receiver.expectedWeth9Source(), address(0));
|
||||
}
|
||||
|
||||
function test_setExpectedWeth9Source_success() public {
|
||||
vm.prank(admin);
|
||||
receiver.setExpectedWeth9Source(bridge);
|
||||
assertEq(receiver.getExpectedWeth9Source(), bridge);
|
||||
assertEq(receiver.expectedWeth9Source(), bridge);
|
||||
}
|
||||
|
||||
function test_setExpectedWeth9Source_revert_notAdmin() public {
|
||||
vm.prank(keeper);
|
||||
vm.expectRevert();
|
||||
receiver.setExpectedWeth9Source(bridge);
|
||||
}
|
||||
|
||||
function test_receive_acceptsEth() public {
|
||||
(bool sent,) = address(receiver).call{value: 1 ether}("");
|
||||
assertTrue(sent);
|
||||
assertEq(address(receiver).balance, 1 ether);
|
||||
}
|
||||
|
||||
function test_constants_matchMainnet() public view {
|
||||
assertEq(receiver.WETH9_MAINNET(), 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
|
||||
assertEq(receiver.USDC_MAINNET(), 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
|
||||
assertEq(receiver.USDT_MAINNET(), 0xdAC17F958D2ee523a2206206994597C13D831ec7);
|
||||
}
|
||||
}
|
||||
180
test/treasury/StrategyExecutor138.t.sol
Normal file
180
test/treasury/StrategyExecutor138.t.sol
Normal file
@@ -0,0 +1,180 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Test, console} from "forge-std/Test.sol";
|
||||
import {TreasuryVault} from "../../contracts/treasury/TreasuryVault.sol";
|
||||
import {CcipBridgeAdapter138} from "../../contracts/treasury/CcipBridgeAdapter138.sol";
|
||||
import {StrategyExecutor138} from "../../contracts/treasury/StrategyExecutor138.sol";
|
||||
|
||||
contract MockWETH {
|
||||
mapping(address => uint256) public balanceOf;
|
||||
function mint(address to, uint256 amount) external {
|
||||
balanceOf[to] += amount;
|
||||
}
|
||||
function transfer(address to, uint256 amount) external returns (bool) {
|
||||
balanceOf[msg.sender] -= amount;
|
||||
balanceOf[to] += amount;
|
||||
return true;
|
||||
}
|
||||
function transferFrom(address from, address to, uint256 amount) external returns (bool) {
|
||||
balanceOf[from] -= amount;
|
||||
balanceOf[to] += amount;
|
||||
return true;
|
||||
}
|
||||
function approve(address, uint256) external pure returns (bool) { return true; }
|
||||
}
|
||||
|
||||
contract MockBridge {
|
||||
function sendCrossChain(uint64, address, uint256) external payable returns (bytes32) {
|
||||
return keccak256("ok");
|
||||
}
|
||||
}
|
||||
|
||||
contract StrategyExecutor138Test is Test {
|
||||
TreasuryVault public vault;
|
||||
MockBridge public bridge;
|
||||
CcipBridgeAdapter138 public adapter;
|
||||
StrategyExecutor138 public executor;
|
||||
MockWETH public weth9;
|
||||
address public admin;
|
||||
address public keeper;
|
||||
address public receiverMainnet = address(0x99);
|
||||
|
||||
function setUp() public {
|
||||
admin = address(1);
|
||||
keeper = address(2);
|
||||
weth9 = new MockWETH();
|
||||
vault = new TreasuryVault(admin);
|
||||
bridge = new MockBridge();
|
||||
adapter = new CcipBridgeAdapter138(
|
||||
address(weth9),
|
||||
address(bridge),
|
||||
receiverMainnet,
|
||||
admin
|
||||
);
|
||||
executor = new StrategyExecutor138(address(vault), address(adapter), admin);
|
||||
vm.startPrank(admin);
|
||||
adapter.setStrategyExecutor(address(executor));
|
||||
vault.setModule(address(executor), true);
|
||||
vault.setModule(address(adapter), true);
|
||||
vault.setToken(address(weth9), true);
|
||||
executor.setToken(address(weth9), true);
|
||||
executor.grantRole(executor.KEEPER_ROLE(), keeper);
|
||||
adapter.setExportsEnabled(true);
|
||||
vm.stopPrank();
|
||||
|
||||
weth9.mint(address(vault), 100e18);
|
||||
}
|
||||
|
||||
function test_exportToMainnet_revert_tokenNotApproved() public {
|
||||
MockWETH other = new MockWETH();
|
||||
other.mint(address(vault), 50e18);
|
||||
vm.prank(admin);
|
||||
vault.setToken(address(other), true);
|
||||
vm.prank(keeper);
|
||||
vm.expectRevert(StrategyExecutor138.TokenNotApproved.selector);
|
||||
executor.exportToMainnet(address(other), 50e18, block.timestamp + 3600);
|
||||
}
|
||||
|
||||
function test_exportToMainnet_revert_cooldown() public {
|
||||
vm.prank(admin);
|
||||
executor.setCooldownBlocks(1);
|
||||
vm.prank(keeper);
|
||||
executor.exportToMainnet(address(weth9), 10e18, block.timestamp + 3600);
|
||||
vm.prank(keeper);
|
||||
vm.expectRevert(StrategyExecutor138.CooldownNotElapsed.selector);
|
||||
executor.exportToMainnet(address(weth9), 10e18, block.timestamp + 3600);
|
||||
}
|
||||
|
||||
function test_setExportPolicy_success() public {
|
||||
StrategyExecutor138.ExportPolicy memory policy = StrategyExecutor138.ExportPolicy({
|
||||
mode: StrategyExecutor138.ExportMode.Threshold,
|
||||
minExportUsd: 10_000e6,
|
||||
maxPerTxUsd: 50_000e6,
|
||||
maxDailyUsd: 100_000e6,
|
||||
rateLimitPerHour: 5,
|
||||
cooldownBlocks: 10,
|
||||
exportAsset: address(weth9),
|
||||
destinationSelector: 5009297550715157269,
|
||||
destinationReceiver: receiverMainnet
|
||||
});
|
||||
vm.prank(admin);
|
||||
executor.setExportPolicy(policy);
|
||||
(StrategyExecutor138.ExportMode mode, uint256 minExportUsd,,,, uint256 cooldownBlocks,,,) = executor.exportPolicy();
|
||||
assertEq(uint8(mode), uint8(StrategyExecutor138.ExportMode.Threshold));
|
||||
assertEq(minExportUsd, 10_000e6);
|
||||
assertEq(cooldownBlocks, 10);
|
||||
assertEq(executor.cooldownBlocks(), 10);
|
||||
}
|
||||
|
||||
function test_recordExportIntent_success() public {
|
||||
vm.prank(admin);
|
||||
adapter.setExportsEnabled(false);
|
||||
vm.prank(keeper);
|
||||
executor.recordExportIntent(address(weth9), 5e18);
|
||||
assertEq(executor.pendingIntentToken(), address(weth9));
|
||||
assertEq(executor.pendingIntentAmount(), 5e18);
|
||||
}
|
||||
|
||||
function test_recordExportIntent_revert_exportsEnabled() public {
|
||||
vm.prank(admin);
|
||||
adapter.setExportsEnabled(true);
|
||||
vm.prank(keeper);
|
||||
vm.expectRevert(StrategyExecutor138.ExportsNotEnabled.selector);
|
||||
executor.recordExportIntent(address(weth9), 5e18);
|
||||
}
|
||||
|
||||
function test_recordExportIntent_revert_tokenNotApproved() public {
|
||||
MockWETH other = new MockWETH();
|
||||
vm.prank(admin);
|
||||
adapter.setExportsEnabled(false);
|
||||
vm.prank(keeper);
|
||||
vm.expectRevert(StrategyExecutor138.TokenNotApproved.selector);
|
||||
executor.recordExportIntent(address(other), 1e18);
|
||||
}
|
||||
|
||||
function test_processPendingIntent_revert_noIntent() public {
|
||||
vm.prank(keeper);
|
||||
vm.expectRevert(StrategyExecutor138.NoPendingIntent.selector);
|
||||
executor.processPendingIntent{value: 0}(block.timestamp + 3600);
|
||||
}
|
||||
|
||||
function test_processPendingIntent_revert_exportsDisabled() public {
|
||||
vm.prank(admin);
|
||||
adapter.setExportsEnabled(false);
|
||||
vm.prank(keeper);
|
||||
executor.recordExportIntent(address(weth9), 5e18);
|
||||
vm.prank(admin);
|
||||
adapter.setExportsEnabled(false);
|
||||
vm.prank(keeper);
|
||||
vm.expectRevert(StrategyExecutor138.ExportsNotEnabled.selector);
|
||||
executor.processPendingIntent{value: 0}(block.timestamp + 3600);
|
||||
}
|
||||
|
||||
function test_processPendingIntent_success() public {
|
||||
vm.prank(admin);
|
||||
adapter.setExportsEnabled(false);
|
||||
vm.prank(keeper);
|
||||
executor.recordExportIntent(address(weth9), 5e18);
|
||||
vm.prank(admin);
|
||||
adapter.setExportsEnabled(true);
|
||||
uint256 vaultBefore = weth9.balanceOf(address(vault));
|
||||
vm.prank(keeper);
|
||||
executor.processPendingIntent{value: 0}(block.timestamp + 3600);
|
||||
assertEq(executor.pendingIntentToken(), address(0));
|
||||
assertEq(executor.pendingIntentAmount(), 0);
|
||||
assertEq(weth9.balanceOf(address(vault)), vaultBefore - 5e18);
|
||||
}
|
||||
|
||||
function test_harvestFees_revert_notImplemented() public {
|
||||
vm.prank(keeper);
|
||||
vm.expectRevert(StrategyExecutor138.NotImplemented.selector);
|
||||
executor.harvestFees();
|
||||
}
|
||||
|
||||
function test_rebalanceLp_revert_notImplemented() public {
|
||||
vm.prank(keeper);
|
||||
vm.expectRevert(StrategyExecutor138.NotImplemented.selector);
|
||||
executor.rebalanceLp();
|
||||
}
|
||||
}
|
||||
58
test/treasury/TreasuryVault.t.sol
Normal file
58
test/treasury/TreasuryVault.t.sol
Normal file
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Test} from "forge-std/Test.sol";
|
||||
import {TreasuryVault} from "../../contracts/treasury/TreasuryVault.sol";
|
||||
|
||||
contract MockERC20 {
|
||||
mapping(address => uint256) public balanceOf;
|
||||
function mint(address to, uint256 amount) external {
|
||||
balanceOf[to] += amount;
|
||||
}
|
||||
function transfer(address to, uint256 amount) external returns (bool) {
|
||||
balanceOf[msg.sender] -= amount;
|
||||
balanceOf[to] += amount;
|
||||
return true;
|
||||
}
|
||||
function transferFrom(address from, address to, uint256 amount) external returns (bool) {
|
||||
balanceOf[from] -= amount;
|
||||
balanceOf[to] += amount;
|
||||
return true;
|
||||
}
|
||||
function approve(address, uint256) external pure returns (bool) { return true; }
|
||||
}
|
||||
|
||||
contract TreasuryVaultTest is Test {
|
||||
TreasuryVault vault;
|
||||
MockERC20 token;
|
||||
address admin = address(1);
|
||||
address module1 = address(2);
|
||||
address module2 = address(3);
|
||||
|
||||
function setUp() public {
|
||||
vault = new TreasuryVault(admin);
|
||||
token = new MockERC20();
|
||||
token.mint(address(vault), 1000000e18);
|
||||
vm.prank(admin);
|
||||
vault.setToken(address(token), true);
|
||||
vm.prank(admin);
|
||||
vault.setModule(module1, true);
|
||||
vm.prank(admin);
|
||||
vault.setModule(module2, true);
|
||||
}
|
||||
|
||||
function test_requestTransfer_success() public {
|
||||
token.mint(address(vault), 100e18);
|
||||
vm.prank(module1);
|
||||
vault.requestTransfer(address(token), 50e18, module2);
|
||||
assertEq(token.balanceOf(module2), 50e18);
|
||||
}
|
||||
|
||||
function test_requestTransfer_revert_tokenNotApproved() public {
|
||||
MockERC20 other = new MockERC20();
|
||||
other.mint(address(vault), 100e18);
|
||||
vm.prank(module1);
|
||||
vm.expectRevert(TreasuryVault.TokenNotApproved.selector);
|
||||
vault.requestTransfer(address(other), 50e18, module2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user