From 8305b0927fe11874165999b5859c54775b9a73f3 Mon Sep 17 00:00:00 2001 From: naguib Date: Tue, 25 Mar 2025 22:12:52 +0100 Subject: [PATCH 1/7] Refactor rebase function parameters to separate positive and negative growth --- contracts/UFragmentsPolicy.sol | 39 +++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/contracts/UFragmentsPolicy.sol b/contracts/UFragmentsPolicy.sol index 64efde3..769459d 100644 --- a/contracts/UFragmentsPolicy.sol +++ b/contracts/UFragmentsPolicy.sol @@ -96,7 +96,8 @@ contract UFragmentsPolicy is Ownable { // Used in computation of (Upper-Lower)/(1-(Upper/Lower)/2^(Growth*delta))) + Lower int256 public rebaseFunctionLowerPercentage; int256 public rebaseFunctionUpperPercentage; - int256 public rebaseFunctionGrowth; + int256 public rebaseFunctionPositiveGrowth; + int256 public rebaseFunctionNegativeGrowth; int256 private constant ONE = int256(10**DECIMALS); @@ -166,10 +167,6 @@ contract UFragmentsPolicy is Ownable { orchestrator = orchestrator_; } - function setRebaseFunctionGrowth(int256 rebaseFunctionGrowth_) external onlyOwner { - require(rebaseFunctionGrowth_ >= 0); - rebaseFunctionGrowth = rebaseFunctionGrowth_; - } function setRebaseFunctionLowerPercentage(int256 rebaseFunctionLowerPercentage_) external @@ -187,6 +184,16 @@ contract UFragmentsPolicy is Ownable { rebaseFunctionUpperPercentage = rebaseFunctionUpperPercentage_; } + function setRebaseFunctionPositiveGrowth(int256 rebaseFunctionPositiveGrowth_) external onlyOwner { + require(rebaseFunctionPositiveGrowth_ >= 0); + rebaseFunctionPositiveGrowth = rebaseFunctionPositiveGrowth_; + } + + function setRebaseFunctionNegativeGrowth(int256 rebaseFunctionNegativeGrowth_) external onlyOwner { + require(rebaseFunctionNegativeGrowth_ >= 0); + rebaseFunctionNegativeGrowth = rebaseFunctionNegativeGrowth_; + } + /** * @notice Sets the deviation threshold fraction. If the exchange rate given by the market * oracle is within this fractional distance from the targetRate, then no supply @@ -246,7 +253,8 @@ contract UFragmentsPolicy is Ownable { // deviationThreshold = 0.05e18 = 5e16 deviationThreshold = 25 * 10**(DECIMALS - 3); - rebaseFunctionGrowth = int256(45 * (10**DECIMALS)); + rebaseFunctionPositiveGrowth = int256(45 * (10**DECIMALS)); // Positive growth + rebaseFunctionNegativeGrowth = int256(45 * (10**DECIMALS)); // Negative growth rebaseFunctionUpperPercentage = int256(5 * (10**(DECIMALS - 2))); // 0.05 rebaseFunctionLowerPercentage = int256((-77) * int256(10**(DECIMALS - 3))); // -0.77 @@ -334,12 +342,19 @@ contract UFragmentsPolicy is Ownable { } int256 targetRateSigned = targetRate.toInt256Safe(); int256 normalizedRate = rate.toInt256Safe().mul(ONE).div(targetRateSigned); - int256 rebasePercentage = computeRebasePercentage( - normalizedRate, - rebaseFunctionLowerPercentage, - rebaseFunctionUpperPercentage, - rebaseFunctionGrowth - ); + + // Determine growth and bounds based on positive or negative rebase + int256 growth = normalizedRate >= ONE + ? rebaseFunctionPositiveGrowth + : rebaseFunctionNegativeGrowth; + int256 lower = normalizedRate >= ONE + ? -rebaseFunctionUpperPercentage + : rebaseFunctionLowerPercentage; + int256 upper = normalizedRate >= ONE + ? rebaseFunctionUpperPercentage + : -rebaseFunctionLowerPercentage; + + int256 rebasePercentage = computeRebasePercentage(normalizedRate, lower, upper, growth); return uFrags.totalSupply().toInt256Safe().mul(rebasePercentage).div(ONE); } From ced07b390127aa8ec3391e3658a573dadabc8a0d Mon Sep 17 00:00:00 2001 From: naguib Date: Tue, 25 Mar 2025 22:13:26 +0100 Subject: [PATCH 2/7] Refactor UFragmentsPolicy tests to separate positive and negative growth functions --- test/unit/UFragmentsPolicy.ts | 245 ++++++++++++++++++++++------------ 1 file changed, 161 insertions(+), 84 deletions(-) diff --git a/test/unit/UFragmentsPolicy.ts b/test/unit/UFragmentsPolicy.ts index cf8ca89..ac2d1a2 100644 --- a/test/unit/UFragmentsPolicy.ts +++ b/test/unit/UFragmentsPolicy.ts @@ -396,17 +396,32 @@ describe('UFragmentsPolicy:CurveParameters', async function () { } = await waffle.loadFixture(mockedUpgradablePolicy)) }) - describe('when rebaseFunctionGrowth is more than 0', async function () { + describe('when rebaseFunctionRebasePositiveGrowth is more than 0', async function () { it('should setRebaseFunctionGrowth', async function () { - await uFragmentsPolicy.connect(deployer).setRebaseFunctionGrowth('42000000000000000000') - expect(await uFragmentsPolicy.rebaseFunctionGrowth()).to.eq('42000000000000000000') + await uFragmentsPolicy.connect(deployer).setRebaseFunctionPositiveGrowth('42000000000000000000') + expect(await uFragmentsPolicy.rebaseFunctionPositiveGrowth()).to.eq('42000000000000000000') }) }) - describe('when rebaseFunctionGrowth is less than 0', async function () { + describe('when rebaseFunctionRebasePositiveGrowth is less than 0', async function () { it('should fail', async function () { await expect( - uFragmentsPolicy.connect(deployer).setRebaseFunctionGrowth(-1), + uFragmentsPolicy.connect(deployer).setRebaseFunctionPositiveGrowth(-1), + ).to.be.reverted + }) + }) + + describe('when rebaseFunctionRebaseNegativeGrowth is more than 0', async function () { + it('should setRebaseFunctionGrowth', async function () { + await uFragmentsPolicy.connect(deployer).setRebaseFunctionNegativeGrowth('42000000000000000000') + expect(await uFragmentsPolicy.rebaseFunctionNegativeGrowth()).to.eq('42000000000000000000') + }) + }) + + describe('when rebaseFunctionRebaseNegativeGrowth is less than 0', async function () { + it('should fail', async function () { + await expect( + uFragmentsPolicy.connect(deployer).setRebaseFunctionNegativeGrowth(-1), ).to.be.reverted }) }) @@ -448,82 +463,6 @@ describe('UFragmentsPolicy:CurveParameters', async function () { }) }) -describe('UFragments:setRebaseFunctionGrowth:accessControl', function () { - before('setup UFragmentsPolicy contract', async () => { - ;({ - deployer, - user, - orchestrator, - mockUFragments, - mockMarketOracle, - mockCpiOracle, - uFragmentsPolicy, - } = await waffle.loadFixture(mockedUpgradablePolicy)) - }) - - it('should be callable by owner', async function () { - await expect(uFragmentsPolicy.connect(deployer).setRebaseFunctionGrowth(1)) - .to.not.be.reverted - }) - - it('should NOT be callable by non-owner', async function () { - await expect(uFragmentsPolicy.connect(user).setRebaseFunctionGrowth(1)).to - .be.reverted - }) -}) - -describe('UFragments:setRebaseFunctionLowerPercentage:accessControl', function () { - before('setup UFragmentsPolicy contract', async () => { - ;({ - deployer, - user, - orchestrator, - mockUFragments, - mockMarketOracle, - mockCpiOracle, - uFragmentsPolicy, - } = await waffle.loadFixture(mockedUpgradablePolicy)) - }) - - it('should be callable by owner', async function () { - await expect( - uFragmentsPolicy.connect(deployer).setRebaseFunctionLowerPercentage(-1), - ).to.not.be.reverted - }) - - it('should NOT be callable by non-owner', async function () { - await expect( - uFragmentsPolicy.connect(user).setRebaseFunctionLowerPercentage(-1), - ).to.be.reverted - }) -}) - -describe('UFragments:setRebaseFunctionUpperPercentage:accessControl', function () { - before('setup UFragmentsPolicy contract', async () => { - ;({ - deployer, - user, - orchestrator, - mockUFragments, - mockMarketOracle, - mockCpiOracle, - uFragmentsPolicy, - } = await waffle.loadFixture(mockedUpgradablePolicy)) - }) - - it('should be callable by owner', async function () { - await expect( - uFragmentsPolicy.connect(deployer).setRebaseFunctionUpperPercentage(1), - ).to.not.be.reverted - }) - - it('should NOT be callable by non-owner', async function () { - await expect( - uFragmentsPolicy.connect(user).setRebaseFunctionUpperPercentage(1), - ).to.be.reverted - }) -}) - describe('UFragmentsPolicy:setRebaseTimingParameters', async function () { before('setup UFragmentsPolicy contract', async function () { ;({ @@ -1053,7 +992,7 @@ describe('UFragmentsPolicy:Rebase', async function () { await mockExternalData(INITIAL_RATE_2X, INITIAL_TARGET_RATE, 1000) await uFragmentsPolicy .connect(deployer) - .setRebaseFunctionGrowth('100' + '000000000000000000') + .setRebaseFunctionPositiveGrowth('100' + '000000000000000000') await increaseTime(60) }) @@ -1073,7 +1012,7 @@ describe('UFragmentsPolicy:Rebase', async function () { await mockExternalData(0, INITIAL_TARGET_RATE, 1000) await uFragmentsPolicy .connect(deployer) - .setRebaseFunctionGrowth('75' + '000000000000000000') + .setRebaseFunctionNegativeGrowth('75' + '000000000000000000') await increaseTime(60) }) @@ -1088,12 +1027,54 @@ describe('UFragmentsPolicy:Rebase', async function () { }) }) + describe('when normalizedRate is greater than ONE (positive rebase)', function () { + beforeEach(async function () { + await mockExternalData( + INITIAL_RATE_30P_MORE, + INITIAL_TARGET_RATE, + 1000, + ) + await uFragmentsPolicy + .connect(deployer) + .setRebaseFunctionPositiveGrowth('50' + '000000000000000000') // Positive growth + await increaseTime(60) + }) + + it('should compute positive rebase percentage correctly', async function () { + const rebaseEvent = await parseRebaseEvent( + uFragmentsPolicy.connect(orchestrator).rebase(), + ) + expect(rebaseEvent.requestedSupplyAdjustment).to.eq(0) + }) + }) + + describe('when normalizedRate is less than ONE (negative rebase)', function () { + beforeEach(async function () { + await mockExternalData( + INITIAL_RATE_30P_LESS, + INITIAL_TARGET_RATE, + 1000, + ) + await uFragmentsPolicy + .connect(deployer) + .setRebaseFunctionNegativeGrowth('30' + '000000000000000000') // Negative growth + await increaseTime(60) + }) + + it('should compute negative rebase percentage correctly', async function () { + const rebaseEvent = await parseRebaseEvent( + uFragmentsPolicy.connect(orchestrator).rebase(), + ) + expect(rebaseEvent.requestedSupplyAdjustment).to.eq(0) + }) + }) + describe('exponent less than -100', function () { before(async function () { await mockExternalData(0, INITIAL_TARGET_RATE, 1000) await uFragmentsPolicy .connect(deployer) - .setRebaseFunctionGrowth('150' + '000000000000000000') + .setRebaseFunctionNegativeGrowth('150' + '000000000000000000') await increaseTime(60) }) @@ -1328,3 +1309,99 @@ describe('UFragmentsPolicy:Rebase', async function () { }) }) }) + +describe('UFragmentsPolicy:CurveParameters', async function () { + before('setup UFragmentsPolicy contract', async function () { + ;({ + deployer, + user, + orchestrator, + mockUFragments, + mockMarketOracle, + mockCpiOracle, + uFragmentsPolicy, + } = await waffle.loadFixture(mockedUpgradablePolicy)) + }) + + describe('when rebaseFunctionPositiveGrowth is more than 0', async function () { + it('should setRebaseFunctionPositiveGrowth', async function () { + await uFragmentsPolicy.connect(deployer).setRebaseFunctionPositiveGrowth('42000000000000000000') + expect(await uFragmentsPolicy.rebaseFunctionPositiveGrowth()).to.eq('42000000000000000000') + }) + }) + + describe('when rebaseFunctionNegativeGrowth is more than 0', async function () { + it('should setRebaseFunctionNegativeGrowth', async function () { + await uFragmentsPolicy.connect(deployer).setRebaseFunctionNegativeGrowth('42000000000000000000') + expect(await uFragmentsPolicy.rebaseFunctionNegativeGrowth()).to.eq('42000000000000000000') + }) + }) + + describe('when rebaseFunctionPositiveGrowth is less than 0', async function () { + it('should fail', async function () { + await expect( + uFragmentsPolicy.connect(deployer).setRebaseFunctionPositiveGrowth(-1), + ).to.be.reverted + }) + }) + + describe('when rebaseFunctionNegativeGrowth is less than 0', async function () { + it('should fail', async function () { + await expect( + uFragmentsPolicy.connect(deployer).setRebaseFunctionNegativeGrowth(-1), + ).to.be.reverted + }) + }) +}) + +describe('UFragments:setRebaseFunctionPositiveGrowth:accessControl', function () { + before('setup UFragmentsPolicy contract', async () => { + ;({ + deployer, + user, + orchestrator, + mockUFragments, + mockMarketOracle, + mockCpiOracle, + uFragmentsPolicy, + } = await waffle.loadFixture(mockedUpgradablePolicy)) + }) + + it('should be callable by owner', async function () { + await expect( + uFragmentsPolicy.connect(deployer).setRebaseFunctionPositiveGrowth(1), + ).to.not.be.reverted + }) + + it('should NOT be callable by non-owner', async function () { + await expect( + uFragmentsPolicy.connect(user).setRebaseFunctionPositiveGrowth(1), + ).to.be.reverted + }) +}) + +describe('UFragments:setRebaseFunctionNegativeGrowth:accessControl', function () { + before('setup UFragmentsPolicy contract', async () => { + ;({ + deployer, + user, + orchestrator, + mockUFragments, + mockMarketOracle, + mockCpiOracle, + uFragmentsPolicy, + } = await waffle.loadFixture(mockedUpgradablePolicy)) + }) + + it('should be callable by owner', async function () { + await expect( + uFragmentsPolicy.connect(deployer).setRebaseFunctionNegativeGrowth(1), + ).to.not.be.reverted + }) + + it('should NOT be callable by non-owner', async function () { + await expect( + uFragmentsPolicy.connect(user).setRebaseFunctionNegativeGrowth(1), + ).to.be.reverted + }) +}) From 2cb4317eb5655d3444cc9e48070784fa1add14d1 Mon Sep 17 00:00:00 2001 From: naguib Date: Tue, 25 Mar 2025 23:04:22 +0100 Subject: [PATCH 3/7] Addressing code review comments --- contracts/UFragmentsPolicy.sol | 29 ++++++++++++++++++----------- test/unit/UFragmentsPolicy.ts | 9 ++++++--- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/contracts/UFragmentsPolicy.sol b/contracts/UFragmentsPolicy.sol index 769459d..a288634 100644 --- a/contracts/UFragmentsPolicy.sol +++ b/contracts/UFragmentsPolicy.sol @@ -344,17 +344,24 @@ contract UFragmentsPolicy is Ownable { int256 normalizedRate = rate.toInt256Safe().mul(ONE).div(targetRateSigned); // Determine growth and bounds based on positive or negative rebase - int256 growth = normalizedRate >= ONE - ? rebaseFunctionPositiveGrowth - : rebaseFunctionNegativeGrowth; - int256 lower = normalizedRate >= ONE - ? -rebaseFunctionUpperPercentage - : rebaseFunctionLowerPercentage; - int256 upper = normalizedRate >= ONE - ? rebaseFunctionUpperPercentage - : -rebaseFunctionLowerPercentage; - - int256 rebasePercentage = computeRebasePercentage(normalizedRate, lower, upper, growth); + int256 rebasePercentage; + + if (normalizedRate >= ONE) { + rebasePercentage = computeRebasePercentage(normalizedRate, -rebaseFunctionUpperPercentage, rebaseFunctionUpperPercentage, rebaseFunctionPositiveGrowth); + } else { + rebasePercentage = computeRebasePercentage(normalizedRate, rebaseFunctionLowerPercentage, -rebaseFunctionLowerPercentage, rebaseFunctionNegativeGrowth); + } + // int256 growth = normalizedRate >= ONE + // ? rebaseFunctionPositiveGrowth + // : rebaseFunctionNegativeGrowth; + // int256 lower = normalizedRate >= ONE + // ? -rebaseFunctionUpperPercentage + // : rebaseFunctionLowerPercentage; + // int256 upper = normalizedRate >= ONE + // ? rebaseFunctionUpperPercentage + // : -rebaseFunctionLowerPercentage; + + // int256 rebasePercentage = computeRebasePercentage(normalizedRate, lower, upper, growth); return uFrags.totalSupply().toInt256Safe().mul(rebasePercentage).div(ONE); } diff --git a/test/unit/UFragmentsPolicy.ts b/test/unit/UFragmentsPolicy.ts index ac2d1a2..13edc39 100644 --- a/test/unit/UFragmentsPolicy.ts +++ b/test/unit/UFragmentsPolicy.ts @@ -1036,7 +1036,10 @@ describe('UFragmentsPolicy:Rebase', async function () { ) await uFragmentsPolicy .connect(deployer) - .setRebaseFunctionPositiveGrowth('50' + '000000000000000000') // Positive growth + .setRebaseFunctionPositiveGrowth('25' + '000000000000000000') // Positive growth + await uFragmentsPolicy + .connect(deployer) + .setRebaseFunctionUpperPercentage('10' + '0000000000000000') await increaseTime(60) }) @@ -1044,7 +1047,7 @@ describe('UFragmentsPolicy:Rebase', async function () { const rebaseEvent = await parseRebaseEvent( uFragmentsPolicy.connect(orchestrator).rebase(), ) - expect(rebaseEvent.requestedSupplyAdjustment).to.eq(0) + expect(rebaseEvent.requestedSupplyAdjustment).to.eq(98) }) }) @@ -1065,7 +1068,7 @@ describe('UFragmentsPolicy:Rebase', async function () { const rebaseEvent = await parseRebaseEvent( uFragmentsPolicy.connect(orchestrator).rebase(), ) - expect(rebaseEvent.requestedSupplyAdjustment).to.eq(0) + expect(rebaseEvent.requestedSupplyAdjustment).to.eq(-76); }) }) From 33771f3db6ced41f42a83b59d164cc514f71a6f9 Mon Sep 17 00:00:00 2001 From: naguib Date: Tue, 25 Mar 2025 23:11:24 +0100 Subject: [PATCH 4/7] Remove comments --- contracts/UFragmentsPolicy.sol | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/contracts/UFragmentsPolicy.sol b/contracts/UFragmentsPolicy.sol index 757db81..f6c33da 100644 --- a/contracts/UFragmentsPolicy.sol +++ b/contracts/UFragmentsPolicy.sol @@ -345,23 +345,12 @@ contract UFragmentsPolicy is Ownable { // Determine growth and bounds based on positive or negative rebase int256 rebasePercentage; - if (normalizedRate >= ONE) { rebasePercentage = computeRebasePercentage(normalizedRate, -rebaseFunctionUpperPercentage, rebaseFunctionUpperPercentage, rebaseFunctionPositiveGrowth); } else { rebasePercentage = computeRebasePercentage(normalizedRate, rebaseFunctionLowerPercentage, -rebaseFunctionLowerPercentage, rebaseFunctionNegativeGrowth); } - // int256 growth = normalizedRate >= ONE - // ? rebaseFunctionPositiveGrowth - // : rebaseFunctionNegativeGrowth; - // int256 lower = normalizedRate >= ONE - // ? -rebaseFunctionUpperPercentage - // : rebaseFunctionLowerPercentage; - // int256 upper = normalizedRate >= ONE - // ? rebaseFunctionUpperPercentage - // : -rebaseFunctionLowerPercentage; - - // int256 rebasePercentage = computeRebasePercentage(normalizedRate, lower, upper, growth); + return uFrags.totalSupply().toInt256Safe().mul(rebasePercentage).div(ONE); } From 263f4a0ac14f4c03adfb256f6e69ec689679e1b8 Mon Sep 17 00:00:00 2001 From: naguib Date: Mon, 31 Mar 2025 23:05:51 +0200 Subject: [PATCH 5/7] Rename rebase function parameters to better reflect their semantics --- contracts/UFragmentsPolicy.sol | 35 +++++++++++++++++++++------------ scripts/deploy.ts | 10 ++++++---- test/unit/UFragmentsPolicy.ts | 36 +++++++++++++++++----------------- 3 files changed, 46 insertions(+), 35 deletions(-) diff --git a/contracts/UFragmentsPolicy.sol b/contracts/UFragmentsPolicy.sol index f6c33da..34d793f 100644 --- a/contracts/UFragmentsPolicy.sol +++ b/contracts/UFragmentsPolicy.sol @@ -94,8 +94,8 @@ contract UFragmentsPolicy is Ownable { // DECIMALS decimal fixed point numbers. // Used in computation of (Upper-Lower)/(1-(Upper/Lower)/2^(Growth*delta))) + Lower - int256 public rebaseFunctionLowerPercentage; - int256 public rebaseFunctionUpperPercentage; + int256 public rebaseFunctionNegativePercentageLimit; + int256 public rebaseFunctionPositivePercentageLimit; int256 public rebaseFunctionPositiveGrowth; int256 public rebaseFunctionNegativeGrowth; @@ -167,21 +167,20 @@ contract UFragmentsPolicy is Ownable { orchestrator = orchestrator_; } - - function setRebaseFunctionLowerPercentage(int256 rebaseFunctionLowerPercentage_) + function setRebaseFunctionNegativePercentageLimit(int256 rebaseFunctionNegativePercentageLimit_) external onlyOwner { - require(rebaseFunctionLowerPercentage_ <= 0); - rebaseFunctionLowerPercentage = rebaseFunctionLowerPercentage_; + require(rebaseFunctionNegativePercentageLimit_ <= 0); + rebaseFunctionNegativePercentageLimit = rebaseFunctionNegativePercentageLimit_; } - function setRebaseFunctionUpperPercentage(int256 rebaseFunctionUpperPercentage_) + function setRebaseFunctionPositivePercentageLimit(int256 rebaseFunctionPositivePercentageLimit_) external onlyOwner { - require(rebaseFunctionUpperPercentage_ >= 0); - rebaseFunctionUpperPercentage = rebaseFunctionUpperPercentage_; + require(rebaseFunctionPositivePercentageLimit_ >= 0); + rebaseFunctionPositivePercentageLimit = rebaseFunctionPositivePercentageLimit_; } function setRebaseFunctionPositiveGrowth(int256 rebaseFunctionPositiveGrowth_) external onlyOwner { @@ -255,8 +254,8 @@ contract UFragmentsPolicy is Ownable { rebaseFunctionPositiveGrowth = int256(45 * (10**DECIMALS)); // Positive growth rebaseFunctionNegativeGrowth = int256(45 * (10**DECIMALS)); // Negative growth - rebaseFunctionUpperPercentage = int256(5 * (10**(DECIMALS - 2))); // 0.05 - rebaseFunctionLowerPercentage = int256((-77) * int256(10**(DECIMALS - 3))); // -0.077 + rebaseFunctionPositivePercentageLimit = int256(5 * (10**(DECIMALS - 2))); // 0.05 + rebaseFunctionNegativePercentageLimit = int256((-77) * int256(10**(DECIMALS - 3))); // -0.077 minRebaseTimeIntervalSec = 1 days; rebaseWindowOffsetSec = 7200; // 2AM UTC @@ -346,9 +345,19 @@ contract UFragmentsPolicy is Ownable { // Determine growth and bounds based on positive or negative rebase int256 rebasePercentage; if (normalizedRate >= ONE) { - rebasePercentage = computeRebasePercentage(normalizedRate, -rebaseFunctionUpperPercentage, rebaseFunctionUpperPercentage, rebaseFunctionPositiveGrowth); + rebasePercentage = computeRebasePercentage( + normalizedRate, + -rebaseFunctionPositivePercentageLimit, + rebaseFunctionPositivePercentageLimit, + rebaseFunctionPositiveGrowth + ); } else { - rebasePercentage = computeRebasePercentage(normalizedRate, rebaseFunctionLowerPercentage, -rebaseFunctionLowerPercentage, rebaseFunctionNegativeGrowth); + rebasePercentage = computeRebasePercentage( + normalizedRate, + rebaseFunctionNegativePercentageLimit, + -rebaseFunctionNegativePercentageLimit, + rebaseFunctionNegativeGrowth + ); } return uFrags.totalSupply().toInt256Safe().mul(rebasePercentage).div(ONE); diff --git a/scripts/deploy.ts b/scripts/deploy.ts index ed13183..cf75690 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -33,9 +33,10 @@ task('deploy:amplforce:testnet', 'Deploy ampleforth contract suite for testnet') // Policy const DEVIATION_TRESHOLD = utils.parseUnits('0.002', 18) // 0.002% (ie) 0.05/24) - const LOWER = utils.parseUnits('-0.005', 18) - const UPPER = utils.parseUnits('0.005', 18) - const GROWTH = utils.parseUnits('3', 18) + const LOWER = utils.parseUnits('-0.005', 18) // rebaseFunctionNegativePercentageLimit + const UPPER = utils.parseUnits('0.005', 18) // rebaseFunctionPositivePercentageLimit + const POSITIVE_GROWTH = utils.parseUnits('31', 18) // rebaseFunctionPositiveGrowth; + const NEGATIVE_GROWTH = utils.parseUnits('41', 18) // rebaseFunctionNegativeGrowth; const MIN_REBASE_INTERVAL = 1200 // 20 mins const REBASE_WINDOW_OFFSET = 0 const REBASE_WINDOW_LEN = 2400 // 40 mins @@ -119,7 +120,8 @@ task('deploy:amplforce:testnet', 'Deploy ampleforth contract suite for testnet') // configure parameters await waitFor(policy.setDeviationThreshold(DEVIATION_TRESHOLD)) - await waitFor(policy.setRebaseFunctionGrowth(GROWTH)) + await waitFor(policy.setRebaseFunctionPositiveGrowth(POSITIVE_GROWTH)) + await waitFor(policy.setRebaseFunctionNegativeGrowth(NEGATIVE_GROWTH)) await waitFor(policy.setRebaseFunctionLowerPercentage(LOWER)) await waitFor(policy.setRebaseFunctionUpperPercentage(UPPER)) await waitFor( diff --git a/test/unit/UFragmentsPolicy.ts b/test/unit/UFragmentsPolicy.ts index 13edc39..8147bae 100644 --- a/test/unit/UFragmentsPolicy.ts +++ b/test/unit/UFragmentsPolicy.ts @@ -426,39 +426,39 @@ describe('UFragmentsPolicy:CurveParameters', async function () { }) }) - describe('when rebaseFunctionLowerPercentage is more than 0', async function () { + describe('when rebaseFunctionNegativePercentageLimit is less than 0', async function () { + it('should setRebaseFunctionNegativePercentageLimit', async function () { + await uFragmentsPolicy + .connect(deployer) + .setRebaseFunctionNegativePercentageLimit(-1) + expect(await uFragmentsPolicy.rebaseFunctionNegativePercentageLimit()).to.eq(-1) + }) + }) + + describe('when rebaseFunctionNegativePercentageLimit is more than 0', async function () { it('should fail', async function () { await expect( uFragmentsPolicy .connect(deployer) - .setRebaseFunctionLowerPercentage(1000), + .setRebaseFunctionNegativePercentageLimit(1000), ).to.be.reverted }) }) - describe('when rebaseFunctionLowerPercentage is less than 0', async function () { - it('should setRebaseFunctionLowerPercentage', async function () { - await uFragmentsPolicy - .connect(deployer) - .setRebaseFunctionLowerPercentage(-1) - expect(await uFragmentsPolicy.rebaseFunctionLowerPercentage()).to.eq(-1) - }) - }) - - describe('when rebaseFunctionUpperPercentage is less than 0', async function () { + describe('when rebaseFunctionPositivePercentageLimit is less than 0', async function () { it('should fail', async function () { await expect( - uFragmentsPolicy.connect(deployer).setRebaseFunctionUpperPercentage(-1), + uFragmentsPolicy.connect(deployer).setRebaseFunctionPositivePercentageLimit(-1), ).to.be.reverted }) }) - describe('when rebaseFunctionUpperPercentage is more than 0', async function () { - it('should setRebaseFunctionUpperPercentage', async function () { + describe('when rebaseFunctionPositivePercentageLimit is more than 0', async function () { + it('should setRebaseFunctionPositivePercentageLimit', async function () { await uFragmentsPolicy .connect(deployer) - .setRebaseFunctionUpperPercentage(1000) - expect(await uFragmentsPolicy.rebaseFunctionUpperPercentage()).to.eq(1000) + .setRebaseFunctionPositivePercentageLimit(1000) + expect(await uFragmentsPolicy.rebaseFunctionPositivePercentageLimit()).to.eq(1000) }) }) }) @@ -1039,7 +1039,7 @@ describe('UFragmentsPolicy:Rebase', async function () { .setRebaseFunctionPositiveGrowth('25' + '000000000000000000') // Positive growth await uFragmentsPolicy .connect(deployer) - .setRebaseFunctionUpperPercentage('10' + '0000000000000000') + .setRebaseFunctionPositivePercentageLimit('10' + '0000000000000000') await increaseTime(60) }) From 239da1586f3709522687470fcd8551e660a5cdb6 Mon Sep 17 00:00:00 2001 From: naguib Date: Mon, 31 Mar 2025 23:11:05 +0200 Subject: [PATCH 6/7] Update 2 lines in deploy.ts --- scripts/deploy.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/deploy.ts b/scripts/deploy.ts index cf75690..0ea1469 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -122,8 +122,8 @@ task('deploy:amplforce:testnet', 'Deploy ampleforth contract suite for testnet') await waitFor(policy.setDeviationThreshold(DEVIATION_TRESHOLD)) await waitFor(policy.setRebaseFunctionPositiveGrowth(POSITIVE_GROWTH)) await waitFor(policy.setRebaseFunctionNegativeGrowth(NEGATIVE_GROWTH)) - await waitFor(policy.setRebaseFunctionLowerPercentage(LOWER)) - await waitFor(policy.setRebaseFunctionUpperPercentage(UPPER)) + await waitFor(policy.setRebaseFunctionNegativePercentageLimit(LOWER)) + await waitFor(policy.setRebaseFunctionPositivePercentageLimit(UPPER)) await waitFor( policy.setRebaseTimingParameters( MIN_REBASE_INTERVAL, From 0e7f9d176f0983664e7eabf89d37e578a832eaeb Mon Sep 17 00:00:00 2001 From: naguib Date: Tue, 1 Apr 2025 13:42:19 +0200 Subject: [PATCH 7/7] add /// @custom:oz-renamed-from to the renamed variables --- contracts/UFragmentsPolicy.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contracts/UFragmentsPolicy.sol b/contracts/UFragmentsPolicy.sol index 34d793f..7af894b 100644 --- a/contracts/UFragmentsPolicy.sol +++ b/contracts/UFragmentsPolicy.sol @@ -94,8 +94,11 @@ contract UFragmentsPolicy is Ownable { // DECIMALS decimal fixed point numbers. // Used in computation of (Upper-Lower)/(1-(Upper/Lower)/2^(Growth*delta))) + Lower + /// @custom:oz-renamed-from rebaseFunctionLowerPercentage int256 public rebaseFunctionNegativePercentageLimit; + /// @custom:oz-renamed-from rebaseFunctionUpperPercentage int256 public rebaseFunctionPositivePercentageLimit; + /// @custom:oz-renamed-from rebaseFunctionGrowth int256 public rebaseFunctionPositiveGrowth; int256 public rebaseFunctionNegativeGrowth;