Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C4 audit fixes #33

Merged
merged 7 commits into from
Jul 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion contracts/DAO/FlashGovernanceArbiter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
28 changes: 13 additions & 15 deletions contracts/DAO/LimboDAO.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -102,10 +102,9 @@ 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;
// 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) {
Expand All @@ -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;
Expand Down Expand Up @@ -213,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);
}
}
Expand All @@ -233,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);
}

Expand Down Expand Up @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion contracts/DAO/ProposalFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion contracts/DAO/Proposals/TurnOnFateMintingProposal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ contract TurnOnFateMintingProposal is Proposal {
}

function execute() internal override returns (bool) {
DAO.setFateToFlan(rate);
DAO.setFlanPerFate(rate);
return true;
}
}
35 changes: 18 additions & 17 deletions contracts/Limbo.sol
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -195,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);
}

Expand All @@ -218,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;
Expand Down Expand Up @@ -254,10 +253,10 @@ 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){
if (!protocolEnabled) {
revert ProtocolDisabled();
}
_;
Expand All @@ -273,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);
Expand Down Expand Up @@ -480,7 +479,8 @@ contract Limbo is Governable {
revert InvalidSoulState(token, uint256(soul.state));
}
updateSoul(token, soul);
User storage user = userInfo[token][holder][latestIndex[token]];
uint256 index = latestIndex[token];
User storage user = userInfo[token][holder][index];
if (user.stakedAmount < amount) {
revert ExcessiveWithdrawalRequest(token, amount, user.stakedAmount);
}
Expand All @@ -490,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);
}
}
Expand Down
20 changes: 3 additions & 17 deletions contracts/UniswapHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -168,26 +164,16 @@ 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) {
uint256 flanToMint = ((DesiredFinalFlanOnLP - priceTilting.currentFLNInFLN_SCX) *
(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);
{
Expand Down
2 changes: 2 additions & 0 deletions contracts/facades/FlanLike.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 1 addition & 1 deletion contracts/facades/LimboDAOLike.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,5 @@ abstract contract LimboDAOLike {
address
);

function setFateToFlan(uint256 rate) public virtual;
function setFlanPerFate(uint256 rate) public virtual;
}
2 changes: 1 addition & 1 deletion contracts/facades/TokenProxyLike.sol
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
2 changes: 1 addition & 1 deletion contracts/openzeppelin/ERC20Burnable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion contracts/openzeppelin/IERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 1 addition & 2 deletions contracts/periphery/BehodlerLite/BehodlerLite.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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");
_;
}
Expand Down
4 changes: 1 addition & 3 deletions contracts/periphery/BehodlerLite/LiquidityReceiver.sol
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -818,7 +817,6 @@ contract LiquidityReceiver is Ownable {
}

constructor(address _lachesis) {
console.log('lachesis %s',_lachesis);
config.lachesis = LachesisLike(_lachesis);
}

Expand Down
6 changes: 1 addition & 5 deletions contracts/periphery/BehodlerLite/PyroWethProxy.sol
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion contracts/periphery/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 0 additions & 2 deletions contracts/periphery/LimboOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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)];

Expand All @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/periphery/UniswapV2/UniswapV2Router02.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading