Skip to content

Commit

Permalink
Emit Transfer event on update exit queue
Browse files Browse the repository at this point in the history
  • Loading branch information
tsudmi committed Mar 6, 2024
1 parent 5dc56ec commit 0192ff6
Show file tree
Hide file tree
Showing 19 changed files with 90 additions and 81 deletions.
10 changes: 10 additions & 0 deletions contracts/vaults/ethereum/EthErc20Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ contract EthErc20Vault is
return _version;
}

/// @inheritdoc VaultState
function _updateExitQueue()
internal
virtual
override(VaultState, VaultToken)
returns (uint256 burnedShares)
{
return super._updateExitQueue();
}

/// @inheritdoc VaultState
function _mintShares(
address owner,
Expand Down
20 changes: 10 additions & 10 deletions contracts/vaults/ethereum/EthPrivErc20Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ contract EthPrivErc20Vault is Initializable, EthErc20Vault, VaultWhitelist, IEth
__VaultWhitelist_init(_admin);
}

/// @inheritdoc IVaultVersion
function vaultId() public pure virtual override(IVaultVersion, EthErc20Vault) returns (bytes32) {
return keccak256('EthPrivErc20Vault');
}

/// @inheritdoc IVaultVersion
function version() public pure virtual override(IVaultVersion, EthErc20Vault) returns (uint8) {
return _version;
}

/// @inheritdoc IVaultEthStaking
function deposit(
address receiver,
Expand Down Expand Up @@ -101,16 +111,6 @@ contract EthPrivErc20Vault is Initializable, EthErc20Vault, VaultWhitelist, IEth
return super.mintOsToken(receiver, osTokenShares, referrer);
}

/// @inheritdoc IVaultVersion
function vaultId() public pure virtual override(IVaultVersion, EthErc20Vault) returns (bytes32) {
return keccak256('EthPrivErc20Vault');
}

/// @inheritdoc IVaultVersion
function version() public pure virtual override(IVaultVersion, EthErc20Vault) returns (uint8) {
return _version;
}

/// @inheritdoc ERC20Upgradeable
function _transfer(address from, address to, uint256 amount) internal virtual override {
_checkWhitelist(from);
Expand Down
5 changes: 4 additions & 1 deletion contracts/vaults/modules/VaultEnterExit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,10 @@ abstract contract VaultEnterExit is VaultImmutables, Initializable, VaultState,
if (totalExitedTickets <= positionTicket) return (0, 0);

// calculate exited tickets and assets
exitedTickets = Math.min(exitingTickets, totalExitedTickets - positionTicket);
unchecked {
// cannot underflow as totalExitedTickets > positionTicket
exitedTickets = Math.min(exitingTickets, totalExitedTickets - positionTicket);
}
return (exitedTickets, _convertExitTicketsToAssets(exitedTickets));
}

Expand Down
43 changes: 15 additions & 28 deletions contracts/vaults/modules/VaultOsToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ abstract contract VaultOsToken is VaultImmutables, VaultState, VaultEnterExit, I
}

