From 20bee74f35535a958b416a32fb4da3c7f874b324 Mon Sep 17 00:00:00 2001 From: Justin Goro Date: Fri, 1 Jul 2022 05:09:11 +0200 Subject: [PATCH 1/7] c4 issue 217 --- contracts/DAO/LimboDAO.sol | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/contracts/DAO/LimboDAO.sol b/contracts/DAO/LimboDAO.sol index f173bf5..c7abc0c 100644 --- a/contracts/DAO/LimboDAO.sol +++ b/contracts/DAO/LimboDAO.sol @@ -102,7 +102,6 @@ contract LimboDAO is Ownable { mapping(address => mapping(address => AssetClout)) public stakedUserAssetWeight; //user->asset->weight ProposalState public currentProposalState; - ProposalState public previousProposalState; // Since staking EYE precludes it from earning Flan on Limbo, fateToFlan can optionally be set to a non zero number to allow fat holders to spend their fate for Flan. uint256 public fateToFlan; @@ -120,7 +119,6 @@ contract LimboDAO is Ownable { } function nextProposal() internal { - previousProposalState = currentProposalState; currentProposalState.proposal.setLocked(false); currentProposalState.proposal = Proposal(address(0)); currentProposalState.fate = 0; @@ -271,7 +269,7 @@ contract LimboDAO is Ownable { ///@notice handles proposal voting logic. ///@param proposal contract to be voted on ///@param fate positive is YES, negative is NO. Absolute value is deducted from caller. - function vote(address proposal, int256 fate) public incrementFate isLive { + function vote(address proposal, int256 fate) public isLive incrementFate{ //this is just to protect users with out of sync UIs if (proposal != address(currentProposalState.proposal)) revert ProposalMismatch(proposal, address(currentProposalState.proposal)); From 0b56431f7d64abbd9ac3e980b89f2bf6fc0e8273 Mon Sep 17 00:00:00 2001 From: Justin Goro Date: Fri, 1 Jul 2022 05:10:32 +0200 Subject: [PATCH 2/7] c4 issue 205 --- contracts/Limbo.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/Limbo.sol b/contracts/Limbo.sol index 9049297..0d5b1f4 100644 --- a/contracts/Limbo.sol +++ b/contracts/Limbo.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.13; -import "./openzeppelin/Ownable.sol"; import "./facades/LimboDAOLike.sol"; import "./facades/Burnable.sol"; import "./facades/BehodlerLike.sol"; From 02686966240483026a6fe38737f0615025540160 Mon Sep 17 00:00:00 2001 From: Justin Goro Date: Fri, 1 Jul 2022 05:33:59 +0200 Subject: [PATCH 3/7] 197,188,187 --- contracts/DAO/LimboDAO.sol | 14 ++++++------- .../Proposals/TurnOnFateMintingProposal.sol | 2 +- contracts/UniswapHelper.sol | 2 +- contracts/facades/LimboDAOLike.sol | 2 +- contracts/openzeppelin/ERC20Burnable.sol | 2 +- contracts/periphery/Errors.sol | 2 +- test/limbo.dao.proposals.test.ts | 20 +++++++++---------- 7 files changed, 21 insertions(+), 23 deletions(-) diff --git a/contracts/DAO/LimboDAO.sol b/contracts/DAO/LimboDAO.sol index c7abc0c..eb7284a 100644 --- a/contracts/DAO/LimboDAO.sol +++ b/contracts/DAO/LimboDAO.sol @@ -103,8 +103,8 @@ contract LimboDAO is Ownable { ProposalState public currentProposalState; - // Since staking EYE precludes it from earning Flan on Limbo, fateToFlan can optionally be set to a non zero number to allow fat holders to spend their fate for Flan. - uint256 public fateToFlan; + // Since staking EYE precludes it from earning Flan on Limbo, flanPerFate can optionally be set to a non zero number to allow fat holders to spend their fate for Flan. + uint256 public flanPerFate; modifier isLive() { if (!domainConfig.live) { @@ -231,15 +231,15 @@ contract LimboDAO is Ownable { } // ///@notice optional conversion rate of Fate to Flan - function setFateToFlan(uint256 rate) public onlySuccessfulProposal { - fateToFlan = rate; + function setFlanPerFate(uint256 rate) public onlySuccessfulProposal { + flanPerFate = rate; } // ///@notice caller spends their Fate to earn Flan - function convertFateToFlan(uint256 fate) public returns (uint256 flan) { - if (fateToFlan == 0) revert FateToFlanConversionDisabled(); + function convertFlanPerFate(uint256 fate) public returns (uint256 flan) { + if (flanPerFate == 0) revert FlanPerFateConversionDisabled(); fateState[msg.sender].fateBalance -= fate; - flan = (fateToFlan * fate) / ONE; + flan = (flanPerFate * fate) / ONE; Flan(domainConfig.flan).mint(msg.sender, flan); } diff --git a/contracts/DAO/Proposals/TurnOnFateMintingProposal.sol b/contracts/DAO/Proposals/TurnOnFateMintingProposal.sol index f7c3bcc..6392ffd 100644 --- a/contracts/DAO/Proposals/TurnOnFateMintingProposal.sol +++ b/contracts/DAO/Proposals/TurnOnFateMintingProposal.sol @@ -20,7 +20,7 @@ contract TurnOnFateMintingProposal is Proposal { } function execute() internal override returns (bool) { - DAO.setFateToFlan(rate); + DAO.setFlanPerFate(rate); return true; } } diff --git a/contracts/UniswapHelper.sol b/contracts/UniswapHelper.sol index 4f7a9c9..17aa0c9 100644 --- a/contracts/UniswapHelper.sol +++ b/contracts/UniswapHelper.sol @@ -56,7 +56,7 @@ contract UniswapHelper is Governable, AMMHelper { uint256 constant EXA = 1e18; //needs to be updated for future Martian, Lunar and Venusian blockchains although I suspect Lunar colonies will be very Terracentric because of low time lag. - uint256 constant year = (1 days * 365); + uint256 constant year = 31536000; // seconds in 365 day year constructor(address _limbo, address limboDAO) Governable(limboDAO) { limbo = _limbo; diff --git a/contracts/facades/LimboDAOLike.sol b/contracts/facades/LimboDAOLike.sol index 1f0304f..8cd92af 100644 --- a/contracts/facades/LimboDAOLike.sol +++ b/contracts/facades/LimboDAOLike.sol @@ -58,5 +58,5 @@ abstract contract LimboDAOLike { address ); - function setFateToFlan(uint256 rate) public virtual; + function setFlanPerFate(uint256 rate) public virtual; } diff --git a/contracts/openzeppelin/ERC20Burnable.sol b/contracts/openzeppelin/ERC20Burnable.sol index dfd82f4..f4f4ec0 100644 --- a/contracts/openzeppelin/ERC20Burnable.sol +++ b/contracts/openzeppelin/ERC20Burnable.sol @@ -191,7 +191,7 @@ contract ERC20 is IERC20, IERC20Metadata { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][msg.sender]; - if (amount > currentAllowance) { + if (currentAllowance != type(uint).max && amount > currentAllowance) { revert AllowanceExceeded(currentAllowance, amount); } _approve(sender, msg.sender, currentAllowance - amount); diff --git a/contracts/periphery/Errors.sol b/contracts/periphery/Errors.sol index 3f0e8f4..61ca22c 100644 --- a/contracts/periphery/Errors.sol +++ b/contracts/periphery/Errors.sol @@ -59,7 +59,7 @@ error AssetMustBeEYE (address eye, address invalidAsset); error FlashGovernerNotSet(); error ProposalMismatch(address proposal, address currrentProposal); error OnlyProposalFactory(address msg_sender, address factory); -error FateToFlanConversionDisabled(); +error FlanPerFateConversionDisabled(); error UniswapV2FactoryMismatch (address pairFactory,address trueFactory); error InvalidVoteCast(int fateCast, int currentProposalFate); error VotingPeriodOver (uint blockTime,uint proposalStartTime,uint votingDuration); diff --git a/test/limbo.dao.proposals.test.ts b/test/limbo.dao.proposals.test.ts index 438fccb..8bb95cc 100644 --- a/test/limbo.dao.proposals.test.ts +++ b/test/limbo.dao.proposals.test.ts @@ -381,8 +381,6 @@ describe("DAO Proposals", function () { const fateAfterExecute = (await dao.fateState(owner.address))[1]; await expect(fateBeforeExecute).to.equal(fateBeforeExecute); - const decisionState = (await dao.previousProposalState())[1]; - expect(decisionState).to.equal(2); const configAfter = await dao.proposalConfig(); expect(configAfter[0].toString()).to.equal(configBefore[0].toString()); @@ -526,33 +524,33 @@ describe("DAO Proposals", function () { }); it("t12. trying to convert fate to flan without a rate mints zero flan", async function () { - await expect(dao.convertFateToFlan(1000)).to.be.revertedWith("FateToFlanConversionDisabled()"); + await expect(dao.convertFlanPerFate(1000)).to.be.revertedWith("FlanPerFateConversionDisabled()"); }); - it("t13. setting fateToFlan to positive number mints flan, depletes fate", async function () { - const FateToFlanProposal = await ethers.getContractFactory("TurnOnFateMintingProposal"); - const fateToFlanProposal = await FateToFlanProposal.deploy(dao.address, "minting"); - await fateToFlanProposal.parameterize("2000000000000000000"); + it("t13. setting flanPerFate to positive number mints flan, depletes fate", async function () { + const FlanPerFateProposal = await ethers.getContractFactory("TurnOnFateMintingProposal"); + const flanPerFateProposal = await FlanPerFateProposal.deploy(dao.address, "minting"); + await flanPerFateProposal.parameterize("2000000000000000000"); const requiredFate = (await dao.proposalConfig())[1]; await dao.burnAsset(eye.address, requiredFate, false); - await toggleWhiteList(fateToFlanProposal.address, this.whiteListingProposal); + await toggleWhiteList(flanPerFateProposal.address, this.whiteListingProposal); - await proposalFactory.lodgeProposal(fateToFlanProposal.address); + await proposalFactory.lodgeProposal(flanPerFateProposal.address); const fateAfterLodge = BigInt((await dao.fateState(owner.address))[1].toString()); const expectedFlan = fateAfterLodge * BigInt(2); await eye.transfer(secondPerson.address, "1000000000"); await eye.connect(secondPerson).approve(dao.address, "1000000000"); await dao.connect(secondPerson).burnAsset(eye.address, "1000000000", false); - await dao.connect(secondPerson).vote(fateToFlanProposal.address, "10000"); + await dao.connect(secondPerson).vote(flanPerFateProposal.address, "10000"); await advanceTime(259200); await dao.executeCurrentProposal(); - await dao.convertFateToFlan(fateAfterLodge); + await dao.convertFlanPerFate(fateAfterLodge); const flanBalance = (await this.flan.balanceOf(owner.address)).toString(); expect(flanBalance).to.equal(expectedFlan.toString()); From b9ba17d265569628538ce5e875ed94e8a5bbcea6 Mon Sep 17 00:00:00 2001 From: Justin Goro Date: Sun, 3 Jul 2022 06:33:25 +0200 Subject: [PATCH 4/7] added correct error messages to limbo tests --- contracts/DAO/LimboDAO.sol | 2 +- contracts/Limbo.sol | 16 +++++----- contracts/facades/FlanLike.sol | 2 ++ test/limbo.test.ts | 58 +++++++++++++++++----------------- 4 files changed, 40 insertions(+), 38 deletions(-) diff --git a/contracts/DAO/LimboDAO.sol b/contracts/DAO/LimboDAO.sol index eb7284a..7e485df 100644 --- a/contracts/DAO/LimboDAO.sol +++ b/contracts/DAO/LimboDAO.sol @@ -211,7 +211,7 @@ contract LimboDAO is Ownable { } for (uint256 i = 0; i < uniMetaLPs.length; i++) { if (IUniswapV2Pair(uniMetaLPs[i]).factory() != uniFactory) - revert UniswapV2FactoryMismatch(IUniswapV2Pair(uniMetaLPs[i]).factory(), sushiFactory); + revert UniswapV2FactoryMismatch(IUniswapV2Pair(uniMetaLPs[i]).factory(), uniFactory); _setApprovedAsset(uniMetaLPs[i], true, true, 0); } } diff --git a/contracts/Limbo.sol b/contracts/Limbo.sol index 0d5b1f4..cdcedb5 100644 --- a/contracts/Limbo.sol +++ b/contracts/Limbo.sol @@ -194,11 +194,11 @@ library MigrationLib { uint256 lpMinted = AMMHelper(crossingConfig.ammHelper).stabilizeFlan(scxBalance); //reward caller and update soul state - (bool noException, bytes memory result) = address(flan).call( - abi.encodeWithSignature("mint(address,uint)", msg.sender, crossingConfig.migrationInvocationReward) - ); - bool success = abi.decode(result, (bool)); - if (!noException || !success) { + uint256 flanOfCallerBefore = flan.balanceOf(msg.sender); + uint256 reward = crossingConfig.migrationInvocationReward; + flan.mint(msg.sender, reward); + uint256 change = flan.balanceOf(msg.sender) - flanOfCallerBefore; + if (change != reward) { revert InvocationRewardFailed(msg.sender); } @@ -256,7 +256,7 @@ contract Limbo is Governable { FlanLike Flan; modifier enabled() { - if(!protocolEnabled){ + if (!protocolEnabled) { revert ProtocolDisabled(); } _; @@ -272,8 +272,8 @@ contract Limbo is Governable { uint256 daiThreshold ) public governanceApproved(false) { Soul storage soul = currentSoul(token); - if(soul.soulType != SoulType.threshold){ - revert InvalidSoulType(token, uint(soul.soulType), uint(SoulType.threshold)); + if (soul.soulType != SoulType.threshold) { + revert InvalidSoulType(token, uint256(soul.soulType), uint256(SoulType.threshold)); } uint256 fps = AMMHelper(crossingConfig.ammHelper).minAPY_to_FPS(desiredAPY, daiThreshold); flashGoverner().enforceTolerance(soul.flanPerSecond, fps); diff --git a/contracts/facades/FlanLike.sol b/contracts/facades/FlanLike.sol index c178182..f167791 100644 --- a/contracts/facades/FlanLike.sol +++ b/contracts/facades/FlanLike.sol @@ -10,4 +10,6 @@ abstract contract FlanLike { function setBurnOnTransferFee(uint8 fee) public virtual; function burn(uint256 amount) public virtual returns (bool); + + function balanceOf(address holder) public virtual returns (uint); } diff --git a/test/limbo.test.ts b/test/limbo.test.ts index d3eb7cb..23fb017 100644 --- a/test/limbo.test.ts +++ b/test/limbo.test.ts @@ -444,11 +444,11 @@ describe.only("Limbo", function () { await this.limbo.endConfiguration(this.limboDAO.address); - await expect(this.limbo.configureSoul(this.aave.address, 10000000, 0, 0, 0, 10000000)).to.be.revertedWith("EJ"); + await expect(this.limbo.configureSoul(this.aave.address, 10000000, 0, 0, 0, 10000000)).to.be.revertedWith("GovernanceActionFailed"); await this.aave.transfer(this.limbo.address, 1000); // enableProtocol - await expect(this.limbo.enableProtocol()).to.be.revertedWith("ProtocolDisabled"); + await expect(this.limbo.enableProtocol()).to.be.revertedWith("GovernanceActionFailed"); // governanceShutdown // configureCrossingConfig await expect( @@ -460,20 +460,20 @@ describe.only("Limbo", function () { 10000000, 10000 ) - ).to.be.revertedWith("EJ"); + ).to.be.revertedWith("GovernanceActionFailed"); //governanceApproved: //disableProtocol - await expect(this.limbo.disableProtocol()).to.be.revertedWith("ERC20: transfer amount exceeds allowance"); - await expect(this.limbo.enableProtocol()).to.be.revertedWith("EJ"); + await expect(this.limbo.disableProtocol()).to.be.revertedWith("unrecognized custom error"); + await expect(this.limbo.enableProtocol()).to.be.revertedWith("GovernanceActionFailed"); //adjustSoul await expect(this.limbo.adjustSoul(this.aave.address, 1, 0, 10)).to.be.revertedWith( - "ERC20: transfer amount exceeds allowance" + "unrecognized custom error" ); //configureCrossingParameters await expect(this.limbo.configureCrossingParameters(this.aave.address, 1, 1, true, 10000010)).to.be.revertedWith( - "ERC20: transfer amount exceeds allowance" + "unrecognized custom error" ); }); @@ -640,7 +640,7 @@ describe.only("Limbo", function () { //try to adjust soul and fail await expect(this.limbo.adjustSoul(this.aave.address, 1, 10, 200)).to.be.revertedWith( - "ERC20: transfer amount exceeds allowance" + "unrecognized custom error" ); //stake requisite tokens, try again and succeed. @@ -670,7 +670,7 @@ describe.only("Limbo", function () { await this.limbo.configureCrossingParameters(this.aave.address, 1, 1, true, 10000010); await expect(this.flashGovernance.withdrawGovernanceAsset(this.limbo.address, this.eye.address)).to.be.revertedWith( - "Limbo: Flashgovernance decision pending." + "FlashDecisionPending" ); await advanceTime(604801); @@ -758,7 +758,7 @@ describe.only("Limbo", function () { //try to withdraw flash gov asset and fail. Assert money still there await expect(this.flashGovernance.withdrawGovernanceAsset(this.limbo.address, this.eye.address)).to.be.revertedWith( - "Limbo: Flashgovernance decision pending." + "FlashDecisionPending" ); //execute burn proposal @@ -955,8 +955,8 @@ describe.only("Limbo", function () { const soulStats = await soulReader.SoulStats(this.aave.address, this.limbo.address); expect(soulStats[0].toNumber()).to.equal(2); - await expect(this.limbo.stake(this.aave.address, "10000")).to.be.revertedWith("E2"); - await expect(this.limbo.unstake(this.aave.address, "10000")).to.be.revertedWith("E2"); + await expect(this.limbo.stake(this.aave.address, "10000")).to.be.revertedWith("InvalidSoulState"); + await expect(this.limbo.unstake(this.aave.address, "10000")).to.be.revertedWith("InvalidSoulState"); await updateSoulConfigProposal.parameterize( this.aave.address, //token @@ -1010,7 +1010,7 @@ describe.only("Limbo", function () { await advanceTime(6048010); await this.limboDAO.executeCurrentProposal(); - await expect(this.limbo.stake(this.aave.address, "10000")).to.be.revertedWith("E2"); + await expect(this.limbo.stake(this.aave.address, "10000")).to.be.revertedWith("InvalidSoulState"); const aaveBalance = await this.aave.balanceOf(this.limbo.address); await balanceCheck(); await this.limbo.unstake(this.aave.address, "500"); @@ -1029,10 +1029,10 @@ describe.only("Limbo", function () { 0, 10000000 ); - await expect(this.limbo.stake(this.titan.address, "10000")).to.be.revertedWith("E1"); + await expect(this.limbo.stake(this.titan.address, "10000")).to.be.revertedWith("InvalidSoul"); }); - it("t-15. unstaking amount larger than balance reverts with E4", async function () { + it("t-15. unstaking amount larger than balance reverts with ExcessiveWithdrawalRequest", async function () { await this.limbo.configureSoul( this.aave.address, 10000000, //crossingThreshold @@ -1047,10 +1047,10 @@ describe.only("Limbo", function () { await this.aave.approve(this.limbo.address, "10000001"); await this.limbo.stake(this.aave.address, "10000"); - await expect(this.limbo.unstake(this.aave.address, "10001")).to.be.revertedWith("E4"); + await expect(this.limbo.unstake(this.aave.address, "10001")).to.be.revertedWith("ExcessiveWithdrawalRequest"); }); - it("t-16. unstaking amount larger than balance reverts with E4", async function () { + it("t-16. unstaking amount larger than balance reverts with ExcessiveWithdrawalRequest", async function () { await this.limbo.configureSoul( this.aave.address, 10000000, //crossingThreshold @@ -1065,7 +1065,7 @@ describe.only("Limbo", function () { await this.aave.approve(this.limbo.address, "10000001"); await this.limbo.stake(this.aave.address, "10000"); - await expect(this.limbo.unstake(this.aave.address, "10001")).to.be.revertedWith("E4"); + await expect(this.limbo.unstake(this.aave.address, "10001")).to.be.revertedWith("ExcessiveWithdrawalRequest"); }); it("t-17. claiming staked reward resets unclaimed to zero", async function () { @@ -1107,7 +1107,7 @@ describe.only("Limbo", function () { await this.limbo.stake(this.aave.address, "10000"); await advanceTime(1000); - await expect(this.limbo.claimBonus(this.aave.address, 0)).to.be.revertedWith("E2"); + await expect(this.limbo.claimBonus(this.aave.address, 0)).to.be.revertedWith("InvalidSoulState"); }); it("t-19. claiming negative bonus fails", async function () { @@ -1129,7 +1129,7 @@ describe.only("Limbo", function () { await advanceTime(1000); await this.limbo.stake(this.aave.address, "2"); - await expect(this.limbo.claimBonus(this.aave.address, 0)).to.be.revertedWith("ED"); + await expect(this.limbo.claimBonus(this.aave.address, 0)).to.be.revertedWith("FlanBonusMustBePositive"); }); it("t-20. migration fails on not waitingToCross", async function () { @@ -1144,7 +1144,7 @@ describe.only("Limbo", function () { //stake tokens await this.aave.approve(this.limbo.address, "10000001"); await this.limbo.stake(this.aave.address, "10000"); - await expect(this.limbo.migrate(this.aave.address)).to.be.revertedWith("E2"); + await expect(this.limbo.migrate(this.aave.address)).to.be.revertedWith("InvalidSoulState"); }); it("t-21. only threshold souls can migrate", async function () { @@ -1195,7 +1195,7 @@ describe.only("Limbo", function () { await advanceTime(minQuoteWaitDuration + 1); //no longer explicit quote generation - await expect(this.limbo.migrate(this.aave.address)).to.be.revertedWith("EB"); + await expect(this.limbo.migrate(this.aave.address)).to.be.revertedWith("InvalidSoulType"); }); it("t-22. multiple migrations (STABILIZE) to real uniswap tilts price", async function () { @@ -1479,7 +1479,7 @@ describe.only("Limbo", function () { it("t-23. any whitelisted contract can mint flan", async function () { //assert secondPerson can't mint flan await expect(this.flan.connect(secondPerson).mint(owner.address, 1000)).to.be.revertedWith( - "Flan: Mint allowance exceeded" + "MintAllowanceExceeded" ); //whitelist secondPerson @@ -1495,7 +1495,7 @@ describe.only("Limbo", function () { //assert secondPerson can't mint flan await expect(this.flan.connect(secondPerson).mint(owner.address, 1000)).to.be.revertedWith( - "Flan: Mint allowance exceeded" + "MintAllowanceExceeded" ); }); @@ -1650,7 +1650,7 @@ describe.only("Limbo", function () { 1300, // 13% 0 //let helper figure this out ) - ).to.be.revertedWith("EI"); + ).to.be.revertedWith("InvalidSoulType"); }); it("t-26. attemptToTargetAPY sets fps correctly, use to test multiple token migrations", async function () { @@ -1887,7 +1887,7 @@ describe.only("Limbo", function () { await sushi.mint("10000"); await sushi.transfer(this.limbo.address, "10000"); - await expect(this.limbo.claimSecondaryRewards(sushi.address)).to.be.revertedWith("E7"); + await expect(this.limbo.claimSecondaryRewards(sushi.address)).to.be.revertedWith("TokenAccountedFor"); }); it("t-28. flash governance tolerance enforced for flash loan but not successful proposals or unconfigured", async function () { @@ -2146,7 +2146,7 @@ describe.only("Limbo", function () { 2000, // 13% 10000 ) - ).to.be.revertedWith("FE1"); + ).to.be.revertedWith("FlashToleranceViolated"); }); it("t-30. FOT token accounting handled correctly", async function () { @@ -2715,7 +2715,7 @@ describe.only("Limbo", function () { //stake requisite tokens, try again and succeed. await this.eye.approve(this.flashGovernance.address, 21000000); await expect(this.limbo.adjustSoul(this.aave.address, 20000000001, -1001, 10000001)).to.be.revertedWith( - "LIMBO: EP" + "FlashGovernanceDisabled" ); }); @@ -2774,7 +2774,7 @@ describe.only("Limbo", function () { if (newDepositRequirement < initialStakeAmount) contextString = "decreases"; else if (newDepositRequirement > initialStakeAmount) contextString = "increases"; - console.log("DEPOSIT REQUIREMENT BETWEEN FLASH LOANS " + contextString); + console.log("DFlashGovernanceDisabledOSIT REQUIREMENT BETWEEN FLASH LOANS " + contextString); //configure soul let result = await executionResult(this.limbo.configureSoul(this.aave.address, 10000000, 1, 1, 0, 10000000)); From 67b0c5eae104f7d5e2008c79813c03efd57bb01f Mon Sep 17 00:00:00 2001 From: Justin Goro Date: Sun, 3 Jul 2022 06:39:51 +0200 Subject: [PATCH 5/7] added event to unstake --- contracts/Limbo.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/Limbo.sol b/contracts/Limbo.sol index cdcedb5..06986f3 100644 --- a/contracts/Limbo.sol +++ b/contracts/Limbo.sol @@ -479,7 +479,8 @@ contract Limbo is Governable { revert InvalidSoulState(token, uint256(soul.state)); } updateSoul(token, soul); - User storage user = userInfo[token][holder][latestIndex[token]]; + uint index = latestIndex[token]; + User storage user = userInfo[token][holder][index]; if (user.stakedAmount < amount) { revert ExcessiveWithdrawalRequest(token, amount, user.stakedAmount); } @@ -489,6 +490,7 @@ contract Limbo is Governable { user.stakedAmount = user.stakedAmount - amount; IERC20(token).safeTransfer(address(unstaker), amount); rewardAdjustDebt(unstaker, pending, soul.accumulatedFlanPerShare, user); + emit ClaimedReward(unstaker, token, index, pending); emit Unstaked(unstaker, token, amount); } } From 5325afb2d8b54ba1b70e62e18640a701da4b7a84 Mon Sep 17 00:00:00 2001 From: Justin Goro Date: Mon, 4 Jul 2022 05:15:46 +0200 Subject: [PATCH 6/7] removed debugging clutter --- contracts/UniswapHelper.sol | 18 ++---------------- contracts/openzeppelin/IERC20.sol | 2 +- .../periphery/BehodlerLite/BehodlerLite.sol | 3 +-- .../BehodlerLite/LiquidityReceiver.sol | 4 +--- .../periphery/BehodlerLite/PyroWethProxy.sol | 6 +----- contracts/periphery/LimboOracle.sol | 2 -- .../periphery/UniswapV2/UniswapV2Router02.sol | 2 +- .../libraries/UniswapV2OracleLibrary.sol | 7 ++----- contracts/periphery/UniswapV2/test/ERC20.sol | 2 +- 9 files changed, 10 insertions(+), 36 deletions(-) diff --git a/contracts/UniswapHelper.sol b/contracts/UniswapHelper.sol index 17aa0c9..f20b1b6 100644 --- a/contracts/UniswapHelper.sol +++ b/contracts/UniswapHelper.sol @@ -114,10 +114,6 @@ contract UniswapHelper is Governable, AMMHelper { address fln_scx = VARS.factory.getPair(flan, behodler); address dai_scx = VARS.factory.getPair(VARS.DAI, behodler); address scx__fln_scx = VARS.factory.getPair(behodler, fln_scx); - // console.log("dai %s", VARS.DAI); - // console.log("fln_scx %s", fln_scx); - // console.log("dai_scx %s", dai_scx); - // console.log("scx__fln_scx %s", scx__fln_scx); address zero = address(0); @@ -168,18 +164,9 @@ contract UniswapHelper is Governable, AMMHelper { PriceTiltVARS memory priceTilting = getPriceTiltVARS(); uint256 transferredSCX = (mintedSCX * 98) / 100; uint256 finalSCXBalanceOnLP = (transferredSCX) + priceTilting.currentSCXInFLN_SCX; - // console.log( - // "finalSCXBalanceOnLP %s, currentSCXInFLN_SCX %s", - // finalSCXBalanceOnLP, - // priceTilting.currentSCXInFLN_SCX - // ); - // console.log( - // "actual balance of SCX in FLN_SCX %s", - // IERC20(VARS.behodler).balanceOf(address(VARS.oracleSet.fln_scx)) - // ); + uint256 DesiredFinalFlanOnLP = (finalSCXBalanceOnLP * priceTilting.FlanPerSCX) / SPOT; - // console.log("FlanPerSCX %s ", priceTilting.FlanPerSCX); - // console.log("desiredFlanOnLP %s", DesiredFinalFlanOnLP); + address pair = address(VARS.oracleSet.fln_scx); if (priceTilting.currentFLNInFLN_SCX < DesiredFinalFlanOnLP) { @@ -187,7 +174,6 @@ contract UniswapHelper is Governable, AMMHelper { (100 - VARS.priceBoostOvershoot)) / 100; flanToMint = flanToMint == 0 ? DesiredFinalFlanOnLP - priceTilting.currentFLNInFLN_SCX : flanToMint; FlanLike(VARS.flan).mint(pair, flanToMint); - // console.log("MINTED SCX %s, scx balance %s", transferredSCX, IERC20(VARS.behodler).balanceOf(address(this))); IERC20(VARS.behodler).transfer(pair, transferredSCX); { diff --git a/contracts/openzeppelin/IERC20.sol b/contracts/openzeppelin/IERC20.sol index cb0933a..2e7559c 100644 --- a/contracts/openzeppelin/IERC20.sol +++ b/contracts/openzeppelin/IERC20.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.13; import "../periphery/Errors.sol"; -import "hardhat/console.sol"; +// import "hardhat/console.sol"; /** * @dev Interface of the ERC20 standard as defined in the EIP. diff --git a/contracts/periphery/BehodlerLite/BehodlerLite.sol b/contracts/periphery/BehodlerLite/BehodlerLite.sol index 3c07ca3..3985071 100644 --- a/contracts/periphery/BehodlerLite/BehodlerLite.sol +++ b/contracts/periphery/BehodlerLite/BehodlerLite.sol @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.13; -import "hardhat/console.sol"; +// import "hardhat/console.sol"; import "./CommonIERC20.sol"; abstract contract Burnable { @@ -356,7 +356,6 @@ contract BehodlerLite is ScarcityLite { } modifier onlyValidToken(address token) { - if (!validTokens[token]) console.log("BEHODLER LITE: invalid token %s", token); require(lachesis == address(0) || validTokens[token], "BehodlerLite: tokenInvalid"); _; } diff --git a/contracts/periphery/BehodlerLite/LiquidityReceiver.sol b/contracts/periphery/BehodlerLite/LiquidityReceiver.sol index cec08bb..5b2ca71 100644 --- a/contracts/periphery/BehodlerLite/LiquidityReceiver.sol +++ b/contracts/periphery/BehodlerLite/LiquidityReceiver.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; -import "hardhat/console.sol"; +// import "hardhat/console.sol"; enum FeeExemption { NO_EXEMPTIONS, @@ -490,7 +490,6 @@ contract PyroToken is ERC20, ReentrancyGuard { //fee on transfer tokens uint256 trueTransfer = config.baseToken.balanceOf(address(this)) - initialBalance; uint256 pyro = ( ONE* trueTransfer) / _redeemRate; - console.log("minted pyro %s, baseTokenAmount %s", pyro, trueTransfer); _mint(recipient, pyro); emit Transfer(address(0), recipient, uint128(pyro), 0); return pyro; @@ -818,7 +817,6 @@ contract LiquidityReceiver is Ownable { } constructor(address _lachesis) { - console.log('lachesis %s',_lachesis); config.lachesis = LachesisLike(_lachesis); } diff --git a/contracts/periphery/BehodlerLite/PyroWethProxy.sol b/contracts/periphery/BehodlerLite/PyroWethProxy.sol index c55f7c1..d017b2f 100644 --- a/contracts/periphery/BehodlerLite/PyroWethProxy.sol +++ b/contracts/periphery/BehodlerLite/PyroWethProxy.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.13; -import "hardhat/console.sol"; +// import "hardhat/console.sol"; contract Ownable { address private _owner; @@ -599,10 +599,6 @@ contract WETH10 is IWETH10 { uint256 allowed = allowance[from][msg.sender]; if (allowed != type(uint256).max) { - if (allowed < value) { - console.log("FROM: %s TO: %s", from, to); - console.log("allowed: %s value: %s", allowed, value); - } require(allowed >= value, "WETH: request exceeds allowance"); uint256 reduced = allowed - value; allowance[from][msg.sender] = reduced; diff --git a/contracts/periphery/LimboOracle.sol b/contracts/periphery/LimboOracle.sol index f7c7d7d..37bc338 100644 --- a/contracts/periphery/LimboOracle.sol +++ b/contracts/periphery/LimboOracle.sol @@ -101,7 +101,6 @@ contract LimboOracle is Governable { address tokenOut, uint256 amountIn ) external view validPair(tokenIn, tokenOut) returns (uint256 amountOut) { - console.log("correct oracle"); IUniswapV2Pair pair = IUniswapV2Pair(factory.getPair(tokenIn, tokenOut)); PairMeasurement memory measurement = pairMeasurements[address(pair)]; @@ -114,7 +113,6 @@ contract LimboOracle is Governable { amountOut = (measurement.price1Average.mul(amountIn)).decode144(); } - console.log("In oracle amountOut %s", amountOut); if (amountOut == 0) { revert UpdateOracle(tokenIn, tokenOut, amountIn); } diff --git a/contracts/periphery/UniswapV2/UniswapV2Router02.sol b/contracts/periphery/UniswapV2/UniswapV2Router02.sol index 0cab75c..a35308a 100644 --- a/contracts/periphery/UniswapV2/UniswapV2Router02.sol +++ b/contracts/periphery/UniswapV2/UniswapV2Router02.sol @@ -4,7 +4,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; -import "hardhat/console.sol"; +// import "hardhat/console.sol"; interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint256 value); event Transfer(address indexed from, address indexed to, uint256 value); diff --git a/contracts/periphery/UniswapV2/libraries/UniswapV2OracleLibrary.sol b/contracts/periphery/UniswapV2/libraries/UniswapV2OracleLibrary.sol index 817044d..8b9858f 100644 --- a/contracts/periphery/UniswapV2/libraries/UniswapV2OracleLibrary.sol +++ b/contracts/periphery/UniswapV2/libraries/UniswapV2OracleLibrary.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.13; import "../interfaces/IUniswapV2Pair.sol"; import "../lib/FixedPoint.sol"; -import "hardhat/console.sol"; +// import "hardhat/console.sol"; // library with helper methods for oracles that are concerned with computing average prices library UniswapV2OracleLibrary { @@ -27,9 +27,7 @@ library UniswapV2OracleLibrary { blockTimestamp = currentBlockTimestamp(); price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast(); price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast(); - - uint price0Before = price0Cumulative; - uint price1Before = price1Cumulative; + // if time has elapsed since the last update on the pair, mock the accumulated price values (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = IUniswapV2Pair(pair).getReserves(); if (blockTimestampLast != blockTimestamp) { @@ -41,6 +39,5 @@ library UniswapV2OracleLibrary { // counterfactual price1Cumulative += uint256(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed; } - // console.log("counterfactual boost: price0Cumulative %s, price1Cumulative %s", price0Cumulative-price0Before, price1Cumulative-price1Before); } } diff --git a/contracts/periphery/UniswapV2/test/ERC20.sol b/contracts/periphery/UniswapV2/test/ERC20.sol index 3e8c842..82c66fd 100644 --- a/contracts/periphery/UniswapV2/test/ERC20.sol +++ b/contracts/periphery/UniswapV2/test/ERC20.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.13; import '../UniswapV2ERC20.sol'; contract ERC20 is UniswapV2ERC20 { - constructor(uint _totalSupply) public { + constructor(uint _totalSupply) { _mint(msg.sender, _totalSupply); } } From 1422434796dadacd05cf7b5381da683dede63797 Mon Sep 17 00:00:00 2001 From: Justin Goro Date: Mon, 4 Jul 2022 16:35:47 +0200 Subject: [PATCH 7/7] events and immutable --- contracts/DAO/FlashGovernanceArbiter.sol | 2 +- contracts/DAO/LimboDAO.sol | 8 ++++---- contracts/DAO/ProposalFactory.sol | 2 +- contracts/Limbo.sol | 16 ++++++++-------- contracts/facades/TokenProxyLike.sol | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/contracts/DAO/FlashGovernanceArbiter.sol b/contracts/DAO/FlashGovernanceArbiter.sol index 48cd1f5..9ff72b6 100644 --- a/contracts/DAO/FlashGovernanceArbiter.sol +++ b/contracts/DAO/FlashGovernanceArbiter.sol @@ -31,7 +31,7 @@ contract FlashGovernanceArbiter is Governable { * @param amount is the amount of the deposit_asset to be put up as decision collateral. * @param target is the contract that will be affected by the flash governance decision. */ - event flashDecision(address actor, address deposit_asset, uint256 amount, address target); + event flashDecision(address indexed actor, address indexed deposit_asset, uint256 amount, address indexed target); mapping(address => bool) enforceLimitsActive; diff --git a/contracts/DAO/LimboDAO.sol b/contracts/DAO/LimboDAO.sol index 7e485df..92fb0cd 100644 --- a/contracts/DAO/LimboDAO.sol +++ b/contracts/DAO/LimboDAO.sol @@ -80,11 +80,11 @@ struct AssetClout { contract LimboDAO is Ownable { using SafeERC20 for IERC20; event daoKilled(address newOwner); - event proposalLodged(address proposal, address proposer); - event voteCast(address voter, address proposal, int256 fateCast); + event proposalLodged(address indexed proposal, address indexed proposer); + event voteCast(address indexed voter, address indexed proposal, int256 fateCast); event assetApproval(address asset, bool appoved); - event proposalExecuted(address proposal, bool status); - event assetBurnt(address burner, address asset, uint256 fateCreated); + event proposalExecuted(address indexed proposal, bool status); + event assetBurnt(address indexed burner, address indexed asset, uint256 fateCreated); uint256 constant ONE = 1 ether; diff --git a/contracts/DAO/ProposalFactory.sol b/contracts/DAO/ProposalFactory.sol index 71b7531..1a09096 100644 --- a/contracts/DAO/ProposalFactory.sol +++ b/contracts/DAO/ProposalFactory.sol @@ -13,7 +13,7 @@ import "../periphery/Errors.sol"; abstract contract Proposal { string public description; bool public locked; - LimboDAOLike DAO; + LimboDAOLike immutable DAO; constructor(address dao, string memory _description) { DAO = LimboDAOLike(dao); diff --git a/contracts/Limbo.sol b/contracts/Limbo.sol index 06986f3..7cc17f7 100644 --- a/contracts/Limbo.sol +++ b/contracts/Limbo.sol @@ -217,14 +217,14 @@ contract Limbo is Governable { using MigrationLib for address; using CrossingLib for CrossingParameters; - event SoulUpdated(address soul, uint256 fps); - event Staked(address staker, address soul, uint256 amount); - event Unstaked(address staker, address soul, uint256 amount); - event TokenListed(address token, uint256 amount, uint256 scxfln_LP_minted); + event SoulUpdated(address indexed soul, uint256 fps); + event Staked(address indexed staker, address indexed soul, uint256 amount); + event Unstaked(address indexed staker, address indexed soul, uint256 amount); + event TokenListed(address indexed token, uint256 amount, uint256 scxfln_LP_minted); - event ClaimedReward(address staker, address soul, uint256 index, uint256 amount); + event ClaimedReward(address indexed staker, address indexed soul, uint256 index, uint256 amount); - event BonusPaid(address token, uint256 index, address recipient, uint256 bonus); + event BonusPaid(address indexed token, uint256 index, address indexed recipient, uint256 bonus); struct User { uint256 stakedAmount; @@ -253,7 +253,7 @@ contract Limbo is Governable { ///@dev soul->owner->unstaker->amount mapping(address => mapping(address => mapping(address => uint256))) public unstakeApproval; - FlanLike Flan; + FlanLike immutable Flan; modifier enabled() { if (!protocolEnabled) { @@ -479,7 +479,7 @@ contract Limbo is Governable { revert InvalidSoulState(token, uint256(soul.state)); } updateSoul(token, soul); - uint index = latestIndex[token]; + uint256 index = latestIndex[token]; User storage user = userInfo[token][holder][index]; if (user.stakedAmount < amount) { revert ExcessiveWithdrawalRequest(token, amount, user.stakedAmount); diff --git a/contracts/facades/TokenProxyLike.sol b/contracts/facades/TokenProxyLike.sol index a7e6eed..87f13ee 100644 --- a/contracts/facades/TokenProxyLike.sol +++ b/contracts/facades/TokenProxyLike.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.13; abstract contract TokenProxyLike { - address internal baseToken; + address internal immutable baseToken; uint constant internal ONE = 1 ether; constructor (address _baseToken) { baseToken=_baseToken;