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

Size limits & Gas Improvements #181

Merged
merged 4 commits into from
Oct 5, 2023
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
9 changes: 1 addition & 8 deletions src/BaseGauge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ pragma solidity ^0.8.15;

import "src/libraries/Math.sol";
import "src/interfaces/IBribe.sol";
import "src/interfaces/IGaugeFactory.sol";
import "src/interfaces/IBaseGauge.sol";
import "src/interfaces/IVoter.sol";
import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
Expand Down Expand Up @@ -39,7 +38,7 @@ abstract contract BaseGauge is IBaseGauge {
View functions
*/

function getVotingStage(uint256 timestamp) public pure returns (VotingStage) {
function getVotingStage(uint256 timestamp) external pure returns (VotingStage) {
uint256 modTime = timestamp % (1 weeks);
if (modTime < BRIBE_LAG) {
return VotingStage.BribesPhase;
Expand Down Expand Up @@ -100,12 +99,6 @@ abstract contract BaseGauge is IBaseGauge {
require(success && (data.length == 0 || abi.decode(data, (bool))));
}

function _safeApprove(address token, address spender, uint256 value) internal {
require(token.code.length > 0);
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, spender, value));
require(success && (data.length == 0 || abi.decode(data, (bool))));
}

/**
* @notice Override function to implement passthrough logic
* @param _amount Amount of rewards
Expand Down
7 changes: 4 additions & 3 deletions src/Bribe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ contract Bribe is IBribe {
uint256 public supplyNumCheckpoints;
uint256 public totalSupply;

address public veALCX;
address public voter;
address public immutable veALCX;
address public immutable voter;
address public gauge; // Address of the gauge that the bribes are for
address[] public rewards;

Expand Down Expand Up @@ -250,7 +250,8 @@ contract Bribe is IBribe {
function getRewardForOwner(uint256 tokenId, address[] memory tokens) external lock {
require(msg.sender == voter, "not voter");
address _owner = IVotingEscrow(veALCX).ownerOf(tokenId);
for (uint256 i = 0; i < tokens.length; i++) {
uint256 length = tokens.length;
for (uint256 i = 0; i < length; i++) {
uint256 _reward = earned(tokens[i], tokenId);

require(_reward > 0, "no rewards to claim");
Expand Down
10 changes: 3 additions & 7 deletions src/CurveEthPoolAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,14 @@ import "src/libraries/TokenUtils.sol";
import "src/interfaces/IWETH9.sol";

contract CurveEthPoolAdapter is IPoolAdapter {
address public override pool;
address public immutable override pool;

mapping(address => int128) public tokenIds;
bool public isMetapool;

address public weth;
address public immutable weth;

constructor(
address _pool,
address[] memory _tokens,
address _weth
) {
constructor(address _pool, address[] memory _tokens, address _weth) {
weth = _weth;
pool = _pool;
for (uint256 i; i < _tokens.length; i++) {
Expand Down
77 changes: 77 additions & 0 deletions src/FluxToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.15;

import "src/interfaces/IFluxToken.sol";
import "src/interfaces/IVotingEscrow.sol";
import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";

Expand All @@ -14,10 +15,19 @@ contract FluxToken is ERC20("Flux", "FLUX"), IFluxToken {

/// @dev The address which enables the minting of tokens.
address public minter;
address public voter;
address public veALCX;
address public admin; // the timelock executor
address public pendingAdmin; // the timelock executor

mapping(uint256 => uint256) public unclaimedFlux; // tokenId => amount of unclaimed flux

constructor(address _minter) {
require(_minter != address(0), "FluxToken: minter cannot be zero address");
minter = _minter;
voter = _minter;
veALCX = _minter;
admin = _minter;
}

/// @dev Modifier which checks that the caller has the minter role.
Expand All @@ -26,6 +36,33 @@ contract FluxToken is ERC20("Flux", "FLUX"), IFluxToken {
_;
}

/// @inheritdoc IFluxToken
function setAdmin(address _admin) external {
require(msg.sender == admin, "not admin");
pendingAdmin = _admin;
}

/// @inheritdoc IFluxToken
function acceptAdmin() external {
require(msg.sender == pendingAdmin, "not pending admin");
admin = pendingAdmin;
emit AdminUpdated(pendingAdmin);
}

/// @inheritdoc IFluxToken
function setVoter(address _voter) external {
require(msg.sender == admin, "not admin");
require(_voter != address(0), "FluxToken: voter cannot be zero address");
voter = _voter;
}

/// @inheritdoc IFluxToken
function setVeALCX(address _veALCX) external {
require(msg.sender == admin, "not admin");
require(_veALCX != address(0), "FluxToken: veALCX cannot be zero address");
veALCX = _veALCX;
}

/// @inheritdoc IFluxToken
function setMinter(address _minter) external onlyMinter {
require(_minter != address(0), "FluxToken: minter cannot be zero address");
Expand All @@ -44,4 +81,44 @@ contract FluxToken is ERC20("Flux", "FLUX"), IFluxToken {
_approve(_account, msg.sender, newAllowance);
_burn(_account, _amount);
}

/// @inheritdoc IFluxToken
function getUnclaimedFlux(uint256 _tokenId) external view returns (uint256) {
return unclaimedFlux[_tokenId];
}

/// @inheritdoc IFluxToken
function mergeFlux(uint256 _fromTokenId, uint256 _toTokenId) external {
require(msg.sender == veALCX, "not veALCX");

unclaimedFlux[_toTokenId] += unclaimedFlux[_fromTokenId];
unclaimedFlux[_fromTokenId] = 0;
}

/// @inheritdoc IFluxToken
function accrueFlux(uint256 _tokenId) external {
require(msg.sender == voter, "not voter");
uint256 amount = IVotingEscrow(veALCX).claimableFlux(_tokenId);
unclaimedFlux[_tokenId] += amount;
}

/// @inheritdoc IFluxToken
function updateFlux(uint256 _tokenId, uint256 _amount) external {
require(msg.sender == voter, "not voter");
require(_amount <= unclaimedFlux[_tokenId], "not enough flux");
unclaimedFlux[_tokenId] -= _amount;
}

/// @inheritdoc IFluxToken
function claimFlux(uint256 _tokenId, uint256 _amount) external {
require(unclaimedFlux[_tokenId] >= _amount, "amount greater than unclaimed balance");

if (msg.sender != veALCX) {
require(IVotingEscrow(veALCX).isApprovedOrOwner(msg.sender, _tokenId), "not approved");
}

unclaimedFlux[_tokenId] -= _amount;

_mint(IVotingEscrow(veALCX).ownerOf(_tokenId), _amount);
}
}
14 changes: 5 additions & 9 deletions src/Minter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ contract Minter is IMinter {
using SafeMath for uint256;

// Allows minting once per epoch (epoch = 1 week, reset every Thursday 00:00 UTC)
uint256 public constant WEEK = 1 weeks;
uint256 public immutable WEEK = 1 weeks;
uint256 public immutable BPS = 10_000;
uint256 public constant TAIL_EMISSIONS_RATE = 2194e18; // Tail emissions rate
uint256 public constant BPS = 10_000;

uint256 public epochEmissions;
uint256 public activePeriod;
Expand All @@ -39,9 +39,7 @@ contract Minter is IMinter {
address public initializer;
address public treasury;

bool public initialized;

IAlchemixToken public alcx;
IAlchemixToken public immutable alcx;
IVoter public immutable voter;
IVotingEscrow public immutable ve;
IRewardsDistributor public immutable rewardsDistributor;
Expand Down Expand Up @@ -87,11 +85,9 @@ contract Minter is IMinter {
}

function initialize() external {
require(msg.sender != address(0), "cannot be zero address");
require(initialized == false, "already initialized");
require(initializer == msg.sender, "not initializer");
require(msg.sender != address(0), "already initialized");
initializer = address(0);
initialized = true;
}

/*
Expand Down Expand Up @@ -173,7 +169,7 @@ contract Minter is IMinter {

revenueHandler.checkpoint();

emit Mint(msg.sender, epochEmissions, circulatingEmissionsSupply());
emit Mint(msg.sender, epochEmissions, supply);
}
return period;
}
Expand Down
35 changes: 18 additions & 17 deletions src/RevenueHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ contract RevenueHandler is IRevenueHandler, Ownable {
uint256 internal constant WEEK = 1 weeks;
uint256 internal constant BPS = 10_000;

address public veALCX;
address public immutable veALCX;
address[] public revenueTokens;
mapping(address => bool) public alchemicTokens; // token => is alchemic-token (true/false)
mapping(address => RevenueTokenConfig) public revenueTokenConfigs; // token => RevenueTokenConfig
Expand Down Expand Up @@ -83,7 +83,8 @@ contract RevenueHandler is IRevenueHandler, Ownable {

/// @inheritdoc IRevenueHandler
function addRevenueToken(address revenueToken) external override onlyOwner {
for (uint256 i = 0; i < revenueTokens.length; i++) {
uint256 length = revenueTokens.length;
for (uint256 i = 0; i < length; i++) {
if (revenueTokens[i] == revenueToken) {
revert("revenue token already exists");
}
Expand All @@ -94,9 +95,10 @@ contract RevenueHandler is IRevenueHandler, Ownable {

/// @inheritdoc IRevenueHandler
function removeRevenueToken(address revenueToken) external override onlyOwner {
for (uint256 i = 0; i < revenueTokens.length; i++) {
uint256 length = revenueTokens.length;
for (uint256 i = 0; i < length; i++) {
if (revenueTokens[i] == revenueToken) {
revenueTokens[i] = revenueTokens[revenueTokens.length - 1];
revenueTokens[i] = revenueTokens[length - 1];
revenueTokens.pop();
emit RevenueTokenTokenRemoved(revenueToken);
return;
Expand Down Expand Up @@ -211,41 +213,40 @@ contract RevenueHandler is IRevenueHandler, Ownable {
if (block.timestamp >= currentEpoch + WEEK /* && initializer == address(0) */) {
currentEpoch = (block.timestamp / WEEK) * WEEK;

for (uint256 i = 0; i < revenueTokens.length; i++) {
uint256 length = revenueTokens.length;
for (uint256 i = 0; i < length; i++) {
// These will be zero if the revenue token is not an alchemic-token
uint256 treasuryAmt = 0;
uint256 amountReceived = 0;
address token = revenueTokens[i];

RevenueTokenConfig memory tokenConfig = revenueTokenConfigs[token];

// If a revenue token is disabled, skip it.
if (revenueTokenConfigs[token].disabled) continue;
if (tokenConfig.disabled) continue;

uint256 thisBalance = IERC20(token).balanceOf(address(this));

// If poolAdapter is set, the revenue token is an alchemic-token
if (revenueTokenConfigs[token].poolAdapter != address(0)) {
if (tokenConfig.poolAdapter != address(0)) {
// Treasury only receives revenue if the token is an alchemic-token
treasuryAmt = (IERC20(token).balanceOf(address(this)) * treasuryPct) / BPS;
treasuryAmt = (thisBalance * treasuryPct) / BPS;
IERC20(token).safeTransfer(treasury, treasuryAmt);

// Only melt if there is an alchemic-token to melt to
amountReceived = _melt(token);

// Update amount of alchemic-token revenue received for this epoch
epochRevenues[currentEpoch][revenueTokenConfigs[token].debtToken] += amountReceived;
epochRevenues[currentEpoch][tokenConfig.debtToken] += amountReceived;
} else {
// If the revenue token doesn't have a poolAdapter, it is not an alchemic-token
amountReceived = IERC20(token).balanceOf(address(this));
amountReceived = thisBalance;

// Update amount of non-alchemic-token revenue received for this epoch
epochRevenues[currentEpoch][token] += amountReceived;
}

emit RevenueRealized(
currentEpoch,
token,
revenueTokenConfigs[revenueTokens[i]].debtToken,
amountReceived,
treasuryAmt
);
emit RevenueRealized(currentEpoch, token, tokenConfig.debtToken, amountReceived, treasuryAmt);
}
}
}
Expand Down
Loading
Loading