Skip to content

Commit

Permalink
(migration): convert v1 to v2 with linear interpolation
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminbollen committed Dec 11, 2023
1 parent c4f3549 commit d7ed2fd
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 6 deletions.
5 changes: 3 additions & 2 deletions src/migration/IHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ interface IHubV1 {

function deployedAt() external returns (uint256);
function initialIssuance() external returns (uint256);
function issuance() external returns (uint256);
function issuanceByStep(uint256 _periods) external returns (uint256);
// function issuance() external returns (uint256);
// function issuanceByStep(uint256 periods) external returns (uint256);
function inflate(uint256 initial, uint256 periods) external returns (uint256);
function inflation() external returns (uint256);
function divisor() external returns (uint256);
function period() external returns (uint256);
Expand Down
34 changes: 30 additions & 4 deletions src/migration/Migration.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import "./IToken.sol";
import "../graph/IGraph.sol";

contract CirclesMigration {
// Constant

uint256 private constant ACCURACY = uint256(10**8);

// State variables

IHubV1 public immutable hubV1;
Expand Down Expand Up @@ -78,17 +82,39 @@ contract CirclesMigration {
return stopped_ = _originCircle.stopped();
}

// Private functions

function convertFromV1ToTimeCircles(uint256 _amount) private returns (uint256 timeCircleAmount_) {
function convertFromV1ToTimeCircles(uint256 _amount) public returns (uint256 timeCircleAmount_) {
uint256 currentPeriod = hubV1.periods();
uint256 nextPeriod = currentPeriod + 1;

uint256 startOfPeriod = hubV1.deployedAt() + currentPeriod * hubV1.period();
uint256 startOfPeriod = deployedAt + currentPeriod * period;

// number of seconds into the new period
uint256 secondsIntoCurrentPeriod = block.timestamp - startOfPeriod;

// rather than using initial issuance; use a clean order of magnitude
// to calculate the conversion factor.
// This is because initial issuance (originally ~ 8 CRC / day;
// then corrected to 24 CRC / day) is ever so slightly less than 1 CRC / hour
// ( 0.9999999999999936 CRC / hour to be precise )
// but if we later divide by this, then the error is ever so slightly
// in favor of converting - note there are many more errors,
// but we try to have each error always be in disadvantage of v1 so that
// there is no adverse incentive to mint and convert from v1
uint256 factorCurrentPeriod = hubV1.inflate(ACCURACY, currentPeriod);
uint256 factorNextPeriod = hubV1.inflate(ACCURACY, nextPeriod);

// linear interpolation of inflation rate
// r = x * (1 - a) + y * a
// if a = secondsIntoCurrentPeriod / Period = s / P
// => P * r = x * (P - s) + y * s
uint256 rP = factorCurrentPeriod * (period - secondsIntoCurrentPeriod)
+ factorNextPeriod * secondsIntoCurrentPeriod;

// account for the adjustment of the accepted gauge of 24 CRC / day,
// rather than 8 CRC / day, so multiply by 3
// and divide by the inflation rate to convert to temporally discounted units
// (as if inflation would have been continuously adjusted. This is not the case,
// it is only annually compounded, but the disadvantage is for v1 vs v2).
return timeCircleAmount_ = (_amount * 3 * ACCURACY * period) / rP;
}
}
39 changes: 39 additions & 0 deletions test/graph/MockHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ contract MockHubV1 is IHubV1 {
return uint256(92592592592592);
}

function inflate(uint256 _initial, uint256 _periods) external returns (uint256) {
// copy of the implementation from circles contracts v1
// to mirror the same numerical errors as hub v1 has.
// https://github.com/CirclesUBI/circles-contracts/blob/master/contracts/Hub.sol#L96-L103
uint256 q = pow(inflation(), _periods);
uint256 d = pow(divisor(), _periods);
return (_initial * q) / d;
}

function inflation() public returns (uint256) {
return uint256(107);
}
Expand All @@ -58,7 +67,37 @@ contract MockHubV1 is IHubV1 {
return (block.timestamp - deployedAt()) / period();
}

// Private functions

function notMocked() private pure {
assert(false);
}

/// @dev this is an implementation of exponentiation by squares
/// @param base the base to be used in the calculation
/// @param exponent the exponent to be used in the calculation
/// @return the result of the calculation
function pow(uint256 base, uint256 exponent) public pure returns (uint256) {
if (base == 0) {
return 0;
}
if (exponent == 0) {
return 1;
}
if (exponent == 1) {
return base;
}
uint256 y = 1;
while(exponent > 1) {
if(exponent % 2 == 0) {
base = base * base;
exponent = exponent / 2;
} else {
y = base * y;
base = base * base;
exponent = (exponent - 1) / 2;
}
}
return base * y;
}
}

0 comments on commit d7ed2fd

Please sign in to comment.