Skip to content
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d90dec4
test: Setup and deposit
CheyenneAtapour Dec 3, 2025
c68e67b
test: Basic vault functions
CheyenneAtapour Dec 3, 2025
b37c4b3
test: Deposit with sig
CheyenneAtapour Dec 4, 2025
8b144f0
test: Withdraw w sig
CheyenneAtapour Dec 4, 2025
33ea07d
fix: Non-owner withdraw w sig
CheyenneAtapour Dec 4, 2025
a3cd654
test: Signature functions
CheyenneAtapour Dec 4, 2025
10a15ac
test: Fuzz existing tests
CheyenneAtapour Dec 4, 2025
4f34f40
test: Deploy and deposit fail cases
CheyenneAtapour Dec 4, 2025
2a0b5de
test: Basic unit tests
CheyenneAtapour Dec 4, 2025
1e2450d
fix: Generalize failure cases
CheyenneAtapour Dec 4, 2025
0ded842
fix: Address pr comments
CheyenneAtapour Dec 5, 2025
1fd7c56
chore: cleanup
CheyenneAtapour Dec 5, 2025
fe8af6f
test: Invalid signature cases
CheyenneAtapour Dec 5, 2025
1c2b38f
test: Insufficient allowance tests
CheyenneAtapour Dec 8, 2025
090b396
fix: Pr comments
CheyenneAtapour Dec 9, 2025
0c71ed4
fix: gas snapshot
CheyenneAtapour Dec 9, 2025
d8e2d24
Merge remote-tracking branch 'origin/feat/vault-spoke' into test/vaul…
CheyenneAtapour Dec 15, 2025
72937b3
merge in upstream
CheyenneAtapour Dec 16, 2025
13f4be2
fix: Remove duplicated tests
CheyenneAtapour Dec 16, 2025
8832daa
chore: Try linter
CheyenneAtapour Dec 16, 2025
3e4e65b
chore: lint
CheyenneAtapour Dec 16, 2025
a1a79c3
fix: Pr comments
CheyenneAtapour Dec 16, 2025
8ab9b3e
fix: Remove unused code
CheyenneAtapour Dec 16, 2025
5f1a0c9
Merge remote-tracking branch 'origin/feat/vault-spoke' into test/vaul…
CheyenneAtapour Dec 17, 2025
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
11 changes: 9 additions & 2 deletions tests/Base.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import {console2 as console} from 'forge-std/console2.sol';

// dependencies
import {AggregatorV3Interface} from 'src/dependencies/chainlink/AggregatorV3Interface.sol';
import {TransparentUpgradeableProxy, ITransparentUpgradeableProxy} from 'src/dependencies/openzeppelin/TransparentUpgradeableProxy.sol';
import {
TransparentUpgradeableProxy,
ITransparentUpgradeableProxy
} from 'src/dependencies/openzeppelin/TransparentUpgradeableProxy.sol';
import {ProxyAdmin} from 'src/dependencies/openzeppelin/ProxyAdmin.sol';
import {IERC20Metadata} from 'src/dependencies/openzeppelin/IERC20Metadata.sol';
import {SafeCast} from 'src/dependencies/openzeppelin/SafeCast.sol';
Expand Down Expand Up @@ -45,7 +48,11 @@ import {AccessManagerEnumerable} from 'src/access/AccessManagerEnumerable.sol';
import {HubConfigurator, IHubConfigurator} from 'src/hub/HubConfigurator.sol';
import {Hub, IHub, IHubBase} from 'src/hub/Hub.sol';
import {SharesMath} from 'src/hub/libraries/SharesMath.sol';
import {AssetInterestRateStrategy, IAssetInterestRateStrategy, IBasicInterestRateStrategy} from 'src/hub/AssetInterestRateStrategy.sol';
import {
AssetInterestRateStrategy,
IAssetInterestRateStrategy,
IBasicInterestRateStrategy
} from 'src/hub/AssetInterestRateStrategy.sol';

// spoke
import {Spoke, ISpoke, ISpokeBase} from 'src/spoke/Spoke.sol';
Expand Down
92 changes: 92 additions & 0 deletions tests/unit/VaultSpoke/VaultSpoke.Base.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ contract VaultSpokeBaseTest is Base {
});
}

function _depositData(
IVaultSpoke vault_,
address who,
uint256 amount,
uint256 deadline
) internal view returns (EIP712Types.VaultDeposit memory) {
return
EIP712Types.VaultDeposit({
depositor: who,
assets: amount,
receiver: who,
nonce: vault_.nonces(who),
deadline: deadline
});
}

function _mintData(
IVaultSpoke vault,
address who,
Expand All @@ -46,6 +62,22 @@ contract VaultSpokeBaseTest is Base {
});
}

function _mintData(
IVaultSpoke vault_,
address who,
uint256 shares,
uint256 deadline
) internal view returns (EIP712Types.VaultMint memory) {
return
EIP712Types.VaultMint({
depositor: who,
shares: shares,
receiver: who,
nonce: vault_.nonces(who),
deadline: deadline
});
}

