Skip to content

Commit 061a491

Browse files
committed
unit tests
1 parent 4bbbd2e commit 061a491

File tree

4 files changed

+519
-0
lines changed

4 files changed

+519
-0
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// SPDX-License-Identifier: AGPLv3
2+
pragma solidity ^0.8.23;
3+
4+
import { YieldBackendUnitTestBase } from "./YieldBackendUnitTestBase.sol";
5+
import { AaveETHYieldBackend } from "../../../../contracts/superfluid/AaveETHYieldBackend.sol";
6+
import { IYieldBackend } from "../../../../contracts/interfaces/superfluid/IYieldBackend.sol";
7+
import { IERC20 } from "../../../../contracts/interfaces/superfluid/ISuperfluid.sol";
8+
import { IPool } from "aave-v3/src/contracts/interfaces/IPool.sol";
9+
10+
/**
11+
* @title tests for AaveETHYieldBackend with ETH/WETH on Base
12+
* Tests the backend in isolation using delegatecall
13+
*/
14+
contract AaveETHYieldBackendUnitTest is YieldBackendUnitTestBase {
15+
uint256 internal constant CHAIN_ID = 8453;
16+
string internal constant RPC_URL = "https://mainnet.base.org";
17+
18+
address internal constant AAVE_POOL = 0xA238Dd80C259a72e81d7e4664a9801593F98d1c5;
19+
address internal constant WETH = 0x4200000000000000000000000000000000000006;
20+
21+
AaveETHYieldBackend internal aaveETHBackend;
22+
23+
function getRpcUrl() internal pure override returns (string memory) {
24+
return RPC_URL;
25+
}
26+
27+
function getChainId() internal pure override returns (uint256) {
28+
return CHAIN_ID;
29+
}
30+
31+
/// @notice toUnderlyingAmount for ETH (18 decimals) - uses base implementation
32+
/// @dev No override needed, ETH has 18 decimals like SuperToken
33+
34+
function createBackend() internal override returns (IYieldBackend) {
35+
aaveETHBackend = new AaveETHYieldBackend(
36+
IPool(AAVE_POOL),
37+
SURPLUS_RECEIVER
38+
);
39+
return IYieldBackend(address(aaveETHBackend));
40+
}
41+
42+
function getAssetToken() internal pure override returns (IERC20) {
43+
// For AaveETHYieldBackend, the asset token is WETH
44+
return IERC20(WETH);
45+
}
46+
47+
function fundTestContract() internal override {
48+
// Fund with ETH (will be wrapped to WETH on deposit)
49+
vm.deal(address(this), 10_000 ether);
50+
}
51+
52+
function getAssetDecimals() internal pure override returns (uint8) {
53+
return 18; // ETH/WETH has 18 decimals
54+
}
55+
56+
function _getProtocolAddress() internal pure override returns (address) {
57+
return AAVE_POOL;
58+
}
59+
60+
/// @notice Override _boundAmount to ensure minimum viable amounts for ETH
61+
/// @dev Aave may have minimum deposit requirements, so we use a higher minimum
62+
function _boundAmount(uint256 amount) internal pure override returns (uint256) {
63+
// Minimum: 0.001 ETH (1e15 wei) to avoid issues with very small amounts
64+
// Maximum: 1000 ETH
65+
uint256 minAmount = 1e15; // 0.001 ETH
66+
uint256 maxAmount = 1000 * 1e18; // 1000 ETH
67+
return bound(amount, minAmount, maxAmount);
68+
}
69+
70+
/// @notice Override _fundAsset to handle ETH (native token)
71+
function _fundAsset(uint256 amount) internal override {
72+
// Ensure we have at least the amount in ETH
73+
uint256 currentBalance = address(this).balance;
74+
if (currentBalance < amount) {
75+
vm.deal(address(this), amount);
76+
}
77+
}
78+
79+
/// @notice Override _getAssetBalance to handle ETH balance
80+
/// @dev For ETH backend, we track ETH balance (not WETH)
81+
/// @dev Before deposit: ETH balance
82+
/// @dev After deposit: ETH is wrapped and deposited, so ETH balance decreases
83+
/// @dev After withdraw: ETH is unwrapped back, so ETH balance increases
84+
function _getAssetBalance() internal view override returns (uint256) {
85+
// Track ETH balance directly (the native token)
86+
// WETH is just an intermediate step in the deposit/withdraw process
87+
return address(this).balance;
88+
}
89+
90+
/// @notice Override _getSurplusReceiverBalance for WETH
91+
function _getSurplusReceiverBalance() internal view override returns (uint256) {
92+
// Note: Surplus is paid in WETH, not ETH
93+
// Use assetToken (IERC20) which has balanceOf
94+
return assetToken.balanceOf(SURPLUS_RECEIVER);
95+
}
96+
97+
/// @notice Allow the test contract to receive ETH
98+
/// @dev Required for unwrapWETHAndForwardETH to send ETH back to the test contract
99+
receive() external payable { }
100+
}
101+
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// SPDX-License-Identifier: AGPLv3
2+
pragma solidity ^0.8.23;
3+
4+
import { YieldBackendUnitTestBase } from "./YieldBackendUnitTestBase.sol";
5+
import { AaveYieldBackend } from "../../../../contracts/superfluid/AaveYieldBackend.sol";
6+
import { IYieldBackend } from "../../../../contracts/interfaces/superfluid/IYieldBackend.sol";
7+
import { IERC20 } from "../../../../contracts/interfaces/superfluid/ISuperfluid.sol";
8+
import { IPool } from "aave-v3/src/contracts/interfaces/IPool.sol";
9+
10+
/**
11+
* @title Unit tests for AaveYieldBackend with USDC on Base
12+
* Tests the backend in isolation using delegatecall
13+
*/
14+
contract AaveYieldBackendUnitTest is YieldBackendUnitTestBase {
15+
uint256 internal constant CHAIN_ID = 8453;
16+
string internal constant RPC_URL = "https://mainnet.base.org";
17+
18+
address internal constant AAVE_POOL = 0xA238Dd80C259a72e81d7e4664a9801593F98d1c5;
19+
address internal constant USDC = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913;
20+
21+
AaveYieldBackend internal aaveBackend;
22+
23+
function getRpcUrl() internal pure override returns (string memory) {
24+
return RPC_URL;
25+
}
26+
27+
function getChainId() internal pure override returns (uint256) {
28+
return CHAIN_ID;
29+
}
30+
31+
/// @notice Override toUnderlyingAmount for USDC (6 decimals)
32+
function toUnderlyingAmount(uint256 amount)
33+
external
34+
pure
35+
override
36+
returns (uint256 underlyingAmount, uint256 adjustedAmount)
37+
{
38+
// USDC has 6 decimals, SuperToken has 18 decimals
39+
uint256 factor = 10 ** (18 - 6);
40+
underlyingAmount = amount / factor;
41+
adjustedAmount = underlyingAmount * factor;
42+
}
43+
44+
function createBackend() internal override returns (IYieldBackend) {
45+
aaveBackend = new AaveYieldBackend(
46+
IERC20(USDC),
47+
IPool(AAVE_POOL),
48+
SURPLUS_RECEIVER
49+
);
50+
return IYieldBackend(address(aaveBackend));
51+
}
52+
53+
function getAssetToken() internal override returns (IERC20) {
54+
return IERC20(USDC);
55+
}
56+
57+
function fundTestContract() internal override {
58+
// Fund with 200M USDC (6 decimals)
59+
deal(USDC, address(this), 200_000_000 * 1e6);
60+
}
61+
62+
function getAssetDecimals() internal pure override returns (uint8) {
63+
return 6;
64+
}
65+
66+
function _getProtocolAddress() internal view override returns (address) {
67+
return AAVE_POOL;
68+
}
69+
}
70+
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// SPDX-License-Identifier: AGPLv3
2+
pragma solidity ^0.8.23;
3+
4+
import { YieldBackendUnitTestBase } from "./YieldBackendUnitTestBase.sol";
5+
import { ERC4626YieldBackend } from "../../../../contracts/superfluid/ERC4626YieldBackend.sol";
6+
import { IYieldBackend } from "../../../../contracts/interfaces/superfluid/IYieldBackend.sol";
7+
import { IERC20 } from "../../../../contracts/interfaces/superfluid/ISuperfluid.sol";
8+
import { IERC4626 } from "@openzeppelin-v5/contracts/interfaces/IERC4626.sol";
9+
10+
/**
11+
* @title Unit tests for ERC4626YieldBackend with Spark USDS on Ethereum
12+
* Tests the backend in isolation using delegatecall
13+
*/
14+
contract ERC4626YieldBackendUnitTest is YieldBackendUnitTestBase {
15+
uint256 internal constant CHAIN_ID = 1;
16+
string internal constant RPC_URL = "https://eth.drpc.org";
17+
address internal constant VAULT = 0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD; // sUSDS on Ethereum
18+
19+
ERC4626YieldBackend internal erc4626Backend;
20+
21+
function getRpcUrl() internal pure override returns (string memory) {
22+
return RPC_URL;
23+
}
24+
25+
function getChainId() internal pure override returns (uint256) {
26+
return CHAIN_ID;
27+
}
28+
29+
/// @notice toUnderlyingAmount for USDS (18 decimals) - uses base implementation
30+
/// @dev No override needed, USDS has 18 decimals like SuperToken
31+
32+
function createBackend() internal override returns (IYieldBackend) {
33+
erc4626Backend = new ERC4626YieldBackend(
34+
IERC4626(VAULT),
35+
SURPLUS_RECEIVER
36+
);
37+
return IYieldBackend(address(erc4626Backend));
38+
}
39+
40+
function getAssetToken() internal view override returns (IERC20) {
41+
return IERC20((IERC4626(VAULT)).asset());
42+
}
43+
44+
function fundTestContract() internal override {
45+
// Fund with 10M USDS (18 decimals)
46+
deal(address(getAssetToken()), address(this), 10_000_000 * 1e18);
47+
}
48+
49+
function getAssetDecimals() internal pure override returns (uint8) {
50+
return 18; // USDS has 18 decimals
51+
}
52+
53+
function _getProtocolAddress() internal pure override returns (address) {
54+
return VAULT;
55+
}
56+
}
57+

0 commit comments

Comments
 (0)