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

build: deposit limit #17

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
37 changes: 34 additions & 3 deletions src/L1YearnEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ contract L1YearnEscrow is L1Escrow {
*/
event UpdateMinimumBuffer(uint256 newMinimumBuffer);

/**
* @dev Emitted when the deposit limit is updated.
*/
event UpdateDepositLimit(uint256 newDepositLimit);

// ****************************
// * ERC-7201 Storage *
// **************************
Expand All @@ -38,7 +43,8 @@ contract L1YearnEscrow is L1Escrow {
struct VaultStorage {
IVault vaultAddress;
uint256 deposited;
uint256 minimumBuffer;
uint128 minimumBuffer;
uint128 depositLimit;
}

// keccak256(abi.encode(uint256(keccak256("yearn.storage.vault")) - 1)) & ~bytes32(uint256(0xff))
Expand Down Expand Up @@ -66,6 +72,11 @@ contract L1YearnEscrow is L1Escrow {
return $.minimumBuffer;
}

function depositLimit() public view returns (uint256) {
VaultStorage storage $ = _getVaultStorage();
return $.depositLimit;
}

// ****************************
// * Initializer *
// ****************************
Expand Down Expand Up @@ -107,6 +118,9 @@ contract L1YearnEscrow is L1Escrow {
// Set the vault variable
VaultStorage storage $ = _getVaultStorage();
$.vaultAddress = IVault(_vaultAddress);

// Default to no deposit limit.
$.depositLimit = type(uint128).max;
}

// ****************************
Expand All @@ -120,10 +134,12 @@ contract L1YearnEscrow is L1Escrow {
function _receiveTokens(
uint256 amount
) internal virtual override whenNotPaused {
VaultStorage storage $ = _getVaultStorage();
require($.deposited + amount <= $.depositLimit, "deposit limit");

Choose a reason for hiding this comment

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

I personally like to use string error codes when using requires (e.g. "DEPOSIT_LIMIT") - or custom errors with reverts.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

not sure i follow.

Are you saying just change the revert string to "DEPOSIT_LIMIT" instead of "deposit limit" ?

Choose a reason for hiding this comment

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

yeah, but it's minor

I find it easier to integrate with frontends etc


IERC20 originToken = originTokenAddress();
originToken.safeTransferFrom(msg.sender, address(this), amount);

VaultStorage storage $ = _getVaultStorage();
unchecked {
$.deposited += amount;
}
Expand Down Expand Up @@ -281,17 +297,32 @@ contract L1YearnEscrow is L1Escrow {

/**
* @dev Update the minimum buffer to keep in the escrow.
* uint128 max would be the max buffer.
* @param _minimumBuffer The new minimum buffer to enforce.
*/
function updateMinimumBuffer(
uint256 _minimumBuffer
uint128 _minimumBuffer
) external virtual onlyRole(DEFAULT_ADMIN_ROLE) {
VaultStorage storage $ = _getVaultStorage();
$.minimumBuffer = _minimumBuffer;

emit UpdateMinimumBuffer(_minimumBuffer);
}

/**
* @dev Update the deposit limit to use for the escrow.
* uint128 is the max and means no deposit limit.
* @param _depositLimit The new deposit limit to enforce.
*/
function updateDepositLimit(
uint128 _depositLimit
) external virtual onlyRole(DEFAULT_ADMIN_ROLE) {
VaultStorage storage $ = _getVaultStorage();
$.depositLimit = _depositLimit;

emit UpdateDepositLimit(_depositLimit);
}

/**
* @notice Rebalance the funds to support the minimum buffer.
* @dev Will revert if the difference is over the maxDeposit.
Expand Down
102 changes: 95 additions & 7 deletions test/L1Escrow.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,94 @@ contract EscrowTest is Setup {
assertEq(vault.balanceOf(address(mockEscrow)), 0);
}

function test_bridgeAsset_maxDepositLimit(uint256 _amount) public {
function test_bridgeAsset_escrowDepositLimit(uint256 _amount) public {
_amount = bound(_amount, minFuzzAmount, maxFuzzAmount);

Choose a reason for hiding this comment

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

can _amount be 0?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes, will add a section to show that

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

address counterPart = l1Deployer.getL2EscrowAddress(
l2RollupID,
address(asset)
);
mockEscrow = deployMockL1Escrow();

// Only Admin can update deposit limit
vm.expectRevert();

Choose a reason for hiding this comment

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

some comments would be helpful :)

// reverts because caller does is not allowed to change the deposit limit

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

mockEscrow.updateDepositLimit(0);

vm.prank(governator);
mockEscrow.updateDepositLimit(0);

// Simulate a bridge txn
airdrop(asset, user, _amount);

vm.prank(user);
asset.approve(address(mockEscrow), _amount);

// OVer Deposit limit
vm.expectRevert("deposit limit");
vm.prank(user);
mockEscrow.bridgeToken(user, _amount, true);

vm.prank(governator);
mockEscrow.updateDepositLimit(uint128(_amount));

bytes memory data = abi.encode(user, _amount);
uint256 depositCount = polygonZkEVMBridge.depositCount();
vm.expectEmit(true, true, true, true, address(polygonZkEVMBridge));
emit BridgeEvent(
1,
l1RollupID,
address(mockEscrow),
l2RollupID,
counterPart,
0,
data,
uint32(depositCount)
);
vm.prank(user);
mockEscrow.bridgeToken(user, _amount, true);

assertEq(vault.totalAssets(), _amount);
assertEq(mockEscrow.deposited(), _amount);
assertEq(asset.balanceOf(user), 0);
assertEq(asset.balanceOf(address(mockEscrow)), 0);
assertEq(vault.balanceOf(address(mockEscrow)), _amount);

airdrop(asset, user, _amount);

vm.prank(user);
asset.approve(address(mockEscrow), _amount);

vm.expectRevert("deposit limit");
vm.prank(user);
mockEscrow.bridgeToken(user, _amount, true);

vm.prank(governator);
mockEscrow.updateDepositLimit(uint128(_amount * 2));

vm.prank(user);
mockEscrow.bridgeToken(user, _amount, true);

assertEq(vault.totalAssets(), _amount * 2);
assertEq(mockEscrow.deposited(), _amount * 2);
assertEq(asset.balanceOf(user), 0);
assertEq(asset.balanceOf(address(mockEscrow)), 0);
assertEq(vault.balanceOf(address(mockEscrow)), _amount * 2);

// Withdraw half
uint256 toWithdraw = _amount + 10;

data = abi.encode(user, toWithdraw);

vm.prank(address(polygonZkEVMBridge));
mockEscrow.onMessageReceived(counterPart, l2RollupID, data);

assertEq(vault.totalAssets(), _amount - 10);
assertEq(mockEscrow.deposited(), _amount * 2 - toWithdraw);
assertEq(asset.balanceOf(user), toWithdraw);
assertEq(asset.balanceOf(address(mockEscrow)), 0);
assertEq(vault.balanceOf(address(mockEscrow)), _amount - 10);
}

function test_bridgeAsset_vaultDepositLimit(uint256 _amount) public {
_amount = bound(_amount, minFuzzAmount, maxFuzzAmount);
address counterPart = l1Deployer.getL2EscrowAddress(
l2RollupID,
Expand Down Expand Up @@ -227,17 +314,18 @@ contract EscrowTest is Setup {

function test_bridgeAsset_minimumBuffer(
uint256 _amount,
uint256 _minimumBuffer
uint128 _minimumBuffer
) public {
_amount = bound(_amount, minFuzzAmount, maxFuzzAmount);
_minimumBuffer = bound(_minimumBuffer, 10, maxFuzzAmount);
_minimumBuffer = uint128(bound(_minimumBuffer, 10, maxFuzzAmount));
address counterPart = l1Deployer.getL2EscrowAddress(
l2RollupID,
address(asset)
);

mockEscrow = deployMockL1Escrow();

// Only Admin can update
vm.expectRevert();
mockEscrow.updateMinimumBuffer(_minimumBuffer);

Expand Down Expand Up @@ -270,9 +358,9 @@ contract EscrowTest is Setup {
assertEq(vault.balanceOf(address(mockEscrow)), 0);
}

function test_rebalance(uint256 _amount, uint256 _minimumBuffer) public {
function test_rebalance(uint256 _amount, uint128 _minimumBuffer) public {
_amount = bound(_amount, minFuzzAmount, maxFuzzAmount);
_minimumBuffer = bound(_minimumBuffer, 10, maxFuzzAmount);
_minimumBuffer = uint128(bound(_minimumBuffer, 10, maxFuzzAmount));
address counterPart = l1Deployer.getL2EscrowAddress(
l2RollupID,
address(asset)
Expand Down Expand Up @@ -471,10 +559,10 @@ contract EscrowTest is Setup {

function test_illiquidWithdraw_withBuffer(
uint256 _amount,
uint256 _minimumBuffer
uint128 _minimumBuffer
) public {
_amount = bound(_amount, minFuzzAmount, maxFuzzAmount);
_minimumBuffer = bound(_minimumBuffer, 10, _amount / 2);
_minimumBuffer = uint128(bound(_minimumBuffer, 10, _amount / 2));
address counterPart = l1Deployer.getL2EscrowAddress(
l2RollupID,
address(asset)
Expand Down
Loading