Skip to content
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
42 changes: 27 additions & 15 deletions solidity/src/FlowYieldVaultsRequests.sol
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ contract FlowYieldVaultsRequests is ReentrancyGuard, Ownable2Step {
address public constant NATIVE_FLOW =
0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;

/// @notice Default minimum deposit for initially supported tokens
uint256 public constant DEFAULT_MINIMUM_BALANCE = 1 ether;

/// @notice WFLOW (Wrapped FLOW) ERC20 token address
/// @dev On Cadence side, WFLOW is automatically unwrapped to native FlowToken by FlowEVMBridge
address public immutable WFLOW;
Expand Down Expand Up @@ -193,6 +196,9 @@ contract FlowYieldVaultsRequests is ReentrancyGuard, Ownable2Step {
/// @notice COA address cannot be zero
error InvalidCOAAddress();

/// @notice Minimum balance must be non-zero for supported tokens
error InvalidMinimumBalance();

/// @notice Address array cannot be empty
error EmptyAddressArray();

Expand Down Expand Up @@ -489,24 +495,18 @@ contract FlowYieldVaultsRequests is ReentrancyGuard, Ownable2Step {
/// @param coaAddress Address of the authorized COA
/// @param wflowAddress Address of the WFLOW (Wrapped FLOW) ERC20 token
constructor(address coaAddress, address wflowAddress) Ownable(msg.sender) {
if (coaAddress == address(0)) revert InvalidCOAAddress();

authorizedCOA = coaAddress;
WFLOW = wflowAddress;
_requestIdCounter = 1;
maxPendingRequestsPerUser = 10;

allowedTokens[NATIVE_FLOW] = TokenConfig({
isSupported: true,
minimumBalance: 1 ether,
isNative: true
});
_setTokenConfig(NATIVE_FLOW, true, DEFAULT_MINIMUM_BALANCE, true);

// WFLOW is treated as ERC20 on EVM side, but unwraps to native FlowToken on Cadence
if (wflowAddress != address(0)) {
allowedTokens[WFLOW] = TokenConfig({
isSupported: true,
minimumBalance: 1 ether,
isNative: false
});
_setTokenConfig(WFLOW, true, DEFAULT_MINIMUM_BALANCE, false);
}
}

Expand Down Expand Up @@ -627,11 +627,7 @@ contract FlowYieldVaultsRequests is ReentrancyGuard, Ownable2Step {
uint256 minimumBalance,
bool isNative
) external onlyOwner {
allowedTokens[tokenAddress] = TokenConfig({
isSupported: isSupported,
minimumBalance: minimumBalance,
isNative: isNative
});
_setTokenConfig(tokenAddress, isSupported, minimumBalance, isNative);

emit TokenConfigured(
tokenAddress,
Expand Down Expand Up @@ -1443,6 +1439,22 @@ contract FlowYieldVaultsRequests is ReentrancyGuard, Ownable2Step {
// Internal Functions
// ============================================

/// @dev Internal token configuration helper with minimum-balance validation.
function _setTokenConfig(
address tokenAddress,
bool isSupported,
uint256 minimumBalance,
bool isNative
) internal {
if (isSupported && minimumBalance == 0) revert InvalidMinimumBalance();

allowedTokens[tokenAddress] = TokenConfig({
isSupported: isSupported,
minimumBalance: minimumBalance,
isNative: isNative
});
}

/**
* @dev Validates deposit parameters and transfers tokens to this contract for escrow.
* Performs comprehensive validation including amount, token support, and minimum balance checks.
Expand Down
13 changes: 13 additions & 0 deletions solidity/test/FlowYieldVaultsRequests.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,11 @@ contract FlowYieldVaultsRequestsTest is Test {
c.setAuthorizedCOA(address(0));
}

function test_Constructor_RevertZeroCOAAddress() public {
vm.expectRevert(FlowYieldVaultsRequests.InvalidCOAAddress.selector);
new FlowYieldVaultsRequestsTestHelper(address(0), WFLOW);
}

function test_SetTokenConfig() public {
address token = makeAddr("token");

Expand All @@ -427,6 +432,14 @@ contract FlowYieldVaultsRequestsTest is Test {
assertEq(isNative, false);
}

function test_SetTokenConfig_RevertZeroMinimumForSupportedToken() public {
address token = makeAddr("token");

vm.prank(c.owner());
vm.expectRevert(FlowYieldVaultsRequests.InvalidMinimumBalance.selector);
c.setTokenConfig(token, true, 0, false);
}

function test_SetMaxPendingRequestsPerUser() public {
vm.prank(c.owner());
c.setMaxPendingRequestsPerUser(5);
Expand Down