Skip to content
2 changes: 2 additions & 0 deletions contracts/interfaces/IveLON.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ interface IveLON is IERC721, IERC721Metadata {
// TODO need this event?
// event Supply(uint256 prevSupply, uint256 supply);?

function setMaxLockDuration(uint256 _maxLockDuration) external;

function unlockTime(uint256 _tokenId) external view returns (uint256);

function createLock(uint256 _value, uint256 _lockDuration) external returns (uint256);
Expand Down
54 changes: 54 additions & 0 deletions contracts/veLON.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,60 @@ contract veLON is IveLON, ERC721, Ownable, ReentrancyGuard {
poolPointHistory[0].ts = block.timestamp;
}

/// @notice Update the `maxLockDuration`.
/// @param _maxLockDuration new number of seconds for `maxLockDuration`.
function setMaxLockDuration(uint256 _maxLockDuration) external override onlyOwner {
// flush the global voting power change into storage first
_updateLockedPoint(0, LockedBalance(0, 0), LockedBalance(0, 0));

uint256 maxEndTime = block.timestamp.add(_maxLockDuration).div(WEEK).mul(WEEK);
int256 globalDecliningRate;
int256 globalVBalance;
// update every NFT's stored states and calculate global states
for (uint256 _tokenId = 1; _tokenId <= tokenId; _tokenId++) {
// skip NFTs that have been burned
if (ownerOf(_tokenId) == address(0)) {
continue;
}
// skip expired NFTs
if (locked[_tokenId].end < block.timestamp) {
continue;
}

uint256 userEpoch = userPointEpoch[_tokenId];
LockedBalance memory oldLocked = locked[_tokenId];
LockedBalance memory newLocked = locked[_tokenId];
Point memory pointOld = userPointHistory[_tokenId][userEpoch];
Point memory pointNew = Point({ vBalance: 0, decliningRate: 0, ts: block.timestamp, blk: block.number });
if (newLocked.end > maxEndTime) {
newLocked.end = maxEndTime;
}
pointNew.decliningRate = int256(newLocked.amount.div(_maxLockDuration));
int256 duration = int256(newLocked.end.sub(block.timestamp));
pointNew.vBalance = duration * pointNew.decliningRate;

// update the latest user epoch and user point
userEpoch = userEpoch.add(1);
userPointEpoch[_tokenId] = userEpoch;
userPointHistory[_tokenId][userEpoch] = pointNew;
locked[_tokenId] = newLocked;

// update dRateChanges
dRateChanges[oldLocked.end] += pointOld.decliningRate;
dRateChanges[newLocked.end] += pointNew.decliningRate;

globalDecliningRate += pointNew.decliningRate;
globalVBalance += pointNew.vBalance;
}

// update global point
epoch = epoch.add(1);
poolPointHistory[epoch] = Point({ vBalance: globalVBalance, decliningRate: globalDecliningRate, ts: block.timestamp, blk: block.number });

// update the maxLockDuration
maxLockDuration = _maxLockDuration;
}

/// @notice Get timestamp when `_tokenId`'s lock finishes
/// @param _tokenId User NFT
/// @return Epoch time of the lock end
Expand Down