Skip to content

minter: Add inflation bounds to inflation adjustment algorithm #645

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

Open
wants to merge 14 commits into
base: delta
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
4 changes: 2 additions & 2 deletions contracts/token/IMinter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ interface IMinter {

function inflation() external view returns (uint256);

function maxInflation() external view returns (uint256);
function inflationCeiling() external view returns (uint256);

function minInflation() external view returns (uint256);
function inflationFloor() external view returns (uint256);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the rename! Make sure there's no occurences of [Mm]ax.+[Ii]nflation on the project anymore 👀


function inflationChange() external view returns (uint256);

Expand Down
68 changes: 35 additions & 33 deletions contracts/token/Minter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ contract Minter is Manager, IMinter {

// Per round inflation rate
uint256 public inflation;
// Max per round inflation rate
uint256 public maxInflation;
// Min per round inflation rate
uint256 public minInflation;
// Target maximum inflation rate
uint256 public inflationCeiling;
// Target minimum inflation rate
uint256 public inflationFloor;
// Change in inflation rate per round until the target bonding rate is achieved
uint256 public inflationChange;
// Target bonding rate
Expand Down Expand Up @@ -74,24 +74,24 @@ contract Minter is Manager, IMinter {
* @param _inflation Base inflation rate as a percentage of current total token supply
* @param _inflationChange Change in inflation rate each round (increase or decrease) if target bonding rate is not achieved
* @param _targetBondingRate Target bonding rate as a percentage of total bonded tokens / total token supply
* @param _maxInflation Inflation rate ceiling as a percentage of current total token supply
* @param _minInflation Inflation rate floor as a percentage of current total token supply
* @param _inflationCeiling Inflation rate ceiling as a percentage of current total token supply
* @param _inflationFloor Inflation rate floor as a percentage of current total token supply
*/
constructor(
address _controller,
uint256 _inflation,
uint256 _inflationChange,
uint256 _targetBondingRate,
uint256 _maxInflation,
uint256 _minInflation
uint256 _inflationCeiling,
uint256 _inflationFloor
) Manager(_controller) {
// Inflation must be valid percentage
require(MathUtils.validPerc(_inflation), "_inflation is invalid percentage");
// Inflation bounds must be valid percentages
require(MathUtils.validPerc(_maxInflation), "_maxInflation is invalid percentage");
require(MathUtils.validPerc(_minInflation), "_minInflation is invalid percentage");
require(MathUtils.validPerc(_inflationCeiling), "_inflationCeiling is invalid percentage");
require(MathUtils.validPerc(_inflationFloor), "_inflationFloor is invalid percentage");
// Inflation floor should be lower or equal to the ceiling
require(_minInflation <= _maxInflation, "_minInflation must be <= _maxInflation");
require(_inflationFloor <= _inflationCeiling, "_inflationFloor must be <= _inflationCeiling");
// Inflation change must be valid percentage
require(MathUtils.validPerc(_inflationChange), "_inflationChange is invalid percentage");
// Target bonding rate must be valid percentage
Expand All @@ -100,8 +100,8 @@ contract Minter is Manager, IMinter {
inflation = _inflation;
inflationChange = _inflationChange;
targetBondingRate = _targetBondingRate;
maxInflation = _maxInflation;
minInflation = _minInflation;
inflationCeiling = _inflationCeiling;
inflationFloor = _inflationFloor;
}

/**
Expand Down Expand Up @@ -131,33 +131,33 @@ contract Minter is Manager, IMinter {
}

/**
* @notice Set maxInflation. Only callable by Controller owner
* @param _maxInflation New inflation cap as a percentage of total token supply
* @notice Set inflationCeiling. Only callable by Controller owner
* @param _inflationCeiling New inflation cap as a percentage of total token supply
*/
function setMaxInflation(uint256 _maxInflation) external onlyControllerOwner {
function setinflationCeiling(uint256 _inflationCeiling) external onlyControllerOwner {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

Suggested change
function setinflationCeiling(uint256 _inflationCeiling) external onlyControllerOwner {
function setInflationCeiling(uint256 _inflationCeiling) external onlyControllerOwner {

// Must be valid percentage
require(MathUtils.validPerc(_maxInflation), "_maxInflation is invalid percentage");
require(MathUtils.validPerc(_inflationCeiling), "_inflationCeiling is invalid percentage");
// Inflation ceiling should be higher or equal to the floor
require(_maxInflation >= minInflation, "_maxInflation must be >= minInflation");
require(_inflationCeiling >= inflationFloor, "_inflationCeiling must be >= inflationFloor");

maxInflation = _maxInflation;
inflationCeiling = _inflationCeiling;

emit ParameterUpdate("maxInflation");
emit ParameterUpdate("inflationCeiling");
}

/**
* @notice Set minInflation. Only callable by Controller owner
* @param _minInflation New inflation floor as a percentage of total token supply
* @notice Set inflationFloor. Only callable by Controller owner
* @param _inflationFloor New inflation floor as a percentage of total token supply
*/
function setMinInflation(uint256 _minInflation) external onlyControllerOwner {
function setinflationFloor(uint256 _inflationFloor) external onlyControllerOwner {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably mis-replaced the name here:

Suggested change
function setinflationFloor(uint256 _inflationFloor) external onlyControllerOwner {
function setInflationFloor(uint256 _inflationFloor) external onlyControllerOwner {

Will need to rename in other places like tests etc

// Must be valid percentage
require(MathUtils.validPerc(_minInflation), "_minInflation is invalid percentage");
require(MathUtils.validPerc(_inflationFloor), "_inflationFloor is invalid percentage");
// Inflation floor should be lower or equal to the ceiling
require(_minInflation <= maxInflation, "_minInflation must be <= maxInflation");
require(_inflationFloor <= inflationCeiling, "_inflationFloor must be <= inflationCeiling");

minInflation = _minInflation;
inflationFloor = _inflationFloor;

emit ParameterUpdate("minInflation");
emit ParameterUpdate("inflationFloor");
}

/**
Expand Down Expand Up @@ -301,19 +301,21 @@ contract Minter is Manager, IMinter {
}

// Adjust inflation based on current bonding rate and target bonding rate, ensuring it stays within the floor and ceiling
if ((currentBondingRate < targetBondingRate && inflation < maxInflation) || inflation < minInflation) {
if ((currentBondingRate < targetBondingRate && inflation < inflationCeiling) || inflation < inflationFloor) {
// Bonding rate is below the target - increase inflation
if (inflation.add(inflationChange) > maxInflation) {
if (inflation.add(inflationChange) > inflationCeiling) {
// If inflation would go above the ceiling, set it to the ceiling
inflation = maxInflation;
inflation = inflationCeiling;
} else {
inflation = inflation.add(inflationChange);
}
} else if ((currentBondingRate > targetBondingRate && inflation > minInflation) || inflation > maxInflation) {
} else if (
(currentBondingRate > targetBondingRate && inflation > inflationFloor) || inflation > inflationCeiling
) {
// Bonding rate is above the target - decrease inflation
if (minInflation.add(inflationChange) > inflation) {
if (inflationFloor.add(inflationChange) > inflation) {
// If inflation would go below the floor, set it to the floor
inflation = minInflation;
inflation = inflationFloor;
} else {
inflation = inflation.sub(inflationChange);
}
Expand Down
4 changes: 2 additions & 2 deletions deploy/deploy_contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {
config.minter.inflation,
config.minter.inflationChange,
config.minter.targetBondingRate,
config.minter.maxInflation,
config.minter.minInflation
config.minter.inflationCeiling,
config.minter.inflationFloor
]
})

Expand Down
7 changes: 3 additions & 4 deletions deploy/deploy_minter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,17 @@ const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {
)) as Minter

const inflation = await minter.inflation()
const inflationChange = await minter.inflationChange()
const targetBondingRate = await minter.targetBondingRate()

await deploy("Minter", {
from: deployer,
args: [
controllerDeployment.address,
inflation,
inflationChange,
config.minter.inflationChange,
targetBondingRate,
config.minter.maxInflation,
config.minter.minInflation
config.minter.inflationCeiling,
config.minter.inflationFloor
]
})
}
Expand Down
29 changes: 12 additions & 17 deletions deploy/migrations.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ const gethDev = {
inflation: 137,
inflationChange: 3,
targetBondingRate: 500000,
maxInflation: 200,
minInflation: 100
inflationCeiling: 200,
inflationFloor: 100
}
}

Expand Down Expand Up @@ -54,8 +54,8 @@ const defaultConfig = {
inflation: 137,
inflationChange: 3,
targetBondingRate: 500000,
maxInflation: 200,
minInflation: 100
inflationCeiling: 200,
inflationFloor: 100
},
treasury: {
minDelay: 0 // 0s initial proposal execution delay
Expand Down Expand Up @@ -104,8 +104,8 @@ const rinkeby = {
inflation: 137,
inflationChange: 3,
targetBondingRate: 0,
maxInflation: 200,
minInflation: 100
inflationCeiling: 200,
inflationFloor: 100
}
}

Expand Down Expand Up @@ -133,8 +133,8 @@ const arbitrumRinkeby = {
inflation: 137,
inflationChange: 3,
targetBondingRate: 0,
maxInflation: 200,
minInflation: 100
inflationCeiling: 200,
inflationFloor: 100
}
}

Expand Down Expand Up @@ -162,16 +162,11 @@ const arbitrumMainnet = {
roundLockAmount: 100000
},
minter: {
// As of L1 round 2460 inflation was 221500 and bonding rate > 50% so inflation was declining
// The switch to L2 projected to occur in L1 round 2466
// If inflation continues to decrease inflation projected to be 221500 - (6 * 500) = 218500 in L1 round 2466
// No reward calls will happen on L2 until the round after migrations start since it takes a round for orchestrators to become active
// The inflation at the start of that round will be 218500 - 500 = 218000
inflation: 218500,
inflationChange: 500,
inflation: 651000, // Current value at round 3766, but is overwritten by `migrateOldMinterState`
inflationChange: 1000, // Set according to LIP-100
targetBondingRate: 500000000,
maxInflation: 250000,
minInflation: 5000
inflationCeiling: 750000, // Set according to LIP-100
inflationFloor: 50000 // Set according to LIP-100
},
treasury: {
minDelay: 0 // 0s initial proposal execution delay
Expand Down
32 changes: 17 additions & 15 deletions test/integration/GovernorUpdate.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ describe("Governor update", () => {

let migrateData
let migrateTarget
let transferStateData
let transferStateTarget
let migrateOldMinterStateData
let migrateOldMinterStateTarget
let grantRoleData
let grantRoleTarget
let revokeRoleData
Expand All @@ -144,10 +144,10 @@ describe("Governor update", () => {
)
migrateTarget = minter.address

transferStateData = newMinter.interface.encodeFunctionData(
migrateOldMinterStateData = newMinter.interface.encodeFunctionData(
"migrateOldMinterState"
)
transferStateTarget = newMinter.address
migrateOldMinterStateTarget = newMinter.address

setInfoData = controller.interface.encodeFunctionData(
"setContractInfo",
Expand Down Expand Up @@ -187,15 +187,15 @@ describe("Governor update", () => {
const update = {
target: [
migrateTarget,
transferStateTarget,
migrateOldMinterStateTarget,
grantRoleTarget,
revokeRoleTarget,
setInfoTarget
],
value: ["0", "0", "0", "0", "0"],
data: [
migrateData,
transferStateData,
migrateOldMinterStateData,
grantRoleData,
revokeRoleData,
setInfoData
Expand All @@ -219,15 +219,15 @@ describe("Governor update", () => {
const update = {
target: [
migrateTarget,
transferStateTarget,
migrateOldMinterStateTarget,
grantRoleTarget,
revokeRoleTarget,
setInfoTarget
],
value: ["0", "0", "0", "0", "0"],
data: [
migrateData,
transferStateData,
migrateOldMinterStateData,
grantRoleData,
revokeRoleData,
setInfoData
Expand All @@ -252,15 +252,15 @@ describe("Governor update", () => {
const update = {
target: [
migrateTarget,
transferStateTarget,
migrateOldMinterStateTarget,
grantRoleTarget,
revokeRoleTarget,
setInfoTarget
],
value: ["0", "0", "0", "0", "0"],
data: [
migrateData,
transferStateData,
migrateOldMinterStateData,
grantRoleData,
revokeRoleData,
setInfoData
Expand All @@ -275,7 +275,7 @@ describe("Governor update", () => {
)
})

it("step 2 'transferStateData' fails: wrong target", async () => {
it("step 2 'migrateOldMinterState' fails: wrong target", async () => {
const update = {
target: [
migrateTarget,
Expand All @@ -287,7 +287,7 @@ describe("Governor update", () => {
value: ["0", "0", "0", "0", "0"],
data: [
migrateData,
transferStateData,
migrateOldMinterStateData,
grantRoleData,
revokeRoleData,
setInfoData
Expand All @@ -297,22 +297,24 @@ describe("Governor update", () => {

// Run the migrate to new minter update
await governor.stage(update, "0")
await expect(governor.execute(update)).to.be.reverted
await expect(governor.execute(update)).to.be.revertedWith(
"Minter cannot be current Minter"
)
})

it("succesfully executes all updates", async () => {
const update = {
target: [
migrateTarget,
transferStateTarget,
migrateOldMinterStateTarget,
grantRoleTarget,
revokeRoleTarget,
setInfoTarget
],
value: ["0", "0", "0", "0", "0"],
data: [
migrateData,
transferStateData,
migrateOldMinterStateData,
grantRoleData,
revokeRoleData,
setInfoData
Expand Down
8 changes: 4 additions & 4 deletions test/integration/MinterUpgrade.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ describe("MinterUpgrade", () => {
assert.notOk(inflationChange.eq(NEW_INFLATION_CHANGE))

const targetBondingRate = await minter.targetBondingRate()
const maxInflation = await minter.maxInflation()
const minInflation = await minter.minInflation()
const inflationCeiling = await minter.inflationCeiling()
const inflationFloor = await minter.inflationFloor()

// Deploy the new Minter
const newMinter = await (
Expand All @@ -166,8 +166,8 @@ describe("MinterUpgrade", () => {
0,
NEW_INFLATION_CHANGE,
targetBondingRate,
maxInflation,
minInflation
inflationCeiling,
inflationFloor
)

// Migrate from old Minter to new Minter
Expand Down
Loading
Loading