UNPKG

@nodeset/contracts

Version:

Protocol for accessing NodeSet's Constellation Ethereum staking network

177 lines (141 loc) 11 kB
import { expect } from "chai"; import { ethers, upgrades, hardhatArguments } from "hardhat"; import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; import { protocolFixture } from "../test"; describe("Yield Accrual", function () { describe("When sender is not protocol", async () => { it("should revert", async () => { const { protocol, signers, rocketPool } = await loadFixture(protocolFixture); await expect(protocol.operatorDistributor.connect(signers.random5).onEthBeaconRewardsReceived(6, 6, 6)).to.be.revertedWith("Can only be called by Protocol!"); }) }) describe("When sender is protocol", async () => { describe("When rewards are positive", async () => { describe("When insufficient balance", async () => { describe("When there is not enough eth in Asset Router for avgTreasuryFee", async () => { it("should revert", async () => { const { protocol, signers, rocketPool } = await loadFixture(protocolFixture); const reward = ethers.utils.parseEther("1") const avgTreasuryFee = ethers.utils.parseEther("1") const avgOperatorsFee = ethers.utils.parseEther("0") await expect(protocol.operatorDistributor.connect(signers.protocolSigner).onEthBeaconRewardsReceived(reward, avgTreasuryFee, avgOperatorsFee)).to.be.revertedWith("Transfer to treasury failed"); }) }) describe("When there is not enough eth in Asset Router for avgOperatorsFee", async () => { it("should revert", async () => { const { protocol, signers, rocketPool } = await loadFixture(protocolFixture); const reward = ethers.utils.parseEther("1") const avgTreasuryFee = ethers.utils.parseEther("0") const avgOperatorsFee = ethers.utils.parseEther("1") await expect(protocol.operatorDistributor.connect(signers.protocolSigner).onEthBeaconRewardsReceived(reward, avgTreasuryFee, avgOperatorsFee)).to.be.revertedWith("Transfer to operator fee address failed"); }) }) }) describe("When sufficent balance", async () => { describe("When oracle error is true", async () => { describe("When community rewards are positive", async () => { type ParamsType = { avgTreasuryFeeRaw: number; avgOperatorsFeeRaw: number; }; [ { avgTreasuryFeeRaw: .6, avgOperatorsFeeRaw: .4, }, { avgTreasuryFeeRaw: .1, avgOperatorsFeeRaw: .1, }, { avgTreasuryFeeRaw: .5, avgOperatorsFeeRaw: .4, }, { avgTreasuryFeeRaw: .99, avgOperatorsFeeRaw: .01, }, { avgTreasuryFeeRaw: .99999, avgOperatorsFeeRaw: .00001, }, { avgTreasuryFeeRaw: 1, avgOperatorsFeeRaw: 0, }, { avgTreasuryFeeRaw: 0, avgOperatorsFeeRaw: 1, } ].forEach((params: ParamsType) => { it(`should increase balance & call onIncreaseOracleError: avgTreasuryFee=${params.avgTreasuryFeeRaw}, avgOperatorsFee=${params.avgOperatorsFeeRaw}`, async () => { const { protocol, signers, rocketPool } = await loadFixture(protocolFixture); const reward = ethers.utils.parseEther("1") const avgTreasuryFee = ethers.utils.parseEther(`${params.avgTreasuryFeeRaw}`) // 50% const avgOperatorsFee = ethers.utils.parseEther(`${params.avgOperatorsFeeRaw}`) // 50% expect(await ethers.provider.getBalance(protocol.operatorDistributor.address)).equals(0); // simulate reward sent to operatorDistributor await signers.random.sendTransaction({ to: protocol.operatorDistributor.address, value: reward }) expect(await ethers.provider.getBalance(protocol.operatorDistributor.address)).equals(reward); expect(await ethers.provider.getBalance(protocol.yieldDistributor.address)).equals(0); expect(await protocol.wETH.balanceOf(protocol.operatorDistributor.address)).equals(0); const expectedTreasuryPortion = reward.mul(avgTreasuryFee).div(ethers.utils.parseEther("1")) const expectedOperatorPortion = reward.mul(avgOperatorsFee).div(ethers.utils.parseEther("1")) const expectedCommunityPortion = reward.sub(expectedTreasuryPortion.add(expectedOperatorPortion)); const tx = await protocol.operatorDistributor.connect(signers.protocolSigner).onEthBeaconRewardsReceived(reward, avgTreasuryFee, avgOperatorsFee) const receipt = await tx.wait(); const block = receipt.blockNumber; const initialBalanceTreasury = await ethers.provider.getBalance(await protocol.directory.getTreasuryAddress(), block - 1); const finalBalanceTreasury = await ethers.provider.getBalance(await protocol.directory.getTreasuryAddress(), block); expect(finalBalanceTreasury.sub(initialBalanceTreasury)).equals(expectedTreasuryPortion); expect(await ethers.provider.getBalance(protocol.yieldDistributor.address)).equals(expectedOperatorPortion); expect(await ethers.provider.getBalance(protocol.operatorDistributor.address)).equals(expectedCommunityPortion); //expect(await protocol.wETH.balanceOf(protocol.operatorDistributor.address)).equals(expectedCommunityPortion); expect(await protocol.operatorDistributor.oracleError()).equals(expectedCommunityPortion); }) }) }) }) describe("When community rewards are negative", async () => { it("should revert", async () => { const { protocol, signers, rocketPool } = await loadFixture(protocolFixture); const reward = ethers.utils.parseEther("1") const avgTreasuryFee = ethers.utils.parseEther(".9") // 90% const avgOperatorsFee = ethers.utils.parseEther(".9") // 90% expect(await ethers.provider.getBalance(protocol.operatorDistributor.address)).equals(0); // simulate reward sent to asset router await signers.ethWhale.sendTransaction({ to: protocol.operatorDistributor.address, value: reward.mul(10) }) expect(await ethers.provider.getBalance(protocol.operatorDistributor.address)).equals(reward.mul(10)); expect(await ethers.provider.getBalance(protocol.yieldDistributor.address)).equals(0); const expectedTreasuryPortion = reward.mul(avgTreasuryFee).div(ethers.utils.parseEther("1")) const expectedOperatorPortion = reward.mul(avgOperatorsFee).div(ethers.utils.parseEther("1")) // expect the community rewards underflow to cause revert await expect(protocol.operatorDistributor.connect(signers.protocolSigner).onEthBeaconRewardsReceived(reward, avgTreasuryFee, avgOperatorsFee)).to.be.revertedWithPanic('0x11') }) }) }) }) describe("When rewards are 0", async () => { it("does nothing", async () => { const { protocol, signers, rocketPool } = await loadFixture(protocolFixture); const reward = ethers.utils.parseEther("0") const avgTreasuryFee = ethers.utils.parseEther(".6") // 50% const avgOperatorsFee = ethers.utils.parseEther(".4") // 50% expect(await ethers.provider.getBalance(protocol.operatorDistributor.address)).equals(0); // simulate reward sent to asset router await signers.ethWhale.sendTransaction({ to: protocol.operatorDistributor.address, value: reward }) expect(await ethers.provider.getBalance(protocol.operatorDistributor.address)).equals(reward); expect(await ethers.provider.getBalance(protocol.yieldDistributor.address)).equals(0); const initialBalanceTreasury = await ethers.provider.getBalance(await protocol.directory.getTreasuryAddress()); const expectedTreasuryPortion = 0 const expectedOperatorPortion = 0 const expectedCommunityPortion = 0 await protocol.operatorDistributor.connect(signers.protocolSigner).onEthBeaconRewardsReceived(reward, avgTreasuryFee, avgOperatorsFee) const finalBalanceTreasury = await ethers.provider.getBalance(await protocol.directory.getTreasuryAddress()); expect(finalBalanceTreasury.sub(initialBalanceTreasury)).equals(expectedTreasuryPortion); expect(await ethers.provider.getBalance(protocol.yieldDistributor.address)).equals(expectedOperatorPortion); expect(await ethers.provider.getBalance(protocol.operatorDistributor.address)).equals(expectedCommunityPortion); }) }) describe("When rewards are negative", async () => { it("should revert", async () => { const { protocol, signers, rocketPool } = await loadFixture(protocolFixture); const reward = ethers.utils.parseEther("1").mul(-1); const avgTreasuryFee = ethers.utils.parseEther(".6") // 50% const avgOperatorsFee = ethers.utils.parseEther(".4") // 50% expect(await ethers.provider.getBalance(protocol.operatorDistributor.address)).equals(0); // simulate reward sent to asset router await signers.ethWhale.sendTransaction({ to: protocol.operatorDistributor.address, value: reward.mul(-1) }) await expect(protocol.operatorDistributor.connect(signers.protocolSigner).onEthBeaconRewardsReceived(reward, avgTreasuryFee, avgOperatorsFee)).to.be.rejected; }) }) }) })