Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Writing tests for NovaVault interfaces #15

Merged
merged 5 commits into from
May 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/NovaAdapterBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ abstract contract NovaAdapterBase is ERC20 {
sDAI = _sDAI;
}

function deposit(uint256 assets) external returns (bool , uint256) {
function deposit(uint256 assets) external returns (bool, uint256) {
bool success = asset.transferFrom(msg.sender, address(this), assets);
if(!success){
revert TransferFailed(msg.sender, address(this), assets);
Expand Down
4 changes: 4 additions & 0 deletions src/NovaAdapterVelo.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,8 @@ contract NovaAdapterVelo is NovaAdapterBase {

return (amount0, amount1);
}

function getAsset() external view returns (ERC20) {
return asset;
}
}
26 changes: 16 additions & 10 deletions src/NovaVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@ pragma solidity ^0.8.13;
import {Errors} from "./libraries/Errors.sol";
import {INovaVault} from "./interfaces/INovaVault.sol";
import {INovaAdapterBase} from "./interfaces/INovaAdapterBase.sol";
import {ERC20} from "@solmate/tokens/ERC20.sol";

contract NovaVault is INovaVault {
mapping(address => address) public _novaAdapters;

function constructor(
address[] calldata stables,
address[] calldata novaAdapters
constructor(
address[] memory stables,
address[] memory novaAdapters
) {
_approveNovaAdapters(stables, novaAdapters);
}

function _approveNovaAdapters(
address[] calldata stables,
address[] calldata novaAdapters,
address[] memory stables,
address[] memory novaAdapters
) internal {
require(
stables.length == novaAdapters.length,
Expand All @@ -39,7 +40,8 @@ contract NovaVault is INovaVault {
Errors.ADAPTER_ALREADY_APPROVED
);

ERC20 underlyingAsset = INovaAdapterBase(adapter).asset();
ERC20 underlyingAsset = INovaAdapterBase(adapter).getAsset();

require(
address(underlyingAsset) == stable,
Errors.INVALID_STABLE_TO_ADAPTER_MAPPING
Expand All @@ -55,10 +57,14 @@ contract NovaVault is INovaVault {
adapter != address(0),
Errors.NO_ADAPTER_APPROVED
);
(bool success, bytes memory data) = adapter.delegatecall(

ERC20(stable).transferFrom(msg.sender, address(this), assets);
ERC20(stable).approve(adapter, assets);

(bool success, bytes memory data) = adapter.call(
abi.encodeWithSignature("deposit(uint256)", assets)
);
return (success, data)
return (success, data);
}

function withdraw(address stable, uint256 shares) external returns (bool , bytes memory) {
Expand All @@ -67,9 +73,9 @@ contract NovaVault is INovaVault {
adapter != address(0),
Errors.NO_ADAPTER_APPROVED
);
(bool success, bytes memory data) = adapter.delegatecall(
(bool success, bytes memory data) = adapter.call(
abi.encodeWithSignature("withdraw(uint256)", shares)
);
return (success, data)
return (success, data);
}
}
2 changes: 1 addition & 1 deletion src/interfaces/INovaAdapterBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.13;
import {ERC20} from "@solmate/tokens/ERC20.sol";

interface INovaAdapterBase {
function asset() external view returns (ERC20);
function getAsset() external view returns (ERC20);
function deposit(uint256 assets) external returns (bool , uint256);
function withdraw(uint256 shares) external returns (bool, uint256);
}
File renamed without changes.
32 changes: 16 additions & 16 deletions test/NovaAdapterVelo.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {IVelodromePool} from "../src/interfaces/IVelodromePool.sol";
contract NovaAdapterVeloTest is Test {
address public POOL = 0x94c0A04C0d74571aa9EE25Dd6c29E2A36f5699aE;
address public sDAI = 0x2218a117083f5B482B0bB821d27056Ba9c04b1D3;
NovaAdapterVelo public vault;
NovaAdapterVelo public adapter;
IVelodromePool veloPool;
address underlyingAddress;
ERC20 underlying;
Expand All @@ -32,7 +32,7 @@ contract NovaAdapterVeloTest is Test {

underlying = ERC20(underlyingAddress);

vault = new NovaAdapterVelo(
adapter = new NovaAdapterVelo(
underlying,
sDAI,
POOL,
Expand All @@ -50,16 +50,16 @@ contract NovaAdapterVeloTest is Test {
underlying.transfer(alice, aliceUnderlyingAmount);

vm.prank(alice);
underlying.approve(address(vault), aliceUnderlyingAmount);
assertEq(underlying.allowance(alice, address(vault)), aliceUnderlyingAmount);
underlying.approve(address(adapter), aliceUnderlyingAmount);
assertEq(underlying.allowance(alice, address(adapter)), aliceUnderlyingAmount);

vm.prank(alice);
(bool success, uint256 sDaiMinted) = vault.deposit(aliceUnderlyingAmount);
(bool success, uint256 sDaiMinted) = adapter.deposit(aliceUnderlyingAmount);

assert(success);
assertEq(underlying.balanceOf(alice), 0);
assertEq(vault.balanceOf(alice), sDaiMinted);
assertEq(ERC20(sDAI).balanceOf(address(vault)), sDaiMinted);
assertEq(adapter.balanceOf(alice), sDaiMinted);
assertEq(ERC20(sDAI).balanceOf(address(adapter)), sDaiMinted);
}

function testWithdraw() public{
Expand All @@ -70,22 +70,22 @@ contract NovaAdapterVeloTest is Test {
underlying.transfer(alice, aliceUnderlyingAmount);

vm.prank(alice);
underlying.approve(address(vault), aliceUnderlyingAmount);
assertEq(underlying.allowance(alice, address(vault)), aliceUnderlyingAmount);
underlying.approve(address(adapter), aliceUnderlyingAmount);
assertEq(underlying.allowance(alice, address(adapter)), aliceUnderlyingAmount);

vm.prank(alice);
(bool succesDeposit, uint256 sDaiMinted) = vault.deposit(aliceUnderlyingAmount);
(bool succesDeposit, uint256 sDaiMinted) = adapter.deposit(aliceUnderlyingAmount);
assert(succesDeposit);
assertEq(underlying.balanceOf(alice), 0);
assertEq(vault.balanceOf(alice), sDaiMinted);
assertEq(ERC20(sDAI).balanceOf(address(vault)), sDaiMinted);
assertEq(adapter.balanceOf(alice), sDaiMinted);
assertEq(ERC20(sDAI).balanceOf(address(adapter)), sDaiMinted);

vm.prank(alice);
(bool successWithdraw, uint256 underlyingWithdrawn) = vault.withdraw(sDaiMinted);
(bool successWithdraw, uint256 underlyingWithdrawn) = adapter.withdraw(sDaiMinted);
assert(successWithdraw);
assertEq(underlying.balanceOf(alice), underlyingWithdrawn);
assertEq(vault.balanceOf(alice), 0);
assertEq(ERC20(sDAI).balanceOf(address(vault)), 0);
assertEq(underlying.balanceOf(address(vault)), 0);
assertEq(adapter.balanceOf(alice), 0);
assertEq(ERC20(sDAI).balanceOf(address(adapter)), 0);
assertEq(underlying.balanceOf(address(adapter)), 0);
}
}
75 changes: 75 additions & 0 deletions test/NovaVault.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {ERC20} from "@solmate/tokens/ERC20.sol";
import {Test, console} from "forge-std/Test.sol";
import {NovaVault} from "../src/NovaVault.sol";
import {NovaAdapterVelo} from "../src/NovaAdapterVelo.sol";
import {IVelodromePool} from "../src/interfaces/IVelodromePool.sol";

contract NovaVaultTest is Test {
address public POOL = 0x94c0A04C0d74571aa9EE25Dd6c29E2A36f5699aE;
address public sDAI = 0x2218a117083f5B482B0bB821d27056Ba9c04b1D3;
NovaAdapterVelo public adapter;
NovaVault public vault;
IVelodromePool veloPool;
address underlyingAddress;
ERC20 underlying;
address private veloToken0;
address private veloToken1;
address[] stables;
address[] novaAdapters;

address public underlyingWhale = 0xacD03D601e5bB1B275Bb94076fF46ED9D753435A;

function setUp() public {
veloPool = IVelodromePool(POOL);
veloToken0 = veloPool.token0();
veloToken1 = veloPool.token1();
if (veloToken0 == sDAI) {
underlyingAddress = veloToken1;
} else if (veloToken1 == sDAI) {
underlyingAddress = veloToken0;
} else {
revert("Velodrome pool should be made of `asset` and `sDAI`!");
}

underlying = ERC20(underlyingAddress);

adapter = new NovaAdapterVelo(
underlying,
sDAI,
POOL,
"NovaAdapterVelo",
"NV",
18
);

stables.push(underlyingAddress);
novaAdapters.push(address(adapter));

vault = new NovaVault(stables, novaAdapters);
}

function testNovaVaultDepositAndWithdraw() public {
uint256 aliceUnderlyingAmount = 100 * 1e6;
address alice = address(0xABCD);

vm.prank(underlyingWhale);
underlying.transfer(alice, aliceUnderlyingAmount);

vm.prank(alice);
underlying.approve(address(vault), aliceUnderlyingAmount);
assertEq(underlying.allowance(alice, address(vault)), aliceUnderlyingAmount);


vm.prank(alice);
(bool success, bytes memory data) = vault.deposit(address(underlyingAddress), aliceUnderlyingAmount);
assert(success);

vm.prank(alice);
(success, data) = vault.withdraw(underlyingAddress, aliceUnderlyingAmount);
assert(success);
}

}