Skip to content

Commit

Permalink
latest
Browse files Browse the repository at this point in the history
  • Loading branch information
novaknole committed Feb 25, 2025
1 parent e60d02d commit 380111b
Show file tree
Hide file tree
Showing 7 changed files with 999 additions and 856 deletions.
421 changes: 421 additions & 0 deletions gio.yml

Large diffs are not rendered by default.

51 changes: 30 additions & 21 deletions src/escrow/increasing/QuadraticIncreasingEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,12 @@ contract QuadraticIncreasingEscrow is
// endTime => summed up slopes at that endTime
mapping(uint256 => uint128) public slopeChanges;

mapping(uint256 => UserPoint) internal pointHistory;
mapping(uint256 => UserPoint[1000000000]) internal userPointHistory;
mapping(uint256 => UserPoint) internal _pointHistory;
mapping(uint256 => UserPoint[1000000000]) internal _userPointHistory;
mapping(uint256 => uint256) public userPointEpoch;

// ============GIORGI===============


/*//////////////////////////////////////////////////////////////
MATH
//////////////////////////////////////////////////////////////*/

/// @dev precomputed coefficients of the quadratic curve
int256 private constant SHARED_QUADRATIC_COEFFICIENT =
CurveConstantLib.SHARED_QUADRATIC_COEFFICIENT;
Expand Down Expand Up @@ -227,7 +222,7 @@ contract QuadraticIncreasingEscrow is
BALANCE
//////////////////////////////////////////////////////////////*/

/// @notice Returns the TokenPoint at the passed interval
/// @notice Returns the TokenPoint at the passed user epoch.
/// @param _tokenId The NFT to return the TokenPoint for
/// @param _tokenInterval The epoch to return the TokenPoint at
function tokenPointHistory(
Expand All @@ -237,6 +232,16 @@ contract QuadraticIncreasingEscrow is
return _tokenPointHistory[_tokenId][_tokenInterval];
}

/// @notice Returns the global point at the passed epoch
/// @param _epoch The epoch to return the point for
function pointHistory(uint256 _epoch) external view returns (UserPoint memory) {
return _pointHistory[_epoch];
}

function totalSupply(uint256 _ts) external view returns(uint256) {
return BalanceLogicLibrary.supplyAt(slopeChanges, _pointHistory, epoch, _ts);
}

/// @notice Binary search to get the token point interval for a token id at or prior to a given timestamp
/// Once we have the point, we can apply the bias calculation to get the voting power.
/// @dev If a token point does not exist prior to the timestamp, this will return 0.
Expand Down Expand Up @@ -301,7 +306,7 @@ contract QuadraticIncreasingEscrow is
}

function supplyAt(uint256 _timestamp) public view override returns (uint256) {
return BalanceLogicLibrary.supplyAt(slopeChanges, pointHistory, epoch, _timestamp);
return BalanceLogicLibrary.supplyAt(slopeChanges, _pointHistory, epoch, _timestamp);
}

/// @notice Record gper-user data to checkpoints. Used by VotingEscrow system.
Expand Down Expand Up @@ -330,7 +335,7 @@ contract QuadraticIncreasingEscrow is
});

if (_epoch > 0) {
lastPoint = pointHistory[_epoch];
lastPoint = _pointHistory[_epoch];
}

{
Expand All @@ -357,26 +362,30 @@ contract QuadraticIncreasingEscrow is
if (t_i == block.timestamp) {
break;
} else {
pointHistory[_epoch] = lastPoint;
_pointHistory[_epoch] = lastPoint;
}
}
}

uNew.slope = (_newLocked.amount / CurveConstantLib.MAX_TIME).toUint128();
uNew.bias = _newLocked.amount + uNew.slope * accumulationDur;

uNew.start = _newLocked.start;
uNew.ts = currentTime;

if(currentTime - _newLocked.start >= CurveConstantLib.MAX_TIME) {
uNew.slope = 0;
}

uint48 newEnd = (_newLocked.start + CurveConstantLib.MAX_TIME).toUint48();
uint128 newSlope = lastPoint.slope + uNew.slope;
uint208 newBias = lastPoint.bias + uNew.bias;
uint128 newDSlope = slopeChanges[_newLocked.end] + uNew.slope;
uint128 newDSlope = slopeChanges[newEnd] + uNew.slope;

uint256 userEpoch = userPointEpoch[_tokenId];

// The `tokenId` already exists..
if(userEpoch > 0) {
UserPoint storage p = userPointHistory[_tokenId][userEpoch];
UserPoint storage p = _userPointHistory[_tokenId][userEpoch];
uint48 endOld = (p.start + CurveConstantLib.MAX_TIME).toUint48();

if(_newLocked.amount == 0) {
Expand All @@ -402,13 +411,13 @@ contract QuadraticIncreasingEscrow is
// old slope must still be added.
uNew.slope += p.slope;
uNew.bias += (p.bias + (currentTime - p.ts) * p.slope);
if(endOld != _newLocked.end) newDSlope += p.slope;
if(endOld != newEnd) newDSlope += p.slope;
}
}

// If the end date has not changed and is in future,
// we must not clear out slope changes.
if(endOld != _newLocked.end && endOld >= uNew.ts) {
if(endOld != newEnd && endOld >= uNew.ts) {
slopeChanges[endOld] -= p.slope;
}
}
Expand All @@ -419,15 +428,15 @@ contract QuadraticIncreasingEscrow is

// TODO: see aerodome..
epoch = _epoch;
pointHistory[_epoch] = lastPoint;
_pointHistory[_epoch] = lastPoint;

slopeChanges[_newLocked.end] = newDSlope;
slopeChanges[newEnd] = newDSlope;

if (userEpoch != 0 && userPointHistory[_tokenId][userEpoch].ts == block.timestamp) {
userPointHistory[_tokenId][userEpoch] = uNew;
if (userEpoch != 0 && _userPointHistory[_tokenId][userEpoch].ts == block.timestamp) {
_userPointHistory[_tokenId][userEpoch] = uNew;
} else {
userPointEpoch[_tokenId] = ++userEpoch;
userPointHistory[_tokenId][userEpoch] = uNew;
_userPointHistory[_tokenId][userEpoch] = uNew;
}
}

Expand Down
173 changes: 64 additions & 109 deletions src/escrow/increasing/VotingEscrowIncreasing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,6 @@ contract VotingEscrow is

// query the duration lib to get the next time we can deposit
uint256 startTime = IClock(clock).epochCurrentWeekTs();
uint256 endTime = startTime + CurveConstantLib.MAX_TIME;

// increment the total locked supply and get the new tokenId
totalLocked += _value;
Expand All @@ -265,13 +264,12 @@ contract VotingEscrow is
// write the lock and checkpoint the voting power
LockedBalance memory lock = LockedBalance(
_value.toUint208(),
startTime.toUint48(),
endTime.toUint48()
startTime.toUint48()
);
_locked[newTokenId] = lock;

// we don't allow edits in this implementation, so only the new lock is used
_checkpoint(newTokenId, LockedBalance(0, 0, 0), lock, uint48(block.timestamp - lock.start));
_checkpoint(newTokenId, LockedBalance(0, 0), lock, uint48(block.timestamp - lock.start));

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

Expand All @@ -289,62 +287,21 @@ contract VotingEscrow is
return newTokenId;
}

function increaseAmountFor(uint256 _tokenId, uint256 _value, bool _changeEndDate) public {
if (!isApprovedOrOwner(_msgSender(), _tokenId)) {
revert("token not owned or approved for msg sender");
}

if (_value == 0) revert ZeroAmount();

uint256 startTime = IClock(clock).epochCurrentWeekTs();

LockedBalance memory oldLocked = _locked[_tokenId];

// If the tokenId is mature, doesn't make much sense
// to add more amount for the increase.
if (oldLocked.end <= block.timestamp) {
revert("LockExpired");
}

LockedBalance memory newLocked;
newLocked.amount = _value.toUint208();
newLocked.start = uint48(startTime);
newLocked.end = _changeEndDate
? uint48(startTime + CurveConstantLib.MAX_TIME)
: oldLocked.end;

// transfer the tokens into the contract
IERC20(token).safeTransferFrom(_msgSender(), address(this), _value);

_locked[_tokenId] = newLocked;
totalLocked += _value;

_checkpoint(
_tokenId,
LockedBalance(0, 0, 0),
newLocked,
uint48(block.timestamp - newLocked.start)
);
}

function makeIt0(uint256 _tokenId) public {
if (!isApprovedOrOwner(_msgSender(), _tokenId)) {
revert("token not owned or approved for msg sender");
}

uint256 startTime = IClock(clock).epochCurrentWeekTs();

LockedBalance memory newLocked = LockedBalance(
0,
uint48(startTime),
uint48(startTime + CurveConstantLib.MAX_TIME)
_locked[_tokenId].start
);

_locked[_tokenId] = newLocked;

_checkpoint(
_tokenId,
LockedBalance(0, 0, 0),
LockedBalance(0, 0),
newLocked,
uint48(block.timestamp - newLocked.start)
);
Expand All @@ -354,94 +311,92 @@ contract VotingEscrow is
LockedBalance memory oldLockedFrom = _locked[_from];
LockedBalance memory oldLockedTo = _locked[_to];

uint48 oldLockedFromEnd = (oldLockedFrom.start + CurveConstantLib.MAX_TIME).toUint48();
uint48 oldLockedToEnd = (oldLockedTo.start + CurveConstantLib.MAX_TIME).toUint48();

if (
(oldLockedTo.start != oldLockedFrom.start) &&
(block.timestamp <= oldLockedTo.end || block.timestamp <= oldLockedFrom.end)
(block.timestamp <= oldLockedToEnd || block.timestamp <= oldLockedFromEnd)
) {
revert("Tokens either must be mature or start dates must match");
}

// query the duration lib to get the next time we can deposit
uint256 startTime = IClock(clock).epochCurrentWeekTs();
uint256 endTime = startTime + CurveConstantLib.MAX_TIME;

// Update for `_from`.
IERC721EMB(lockNFT).burn(_from);
_locked[_from] = LockedBalance(0, 0, 0);
_locked[_from] = LockedBalance(0, 0);
LockedBalance memory newLockedFrom = LockedBalance({
start: uint48(startTime),
amount: 0,
end: uint48(endTime)
start: oldLockedFrom.start,
amount: 0
});

_checkpoint(
_from,
LockedBalance(0, 0, 0),
LockedBalance(0, 0),
newLockedFrom,
uint48(block.timestamp - newLockedFrom.start)
);

// Update for `_to`.
LockedBalance memory newLockedTo = LockedBalance({
start: uint48(startTime),
amount: oldLockedFrom.amount,
end: uint48(endTime)
start: oldLockedTo.start,
amount: oldLockedFrom.amount
});

uint256 duration = block.timestamp >= oldLockedFrom.end
? oldLockedFrom.end - oldLockedFrom.start
uint256 duration = block.timestamp >= oldLockedFromEnd
? oldLockedFromEnd - oldLockedFrom.start
: block.timestamp - oldLockedFrom.start;

_checkpoint(_to, LockedBalance(0, 0, 0), newLockedTo, uint48(duration));
_checkpoint(_to, LockedBalance(0, 0), newLockedTo, uint48(duration));
_locked[_to] = newLockedTo;
}

// function split(
// uint256 _from,
// uint256 _value
// ) public returns (uint256 _tokenId1, uint256 _tokenId2) {
// LockedBalance memory locked = _locked[_from];
// address owner = _msgSender();

// if (_value == 0) revert ZeroAmount();
// if (locked.amount <= _value) revert("value too big");

// _value = _value.toUint208();

// uint256 startTime = IClock(clock).epochCurrentWeekTs();
// uint256 endTime = startTime + CurveConstantLib.MAX_TIME;

// IERC721EMB(lockNFT).burn(_from);
// _locked[_from] = LockedBalance(0, 0, false);
// _checkpoint(
// _from,
// LockedBalance(0, 0, 0),
// LockedBalance(0, startTime, endTime),
// uint48(block.timestamp - startTime)
// );

// locked.amount -= _value;
// _tokenId1 = _createSplitNFT(owner, locked);

// locked.amount = _value;
// _tokenId2 = _createSplitNFT(owner, locked);
// }

// function _createSplitNFT(
// address _to,
// LockedBalance memory _newLocked,
// uint48 _startTime
// ) private returns (uint256 _tokenId) {
// _tokenId = ++lastLockId;
// _locked[_tokenId] = _newLocked;
// _checkpoint(
// _tokenId,
// LockedBalance(0, 0, 0),
// _newLocked,
// uint48(block.timestamp - _startTime)
// );
// IERC721EMB(lockNFT).mint(_to, _tokenId);
// }
function split(
uint256 _from,
uint256 _value
) public returns (uint256 _tokenId1, uint256 _tokenId2) {
LockedBalance memory locked_ = _locked[_from];
address owner = _msgSender();

if (_value == 0) revert ZeroAmount();
if (locked_.amount <= _value) revert("value too big");

IERC721EMB(lockNFT).burn(_from);
_locked[_from] = LockedBalance(0, 0);
_checkpoint(
_from,
LockedBalance(0, 0),
LockedBalance(0, locked_.start),
0
);

uint48 lockEnd = (locked_.start + CurveConstantLib.MAX_TIME).toUint48();
uint48 duration = block.timestamp >= lockEnd ? uint48(lockEnd - locked_.start) : uint48(block.timestamp - locked_.start);

locked_.amount -= _value.toUint208();
_tokenId1 = _createSplitNFT(owner, locked_, duration);

locked_.amount = _value.toUint208();
_tokenId2 = _createSplitNFT(owner, locked_, duration);
}

function _createSplitNFT(
address _to,
LockedBalance memory _newLocked,
uint48 _duration
) private returns (uint256 _tokenId) {
_tokenId = ++lastLockId;
_locked[_tokenId] = _newLocked;
_checkpoint(
_tokenId,
LockedBalance(0, 0),
_newLocked,
uint48(_duration)
);
IERC721EMB(lockNFT).mint(_to, _tokenId);
}

/// @notice Record per-user data to checkpoints. Used by VotingEscrow system.
/// @param _tokenId NFT token ID
Expand All @@ -464,8 +419,8 @@ contract VotingEscrow is
uint256 checkpointClearTime = IClock(clock).epochCurrentWeekTs();
IEscrowCurve(curve).checkpoint(
_tokenId,
LockedBalance(0, 0, 0),
LockedBalance(0, checkpointClearTime.toUint48(), 0),
LockedBalance(0, 0),
LockedBalance(0, checkpointClearTime.toUint48()),
uint48(block.timestamp - checkpointClearTime)
);
}
Expand Down Expand Up @@ -522,7 +477,7 @@ contract VotingEscrow is
}

// clear out the token data
_locked[_tokenId] = LockedBalance(0, 0, 0);
_locked[_tokenId] = LockedBalance(0, 0);
totalLocked -= value;

// Burn the NFT and transfer the tokens to the user
Expand Down
Loading

0 comments on commit 380111b

Please sign in to comment.