/// @inheritdoc IVaultOsToken
function osTokenPositions(address user) public view override returns (uint128 shares) {
function osTokenPositions(address user) external view override returns (uint128 shares) {
OsTokenPosition memory position = _positions[user];
if (position.shares != 0) _syncPositionFee(position);
return position.shares;
Expand Down Expand Up @@ -272,40 +272,27 @@ abstract contract VaultOsToken is VaultImmutables, VaultState, VaultEnterExit, I
}

/**
* @dev Internal function for retrieving the amount of locked shares for a given user.
* Reverts if the vault is not harvested.
* @notice Internal function for checking position validity. Reverts if it is invalid.
* @param user The address of the user
* @return The amount of locked shares
*/
function _getLockedShares(address user) internal view returns (uint256) {
uint256 osTokenShares = osTokenPositions(user);
if (osTokenShares == 0) return 0;

// calculate locked assets
uint256 lockedAssets = Math.mulDiv(
_osTokenVaultController.convertToAssets(osTokenShares),
_maxPercent,
_osTokenConfig.ltvPercent()
);
if (lockedAssets == 0) return 0;
function _checkOsTokenPosition(address user) internal view {
// fetch user position
OsTokenPosition memory position = _positions[user];
if (position.shares == 0) return;

// check whether vault assets are up to date
_checkHarvested();

// convert to vault shares
return convertToShares(lockedAssets);
}

/**
* @notice Internal function for checking position validity
* @param user The address of the user
*/
function _checkOsTokenPosition(address user) internal view {
uint256 lockedShares = _getLockedShares(user);
if (lockedShares == 0) return;
// sync fee
_syncPositionFee(position);

// validate position LTV
if (lockedShares > _balances[user]) revert Errors.LowLtv();
// calculate and validate position LTV
if (
Math.mulDiv(convertToAssets(_balances[user]), _osTokenConfig.ltvPercent(), _maxPercent) <
_osTokenVaultController.convertToAssets(position.shares)
) {
revert Errors.LowLtv();
}
}

/**
Expand Down
30 changes: 16 additions & 14 deletions contracts/vaults/modules/VaultState.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault
uint128 internal _totalShares;
uint128 internal _totalAssets;

/// @inheritdoc IVaultState
uint128 public override queuedShares;
uint128 internal _unclaimedAssets;

Expand All @@ -32,6 +33,7 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault

uint256 private _capacity;

/// @inheritdoc IVaultState
uint128 public override totalExitingAssets;
uint128 internal _totalExitingTickets;
uint256 internal _totalExitedTickets;
Expand Down Expand Up @@ -118,27 +120,27 @@ abstract contract VaultState is VaultImmutables, Initializable, VaultFee, IVault

// SLOAD to memory
uint256 _totalExitingAssets = totalExitingAssets;
// apply penalty to exiting assets
uint256 exitingAssetsPenalty = Math.mulDiv(
penalty,
_totalExitingAssets,
_totalExitingAssets + newTotalAssets
);
if (_totalExitingAssets > 0) {
// apply penalty to exiting assets
uint256 exitingAssetsPenalty = Math.mulDiv(
penalty,
_totalExitingAssets,
_totalExitingAssets + newTotalAssets
);

unchecked {
// cannot underflow as exitingAssetsPenalty <= penalty
penalty -= exitingAssetsPenalty;
// apply penalty to total exiting assets
unchecked {
// cannot underflow as exitingAssetsPenalty <= penalty
penalty -= exitingAssetsPenalty;
// cannot underflow as exitingAssetsPenalty <= _totalExitingAssets
totalExitingAssets = SafeCast.toUint128(_totalExitingAssets - exitingAssetsPenalty);
}
}

// subtract penalty from total assets (excludes exiting assets)
if (penalty > 0) {
_totalAssets = SafeCast.toUint128(newTotalAssets - penalty);
}

// subtract penalty from total exiting assets
if (exitingAssetsPenalty > 0) {
totalExitingAssets = SafeCast.toUint128(_totalExitingAssets - exitingAssetsPenalty);
}
return;
}

Expand Down
6 changes: 6 additions & 0 deletions contracts/vaults/modules/VaultToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ abstract contract VaultToken is Initializable, ERC20Upgradeable, VaultState, IVa
emit Transfer(owner, address(0), shares);
}

/// @inheritdoc VaultState
function _updateExitQueue() internal virtual override returns (uint256 burnedShares) {
burnedShares = super._updateExitQueue();
if (burnedShares != 0) emit Transfer(address(this), address(0), burnedShares);
}

/// @inheritdoc ERC20Upgradeable
function _transfer(address from, address to, uint256 amount) internal virtual override {
if (from == address(0) || to == address(0)) revert Errors.ZeroAddress();
Expand Down
2 changes: 1 addition & 1 deletion contracts/vaults/modules/VaultWhitelist.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ abstract contract VaultWhitelist is Initializable, VaultAdmin, IVaultWhitelist {
mapping(address => bool) public override whitelistedAccounts;

/// @inheritdoc IVaultWhitelist
function updateWhitelist(address account, bool approved) public override {
function updateWhitelist(address account, bool approved) external override {
if (msg.sender != whitelister) revert Errors.AccessDenied();
if (whitelistedAccounts[account] == approved) return;
whitelistedAccounts[account] = approved;
Expand Down
1 change: 1 addition & 0 deletions test/EthGenesisVault.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ describe('EthGenesisVault', () => {
})

it('skips updating legacy with zero total assets', async () => {
if (MAINNET_FORK.enabled) return
await acceptPoolEscrowOwnership()
await rewardEthToken.setTotalStaked(0n)
await rewardEthToken.setTotalRewards(0n)
Expand Down
6 changes: 3 additions & 3 deletions test/__snapshots__/EthBlocklistErc20Vault.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
exports[`EthBlocklistErc20Vault deposit can be called by not blocked user 1`] = `
Object {
"calldataByteLength": 68,
"gasUsed": 71149,
"gasUsed": 71181,
}
`;

exports[`EthBlocklistErc20Vault deposit deposit through receive fallback can be called by not blocked sender 1`] = `
Object {
"calldataByteLength": 4,
"gasUsed": 78315,
"gasUsed": 78347,
}
`;

Expand All @@ -24,6 +24,6 @@ Object {
exports[`EthBlocklistErc20Vault transfer can transfer 1`] = `
Object {
"calldataByteLength": 68,
"gasUsed": 59012,
"gasUsed": 58987,
}
`;
6 changes: 3 additions & 3 deletions test/__snapshots__/EthErc20Vault.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@
exports[`EthErc20Vault deposit emits transfer event 1`] = `
Object {
"calldataByteLength": 68,
"gasUsed": 68826,
"gasUsed": 68858,
}
`;

exports[`EthErc20Vault deposit through receive fallback function emits transfer event 1`] = `
Object {
"calldataByteLength": 4,
"gasUsed": 76084,
"gasUsed": 76116,
}
`;

exports[`EthErc20Vault enter exit queue emits transfer event 1`] = `
Object {
"calldataByteLength": 68,
"gasUsed": 96055,
"gasUsed": 96030,
}
`;

Expand Down
4 changes: 2 additions & 2 deletions test/__snapshots__/EthGenesisVault.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Object {
exports[`EthGenesisVault pulls withdrawals on claim exited assets 1`] = `
Object {
"calldataByteLength": 100,
"gasUsed": 77231,
"gasUsed": 77206,
}
`;

Expand Down Expand Up @@ -52,7 +52,7 @@ Object {
exports[`EthGenesisVault update state splits penalty between rewardEthToken and vault 1`] = `
Object {
"calldataByteLength": 196,
"gasUsed": 119951,
"gasUsed": 119650,
}
`;

Expand Down
6 changes: 3 additions & 3 deletions test/__snapshots__/EthPrivErc20Vault.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
exports[`EthPrivErc20Vault deposit can be called by whitelisted user 1`] = `
Object {
"calldataByteLength": 68,
"gasUsed": 71137,
"gasUsed": 71169,
}
`;

exports[`EthPrivErc20Vault deposit deposit through receive fallback can be called by whitelisted sender 1`] = `
Object {
"calldataByteLength": 4,
"gasUsed": 78318,
"gasUsed": 78350,
}
`;

Expand All @@ -24,6 +24,6 @@ Object {
exports[`EthPrivErc20Vault transfer can transfer to whitelisted user 1`] = `
Object {
"calldataByteLength": 68,
"gasUsed": 59040,
"gasUsed": 59015,
}
`;
4 changes: 2 additions & 2 deletions test/__snapshots__/EthVault.multicall.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
exports[`EthVault - multicall can update state and queue for exit 1`] = `
Object {
"calldataByteLength": 516,
"gasUsed": 168253,
"gasUsed": 168196,
}
`;

exports[`EthVault - multicall can update state and queue for exit 2`] = `
Object {
"calldataByteLength": 548,
"gasUsed": 109869,
"gasUsed": 109844,
}
`;
4 changes: 2 additions & 2 deletions test/__snapshots__/EthVault.state.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ Object {
exports[`EthVault - state applies penalty when delta is below zero 1`] = `
Object {
"calldataByteLength": 196,
"gasUsed": 117639,
"gasUsed": 117338,
}
`;

exports[`EthVault - state splits penalty between exiting assets and staking assets 1`] = `
Object {
"calldataByteLength": 196,
"gasUsed": 107192,
"gasUsed": 107117,
}
`;

Expand Down
8 changes: 4 additions & 4 deletions test/__snapshots__/EthVault.token.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,27 @@ Object {
exports[`EthVault - token transfer from when the spender has enough allowance when the token owner has enough balance transfers the requested amount 1`] = `
Object {
"calldataByteLength": 100,
"gasUsed": 54827,
"gasUsed": 54802,
}
`;

exports[`EthVault - token transfer from when the spender has unlimited allowance does not decrease the spender allowance 1`] = `
Object {
"calldataByteLength": 100,
"gasUsed": 61303,
"gasUsed": 61278,
}
`;

exports[`EthVault - token transfer when the sender transfers all balance transfers the requested amount 1`] = `
Object {
"calldataByteLength": 68,
"gasUsed": 54490,
"gasUsed": 54465,
}
`;

exports[`EthVault - token transfer when the sender transfers zero tokens transfers the requested amount 1`] = `
Object {
"calldataByteLength": 68,
"gasUsed": 36566,
"gasUsed": 36541,
}
`;
2 changes: 1 addition & 1 deletion test/__snapshots__/EthVault.withdraw.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Object {
exports[`EthVault - withdraw enter exit queue locks assets for the time of exit 1`] = `
Object {
"calldataByteLength": 68,
"gasUsed": 77184,
"gasUsed": 77127,
}
`;

Expand Down
Loading

0 comments on commit 0192ff6

Please sign in to comment.