diff --git a/contracts/0.8.25/vaults/Dashboard.sol b/contracts/0.8.25/vaults/Dashboard.sol index a0daa0437..9dfe6f730 100644 --- a/contracts/0.8.25/vaults/Dashboard.sol +++ b/contracts/0.8.25/vaults/Dashboard.sol @@ -332,7 +332,7 @@ contract Dashboard is AccessControlEnumerable { * @param _amountOfStETH Amount of stETH shares to burn */ function burnSteth(uint256 _amountOfStETH) external virtual onlyRole(DEFAULT_ADMIN_ROLE) { - _burnSharesFrom(msg.sender, STETH.getSharesByPooledEth(_amountOfStETH)); + _burnStETH(_amountOfStETH); } /** @@ -341,10 +341,7 @@ contract Dashboard is AccessControlEnumerable { * @dev The _amountOfWstETH = _amountOfShares by design */ function burnWstETH(uint256 _amountOfWstETH) external virtual onlyRole(DEFAULT_ADMIN_ROLE) { - WSTETH.transferFrom(msg.sender, address(this), _amountOfWstETH); - WSTETH.unwrap(_amountOfWstETH); - - _burnSharesFrom(address(this), _amountOfWstETH); + _burnWstETH(_amountOfWstETH); } /** @@ -401,7 +398,7 @@ contract Dashboard is AccessControlEnumerable { uint256 _amountOfStETH, PermitInput calldata _permit ) external virtual onlyRole(DEFAULT_ADMIN_ROLE) safePermit(address(STETH), msg.sender, address(this), _permit) { - _burnSharesFrom(msg.sender, STETH.getSharesByPooledEth(_amountOfStETH)); + _burnStETH(_amountOfStETH); } /** @@ -413,11 +410,7 @@ contract Dashboard is AccessControlEnumerable { uint256 _amountOfWstETH, PermitInput calldata _permit ) external virtual onlyRole(DEFAULT_ADMIN_ROLE) safePermit(address(WSTETH), msg.sender, address(this), _permit) { - WSTETH.transferFrom(msg.sender, address(this), _amountOfWstETH); - uint256 stETHAmount = WSTETH.unwrap(_amountOfWstETH); - uint256 sharesAmount = STETH.getSharesByPooledEth(stETHAmount); - - _burnSharesFrom(address(this), sharesAmount); + _burnWstETH(_amountOfWstETH); } /** @@ -529,6 +522,26 @@ contract Dashboard is AccessControlEnumerable { vaultHub.mintSharesBackedByVault(address(stakingVault), _recipient, _amountOfShares); } + /** + * @dev Burns stETH tokens from the sender backed by the vault + * @param _amountOfStETH Amount of tokens to burn + */ + function _burnStETH(uint256 _amountOfStETH) internal { + _burnSharesFrom(msg.sender, STETH.getSharesByPooledEth(_amountOfStETH)); + } + + /** + * @dev Burns wstETH tokens from the sender backed by the vault + * @param _amountOfWstETH Amount of tokens to burn + */ + function _burnWstETH(uint256 _amountOfWstETH) internal { + WSTETH.transferFrom(msg.sender, address(this), _amountOfWstETH); + uint256 stETHAmount = WSTETH.unwrap(_amountOfWstETH); + uint256 sharesAmount = STETH.getSharesByPooledEth(stETHAmount); + + _burnSharesFrom(address(this), sharesAmount); + } + /** * @dev Burns stETH tokens from the sender backed by the vault * @param _amountOfShares Amount of tokens to burn diff --git a/test/0.8.25/vaults/dashboard/dashboard.test.ts b/test/0.8.25/vaults/dashboard/dashboard.test.ts index f4e81d446..27d7dec98 100644 --- a/test/0.8.25/vaults/dashboard/dashboard.test.ts +++ b/test/0.8.25/vaults/dashboard/dashboard.test.ts @@ -2,7 +2,6 @@ import { expect } from "chai"; import { randomBytes } from "crypto"; import { MaxUint256, ZeroAddress } from "ethers"; import { ethers } from "hardhat"; -import { bigint } from "hardhat/internal/core/params/argumentTypes"; import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; import { setBalance, time } from "@nomicfoundation/hardhat-network-helpers"; @@ -835,6 +834,48 @@ describe("Dashboard", () => { expect(await steth.balanceOf(vaultOwner)).to.equal(stethBalanceBefore); expect(await wsteth.balanceOf(vaultOwner)).to.equal(wstethBalanceBefore - amountWsteth); }); + + it("reverts on zero burn", async () => { + await expect(dashboard.burnWstETH(0n)).to.be.revertedWith("wstETH: zero amount unwrap not allowed"); + }); + + for (let weiWsteth = 1n; weiWsteth <= 10n; weiWsteth++) { + it(`burns ${weiWsteth} wei wsteth`, async () => { + const weiStethUp = await steth.getPooledEthBySharesRoundUp(weiWsteth); + const weiStethDown = await steth.getPooledEthByShares(weiWsteth); + // !!! weird + const weiWstethDown = await steth.getSharesByPooledEth(weiStethDown); + + // approve for wsteth wrap + await steth.connect(vaultOwner).approve(wsteth, weiStethUp); + // wrap steth to wsteth to get the amount of wsteth for the burn + await wsteth.connect(vaultOwner).wrap(weiStethUp); + + const wstethBalanceBefore = await wsteth.balanceOf(vaultOwner); + expect(wstethBalanceBefore).to.equal(weiWsteth); + const stethBalanceBefore = await steth.balanceOf(vaultOwner); + + // approve wsteth to dashboard contract + await wsteth.connect(vaultOwner).approve(dashboard, weiWsteth); + + const result = await dashboard.burnWstETH(weiWsteth); + + await expect(result).to.emit(wsteth, "Transfer").withArgs(vaultOwner, dashboard, weiWsteth); // transfer wsteth to dashboard + await expect(result).to.emit(steth, "Transfer").withArgs(wsteth, dashboard, weiStethDown); // unwrap wsteth to steth + await expect(result).to.emit(wsteth, "Transfer").withArgs(dashboard, ZeroAddress, weiWsteth); // burn wsteth + + // TODO: weird steth value + //await expect(result).to.emit(steth, "Transfer").withArgs(dashboard, hub, stethRoundDown); + await expect(result).to.emit(steth, "TransferShares").withArgs(dashboard, hub, weiWstethDown); // transfer shares to hub + // TODO: weird everything + // await expect(result) + // .to.emit(steth, "SharesBurnt") + // .withArgs(hub, stethRoundDown, stethRoundDown, weiWstethRoundDown); // burn steth (mocked event data) + + expect(await steth.balanceOf(vaultOwner)).to.equal(stethBalanceBefore); + expect(await wsteth.balanceOf(vaultOwner)).to.equal(wstethBalanceBefore - weiWsteth); + }); + } }); context("burnSharesWithPermit", () => {