Skip to content

Commit

Permalink
split updateTokenVertexConfig into updateTokenVertexConfigPremiumRate…
Browse files Browse the repository at this point in the history
…s and updateTokenVertexConfigBalanceRates
  • Loading branch information
whyareulaughing committed Nov 29, 2023
1 parent 004f9be commit fc4c363
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 18 deletions.
53 changes: 44 additions & 9 deletions contracts/governance/TokenVertexUpdaterGovernor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
pragma solidity =0.8.21;

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/Multicall.sol";
import "../core/interfaces/IPoolFactory.sol";
import "../types/PackedValue.sol";
import "../core/interfaces/IConfigurable.sol";
import "../libraries/Constants.sol";
import "../libraries/SafeCast.sol";

contract TokenVertexUpdaterGovernor is AccessControl {
contract TokenVertexUpdaterGovernor is AccessControl, Multicall {
using SafeCast for uint256;
/// @notice Config data is out-of-date
/// @param timestamp Update timestamp
Expand Down Expand Up @@ -36,11 +37,25 @@ contract TokenVertexUpdaterGovernor is AccessControl {
maxUpdateTimeDeviation = _maxUpdateTimeDeviation;
}

function updateTokenVertexConfig(
function updateTokenVertexConfigPremiumRates(
PackedValue _packedTokenTimestamp,
PackedValue _packedBalanceRates,
PackedValue _packedPremiumRates
) public virtual onlyRole(TOKEN_VERTEX_UPDATER_ROLE) {
_updateTokenVertexConfig(_packedTokenTimestamp, _packedPremiumRates, _verticesUpdatePremiumRates);
}

function updateTokenVertexConfigBalanceRates(
PackedValue _packedTokenTimestamp,
PackedValue _packedBalanceRates
) public virtual onlyRole(TOKEN_VERTEX_UPDATER_ROLE) {
return _updateTokenVertexConfig(_packedTokenTimestamp, _packedBalanceRates, _verticesUpdateBalanceRates);
}

function _updateTokenVertexConfig(
PackedValue _packedTokenTimestamp,
PackedValue _packedData,
function(IERC20, PackedValue) returns (IConfigurable.VertexConfig[] memory) _verticesFn
) internal {
unchecked {
IERC20 token = IERC20(_packedTokenTimestamp.unpackAddress(0));
uint64 timestamp = _packedTokenTimestamp.unpackUint64(160);
Expand Down Expand Up @@ -72,19 +87,39 @@ contract TokenVertexUpdaterGovernor is AccessControl {
tokenFeeRateConfig.referralDiscountRate
) = poolFactory.tokenFeeRateConfigs(token);

IConfigurable.VertexConfig[] memory vertices = new IConfigurable.VertexConfig[](Constants.VERTEX_NUM);
for (uint8 i; i < Constants.VERTEX_NUM; ++i) {
vertices[i].balanceRate = _packedBalanceRates.unpackUint32(i * 32);
vertices[i].premiumRate = _packedPremiumRates.unpackUint32(i * 32);
}

IPoolFactory.TokenPriceConfig memory tokenPriceConfig;
(, tokenPriceConfig.liquidationVertexIndex) = poolFactory.tokenPriceConfigs(token);
IPool pool = poolFactory.pools(token);
(, , , , tokenPriceConfig.maxPriceImpactLiquidity, ) = pool.globalLiquidityPosition();

IConfigurable.VertexConfig[] memory vertices = _verticesFn(token, _packedData);
tokenPriceConfig.vertices = vertices;

poolFactory.updateTokenConfig(token, tokenConfig, tokenFeeRateConfig, tokenPriceConfig);
}
}

function _verticesUpdateBalanceRates(
IERC20 _token,
PackedValue _packedBalanceRates
) internal view returns (IConfigurable.VertexConfig[] memory) {
IConfigurable.VertexConfig[] memory vertices = new IConfigurable.VertexConfig[](Constants.VERTEX_NUM);
for (uint8 i; i < Constants.VERTEX_NUM; ++i) {
vertices[i].balanceRate = _packedBalanceRates.unpackUint32(i * 32);
(, vertices[i].premiumRate) = poolFactory.tokenPriceVertexConfigs(_token, i);
}
return vertices;
}

function _verticesUpdatePremiumRates(
IERC20 _token,
PackedValue _packedPremiumRates
) internal view returns (IConfigurable.VertexConfig[] memory) {
IConfigurable.VertexConfig[] memory vertices = new IConfigurable.VertexConfig[](Constants.VERTEX_NUM);
for (uint8 i; i < Constants.VERTEX_NUM; ++i) {
(vertices[i].balanceRate, ) = poolFactory.tokenPriceVertexConfigs(_token, i);
vertices[i].premiumRate = _packedPremiumRates.unpackUint32(i * 32);
}
return vertices;
}
}
78 changes: 69 additions & 9 deletions test/governance/TokenVertexUpdaterGovernor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,28 +111,30 @@ describe("TokenVertexUpdaterGovernor", () => {
return {s0, s1, s2, tokenVertexUpdaterGovernor, poolFactory, pool, ETH, USDC};
}

it("updateTokenVertexConfig test", async () => {
it("updateTokenVertexConfigBalanceRates test", async () => {
const {s0, s1, s2, tokenVertexUpdaterGovernor, poolFactory, pool, ETH, USDC} = await deployFixture();
const balanceRateList = [0n, 100000n, 2000000n, 3000000n, 4000000n, 5000000n, 6000000n]; // 0->1%->2%...6%
const premiumRateList = [0n, 60000n, 200000n, 250000n, 300000n, 700000n, 11000000n]; // [0%. 0.06%, 0.2%, 0.25%, 0.3%, 0.7%, 11%]
let balanceRateList = [0n, 100000n, 2000000n, 3000000n, 4000000n, 5000000n, 6000000n]; // 0->1%->2%...6%
let previousPremiumRateList = [];
for (let i = 0; i < balanceRateList.length; i++) {
const {balanceRate, premiumRate} = await poolFactory.tokenPriceVertexConfigs(ETH.address, i);
previousPremiumRateList.push(BigInt(premiumRate));
}
let packedBalanceRate = 0n;
let packedPremiumRate = 0n;
for (let i = 0; i < balanceRateList.length; i++) {
packedBalanceRate += balanceRateList[i] << (32n * BigInt(i));
packedPremiumRate += premiumRateList[i] << (32n * BigInt(i));
}
const regexp: RegExp = /is missing role 0x0833596c19f8afe7d32bf2c778d80a2e2b0dcaa54c9ed6c8df6d646a481f4f89$/;
const now = await time.latest();
const packedTokenTimestamp = BigNumber.from(ETH.address).toBigInt() + BigInt(now) * 2n ** 160n;
await expect(
tokenVertexUpdaterGovernor
.connect(s0)
.updateTokenVertexConfig(packedTokenTimestamp, packedBalanceRate, packedPremiumRate)
.updateTokenVertexConfigBalanceRates(packedTokenTimestamp, packedBalanceRate)
).to.be.revertedWith(regexp);
await expect(
tokenVertexUpdaterGovernor
.connect(s2)
.updateTokenVertexConfig(packedTokenTimestamp, packedBalanceRate, packedPremiumRate)
.updateTokenVertexConfigBalanceRates(packedTokenTimestamp, packedBalanceRate)
).to.be.revertedWith(regexp);

const beforeTokenConfigs = await poolFactory.tokenConfigs(ETH.address);
Expand All @@ -148,15 +150,73 @@ describe("TokenVertexUpdaterGovernor", () => {
await expect(
tokenVertexUpdaterGovernor
.connect(s1)
.updateTokenVertexConfig(stalePackedTokenTimestamp, packedBalanceRate, packedPremiumRate)
.updateTokenVertexConfigBalanceRates(stalePackedTokenTimestamp, packedBalanceRate)
).to.be.revertedWithCustomError(tokenVertexUpdaterGovernor, "StaleConfig");

await tokenVertexUpdaterGovernor
.connect(s1)
.updateTokenVertexConfig(packedTokenTimestamp, packedBalanceRate, packedPremiumRate);
.updateTokenVertexConfigBalanceRates(packedTokenTimestamp, packedBalanceRate);
for (let i = 0; i < balanceRateList.length; i++) {
const {balanceRate, premiumRate} = await poolFactory.tokenPriceVertexConfigs(ETH.address, i);
expect(balanceRate).eq(balanceRateList[i]);
expect(premiumRate).eq(previousPremiumRateList[i]);
}
const {maxPriceImpactLiquidity} = await poolFactory.tokenPriceConfigs(ETH.address);
expect(maxPriceImpactLiquidity).eq(beforeTokenConfigs.minMarginPerPosition.mul(200n));
const afterTokenConfigs = await poolFactory.tokenConfigs(ETH.address);
const afterTokenFeeRateConfigs = await poolFactory.tokenFeeRateConfigs(ETH.address);
expect(JSON.stringify(beforeTokenConfigs)).equals(JSON.stringify(afterTokenConfigs));
expect(JSON.stringify(beforeTokenFeeRateConfigs)).equals(JSON.stringify(afterTokenFeeRateConfigs));
});

it("updateTokenVertexConfigPremiumRate test", async () => {
const {s0, s1, s2, tokenVertexUpdaterGovernor, poolFactory, pool, ETH, USDC} = await deployFixture();
let previousBalanceRateList = []; // 0->1%->2%...6%
let premiumRateList = [0n, 60000n, 200000n, 250000n, 300000n, 700000n, 11000000n]; // [0%. 0.06%, 0.2%, 0.25%, 0.3%, 0.7%, 11%]
for (let i = 0; i < premiumRateList.length; i++) {
const {balanceRate, premiumRate} = await poolFactory.tokenPriceVertexConfigs(ETH.address, i);
previousBalanceRateList.push(BigInt(balanceRate));
}
let packedPremiumRate = 0n;
for (let i = 0; i < premiumRateList.length; i++) {
packedPremiumRate += premiumRateList[i] << (32n * BigInt(i));
}
const regexp: RegExp = /is missing role 0x0833596c19f8afe7d32bf2c778d80a2e2b0dcaa54c9ed6c8df6d646a481f4f89$/;
const now = await time.latest();
const packedTokenTimestamp = BigNumber.from(ETH.address).toBigInt() + BigInt(now) * 2n ** 160n;
await expect(
tokenVertexUpdaterGovernor
.connect(s0)
.updateTokenVertexConfigPremiumRates(packedTokenTimestamp, packedPremiumRate)
).to.be.revertedWith(regexp);
await expect(
tokenVertexUpdaterGovernor
.connect(s2)
.updateTokenVertexConfigPremiumRates(packedTokenTimestamp, packedPremiumRate)
).to.be.revertedWith(regexp);

const beforeTokenConfigs = await poolFactory.tokenConfigs(ETH.address);
const beforeTokenFeeRateConfigs = await poolFactory.tokenFeeRateConfigs(ETH.address);
await USDC.transfer(pool.address, beforeTokenConfigs.minMarginPerPosition);
await pool.openLiquidityPosition(
s0.address,
beforeTokenConfigs.minMarginPerPosition,
beforeTokenConfigs.minMarginPerPosition.mul(200n)
);

const stalePackedTokenTimestamp = BigNumber.from(ETH.address).toBigInt() + BigInt(now - 61) * 2n ** 160n;
await expect(
tokenVertexUpdaterGovernor
.connect(s1)
.updateTokenVertexConfigPremiumRates(stalePackedTokenTimestamp, packedPremiumRate)
).to.be.revertedWithCustomError(tokenVertexUpdaterGovernor, "StaleConfig");

await tokenVertexUpdaterGovernor
.connect(s1)
.updateTokenVertexConfigPremiumRates(packedTokenTimestamp, packedPremiumRate);
for (let i = 0; i < premiumRateList.length; i++) {
const {balanceRate, premiumRate} = await poolFactory.tokenPriceVertexConfigs(ETH.address, i);
expect(balanceRate).eq(previousBalanceRateList[i]);
expect(premiumRate).eq(premiumRateList[i]);
}
const {maxPriceImpactLiquidity} = await poolFactory.tokenPriceConfigs(ETH.address);
Expand Down

0 comments on commit fc4c363

Please sign in to comment.