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

Master - no fees #38

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
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
28 changes: 0 additions & 28 deletions contracts/solidity/NFTXInventoryStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import "./proxy/UpgradeableBeacon.sol";
import "./proxy/Create2BeaconProxy.sol";
import "./token/XTokenUpgradeable.sol";
import "./interface/ITimelockExcludeList.sol";
import "./interface/INFTXSimpleFeeDistributor.sol";

// Author: 0xKiwi.

Expand Down Expand Up @@ -121,7 +120,6 @@ contract NFTXInventoryStaking is PausableUpgradeable, UpgradeableBeacon, INFTXIn
// Leave the bar. Claim back your tokens.
// Unlocks the staked + gained tokens and burns xTokens.
function withdraw(uint256 vaultId, uint256 _share) external virtual override {
_distributeFees(vaultId);
IERC20Upgradeable baseToken = IERC20Upgradeable(nftxVaultFactory.vault(vaultId));
XTokenUpgradeable xToken = XTokenUpgradeable(xTokenAddr(address(baseToken)));

Expand Down Expand Up @@ -169,8 +167,6 @@ contract NFTXInventoryStaking is PausableUpgradeable, UpgradeableBeacon, INFTXIn
IERC20Upgradeable baseToken = IERC20Upgradeable(nftxVaultFactory.vault(vaultId));
XTokenUpgradeable xToken = XTokenUpgradeable((xTokenAddr(address(baseToken))));

_distributeFees(vaultId);

uint256 xTokensMinted = xToken.mintXTokens(account, _amount, timelockLength);
return (baseToken, xToken, xTokensMinted);
}
Expand All @@ -194,28 +190,4 @@ contract NFTXInventoryStaking is PausableUpgradeable, UpgradeableBeacon, INFTXIn
assembly { size := extcodesize(account) }
return size != 0;
}

function _distributeFees(uint256 vaultId) internal {
INFTXSimpleFeeDistributor(nftxVaultFactory.feeDistributor()).distribute(vaultId);
}

function totalUndistributedFees(uint256 vaultId) public view returns (uint256) {
INFTXSimpleFeeDistributor feeDistrib = INFTXSimpleFeeDistributor(nftxVaultFactory.feeDistributor());
(address receiverAddr, uint256 receiverAlloc) = feeDistrib.feeReceiverInfo(1);
require(receiverAddr == address(this), "wrong index");
// TODO: fetch allocationtotal from fee distributor
return IERC20Upgradeable(nftxVaultFactory.vault(vaultId)).balanceOf(nftxVaultFactory.feeDistributor()) * receiverAlloc / 1e18;
}

function adjustedXTokenShareValue(uint256 vaultId) public view returns (uint256) {
IERC20Upgradeable baseToken = IERC20Upgradeable(nftxVaultFactory.vault(vaultId));
XTokenUpgradeable xToken = XTokenUpgradeable(xTokenAddr(address(baseToken)));
require(address(xToken) != address(0), "XToken not deployed");

uint256 multiplier = 10 ** 18;
uint256 adjustedBaseTokenBal = baseToken.balanceOf(address(xToken)) + totalUndistributedFees(vaultId);
return xToken.totalSupply() > 0
? multiplier * adjustedBaseTokenBal / xToken.totalSupply()
: multiplier;
}
}
172 changes: 67 additions & 105 deletions contracts/solidity/NFTXLPStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import "./util/Address.sol";
import "./proxy/ClonesUpgradeable.sol";
import "./StakingTokenProvider.sol";
import "./token/TimelockRewardDistributionTokenImpl.sol";
import "./interface/INFTXSimpleFeeDistributor.sol";
import "./interface/INFTXVault.sol";

// Author: 0xKiwi.

