Skip to content

Commit

Permalink
Merge pull request #181 from alchemix-finance/size-limits
Browse files Browse the repository at this point in the history
Size limits & Gas Improvements
  • Loading branch information
toyv0 authored Oct 5, 2023
2 parents f955626 + f7b22c4 commit 45da953
Show file tree
Hide file tree
Showing 22 changed files with 574 additions and 446 deletions.
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

0 comments on commit 45da953

Please sign in to comment.