Skip to content
Open
Show file tree
Hide file tree
Changes from 14 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
4 changes: 2 additions & 2 deletions snapshots/Hub.Operations.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"remove: partial": "81640",
"reportDeficit": "115225",
"restore: full": "80471",
"restore: full - with transfer": "173377",
"restore: full - with transfer": "165877",
"restore: partial": "89137",
"restore: partial - with transfer": "147400",
"restore: partial - with transfer": "144900",
"transferShares": "71192"
}
8 changes: 8 additions & 0 deletions tests/mocks/JsonBindings.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ library JsonBindings {
string constant schema_UpdateUserRiskPremium = "UpdateUserRiskPremium(address spoke,address user,uint256 nonce,uint256 deadline)";
// prettier-ignore
string constant schema_UpdateUserDynamicConfig = "UpdateUserDynamicConfig(address spoke,address user,uint256 nonce,uint256 deadline)";
// prettier-ignore
string constant schema_VaultDeposit = "VaultDeposit(address depositor,uint256 assets,address receiver,uint256 nonce,uint256 deadline)";
// prettier-ignore
string constant schema_VaultMint = "VaultMint(address depositor,uint256 shares,address receiver,uint256 nonce,uint256 deadline)";
// prettier-ignore
string constant schema_VaultWithdraw = "VaultWithdraw(address owner,uint256 assets,address receiver,uint256 nonce,uint256 deadline)";
// prettier-ignore
string constant schema_VaultRedeem = "VaultRedeem(address owner,uint256 shares,address receiver,uint256 nonce,uint256 deadline)";

function serialize(
EIP712Types.SetUserPositionManager memory value
Expand Down
155 changes: 155 additions & 0 deletions tests/unit/Spoke/VaultSpoke.Base.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import 'tests/unit/Spoke/SpokeBase.t.sol';
import 'src/Spoke/Instances/VaultSpokeInstance.sol';
import 'src/Spoke/Interfaces/IVaultSpoke.sol';

contract VaultSpokeBaseTest is SpokeBase {
IVaultSpoke public vault;
address public proxyAdminOwner = makeAddr('proxyAdminOwner');

function setUp() public override {
super.setUp();
address deployer = makeAddr('deployer');
address vaultImpl = address(new VaultSpokeInstance(address(hub1), daiAssetId));
vault = IVaultSpoke(
_proxify(
deployer,
vaultImpl,
proxyAdminOwner,
abi.encodeCall(VaultSpoke.initialize, ('hub1-DAI'))
)
);
// Add VaultSpoke to Hub
IHub.SpokeConfig memory config = IHub.SpokeConfig({
addCap: Constants.MAX_ALLOWED_SPOKE_CAP,
drawCap: Constants.MAX_ALLOWED_SPOKE_CAP,
riskPremiumThreshold: Constants.MAX_ALLOWED_COLLATERAL_RISK,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they must be zero, usually. any reason for not setting zero here now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

active: true,
paused: false
});
vm.prank(ADMIN);
hub1.addSpoke(daiAssetId, address(vault), config);
}

function _depositFromUser(address user, uint256 amount) internal {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it's fine to use just _deposit, no?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we pass the vault as param also?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

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

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

function _depositData(
IVaultSpoke vault_,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
IVaultSpoke vault_,
IVaultSpoke vault,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing this causes compiler warning due to shadowed declaration

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,
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,
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,
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 _getVaultSignature(
uint256 userPk,
bytes32 structHash
) internal view returns (bytes memory) {
bytes32 digest = keccak256(abi.encodePacked('\x19\x01', vault.DOMAIN_SEPARATOR(), structHash));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(userPk, digest);
return abi.encodePacked(r, s, v);
}

function _getTypedDataHash(
IVaultSpoke _vault,
EIP712Types.VaultDeposit memory _params
) internal view returns (bytes32) {
return _typedDataHash(_vault, vm.eip712HashStruct('VaultDeposit', abi.encode(_params)));
}

function _getTypedDataHash(
IVaultSpoke _vault,
EIP712Types.VaultMint memory _params
) internal view returns (bytes32) {
return _typedDataHash(_vault, vm.eip712HashStruct('VaultMint', abi.encode(_params)));
}

function _getTypedDataHash(
IVaultSpoke _vault,
EIP712Types.VaultWithdraw memory _params
) internal view returns (bytes32) {
return _typedDataHash(_vault, vm.eip712HashStruct('VaultWithdraw', abi.encode(_params)));
}

function _getTypedDataHash(
IVaultSpoke _vault,
EIP712Types.VaultRedeem memory _params
) internal view returns (bytes32) {
return _typedDataHash(_vault, vm.eip712HashStruct('VaultRedeem', abi.encode(_params)));
}

function _typedDataHash(IVaultSpoke _vault, bytes32 typeHash) internal view returns (bytes32) {
return keccak256(abi.encodePacked('\x19\x01', _vault.DOMAIN_SEPARATOR(), typeHash));
}

function _sign(uint256 pk, bytes32 digest) internal pure returns (bytes memory) {
(uint8 v, bytes32 r, bytes32 s) = vm.sign(pk, digest);
return abi.encodePacked(r, s, v);
}
}
Loading
Loading