Expand Down Expand Up @@ -123,8 +121,6 @@ contract NFTXLPStaking is PausableUpgradeable {
// Check the pool in case its been updated.
updatePoolForVault(vaultId);

_distributeFees(vaultId);

StakingPool memory pool = vaultStakingInfo[vaultId];
require(pool.stakingToken != address(0), "LPStaking: Nonexistent pool");
IERC20Upgradeable(pool.stakingToken).safeTransferFrom(msg.sender, address(this), amount);
Expand All @@ -149,9 +145,6 @@ contract NFTXLPStaking is PausableUpgradeable {
onlyOwnerIfPaused(10);
// Check the pool in case its been updated.
updatePoolForVault(vaultId);

_distributeFees(vaultId);

StakingPool memory pool = vaultStakingInfo[vaultId];
require(pool.stakingToken != address(0), "LPStaking: Nonexistent pool");
IERC20Upgradeable(pool.stakingToken).safeTransferFrom(msg.sender, address(this), amount);
Expand All @@ -160,7 +153,6 @@ contract NFTXLPStaking is PausableUpgradeable {

function exit(uint256 vaultId) external {
StakingPool memory pool = vaultStakingInfo[vaultId];
_distributeFees(vaultId);
_claimRewards(pool, msg.sender);
_withdraw(pool, balanceOf(vaultId, msg.sender), msg.sender);
}
Expand All @@ -169,7 +161,6 @@ contract NFTXLPStaking is PausableUpgradeable {
StakingPool memory pool = StakingPool(_stakingToken, _rewardToken);
TimelockRewardDistributionTokenImpl dist = _rewardDistributionTokenAddr(pool);
require(isContract(address(dist)), "Not a pool");
_distributeFees(INFTXVault(_rewardToken).vaultId());
_claimRewards(pool, msg.sender);
_withdraw(pool, dist.balanceOf(msg.sender), msg.sender);
}
Expand All @@ -181,47 +172,45 @@ contract NFTXLPStaking is PausableUpgradeable {
_withdraw(pool, dist.balanceOf(msg.sender), msg.sender);
}

// function emergencyMigrate(uint256 vaultId) external {
// StakingPool memory pool = vaultStakingInfo[vaultId];
// IRewardDistributionToken unusedDist = _unusedRewardDistributionTokenAddr(pool);
// IRewardDistributionToken oldDist = _oldRewardDistributionTokenAddr(pool);

// uint256 unusedDistBal;
// if (isContract(address(unusedDist))) {
// unusedDistBal = unusedDist.balanceOf(msg.sender);
// if (unusedDistBal > 0) {
// unusedDist.burnFrom(msg.sender, unusedDistBal);
// }
// }
// uint256 oldDistBal;
// if (isContract(address(oldDist))) {
// oldDistBal = oldDist.balanceOf(msg.sender);
// if (oldDistBal > 0) {
// oldDist.withdrawReward(msg.sender);
// oldDist.burnFrom(msg.sender, oldDistBal);
// }
// }
function emergencyMigrate(uint256 vaultId) external {
StakingPool memory pool = vaultStakingInfo[vaultId];
IRewardDistributionToken unusedDist = _unusedRewardDistributionTokenAddr(pool);
IRewardDistributionToken oldDist = _oldRewardDistributionTokenAddr(pool);

uint256 unusedDistBal;
if (isContract(address(unusedDist))) {
unusedDistBal = unusedDist.balanceOf(msg.sender);
if (unusedDistBal > 0) {
unusedDist.burnFrom(msg.sender, unusedDistBal);
}
}
uint256 oldDistBal;
if (isContract(address(oldDist))) {
oldDistBal = oldDist.balanceOf(msg.sender);
if (oldDistBal > 0) {
oldDist.withdrawReward(msg.sender);
oldDist.burnFrom(msg.sender, oldDistBal);
}
}

// TimelockRewardDistributionTokenImpl newDist = _rewardDistributionTokenAddr(pool);
// if (!isContract(address(newDist))) {
// address deployedDist = _deployDividendToken(pool);
// require(deployedDist == address(newDist), "Not deploying proper distro");
// emit PoolUpdated(vaultId, deployedDist);
// }
// require(unusedDistBal + oldDistBal > 0, "Nothing to migrate");
// newDist.mint(msg.sender, unusedDistBal + oldDistBal);
// }
TimelockRewardDistributionTokenImpl newDist = _rewardDistributionTokenAddr(pool);
if (!isContract(address(newDist))) {
address deployedDist = _deployDividendToken(pool);
require(deployedDist == address(newDist), "Not deploying proper distro");
emit PoolUpdated(vaultId, deployedDist);
}
require(unusedDistBal + oldDistBal > 0, "Nothing to migrate");
newDist.mint(msg.sender, unusedDistBal + oldDistBal);
}

function withdraw(uint256 vaultId, uint256 amount) external {
StakingPool memory pool = vaultStakingInfo[vaultId];
_distributeFees(vaultId);
_claimRewards(pool, msg.sender);
_withdraw(pool, amount, msg.sender);
}

function claimRewards(uint256 vaultId) public {
StakingPool memory pool = vaultStakingInfo[vaultId];
_distributeFees(vaultId);
_claimRewards(pool, msg.sender);
}

Expand All @@ -240,29 +229,29 @@ contract NFTXLPStaking is PausableUpgradeable {
return _rewardDistributionTokenAddr(pool);
}

// function rewardDistributionToken(uint256 vaultId) external view returns (IRewardDistributionToken) {
// StakingPool memory pool = vaultStakingInfo[vaultId];
// if (pool.stakingToken == address(0)) {
// return IRewardDistributionToken(address(0));
// }
// return _unusedRewardDistributionTokenAddr(pool);
// }

// function oldRewardDistributionToken(uint256 vaultId) external view returns (address) {
// StakingPool memory pool = vaultStakingInfo[vaultId];
// if (pool.stakingToken == address(0)) {
// return address(0);
// }
// return address(_oldRewardDistributionTokenAddr(pool));
// }

// function unusedRewardDistributionToken(uint256 vaultId) external view returns (address) {
// StakingPool memory pool = vaultStakingInfo[vaultId];
// if (pool.stakingToken == address(0)) {
// return address(0);
// }
// return address(_unusedRewardDistributionTokenAddr(pool));
// }
function rewardDistributionToken(uint256 vaultId) external view returns (IRewardDistributionToken) {
StakingPool memory pool = vaultStakingInfo[vaultId];
if (pool.stakingToken == address(0)) {
return IRewardDistributionToken(address(0));
}
return _unusedRewardDistributionTokenAddr(pool);
}

function oldRewardDistributionToken(uint256 vaultId) external view returns (address) {
StakingPool memory pool = vaultStakingInfo[vaultId];
if (pool.stakingToken == address(0)) {
return address(0);
}
return address(_oldRewardDistributionTokenAddr(pool));
}

function unusedRewardDistributionToken(uint256 vaultId) external view returns (address) {
StakingPool memory pool = vaultStakingInfo[vaultId];
if (pool.stakingToken == address(0)) {
return address(0);
}
return address(_unusedRewardDistributionTokenAddr(pool));
}

function rewardDistributionTokenAddr(address stakedToken, address rewardToken) public view returns (address) {
StakingPool memory pool = StakingPool(stakedToken, rewardToken);
Expand All @@ -276,19 +265,19 @@ contract NFTXLPStaking is PausableUpgradeable {
return dist.balanceOf(addr);
}

/* function oldBalanceOf(uint256 vaultId, address addr) public view returns (uint256) {
function oldBalanceOf(uint256 vaultId, address addr) public view returns (uint256) {
StakingPool memory pool = vaultStakingInfo[vaultId];
IRewardDistributionToken dist = _oldRewardDistributionTokenAddr(pool);
require(isContract(address(dist)), "Not a pool");
return dist.balanceOf(addr);
} */
}

/* function unusedBalanceOf(uint256 vaultId, address addr) public view returns (uint256) {
function unusedBalanceOf(uint256 vaultId, address addr) public view returns (uint256) {
StakingPool memory pool = vaultStakingInfo[vaultId];
IRewardDistributionToken dist = _unusedRewardDistributionTokenAddr(pool);
require(isContract(address(dist)), "Not a pool");
return dist.balanceOf(addr);
} */
}

function lockedUntil(uint256 vaultId, address who) external view returns (uint256) {
StakingPool memory pool = vaultStakingInfo[vaultId];
Expand Down Expand Up @@ -332,22 +321,18 @@ contract NFTXLPStaking is PausableUpgradeable {
return TimelockRewardDistributionTokenImpl(tokenAddr);
}

// // Note: this function does not guarantee the token is deployed, we leave that check to elsewhere to save gas.
// function _oldRewardDistributionTokenAddr(StakingPool memory pool) public view returns (IRewardDistributionToken) {
// bytes32 salt = keccak256(abi.encodePacked(pool.stakingToken, pool.rewardToken, uint256(1)));
// address tokenAddr = ClonesUpgradeable.predictDeterministicAddress(address(rewardDistTokenImpl), salt);
// return IRewardDistributionToken(tokenAddr);
// }

// // Note: this function does not guarantee the token is deployed, we leave that check to elsewhere to save gas.
// function _unusedRewardDistributionTokenAddr(StakingPool memory pool) public view returns (IRewardDistributionToken) {
// bytes32 salt = keccak256(abi.encodePacked(pool.stakingToken, pool.rewardToken));
// address tokenAddr = ClonesUpgradeable.predictDeterministicAddress(address(rewardDistTokenImpl), salt);
// return IRewardDistributionToken(tokenAddr);
// }
// Note: this function does not guarantee the token is deployed, we leave that check to elsewhere to save gas.
function _oldRewardDistributionTokenAddr(StakingPool memory pool) public view returns (IRewardDistributionToken) {
bytes32 salt = keccak256(abi.encodePacked(pool.stakingToken, pool.rewardToken, uint256(1)));
address tokenAddr = ClonesUpgradeable.predictDeterministicAddress(address(rewardDistTokenImpl), salt);
return IRewardDistributionToken(tokenAddr);
}

function _distributeFees(uint256 vaultId) internal {
INFTXSimpleFeeDistributor(nftxVaultFactory.feeDistributor()).distribute(vaultId);
// Note: this function does not guarantee the token is deployed, we leave that check to elsewhere to save gas.
function _unusedRewardDistributionTokenAddr(StakingPool memory pool) public view returns (IRewardDistributionToken) {
bytes32 salt = keccak256(abi.encodePacked(pool.stakingToken, pool.rewardToken));
address tokenAddr = ClonesUpgradeable.predictDeterministicAddress(address(rewardDistTokenImpl), salt);
return IRewardDistributionToken(tokenAddr);
}

function isContract(address account) internal view returns (bool) {
Expand All @@ -367,27 +352,4 @@ contract NFTXLPStaking is PausableUpgradeable {
xSlp.burnFrom(from, amount);
xSlp.mint(to, amount);
}

function totalUndistributedFees(uint256 vaultId) public view returns (uint256) {
INFTXSimpleFeeDistributor feeDistrib = INFTXSimpleFeeDistributor(nftxVaultFactory.feeDistributor());
(address receiverAddr, uint256 receiverAlloc) = feeDistrib.feeReceiverInfo(0);
require(receiverAddr == address(this), "wrong index");
// TODO: fetch allocationtotal from fee distributor
return IERC20Upgradeable(vaultStakingInfo[vaultId].rewardToken).balanceOf(nftxVaultFactory.feeDistributor()) * receiverAlloc / 1e18;
}

function undistributedFees(uint256 vaultId, address staker) public view returns (uint256) {
TimelockRewardDistributionTokenImpl xSlp = _rewardDistributionTokenAddr(vaultStakingInfo[vaultId]);
uint256 totalSupply = xSlp.totalSupply();
if (totalSupply == 0) {
return 0;
}
uint256 stakerPortion = xSlp.balanceOf(staker) * 1e18 / totalSupply;
return totalUndistributedFees(vaultId) * stakerPortion / 1e18;
}

function adjustedDividendOf(uint256 vaultId, address staker) public view returns (uint256) {
TimelockRewardDistributionTokenImpl xSlp = _rewardDistributionTokenAddr(vaultStakingInfo[vaultId]);
return undistributedFees(vaultId, staker) + xSlp.dividendOf(staker);
}
}
8 changes: 0 additions & 8 deletions contracts/solidity/NFTXSimpleFeeDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ contract NFTXSimpleFeeDistributor is INFTXSimpleFeeDistributor, ReentrancyGuardU
return;
}

if (tokenBalance == 0) {
return;
}

uint256 length = feeReceivers.length;
uint256 leftover;
for (uint256 i; i < length; ++i) {
Expand Down Expand Up @@ -177,8 +173,4 @@ contract NFTXSimpleFeeDistributor is INFTXSimpleFeeDistributor, ReentrancyGuardU
return true;
}
}

function feeReceiverInfo(uint256 index) external override view returns (address, uint256) {
return (feeReceivers[index].receiver, feeReceivers[index].allocPoint);
}
}
Loading