Skip to content

Commit

Permalink
Merge pull request #68 from valory-xyz/adjust_tokenomics_parameters
Browse files Browse the repository at this point in the history
refactor: defer the change tokenomics parameters to the next epoch
  • Loading branch information
DavidMinarsch authored Jan 31, 2023
2 parents 27c5c4a + 7a93809 commit cf07117
Show file tree
Hide file tree
Showing 6 changed files with 420 additions and 236 deletions.
4 changes: 2 additions & 2 deletions contracts/Depository.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ contract Depository is IErrorsTokenomics {
address public owner;
// Individual bond counter
// We assume that the number of bonds will not be bigger than the number of seconds
uint32 bondCounter;
uint32 public bondCounter;
// Bond product counter
// We assume that the number of products will not be bigger than the number of seconds
uint32 productCounter;
uint32 public productCounter;
// Reentrancy lock
uint8 internal _locked;

Expand Down
284 changes: 144 additions & 140 deletions contracts/Tokenomics.sol

Large diffs are not rendered by default.

8 changes: 0 additions & 8 deletions contracts/interfaces/IErrorsTokenomics.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,6 @@ interface IErrorsTokenomics {
/// @dev Caught reentrancy violation.
error ReentrancyGuard();

/// @dev maxBond parameter is locked and cannot be updated.
error MaxBondUpdateLocked();

/// @dev Rejects the max bond adjustment.
/// @param maxBondAmount Max bond amount available at the moment.
/// @param delta Delta bond amount to be subtracted from the maxBondAmount.
error RejectMaxBondAdjustment(uint256 maxBondAmount, uint256 delta);

/// @dev Failure of treasury re-balance during the reward allocation.
/// @param epochNumber Epoch number.
error TreasuryRebalanceFailed(uint256 epochNumber);
Expand Down
68 changes: 62 additions & 6 deletions test/Dispenser.js
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,10 @@ describe("Dispenser", async () => {

// Change the component and agent fractions to zero
await tokenomics.connect(deployer).changeIncentiveFractions(0, 0, 40, 40, 20);
// Changes will take place in the next epoch, need to move more than one epoch in time
await helpers.time.increase(epochLen + 10);
// Start new epoch
await tokenomics.connect(deployer).checkpoint();

// Send donations to services
await treasury.connect(deployer).depositServiceDonationsETH([1, 2], [regDepositFromServices, regDepositFromServices],
Expand Down Expand Up @@ -575,6 +579,10 @@ describe("Dispenser", async () => {

// Change the component fractions to zero
await tokenomics.connect(deployer).changeIncentiveFractions(0, 100, 40, 0, 60);
// Changes will take place in the next epoch, need to move more than one epoch in time
await helpers.time.increase(epochLen + 10);
// Start new epoch
await tokenomics.connect(deployer).checkpoint();

// Send donations to services
await treasury.connect(deployer).depositServiceDonationsETH([1, 2], [regDepositFromServices, regDepositFromServices],
Expand Down Expand Up @@ -668,6 +676,10 @@ describe("Dispenser", async () => {

// Change the component and agent to-up fractions to zero
await tokenomics.connect(deployer).changeIncentiveFractions(50, 30, 100, 0, 0);
// Changes will take place in the next epoch, need to move more than one epoch in time
await helpers.time.increase(epochLen + 10);
// Start new epoch
await tokenomics.connect(deployer).checkpoint();

// Send donations to services
await treasury.connect(deployer).depositServiceDonationsETH([1, 2], [regDepositFromServices, regDepositFromServices],
Expand Down Expand Up @@ -762,19 +774,19 @@ describe("Dispenser", async () => {
// Send donations to services
await treasury.connect(deployer).depositServiceDonationsETH([1, 2], [regDepositFromServices, regDepositFromServices],
{value: twoRegDepositFromServices});
// Change the fractions such that rewards and top-ups are now zero
// Change the fractions such that rewards and top-ups are now zero. However, they will be updated for the next epoch only
await tokenomics.connect(deployer).changeIncentiveFractions(0, 0, 100, 0, 0);
// Move more than one epoch in time
await helpers.time.increase(epochLen + 10);
// Start new epoch and calculate tokenomics parameters and rewards
await tokenomics.connect(deployer).checkpoint();

// Get the last settled epoch counter
const lastPoint = Number(await tokenomics.epochCounter()) - 1;
let lastPoint = Number(await tokenomics.epochCounter()) - 1;
// Get the epoch point of the last epoch
const ep = await tokenomics.getEpochPoint(lastPoint);
let ep = await tokenomics.getEpochPoint(lastPoint);
// Get the unit points of the last epoch
const up = [await tokenomics.getUnitPoint(lastPoint, 0), await tokenomics.getUnitPoint(lastPoint, 1)];
let up = [await tokenomics.getUnitPoint(lastPoint, 0), await tokenomics.getUnitPoint(lastPoint, 1)];
// Calculate rewards based on the points information
const percentFraction = ethers.BigNumber.from(100);
let rewards = [
Expand All @@ -789,8 +801,8 @@ describe("Dispenser", async () => {
ethers.BigNumber.from(ep.totalTopUpsOLAS).mul(ethers.BigNumber.from(up[1].topUpUnitFraction)).div(percentFraction)
];
let accountTopUps = topUps[1].add(topUps[2]);
expect(accountRewards).to.equal(0);
expect(accountTopUps).to.equal(0);
expect(accountRewards).to.greaterThan(0);
expect(accountTopUps).to.greaterThan(0);

// Check for the incentive balances such that their pending relative incentives are not zero
let incentiveBalances = await tokenomics.getIncentiveBalances(0, 1);
Expand All @@ -810,6 +822,46 @@ describe("Dispenser", async () => {
expect(Math.abs(Number(accountRewards.sub(checkedReward)))).to.lessThan(delta);
expect(Math.abs(Number(accountTopUps.sub(checkedTopUp)))).to.lessThan(delta);

// Claim rewards and top-ups
const balanceBeforeTopUps = ethers.BigNumber.from(await olas.balanceOf(deployer.address));
await dispenser.connect(deployer).claimOwnerIncentives([0, 1], [1, 1]);
const balanceAfterTopUps = ethers.BigNumber.from(await olas.balanceOf(deployer.address));

// Check the OLAS balance after receiving incentives
const balance = balanceAfterTopUps.sub(balanceBeforeTopUps);
expect(balance).to.lessThanOrEqual(accountTopUps);
expect(Math.abs(Number(accountTopUps.sub(balance)))).to.lessThan(delta);

// Send donations to services for the next epoch where all the fractions are zero
await treasury.connect(deployer).depositServiceDonationsETH([1, 2], [regDepositFromServices, regDepositFromServices],
{value: twoRegDepositFromServices});
// Move more than one epoch in time
await helpers.time.increase(epochLen + 10);
// Start new epoch and calculate tokenomics parameters and rewards
await tokenomics.connect(deployer).checkpoint();

// Get the last settled epoch counter
lastPoint = Number(await tokenomics.epochCounter()) - 1;
// Get the epoch point of the last epoch
ep = await tokenomics.getEpochPoint(lastPoint);
// Get the unit points of the last epoch
up = [await tokenomics.getUnitPoint(lastPoint, 0), await tokenomics.getUnitPoint(lastPoint, 1)];
// Calculate rewards based on the points information
rewards = [
ethers.BigNumber.from(ep.totalDonationsETH).mul(ethers.BigNumber.from(up[0].rewardUnitFraction)).div(percentFraction),
ethers.BigNumber.from(ep.totalDonationsETH).mul(ethers.BigNumber.from(up[1].rewardUnitFraction)).div(percentFraction)
];
accountRewards = rewards[0].add(rewards[1]);
// Calculate top-ups based on the points information
topUps = [
ethers.BigNumber.from(ep.totalTopUpsOLAS).mul(ethers.BigNumber.from(ep.maxBondFraction)).div(percentFraction),
ethers.BigNumber.from(ep.totalTopUpsOLAS).mul(ethers.BigNumber.from(up[0].topUpUnitFraction)).div(percentFraction),
ethers.BigNumber.from(ep.totalTopUpsOLAS).mul(ethers.BigNumber.from(up[1].topUpUnitFraction)).div(percentFraction)
];
accountTopUps = topUps[1].add(topUps[2]);
expect(accountRewards).to.equal(0);
expect(accountTopUps).to.equal(0);

// Try to claim rewards and top-ups for owners which are essentially zero as all the fractions were set to zero
await expect(
dispenser.connect(deployer).claimOwnerIncentives([0, 1], [1, 1])
Expand Down Expand Up @@ -837,6 +889,10 @@ describe("Dispenser", async () => {

// Change the fractions such that rewards and top-ups are not zero
await tokenomics.connect(deployer).changeIncentiveFractions(0, 0, 100, 0, 0);
// Changes will take place in the next epoch, need to move more than one epoch in time
await helpers.time.increase(epochLen + 10);
// Start new epoch
await tokenomics.connect(deployer).checkpoint();

// Send donations to services
await treasury.connect(deployer).depositServiceDonationsETH([1, 2], [regDepositFromServices, regDepositFromServices],
Expand Down
5 changes: 2 additions & 3 deletions test/Dispenser.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,9 @@ contract DispenserTest is BaseSetup {
// Calculate maxBond
uint256 calculatedMaxBond = (ep.totalTopUpsOLAS * ep.maxBondFraction) / 100;
// Compare it with the max bond calculated from the fraction and the total OLAS inflation for the epoch
// Do not compare directly if it is the current or next epoch of the year change
uint256 numYearsCurEpoch = (block.timestamp - tokenomics.timeLaunch()) / tokenomics.ONE_YEAR();
// Do not compare directly if the next epoch is the epoch where the year changes
uint256 numYearsNextEpoch = (block.timestamp + tokenomics.epochLen() - tokenomics.timeLaunch()) / tokenomics.ONE_YEAR();
if (numYearsCurEpoch == curYear && numYearsNextEpoch == curYear) {
if (numYearsNextEpoch == curYear) {
assertEq(tokenomics.maxBond(), calculatedMaxBond);
}
// Effective bond must be the previous effective bond plus the actual maxBond
Expand Down
Loading

0 comments on commit cf07117

Please sign in to comment.