function _withdrawData(
IVaultSpoke vault,
address who,
Expand All @@ -61,6 +93,22 @@ contract VaultSpokeBaseTest is Base {
});
}

function _withdrawData(
IVaultSpoke vault_,
address who,
uint256 assets,
uint256 deadline
) internal view returns (EIP712Types.VaultWithdraw memory) {
return
EIP712Types.VaultWithdraw({
owner: who,
assets: assets,
receiver: who,
nonce: vault_.nonces(who),
deadline: deadline
});
}

function _redeemData(
IVaultSpoke vault,
address who,
Expand All @@ -76,6 +124,22 @@ contract VaultSpokeBaseTest is Base {
});
}

function _redeemData(
IVaultSpoke vault_,
address who,
uint256 shares,
uint256 deadline
) internal view returns (EIP712Types.VaultRedeem memory) {
return
EIP712Types.VaultRedeem({
owner: who,
shares: shares,
receiver: who,
nonce: vault_.nonces(who),
deadline: deadline
});
}

function _permitData(
IVaultSpoke vault,
address who,
Expand Down Expand Up @@ -137,6 +201,15 @@ contract VaultSpokeBaseTest is Base {
user: who
});
}

function _deposit(IVaultSpoke vault_, address user, uint256 amount) internal {
deal(address(tokenList.dai), user, amount);

vm.startPrank(user);
tokenList.dai.approve(address(vault_), amount);
vault_.deposit(amount, user);
vm.stopPrank();
}
}

contract VaultSpokeInitTest is VaultSpokeBaseTest {
Expand All @@ -156,6 +229,25 @@ contract VaultSpokeInitTest is VaultSpokeBaseTest {
assertEq(instance.decimals(), hub1.getAsset(assetId).decimals);
}

function test_deploy_reverts_InvalidHub() public {
address invalidHub = address(0);
vm.expectRevert();
new VaultSpokeInstance(invalidHub, daiAssetId);
}

/// @dev Cannot re-initialize the contract
function test_reinitialize_revertsWith_InvalidInitialization() public {
vm.expectRevert(Initializable.InvalidInitialization.selector);
VaultSpoke(address(daiVault)).initialize('new name', 'new symbol');
}

/// @dev Cannot directly initialize the implementation contract
function test_cannot_init_impl() public {
VaultSpokeInstance vaultImpl = new VaultSpokeInstance(address(hub1), daiAssetId);
vm.expectRevert(Initializable.InvalidInitialization.selector);
vaultImpl.initialize('impl name', 'impl symbol');
}

function test_setUp() public {
assertEq(daiVault.name(), SHARE_NAME);
assertEq(daiVault.symbol(), SHARE_SYMBOL);
Expand Down
35 changes: 35 additions & 0 deletions tests/unit/VaultSpoke/VaultSpoke.Permit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.0;

import 'tests/unit/VaultSpoke/VaultSpoke.Base.t.sol';
import {IERC4626} from 'src/dependencies/openzeppelin/IERC4626.sol';

contract VaultSpokePermitTest is VaultSpokeBaseTest {
IVaultSpoke public vault;
Expand Down Expand Up @@ -133,4 +134,38 @@ contract VaultSpokePermitTest is VaultSpokeBaseTest {
(, bytes32[] memory writeSlots) = vm.accesses(address(vault));
assertEq(writeSlots.length, 0);
}

function test_depositWithPermit(uint256 depositAmount) public {
depositAmount = bound(depositAmount, 1, MAX_SUPPLY_AMOUNT);
(address user, uint256 userPk) = makeAddrAndKey('user');

deal(address(tokenList.dai), user, depositAmount);

assertEq(tokenList.dai.balanceOf(user), depositAmount);
assertEq(tokenList.dai.balanceOf(address(daiVault)), 0);
assertEq(tokenList.dai.balanceOf(address(hub1)), 0);
assertEq(daiVault.balanceOf(user), 0);

EIP712Types.Permit memory params = EIP712Types.Permit({
owner: user,
spender: address(daiVault),
value: depositAmount,
deadline: vm.getBlockTimestamp() + 1,
nonce: tokenList.dai.nonces(user)
});
(uint8 v, bytes32 r, bytes32 s) = vm.sign(userPk, _getTypedDataHash(tokenList.dai, params));

vm.prank(user);
vm.expectEmit(address(daiVault));
emit IERC4626.Deposit(user, user, depositAmount, depositAmount);
uint256 shares = daiVault.depositWithPermit(depositAmount, user, params.deadline, v, r, s);

assertEq(tokenList.dai.balanceOf(user), 0);
assertEq(tokenList.dai.balanceOf(address(daiVault)), 0);
assertEq(daiVault.totalAssets(), depositAmount);
assertEq(daiVault.balanceOf(user), depositAmount);
assertEq(tokenList.dai.balanceOf(address(hub1)), depositAmount);

assertEq(hub1.getSpokeAddedShares(daiAssetId, address(daiVault)), shares);
}
}
Loading
Loading