From 5d3b2ff815b7ccb953d21c35d1514e98b7cdba19 Mon Sep 17 00:00:00 2001 From: VP Date: Thu, 16 Jan 2025 11:37:16 +0100 Subject: [PATCH] test: fix mint accounting tests --- .../accounting.handleOracleReport.test.ts | 195 ++++++++---------- .../contracts/Lido__MockForAccounting.sol | 10 + 2 files changed, 93 insertions(+), 112 deletions(-) diff --git a/test/0.8.9/accounting.handleOracleReport.test.ts b/test/0.8.9/accounting.handleOracleReport.test.ts index 4c002724b..f4a737512 100644 --- a/test/0.8.9/accounting.handleOracleReport.test.ts +++ b/test/0.8.9/accounting.handleOracleReport.test.ts @@ -279,119 +279,90 @@ describe("Accounting.sol:report", () => { ).not.to.emit(stakingRouter, "Mock__MintedRewardsReported"); }); - // it("Mints shares to itself and then transfers them to recipients if there are fees to distribute as returned from `StakingRouter.getStakingRewardsDistribution`", async () => { - // // initially, before any rebases, one share costs one steth - // expect(await lido.getPooledEthByShares(ether("1.0"))).to.equal(ether("1.0")); - // // thus, the total supply of steth should equal the total number of shares - // expect(await lido.getTotalPooledEther()).to.equal(await lido.getTotalShares()); - - // // mock a single staking module with 5% fee with the total protocol fee of 10% - // const stakingModule = { - // address: certainAddress("lido:handleOracleReport:staking-module"), - // id: 1n, - // fee: 5n * 10n ** 18n, // 5% - // }; - - // const totalFee = 10n * 10n ** 18n; // 10% - // const precisionPoints = 100n * 10n ** 18n; // 100% - - // await stakingRouter.mock__getStakingRewardsDistribution( - // [stakingModule.address], - // [stakingModule.id], - // [stakingModule.fee], - // totalFee, - // precisionPoints, - // ); - - // const clBalance = ether("1.0"); - - // const expectedSharesToMint = - // (clBalance * totalFee * (await lido.getTotalShares())) / - // (((await lido.getTotalPooledEther()) + clBalance) * precisionPoints - clBalance * totalFee); - - // const expectedModuleRewardInShares = expectedSharesToMint / (totalFee / stakingModule.fee); - // const expectedTreasuryCutInShares = expectedSharesToMint - expectedModuleRewardInShares; - - // await expect( - // accounting.handleOracleReport( - // report({ - // clBalance: ether("1.0"), // 1 ether of profit - // }), - // ), - // ) - // .to.emit(lido, "TransferShares") - // .withArgs(ZeroAddress, stakingModule.address, expectedModuleRewardInShares) - // .and.to.emit(lido, "TransferShares") - // .withArgs(ZeroAddress, await lido.getTreasury(), expectedTreasuryCutInShares) - // .and.to.emit(stakingRouter, "Mock__MintedRewardsReported"); - - // expect(await lido.balanceOf(stakingModule.address)).to.equal( - // await lido.getPooledEthByShares(expectedModuleRewardInShares), - // ); - - // expect(await lido.balanceOf(await lido.getTreasury())).to.equal( - // await lido.getPooledEthByShares(expectedTreasuryCutInShares), - // ); - - // // now one share should cost 1.9 steth (10% was distributed as rewards) - // expect(await lido.getPooledEthByShares(ether("1.0"))).to.equal(ether("1.9")); - // }); + it("Mints shares to itself and then transfers them to recipients if there are fees to distribute as returned from `StakingRouter.getStakingRewardsDistribution`", async () => { + // mock a single staking module with 5% fee with the total protocol fee of 10% + const stakingModule = { + address: certainAddress("lido:handleOracleReport:staking-module"), + id: 1n, + fee: 5n * 10n ** 18n, // 5% + }; - // it("Transfers all new shares to treasury if the module fee is zero as returned `StakingRouter.getStakingRewardsDistribution`", async () => { - // // initially, before any rebases, one share costs one steth - // expect(await lido.getPooledEthByShares(ether("1.0"))).to.equal(ether("1.0")); - // // thus, the total supply of steth should equal the total number of shares - // expect(await lido.getTotalPooledEther()).to.equal(await lido.getTotalShares()); - - // // mock a single staking module with 0% fee with the total protocol fee of 10% - // const stakingModule = { - // address: certainAddress("lido:handleOracleReport:staking-module"), - // id: 1n, - // fee: 0n, - // }; - - // const totalFee = 10n * 10n ** 18n; // 10% - // const precisionPoints = 100n * 10n ** 18n; // 100% - - // await stakingRouter.mock__getStakingRewardsDistribution( - // [stakingModule.address], - // [stakingModule.id], - // [stakingModule.fee], - // totalFee, - // precisionPoints, - // ); - - // const clBalance = ether("1.0"); - - // const expectedSharesToMint = - // (clBalance * totalFee * (await lido.getTotalShares())) / - // (((await lido.getTotalPooledEther()) + clBalance) * precisionPoints - clBalance * totalFee); - - // const expectedModuleRewardInShares = 0n; - // const expectedTreasuryCutInShares = expectedSharesToMint; - - // await expect( - // accounting.handleOracleReport( - // report({ - // clBalance: ether("1.0"), // 1 ether of profit - // }), - // ), - // ) - // .and.to.emit(lido, "TransferShares") - // .withArgs(ZeroAddress, await lido.getTreasury(), expectedTreasuryCutInShares) - // .and.to.emit(stakingRouter, "Mock__MintedRewardsReported"); - - // expect(await lido.balanceOf(stakingModule.address)).to.equal( - // await lido.getPooledEthByShares(expectedModuleRewardInShares), - // ); - - // expect(await lido.balanceOf(await lido.getTreasury())).to.equal( - // await lido.getPooledEthByShares(expectedTreasuryCutInShares), - // ); - - // // now one share should cost 1.9 steth (10% was distributed as rewards) - // expect(await lido.getPooledEthByShares(ether("1.0"))).to.equal(ether("1.9")); - // }); + const totalFee = 10n * 10n ** 18n; // 10% + const precisionPoints = 100n * 10n ** 18n; // 100% + + await stakingRouter.mock__getStakingRewardsDistribution( + [stakingModule.address], + [stakingModule.id], + [stakingModule.fee], + totalFee, + precisionPoints, + ); + + const clBalance = ether("1.0"); + const expectedSharesToMint = + (clBalance * totalFee * (await lido.getTotalShares())) / + (((await lido.getTotalPooledEther()) + clBalance) * precisionPoints - clBalance * totalFee); + + const expectedModuleRewardInShares = expectedSharesToMint / (totalFee / stakingModule.fee); + const expectedTreasuryCutInShares = expectedSharesToMint - expectedModuleRewardInShares; + + console.log("expectedModuleRewardInShares", expectedModuleRewardInShares); + console.log("expectedTreasuryCutInShares", expectedTreasuryCutInShares); + console.log("stakingModule.address", stakingModule.address); + console.log("await locator.treasury()", await locator.treasury()); + + await expect( + accounting.handleOracleReport( + report({ + clBalance: ether("1.0"), // 1 ether of profit + }), + ), + ) + .to.emit(lido, "TransferShares") + .withArgs(ZeroAddress, stakingModule.address, expectedModuleRewardInShares) + .and.to.emit(lido, "TransferShares") + .withArgs(ZeroAddress, await locator.treasury(), expectedTreasuryCutInShares) + .and.to.emit(stakingRouter, "Mock__MintedRewardsReported"); + }); + + it("Transfers all new shares to treasury if the module fee is zero as returned `StakingRouter.getStakingRewardsDistribution`", async () => { + // mock a single staking module with 0% fee with the total protocol fee of 10% + const stakingModule = { + address: certainAddress("lido:handleOracleReport:staking-module"), + id: 1n, + fee: 0n, + }; + + const totalFee = 10n * 10n ** 18n; // 10% + const precisionPoints = 100n * 10n ** 18n; // 100% + + await stakingRouter.mock__getStakingRewardsDistribution( + [stakingModule.address], + [stakingModule.id], + [stakingModule.fee], + totalFee, + precisionPoints, + ); + + const clBalance = ether("1.0"); + + const expectedSharesToMint = + (clBalance * totalFee * (await lido.getTotalShares())) / + (((await lido.getTotalPooledEther()) + clBalance) * precisionPoints - clBalance * totalFee); + + const expectedTreasuryCutInShares = expectedSharesToMint; + + await expect( + accounting.handleOracleReport( + report({ + clBalance: ether("1.0"), // 1 ether of profit + }), + ), + ) + .and.to.emit(lido, "TransferShares") + .withArgs(ZeroAddress, await locator.treasury(), expectedTreasuryCutInShares) + .and.to.emit(stakingRouter, "Mock__MintedRewardsReported"); + }); it("Relays the report data to `PostTokenRebaseReceiver`", async () => { await expect(accounting.handleOracleReport(report())).to.emit( diff --git a/test/0.8.9/contracts/Lido__MockForAccounting.sol b/test/0.8.9/contracts/Lido__MockForAccounting.sol index dcc2a5944..19135c140 100644 --- a/test/0.8.9/contracts/Lido__MockForAccounting.sol +++ b/test/0.8.9/contracts/Lido__MockForAccounting.sol @@ -20,6 +20,12 @@ contract Lido__MockForAccounting { uint256 _withdrawalsShareRate, uint256 _etherToLockOnWithdrawalQueue ); + /** + * @notice An executed shares transfer from `sender` to `recipient`. + * + * @dev emitted in pair with an ERC20-defined `Transfer` event. + */ + event TransferShares(address indexed from, address indexed to, uint256 sharesValue); function setMockedDepositedValidators(uint256 _amount) external { depositedValidatorsValue = _amount; @@ -104,4 +110,8 @@ contract Lido__MockForAccounting { emit CLValidatorsUpdated(_reportTimestamp, _preClValidators, _reportClValidators); } + + function mintShares(address _recipient, uint256 _sharesAmount) external { + emit TransferShares(address(0), _recipient, _sharesAmount); + } }