From 4c23d371f42dd03a7edf56efbb543d1cff99360f Mon Sep 17 00:00:00 2001 From: Nick95550 Date: Tue, 25 Jun 2024 11:10:31 +0800 Subject: [PATCH] wip --- contracts/ProtocolTimeManager.sol | 147 ++++++++-- test/protocolTimeManager.test.ts | 440 ++++++++++++++++++++++-------- 2 files changed, 451 insertions(+), 136 deletions(-) diff --git a/contracts/ProtocolTimeManager.sol b/contracts/ProtocolTimeManager.sol index b7944c4e..67cd1c04 100644 --- a/contracts/ProtocolTimeManager.sol +++ b/contracts/ProtocolTimeManager.sol @@ -21,6 +21,11 @@ contract ProtocolTimeManager is */ uint256 start; + /** + * @notice Holds the start delay for the cycle/period intervals in unix + */ + uint256 delay; + /** * @notice Holds the cycle duration in unix */ @@ -48,9 +53,12 @@ contract ProtocolTimeManager is error CannotInitializeWithZeroPeriodDuration(); error CannotSetProtocolStartWithZeroStart(); error CannotSetCycleDurationWithZeroDuration(); - error CannotSetStartInFuture(); + error CannotSetStartInPast(); error CannotSetZeroPeriodDuration(); error CannotSetZeroCycleDuration(); + error CannotSetDuplicateCycleDuration(); + error CannotSetDuplicatePeriodDuration(); + error ProtocolHasNotBegun(); function initialize(uint256 _cycleDuration, uint256 _periodDuration) external initializer { if (_cycleDuration == 0) { @@ -62,9 +70,8 @@ contract ProtocolTimeManager is Ownable2StepUpgradeable.__Ownable2Step_init(); - start = block.timestamp; - _setCycleDuration(_cycleDuration); - _setPeriodDuration(_periodDuration); + cycleDuration = _cycleDuration; + periodDuration = _periodDuration; } /** @@ -77,16 +84,18 @@ contract ProtocolTimeManager is /** * @notice Sets the start time for the cycle/period intervals - * @param _start The start time for the cycle/period intervals in unix + * @param _delay The start time for the cycle/period intervals in unix */ - function setProtocolStart(uint256 _start) external onlyOwner { - if (_start == 0) { + function setProtocolStart(uint256 _delay) external onlyOwner { + if (_delay == 0) { revert CannotSetProtocolStartWithZeroStart(); } - if (_start > block.timestamp) { - revert CannotSetStartInFuture(); - } - start = _start; + + cycleDurationUpdates.set(_delay, cycleDuration); + periodDurationUpdates.set(_delay, periodDuration); + + start = block.timestamp + _delay; + delay = _delay; } /** @@ -105,17 +114,44 @@ contract ProtocolTimeManager is _setPeriodDuration(_periodDuration); } - /** - * @notice Sets the cycle duration - * @param _cycleDuration The duration for which cycles should last in unix - */ function _setCycleDuration(uint256 _cycleDuration) internal { if (_cycleDuration == 0) { revert CannotSetZeroCycleDuration(); } + if (_cycleDuration == cycleDuration) { + revert CannotSetDuplicateCycleDuration(); + } + if (start == 0) { + revert ProtocolHasNotBegun(); + } + if (start > block.timestamp) { + (uint256 firstKey, ) = cycleDurationUpdates.at(0); + cycleDurationUpdates.set(firstKey, _cycleDuration); + cycleDuration = _cycleDuration; + return; + } + + uint256 effectiveTime; + if (start > block.timestamp) { + effectiveTime = 0; // No cycles have started yet + } else { + uint256 timeSinceStart = block.timestamp - start; + + (uint256 previousTimestamp, uint256 currentCycleDuration) = cycleDurationUpdates.at( + cycleDurationUpdates.length() - 1 + ); + + uint256 remaining = currentCycleDuration - (timeSinceStart % currentCycleDuration); + + effectiveTime = timeSinceStart + remaining; + + if ((effectiveTime + delay) < previousTimestamp) { + effectiveTime = (previousTimestamp - delay); + } + } + + cycleDurationUpdates.set(effectiveTime + delay, _cycleDuration); cycleDuration = _cycleDuration; - uint256 timeSinceStart = block.timestamp - start; - cycleDurationUpdates.set(timeSinceStart, cycleDuration); } /** @@ -126,9 +162,40 @@ contract ProtocolTimeManager is if (_periodDuration == 0) { revert CannotSetZeroPeriodDuration(); } + if (_periodDuration == periodDuration) { + revert CannotSetDuplicatePeriodDuration(); + } + if (start == 0) { + revert ProtocolHasNotBegun(); + } + if (start > block.timestamp) { + (uint256 firstKey, ) = periodDurationUpdates.at(0); + periodDurationUpdates.set(firstKey, _periodDuration); + periodDuration = _periodDuration; + return; + } + + uint256 effectiveTime; + if (start > block.timestamp) { + effectiveTime = 0; // No periods have started yet + } else { + uint256 timeSinceStart = block.timestamp - start; + + (uint256 previousTimestamp, uint256 currentPeriodDuration) = periodDurationUpdates.at( + periodDurationUpdates.length() - 1 + ); + + uint256 remaining = currentPeriodDuration - (timeSinceStart % currentPeriodDuration); + + effectiveTime = timeSinceStart + remaining; + + if ((effectiveTime + delay) < previousTimestamp) { + effectiveTime = (previousTimestamp - delay); + } + } + + periodDurationUpdates.set(effectiveTime + delay, _periodDuration); periodDuration = _periodDuration; - uint256 timeSinceStart = block.timestamp - start; - periodDurationUpdates.set(timeSinceStart, periodDuration); } /** @@ -168,22 +235,33 @@ contract ProtocolTimeManager is * (where 200 is the totalTimeElapsed since start) */ function _getCurrentCycle() internal view returns (uint256) { + if (block.timestamp < start || start == 0) { + revert ProtocolHasNotBegun(); + } + uint256 totalTimeElapsed = block.timestamp - start; uint256 processedCycleIntervals = 0; uint256 cycles = 1; for (uint256 i = 0; (i + 1) < cycleDurationUpdates.length(); ++i) { (uint256 timestamp, uint256 intervalDuration) = cycleDurationUpdates.at(i); + (uint256 nextTimestamp, ) = cycleDurationUpdates.at(i + 1); - uint256 cycleInterval = nextTimestamp - timestamp; - processedCycleIntervals += cycleInterval; + uint256 latestCycleInterval = nextTimestamp - timestamp; - cycles += cycleInterval / intervalDuration; + processedCycleIntervals += latestCycleInterval; + + cycles += latestCycleInterval / intervalDuration; + } + + if (totalTimeElapsed < processedCycleIntervals) { + return cycles; } - uint256 remaingCycleInterval = ((totalTimeElapsed - processedCycleIntervals) / - cycleDuration); + uint256 remaingCycleInterval = (totalTimeElapsed - processedCycleIntervals) / + cycleDuration; + uint256 currentCycle = cycles + remaingCycleInterval; return currentCycle; } @@ -199,23 +277,34 @@ contract ProtocolTimeManager is * refer to explaination above for funtionality */ function _getCurrentPeriod() internal view returns (uint256) { + if (block.timestamp < start || start == 0) { + revert ProtocolHasNotBegun(); + } + uint256 totalTimeElapsed = block.timestamp - start; + uint256 processedPeriodIntervals = 0; - uint256 cycles = 1; + uint256 periods = 1; for (uint256 i = 0; (i + 1) < periodDurationUpdates.length(); ++i) { (uint256 timestamp, uint256 intervalDuration) = periodDurationUpdates.at(i); + (uint256 nextTimestamp, ) = periodDurationUpdates.at(i + 1); + uint256 periodInterval = nextTimestamp - timestamp; processedPeriodIntervals += periodInterval; - cycles += periodInterval / intervalDuration; + periods += periodInterval / intervalDuration; + } + + if (totalTimeElapsed < processedPeriodIntervals) { + return periods; } - uint256 remaingPeriodInterval = ((totalTimeElapsed - processedPeriodIntervals) / - periodDuration); - uint256 currentPeriod = cycles + remaingPeriodInterval; + uint256 remaingPeriodInterval = ((totalTimeElapsed - processedPeriodIntervals)) / + periodDuration; + uint256 currentPeriod = periods + (remaingPeriodInterval); return currentPeriod; } diff --git a/test/protocolTimeManager.test.ts b/test/protocolTimeManager.test.ts index ac347249..6ed83567 100644 --- a/test/protocolTimeManager.test.ts +++ b/test/protocolTimeManager.test.ts @@ -5,7 +5,7 @@ import { deployContracts } from './utils'; import { ProtocolTimeManager } from '../typechain-types'; import { getInterfaceId } from './utils'; -describe('Protocol time manager', () => { +describe.only('Protocol time manager', () => { let contracts: SyloContracts; let protocolTimeManager: ProtocolTimeManager; @@ -53,36 +53,19 @@ describe('Protocol time manager', () => { ); }); - it('cannot set protocol start with future start', async () => { - const x = await ethers.provider.getBlock('latest'); - if (!x) { - expect.fail('timestamp undefeind'); - } - - await expect( - protocolTimeManager.setProtocolStart(x.timestamp + 1000), - ).to.be.revertedWithCustomError( - protocolTimeManager, - 'CannotSetStartInFuture', - ); - }); - it('can set protocol start', async () => { - const x = await ethers.provider.getBlock('latest'); - if (!x) { + const latestBlock = await ethers.provider.getBlock('latest'); + if (!latestBlock) { expect.fail('timestamp undefeind'); } const start = await protocolTimeManager.getStart(); - assert.equal(Number(start), x.timestamp); + assert.equal(Number(start), 0); - await network.provider.send('evm_increaseTime', [3000]); - await network.provider.send('evm_mine'); - - await protocolTimeManager.setProtocolStart(x.timestamp + 1000); + await protocolTimeManager.setProtocolStart(1000); const newStart = await protocolTimeManager.getStart(); - assert.equal(Number(newStart), x.timestamp + 1000); + assert.equal(Number(newStart), latestBlock.timestamp + 1001); }); it('cannot set zero cycle duration', async () => { @@ -94,14 +77,23 @@ describe('Protocol time manager', () => { ); }); + it('cannot set duplicate cycle duration', async () => { + await expect( + protocolTimeManager.setCycleDuration(1000), + ).to.be.revertedWithCustomError( + protocolTimeManager, + 'CannotSetDuplicateCycleDuration', + ); + }); + it('can set cycle duration', async () => { - const cycleDuration = await protocolTimeManager.getCycleDuration(); - assert.equal(Number(cycleDuration), 1000); + await protocolTimeManager.setProtocolStart(100); + + await increaseTime(200); await protocolTimeManager.setCycleDuration(2000); - const cycleDurationTwo = await protocolTimeManager.getCycleDuration(); - assert.equal(Number(cycleDurationTwo), 2000); + await checkCycle(1); }); it('cannot set zero period duration', async () => { @@ -114,151 +106,370 @@ describe('Protocol time manager', () => { }); it('can set period duration', async () => { - const periodDuration = await protocolTimeManager.getPeriodDuration(); - assert.equal(Number(periodDuration), 1000); + await protocolTimeManager.setProtocolStart(100); - await protocolTimeManager.setPeriodDuration(2000); + await increaseTime(200); - const periodDurationTwo = await protocolTimeManager.getPeriodDuration(); - assert.equal(Number(periodDurationTwo), 2000); - }); + await checkCycle(1); - it('can get both current cycle and period', async () => { - await network.provider.send('evm_increaseTime', [3000]); - await network.provider.send('evm_mine'); + await protocolTimeManager.setPeriodDuration(2000); - const times = await protocolTimeManager.timeNow(); - assert.equal(Number(times[0]), 4); - assert.equal(Number(times[1]), 4); + await increaseTime(1000); - await protocolTimeManager.setCycleDuration(3000); - await protocolTimeManager.setPeriodDuration(2000); + await checkPeriod(2); + }); - await network.provider.send('evm_increaseTime', [6000]); - await network.provider.send('evm_mine'); + it('Cannot get cycle without protocol start', async () => { + await expect(protocolTimeManager.getCurrentCycle()).revertedWithCustomError( + protocolTimeManager, + 'ProtocolHasNotBegun', + ); + }); - const timesTwo = await protocolTimeManager.timeNow(); - assert.equal(Number(timesTwo[0]), 6); - assert.equal(Number(timesTwo[1]), 7); + it('Cannot get period without protocol start', async () => { + await expect( + protocolTimeManager.getCurrentPeriod(), + ).revertedWithCustomError(protocolTimeManager, 'ProtocolHasNotBegun'); }); it('returns one for first cycle', async () => { - await network.provider.send('evm_increaseTime', [500]); - await network.provider.send('evm_mine'); - const currentCycle = await protocolTimeManager.getCurrentCycle(); - assert.equal(Number(currentCycle), 1); + await protocolTimeManager.setProtocolStart(100); + + await increaseTime(500); + + await checkCycle(1); }); it('can get current cycle without updated duration', async () => { - await network.provider.send('evm_increaseTime', [3500]); - await network.provider.send('evm_mine'); + await protocolTimeManager.setProtocolStart(100); - const currentCycle = await protocolTimeManager.getCurrentCycle(); - assert.equal(Number(currentCycle), 4); + await increaseTime(3500); + + await checkCycle(4); }); it('can get current cycle with one updated duration', async () => { - await network.provider.send('evm_increaseTime', [3000]); - await network.provider.send('evm_mine'); + await protocolTimeManager.setProtocolStart(100); - const currentCycle = await protocolTimeManager.getCurrentCycle(); - assert.equal(Number(currentCycle), 4); + // Timeline -> 1000 + // Timeline P -> 900 + // 100 (1) -> 1100 + await increaseTime(1000); + await checkCycle(1); + + // Timeline -> 1500 + // Timeline P -> 1400 + // 1100 (2) -> 2100 + await increaseTime(500); + console.log('first check'); + await checkCycle(2); await protocolTimeManager.setCycleDuration(200); - await network.provider.send('evm_increaseTime', [7000]); - await network.provider.send('evm_mine'); + console.log('second check'); + await checkCycle(2); - const currentCycleTwo = await protocolTimeManager.getCurrentCycle(); - assert.equal(Number(currentCycleTwo), 39); + // Timeline -> 2500 + // Timeline P -> 2400 + // 2100 (3) -> 2300 + // 2300 (4) -> 2500 + // 2500 (5) -> 2700 + await increaseTime(1000); + await checkCycle(4); }); it('can get current cycle with multiple updated durations', async () => { - await network.provider.send('evm_increaseTime', [3000]); - await network.provider.send('evm_mine'); + await protocolTimeManager.setProtocolStart(100); - const currentCycle = await protocolTimeManager.getCurrentCycle(); - assert.equal(Number(currentCycle), 4); + await increaseTime(150); + + await checkCycle(1); + + await increaseTime(2850); + + await checkCycle(3); await protocolTimeManager.setCycleDuration(200); - await network.provider.send('evm_increaseTime', [7000]); - await network.provider.send('evm_mine'); + await increaseTime(1000); - const currentCycleTwo = await protocolTimeManager.getCurrentCycle(); - assert.equal(Number(currentCycleTwo), 39); + await checkCycle(8); await protocolTimeManager.setCycleDuration(125); - await network.provider.send('evm_increaseTime', [5800]); - await network.provider.send('evm_mine'); + await increaseTime(2000); - const currentCycleThree = await protocolTimeManager.getCurrentCycle(); - assert.equal(Number(currentCycleThree), 85); + await checkCycle(24); await protocolTimeManager.setCycleDuration(2); - await network.provider.send('evm_increaseTime', [200]); - await network.provider.send('evm_mine'); + await increaseTime(200); + + await checkCycle(125); + }); + + it('cycle test one', async () => { + // Protocol start -> 800 + // Timeline -> 0 + await protocolTimeManager.setProtocolStart(800); + + // Timeline -> 500 + // Timeline P -> 0 + await increaseTime(500); + + await protocolTimeManager.setCycleDuration(150); + + // Timeline -> 500 + // Timeline P -> 0 + + await expect(protocolTimeManager.getCurrentCycle()).revertedWithCustomError( + protocolTimeManager, + 'ProtocolHasNotBegun', + ); - const currentCycleFour = await protocolTimeManager.getCurrentCycle(); - assert.equal(Number(currentCycleFour), 185); + // Timeline -> 1000 + // Timeline P -> 200 + // 800 (1) -> 950 (2) -> 1100 + await increaseTime(500); + await checkCycle(2); + await checkCycle(2); + + // Timeline -> 1500 + // Timeline P -> 700 + // 1100 (3) -> 1250 (4) -> 1400 (5) -> 1550 + await increaseTime(500); + await checkCycle(5); + + // CycleDuration -> 50 + // Timeline -> 1500 + // Timeline P -> 700 + await protocolTimeManager.setCycleDuration(50); + + // Timeline -> 1550 + // Timeline P -> 750 + // 1550 (6) -> 1600 + await increaseTime(50); + await checkCycle(6); + + // Timeline -> 1600 + // Timeline P -> 800 + // 1600 (7) -> 1650 + await increaseTime(50); + await checkCycle(7); + + // Timeline -> 1650 + // Timeline P -> 850 + // 1650 (8) -> 1700 + await increaseTime(50); + await checkCycle(8); + + // Timeline -> 1700 + // Timeline P -> 900 + // 1700 (9) -> 1750 + await increaseTime(50); + console.log('time since start ehrehrehe'); + await checkCycle(9); + + // CycleDuration -> 850 + // Timeline -> 1700 + // Timeline P -> 900 + await protocolTimeManager.setCycleDuration(850); + + // Timeline -> 1750 + // Timeline P -> 950 + // 1750 (10) -> 2600) + await increaseTime(50); + console.log('time since start ehrehrehe two'); + await checkCycle(10); + + // Timeline -> 4200 + // Timeline P -> 3400 + // 2600 (11) -> 3450 (12) -> 4300 + await increaseTime(2450); + await checkCycle(12); + + await protocolTimeManager.setCycleDuration(75); + + // Timeline -> 4300 + // Timeline P -> 3500 + // 4300 (13) -> 4375 + await increaseTime(100); + console.log('chekcing 13z'); + await checkCycle(13); + + // Timeline -> 5750 + // Timeline P -> 4950 + // 4375 (14) -> 4450 (15) -> 4525 (16) -> 4600 (17) + // -> 4675 (18) -> 4750 (19) -> 4825 (20) -> 4900 (21) + // -> 4975 (22) + await increaseTime(1450); + await checkCycle(22); + }); + + it('returns one for first period', async () => { + await protocolTimeManager.setProtocolStart(100); + + await increaseTime(500); + + await checkPeriod(1); }); it('can get current period without updated duration', async () => { - await network.provider.send('evm_increaseTime', [3000]); - await network.provider.send('evm_mine'); + await protocolTimeManager.setProtocolStart(100); - const currentPeriod = await protocolTimeManager.getCurrentPeriod(); - assert.equal(Number(currentPeriod), 4); + await increaseTime(3500); + + await checkPeriod(4); }); it('can get current period with one updated duration', async () => { - await network.provider.send('evm_increaseTime', [3000]); - await network.provider.send('evm_mine'); + await protocolTimeManager.setProtocolStart(100); - const currentPeriod = await protocolTimeManager.getCurrentPeriod(); - assert.equal(Number(currentPeriod), 4); + // Timeline -> 1000 + // Timeline P -> 900 + // 100 (1) -> 1100 + await increaseTime(1000); + await checkPeriod(1); - await protocolTimeManager.setPeriodDuration(200); + // Timeline -> 1500 + // Timeline P -> 1400 + // 1100 (2) -> 2100 + await increaseTime(500); + await checkPeriod(2); - await network.provider.send('evm_increaseTime', [7000]); - await network.provider.send('evm_mine'); + await protocolTimeManager.setPeriodDuration(200); - const currentPeriodTwo = await protocolTimeManager.getCurrentPeriod(); - assert.equal(Number(currentPeriodTwo), 39); + // Timeline -> 2600 + // Timeline P -> 2500 + // 2100 (3) -> 2200 + // 2200 (4) -> 2400 + // 2400 (5) -> 2600 + await increaseTime(1000); + await checkPeriod(5); }); it('can get current period with multiple updated durations', async () => { - await network.provider.send('evm_increaseTime', [3000]); - await network.provider.send('evm_mine'); + await protocolTimeManager.setProtocolStart(100); - const currentPeriod = await protocolTimeManager.getCurrentPeriod(); - assert.equal(Number(currentPeriod), 4); + await increaseTime(150); + + await checkPeriod(1); + + await increaseTime(2850); + + await checkPeriod(3); await protocolTimeManager.setPeriodDuration(200); - await network.provider.send('evm_increaseTime', [7000]); - await network.provider.send('evm_mine'); + await increaseTime(1000); - const currentPeriodTwo = await protocolTimeManager.getCurrentPeriod(); - assert.equal(Number(currentPeriodTwo), 39); + await checkPeriod(8); await protocolTimeManager.setPeriodDuration(125); - await network.provider.send('evm_increaseTime', [5800]); - await network.provider.send('evm_mine'); + await increaseTime(2000); - const currentPeriodThree = await protocolTimeManager.getCurrentPeriod(); - assert.equal(Number(currentPeriodThree), 85); + await checkPeriod(24); await protocolTimeManager.setPeriodDuration(2); - await network.provider.send('evm_increaseTime', [200]); - await network.provider.send('evm_mine'); + await increaseTime(200); + + await checkPeriod(125); + }); - const currentPeriodFour = await protocolTimeManager.getCurrentPeriod(); - assert.equal(Number(currentPeriodFour), 185); + it('period test one', async () => { + // Protocol start -> 800 + // Timeline -> 0 + await protocolTimeManager.setProtocolStart(800); + + // Timeline -> 500 + // Timeline P -> 0 + await increaseTime(500); + + await protocolTimeManager.setPeriodDuration(150); + + // Timeline -> 500 + // Timeline P -> 0 + + await expect( + protocolTimeManager.getCurrentPeriod(), + ).revertedWithCustomError(protocolTimeManager, 'ProtocolHasNotBegun'); + + // Timeline -> 1000 + // Timeline P -> 200 + // 800 (1) -> 950 (2) -> 1100 + await increaseTime(500); + await checkPeriod(2); + await checkPeriod(2); + + // Timeline -> 1500 + // Timeline P -> 700 + // 1100 (3) -> 1250 (4) -> 1400 (5) -> 1550 + await increaseTime(500); + await checkPeriod(5); + + // CycleDuration -> 50 + // Timeline -> 1500 + // Timeline P -> 700 + await protocolTimeManager.setPeriodDuration(50); + + // Timeline -> 1550 + // Timeline P -> 750 + // 1550 (6) -> 1600 + await increaseTime(50); + await checkPeriod(6); + + // Timeline -> 1600 + // Timeline P -> 800 + // 1600 (7) -> 1650 + await increaseTime(50); + await checkPeriod(7); + + // Timeline -> 1650 + // Timeline P -> 850 + // 1650 (8) -> 1700 + await increaseTime(50); + await checkPeriod(8); + + // Timeline -> 1700 + // Timeline P -> 900 + // 1700 (9) -> 1750 + await increaseTime(50); + await checkPeriod(9); + + // CycleDuration -> 850 + // Timeline -> 1700 + // Timeline P -> 900 + await protocolTimeManager.setPeriodDuration(850); + + // Timeline -> 1750 + // Timeline P -> 950 + // 1750 (10) -> 2600) + await increaseTime(50); + await checkPeriod(10); + + // Timeline -> 4200 + // Timeline P -> 3400 + // 2600 (11) -> 3450 (12) -> 4300 + await increaseTime(2450); + await checkPeriod(12); + + await protocolTimeManager.setPeriodDuration(75); + + // Timeline -> 4300 + // Timeline P -> 3500 + // 4300 (13) -> 4375 + await increaseTime(100); + await checkPeriod(13); + + // Timeline -> 5750 + // Timeline P -> 4950 + // 4375 (14) -> 4450 (15) -> 4525 (16) -> 4600 (17) + // -> 4675 (18) -> 4750 (19) -> 4825 (20) -> 4900 (21) + // -> 4975 (22) + await increaseTime(1450); + await checkPeriod(22); }); it('supports only protocol time manager interface', async () => { @@ -298,4 +509,19 @@ describe('Protocol time manager', () => { 'Expected protocol time manager to not support incorrect interface', ); }); + + async function increaseTime(time: number) { + await network.provider.send('evm_increaseTime', [time]); + await network.provider.send('evm_mine'); + } + + async function checkCycle(cycle: number) { + const currentCycle = await protocolTimeManager.getCurrentCycle(); + assert.equal(Number(currentCycle), cycle); + } + + async function checkPeriod(period: number) { + const currentPeriod = await protocolTimeManager.getCurrentPeriod(); + assert.equal(Number(currentPeriod), period); + } });