Skip to content

Commit

Permalink
Merge branch 'vg/feat/treasury-contribution' into vg/spike/treasury
Browse files Browse the repository at this point in the history
  • Loading branch information
victorges committed Aug 18, 2023
2 parents 6ec40e4 + 391e444 commit 6283fd3
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 72 deletions.
25 changes: 19 additions & 6 deletions contracts/bonding/BondingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ contract BondingManager is ManagerProxyTarget, IBondingManager {

// The % of newly minted rewards to be routed to the treasury. Represented as a PreciseMathUtils percPoint value.
uint256 public treasuryRewardCutRate;
// The value for `treasuryRewardCutRate` to be set on the next round initialization.
uint256 public nextRoundTreasuryRewardCutRate;

// If the balance of the treasury in LPT is above this value, automatic treasury contributions will halt.
uint256 public treasuryBalanceCeiling;

Expand Down Expand Up @@ -161,11 +164,15 @@ contract BondingManager is ManagerProxyTarget, IBondingManager {
* percentage (<100% specified with 27-digits precision).
*/
function setTreasuryRewardCutRate(uint256 _cutRate) external onlyControllerOwner {
_setTreasuryRewardCutRate(_cutRate);
}

function _setTreasuryRewardCutRate(uint256 _cutRate) internal {
require(PreciseMathUtils.validPerc(_cutRate), "_cutRate is invalid precise percentage");

treasuryRewardCutRate = _cutRate;
nextRoundTreasuryRewardCutRate = _cutRate;

emit ParameterUpdate("treasuryRewardCutRate");
emit ParameterUpdate("nextRoundTreasuryRewardCutRate");
}

/**
Expand Down Expand Up @@ -453,6 +460,12 @@ contract BondingManager is ManagerProxyTarget, IBondingManager {
function setCurrentRoundTotalActiveStake() external onlyRoundsManager {
currentRoundTotalActiveStake = nextRoundTotalActiveStake;

if (nextRoundTreasuryRewardCutRate != treasuryRewardCutRate) {
treasuryRewardCutRate = nextRoundTreasuryRewardCutRate;
// The treasury cut rate changes in a delayed fashion so we want to emit the parameter update event here
emit ParameterUpdate("treasuryRewardCutRate");
}

bondingVotes().checkpointTotalActiveStake(currentRoundTotalActiveStake, roundsManager().currentRound());
}

Expand Down Expand Up @@ -877,9 +890,9 @@ contract BondingManager is ManagerProxyTarget, IBondingManager {

if (treasuryBalanceCeiling > 0) {
uint256 treasuryBalance = livepeerToken().balanceOf(treasury());
if (treasuryBalance >= treasuryBalanceCeiling) {
if (treasuryBalance >= treasuryBalanceCeiling && nextRoundTreasuryRewardCutRate > 0) {
// halt treasury contributions until the cut rate param is updated again
treasuryRewardCutRate = 0;
_setTreasuryRewardCutRate(0);
}
}

Expand Down Expand Up @@ -1611,8 +1624,8 @@ contract BondingManager is ManagerProxyTarget, IBondingManager {
return IRoundsManager(controller.getContract(keccak256("RoundsManager")));
}

function treasury() internal view returns (address payable) {
return payable(controller.getContract(keccak256("Treasury")));
function treasury() internal view returns (address) {
return controller.getContract(keccak256("Treasury"));
}

function bondingVotes() internal view returns (IBondingVotes) {
Expand Down
196 changes: 132 additions & 64 deletions test/unit/BondingManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,17 @@ describe("BondingManager", () => {
describe("setTreasuryRewardCutRate", () => {
const FIFTY_PCT = math.precise.percPoints(BigNumber.from(50), 100)

let currentRound

beforeEach(async () => {
currentRound = 100

await fixture.roundsManager.setMockUint256(
functionSig("currentRound()"),
currentRound
)
})

it("should start as zero", async () => {
assert.equal(
await bondingManager.treasuryRewardCutRate(),
Expand All @@ -157,15 +168,50 @@ describe("BondingManager", () => {
).to.be.revertedWith("caller must be Controller owner")
})

it("should set treasuryRewardCutRate", async () => {
it("should set only nextRoundTreasuryRewardCutRate", async () => {
const tx = await bondingManager.setTreasuryRewardCutRate(FIFTY_PCT)
await expect(tx)
.to.emit(bondingManager, "ParameterUpdate")
.withArgs("nextRoundTreasuryRewardCutRate")

assert.equal(
await bondingManager.nextRoundTreasuryRewardCutRate(),
FIFTY_PCT.toString(),
"wrong nextRoundTreasuryRewardCutRate"
)
assert.equal(
await bondingManager.treasuryRewardCutRate(),
0,
"wrong treasuryRewardCutRate"
)
})

it("should set treasuryRewardCutRate on the next round", async () => {
await bondingManager.setTreasuryRewardCutRate(FIFTY_PCT)

const newValue = await bondingManager.treasuryRewardCutRate()
await fixture.roundsManager.setMockUint256(
functionSig("currentRound()"),
currentRound + 1
)
const tx = await fixture.roundsManager.execute(
bondingManager.address,
functionSig("setCurrentRoundTotalActiveStake()")
)
await expect(tx)
.to.emit(bondingManager, "ParameterUpdate")
.withArgs("treasuryRewardCutRate")

assert.equal(
newValue.toString(),
await bondingManager.treasuryRewardCutRate(),
FIFTY_PCT.toString(),
"wrong treasuryRewardCutRate"
)
// sanity check that this hasn't changed either
assert.equal(
await bondingManager.nextRoundTreasuryRewardCutRate(),
FIFTY_PCT.toString(),
"wrong nextRoundTreasuryRewardCutRate"
)
})
})

Expand Down Expand Up @@ -4697,6 +4743,16 @@ describe("BondingManager", () => {

await bondingManager.setTreasuryRewardCutRate(TREASURY_CUT)
await bondingManager.setTreasuryBalanceCeiling(1000)

// treasury cut rate update only takes place on the next round
await fixture.roundsManager.setMockUint256(
functionSig("currentRound()"),
currentRound + 1
)
await fixture.roundsManager.execute(
bondingManager.address,
functionSig("setCurrentRoundTotalActiveStake()")
)
})

it("should update caller with rewards after treasury contribution", async () => {
Expand Down Expand Up @@ -4803,77 +4859,89 @@ describe("BondingManager", () => {
})
})

describe("when at limit", () => {
beforeEach(async () => {
await fixture.token.setMockUint256(
functionSig("balanceOf(address)"),
1000
)
})
const atCeilingTest = (title, balance) => {
describe(title, () => {
beforeEach(async () => {
await fixture.token.setMockUint256(
functionSig("balanceOf(address)"),
balance
)
})

it("should not mint any treasury rewards", async () => {
const tx = await bondingManager
.connect(transcoder)
.reward()
it("should zero the nextRoundTreasuryRewardCutRate", async () => {
const tx = await bondingManager
.connect(transcoder)
.reward()

await expect(tx).not.to.emit(
fixture.minter,
"TrustedTransferTokens"
)
await expect(tx).not.to.emit(
bondingManager,
"TreasuryReward"
)
})
// it should still send treasury rewards
await expect(tx).to.emit(
fixture.minter,
"TrustedTransferTokens"
)
await expect(tx).to.emit(
bondingManager,
"TreasuryReward"
)

it("should also clear treasuryRewardCutRate param", async () => {
await bondingManager.connect(transcoder).reward()
await expect(tx)
.to.emit(bondingManager, "ParameterUpdate")
.withArgs("nextRoundTreasuryRewardCutRate")
assert.equal(
await bondingManager.nextRoundTreasuryRewardCutRate(),
0
)
})

const cutRate =
await bondingManager.treasuryRewardCutRate()
assert.equal(
cutRate.toNumber(),
0,
"cut rate not cleared"
)
})
})
it("should not mint any treasury rewards in the next round", async () => {
await bondingManager.connect(transcoder).reward()

describe("when above limit", () => {
beforeEach(async () => {
await fixture.token.setMockUint256(
functionSig("balanceOf(address)"),
1500
)
})
await fixture.roundsManager.setMockUint256(
functionSig("currentRound()"),
currentRound + 2
)
await fixture.roundsManager.execute(
bondingManager.address,
functionSig("setCurrentRoundTotalActiveStake()")
)

it("should not mint any treasury rewards", async () => {
const tx = await bondingManager
.connect(transcoder)
.reward()
const tx = await bondingManager
.connect(transcoder)
.reward()
await expect(tx).not.to.emit(
fixture.minter,
"TrustedTransferTokens"
)
await expect(tx).not.to.emit(
bondingManager,
"TreasuryReward"
)
})

await expect(tx).not.to.emit(
fixture.minter,
"TrustedTransferTokens"
)
await expect(tx).not.to.emit(
bondingManager,
"TreasuryReward"
)
})
it("should also clear treasuryRewardCutRate param in the next round", async () => {
await bondingManager.connect(transcoder).reward()

it("should also clear treasuryRewardCutRate param", async () => {
await bondingManager.connect(transcoder).reward()
await fixture.roundsManager.setMockUint256(
functionSig("currentRound()"),
currentRound + 2
)
await fixture.roundsManager.execute(
bondingManager.address,
functionSig("setCurrentRoundTotalActiveStake()")
)

const cutRate =
await bondingManager.treasuryRewardCutRate()
assert.equal(
cutRate.toNumber(),
0,
"cut rate not cleared"
)
const cutRate =
await bondingManager.treasuryRewardCutRate()
assert.equal(
cutRate.toNumber(),
0,
"cut rate not cleared"
)
})
})
})
}

atCeilingTest("when at limit", 1000)
atCeilingTest("when above limit", 1500)
})
})
})
Expand Down
7 changes: 5 additions & 2 deletions test/unit/TicketBroker.js
Original file line number Diff line number Diff line change
Expand Up @@ -664,8 +664,11 @@ describe("TicketBroker", () => {
expect(endSenderInfo.sender.deposit).to.be.equal(deposit)
expect(endSenderInfo.reserve.fundsRemaining).to.be.equal(reserve)

expect(tx).to.changeEtherBalance(funder, -(deposit + reserve))
expect(tx).to.changeEtherBalance(fixture.minter, deposit + reserve)
await expect(tx).to.changeEtherBalance(funder, -(deposit + reserve))
await expect(tx).to.changeEtherBalance(
fixture.minter,
deposit + reserve
)
})
})

Expand Down

0 comments on commit 6283fd3

Please sign in to comment.