diff --git a/.github/workflows/ci-jobs.yml b/.github/workflows/ci-jobs.yml index 0524bc6..0a45e19 100644 --- a/.github/workflows/ci-jobs.yml +++ b/.github/workflows/ci-jobs.yml @@ -1,6 +1,6 @@ name: Compile and Test -on: +on: push: branches: [ main ] pull_request: @@ -23,7 +23,9 @@ jobs: - name: Run tests run: forge test --no-match-contract Integration -vvv - - - name: Run Integration tests - run: forge test --match-contract Integration --fork-url https://rpc.ankr.com/eth -vvv - \ No newline at end of file + + - name: Run Mainnet Integration tests + run: forge test --match-contract Integration --no-match-contract ArbiIntegration --fork-url https://rpc.ankr.com/eth -vvv + + - name: Run Arbitrum Integration tests + run: forge test --match-contract ArbiIntegration --fork-url https://arb1.arbitrum.io/rpc -vvv diff --git a/src/test/integrations/aave/AaveV3.t.sol b/src/test/integrations/aave/AaveV3.t.sol new file mode 100644 index 0000000..cf13d5e --- /dev/null +++ b/src/test/integrations/aave/AaveV3.t.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.11; + +import {Errors} from "../../../utils/Errors.sol"; +import {ATokenOracle} from "oracle/aave/ATokenOracle.sol"; +import {IERC20} from "../../../interface/tokens/IERC20.sol"; +import {IAccount} from "../../../interface/core/IAccount.sol"; +import {ArbiIntegrationTestBase} from "../utils/ArbiIntegrationTestBase.sol"; +import {AaveV3Controller} from "controller/aave/AaveV3Controller.sol"; + + +/// @notice runs only on arbitrum +contract AaveV3ArbiIntegrationTest is ArbiIntegrationTestBase { + address account; + address user = cheats.addr(1); + + address aWeth = 0xe50fA9b3c56FfB159cB0FCA61F5c9D750e8128c8; + address aDai = 0x82E64f49Ed5EC1bC6e43DAD4FC8Af9bb3A2312EE; + address pool = 0x794a61358D6845594F94dc1DB02A252b5b4814aD; + + ATokenOracle aTokenOracle; + AaveV3Controller aaveController; + + function setupAaveController() internal { + aTokenOracle = new ATokenOracle(oracle); + oracle.setOracle(aWeth, aTokenOracle); + oracle.setOracle(aDai, aTokenOracle); + + aaveController = new AaveV3Controller(controller); + controller.updateController(pool, aaveController); + controller.updateController(pool, aaveController); + controller.toggleTokenAllowance(aWeth); + } + + function setUp() public { + setupContracts(); + setupOracles(); + setupAaveController(); + setupWethController(); + account = openAccount(user); + } + + function testDepositWeth(uint64 amt) public { + cheats.assume(amt > 1e8 gwei); + // Setup + deposit(user, account, address(0), amt); + wrapEth(account, amt, user); + uint value = IERC20(WETH).balanceOf(account); + + // Encode call data + bytes memory data = abi.encodeWithSignature( + "supply(address,uint256,address,uint16)", + WETH, + value, + account, + 0 + ); + + // Test + cheats.startPrank(user); + accountManager.approve(account, WETH, pool, value); + accountManager.exec(account, pool, 0, data); + cheats.stopPrank(); + + // Assert + assertGt(IERC20(aWeth).balanceOf(account), 0); + assertEq(IAccount(account).assets(0), aWeth); + } + + function testWithdrawWeth(uint64 amt) public { + // Setup + testDepositWeth(amt); + + // Encode call data + bytes memory data = abi.encodeWithSignature( + "withdraw(address,uint256,address)", + WETH, + type(uint256).max, + account + ); + + // Test + cheats.startPrank(user); + accountManager.exec(account, pool, 0, data); + cheats.stopPrank(); + + // Assert + assertEq(IERC20(aWeth).balanceOf(account), 0); + assertGt(IERC20(WETH).balanceOf(account), 0); + assertEq(IAccount(account).assets(0), WETH); + } + + function testDepositDaiError(uint64 amt) public { + // Encode call data + bytes memory data = abi.encodeWithSignature( + "supply(address,uint256,address,uint16)", + aDai, + amt, + account, + 0 + ); + + // Test + cheats.startPrank(user); + cheats.expectRevert(Errors.FunctionCallRestricted.selector); + accountManager.exec(account, pool, 0, data); + cheats.stopPrank(); + } +} \ No newline at end of file diff --git a/src/test/integrations/utils/ArbiIntegrationTestBase.sol b/src/test/integrations/utils/ArbiIntegrationTestBase.sol new file mode 100644 index 0000000..7a6ef4c --- /dev/null +++ b/src/test/integrations/utils/ArbiIntegrationTestBase.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.10; + +import {TestBase} from "../../utils/TestBase.sol"; +import {WETHOracle} from "oracle/weth/WETHOracle.sol"; +import {WETHController} from "controller/weth/WETHController.sol"; + +contract ArbiIntegrationTestBase is TestBase { + + // Controller Contracts + WETHController wEthController; + + // Oracle Contracts + WETHOracle wethOracle; + + // Arbitrum Contracts + address constant WETH = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1; + address constant USDT = 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9; + + function setupWethController() internal { + wEthController = new WETHController(WETH); + controller.updateController(WETH, wEthController); + controller.toggleTokenAllowance(WETH); + + wethOracle = new WETHOracle(); + oracle.setOracle(WETH, wethOracle); + } + + function setupOracles() internal { + cheats.clearMockedCalls(); + } + + function wrapEth(address account, uint amt, address owner) internal { + bytes memory data = abi.encodeWithSignature("deposit()"); + + cheats.prank(owner); + accountManager.exec(account, WETH, amt, data); + } +} \ No newline at end of file