From 287a23f22c172c9e96daf05af2c120459b3dd731 Mon Sep 17 00:00:00 2001 From: jordaniza Date: Thu, 3 Oct 2024 14:49:56 +0400 Subject: [PATCH 01/13] updated the constant with puffer curve coefficients and validated against python and solmate --- src/libs/CurveConstantLib.sol | 22 +- test/e2e.t.sol | 467 --------------------- test/escrow/curve/QuadraticCurveMath.t.sol | 72 ++-- test/python/crosscheck.py | 33 +- 4 files changed, 68 insertions(+), 526 deletions(-) delete mode 100644 test/e2e.t.sol diff --git a/src/libs/CurveConstantLib.sol b/src/libs/CurveConstantLib.sol index 9f4fbde..06b63eb 100644 --- a/src/libs/CurveConstantLib.sol +++ b/src/libs/CurveConstantLib.sol @@ -3,20 +3,20 @@ pragma solidity ^0.8.0; /// @title CurveConstantLib /// @notice Precomputed coefficients for escrow curve -/// This curve implementation is a quadratic curve of the form y = (1/7)t^2 + (2/7)t + 1 -/// Which is a transformation of the quadratic curve y = (x^2 + 6)/7 -/// That starts with 1 unit of voting in period 1, and max 6 in period 6. -/// To use this in zero indexed time, with a per-second rate of increase, -/// we transform this to the polynomial y = (1/7)t^2 + (2/7)t + 1 -/// where t = timestamp / 2_weeks (2 weeks is one period) /// Below are the shared coefficients for the linear and quadratic terms +/// @dev This curve goes from 1x -> 2x voting power over a 2 year time horizon +/// Epochs are still 2 weeks long library CurveConstantLib { int256 internal constant SHARED_CONSTANT_COEFFICIENT = 1e18; - /// @dev 2 / (7 * 2_weeks) - expressed in fixed point - int256 internal constant SHARED_LINEAR_COEFFICIENT = 236205593348; - /// @dev 1 / (7 * (2_weeks)^2) - expressed in fixed point - int256 internal constant SHARED_QUADRATIC_COEFFICIENT = 97637; + + /// @dev straight line so the curve is increasing only in the linear term + /// 1 / (52 * SECONDS_IN_2_WEEKS) + int256 internal constant SHARED_LINEAR_COEFFICIENT = 15898453398; + + /// @dev this curve is linear + int256 internal constant SHARED_QUADRATIC_COEFFICIENT = 0; /// @dev the maxiumum number of epochs the cure can keep increasing - uint256 internal constant MAX_EPOCHS = 5; + /// 26 epochs in a year, 2 years = 52 epochs + uint256 internal constant MAX_EPOCHS = 52; } diff --git a/test/e2e.t.sol b/test/e2e.t.sol deleted file mode 100644 index 4d0eca0..0000000 --- a/test/e2e.t.sol +++ /dev/null @@ -1,467 +0,0 @@ -pragma solidity ^0.8.17; - -import {Test} from "forge-std/Test.sol"; -import {console2 as console} from "forge-std/console2.sol"; - -// aragon contracts -import {IDAO} from "@aragon/osx/core/dao/IDAO.sol"; -import {DAO} from "@aragon/osx/core/dao/DAO.sol"; -import {Multisig, MultisigSetup} from "@aragon/multisig/MultisigSetup.sol"; - -import {MockPluginSetupProcessor} from "@mocks/osx/MockPSP.sol"; -import {MockDAOFactory} from "@mocks/osx/MockDAOFactory.sol"; -import {MockERC20} from "@mocks/MockERC20.sol"; - -import "./helpers/OSxHelpers.sol"; - -import {Clock} from "@clock/Clock.sol"; -import {IEscrowCurveTokenStorage} from "@escrow-interfaces/IEscrowCurveIncreasing.sol"; -import {IWithdrawalQueueErrors} from "src/escrow/increasing/interfaces/IVotingEscrowIncreasing.sol"; -import {IGaugeVote} from "src/voting/ISimpleGaugeVoter.sol"; -import {VotingEscrow, Lock, QuadraticIncreasingEscrow, ExitQueue, SimpleGaugeVoter, SimpleGaugeVoterSetup, ISimpleGaugeVoterSetupParams} from "src/voting/SimpleGaugeVoterSetup.sol"; - -/** - * This is going to be a simple E2E test that will build the contracts on Aragon and run a deposit / withdraw flow. - * - * We need to: - * - * - Deploy the OSx framework - * - Deploy a DAO - * - Define our pluginSetup contract to deploy the VE - * - Deploy the VE - * - Do a deposit - * - Check balance - * - Do a vote - * - Queue a withdraw - * - Withdraw - */ -contract TestE2E is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveTokenStorage { - MultisigSetup multisigSetup; - SimpleGaugeVoterSetup voterSetup; - - // permissions - PermissionLib.MultiTargetPermission[] voterSetupPermissions; - - MockPluginSetupProcessor psp; - MockDAOFactory daoFactory; - MockERC20 token; - - VotingEscrow ve; - Lock nftLock; - QuadraticIncreasingEscrow curve; - SimpleGaugeVoter voter; - ExitQueue queue; - Clock clock; - - IDAO dao; - Multisig multisig; - - address deployer = address(0x420); - address user = address(0x69); - - uint256 constant COOLDOWN = 3 days; - uint256 constant DEPOSIT = 1000 ether; - - uint tokenId; - uint NUM_PERIODS = 5; - - address gaugeTheFirst = address(0x1337); - address gaugeTheSecond = address(0x7331); - - uint depositTime; - - error MinLockNotReached(uint256 tokenId, uint48 expected, uint48 actual); - - function testE2E() public { - // clock reset - vm.roll(0); - vm.warp(0); - - // Deploy the OSx framework - _deployOSX(); - // Deploy a DAO - _deployDAOAndMSig(); - - // new block for multisig - vm.roll(1); - // Define our pluginSetup contract to deploy the VE - _setupVoterContracts(); - - // apply the installation (nothing needed just yet) - _applySetup(); - - _addLabels(); - - // main test - _makeDeposit(); - _checkBalanceOverTime(); - - // setup gauges - _createGaugesActivateVoting(); - - // vote - _vote(); - _checkVoteEpoch(); - - // withdraw - _withdraw(); - } - - function _withdraw() internal { - vm.startPrank(user); - { - uint atm = block.timestamp; - - vm.expectRevert(NotTicketHolder.selector); - ve.withdraw(tokenId); - - // reset votes to clear - voter.reset(tokenId); - - // approve the withdrawal - nftLock.approve(address(ve), tokenId); - - // can't queue because the min lock is not reached - uint256 minLock = queue.timeToMinLock(tokenId); - uint256 expectedTime = depositTime + 20 weeks; - assertEq(minLock, expectedTime, "Min lock time incorrect"); - - bytes memory err = abi.encodeWithSelector( - MinLockNotReached.selector, - 1, - queue.minLock(), - expectedTime - ); - // expect revert - vm.expectRevert(err); - ve.beginWithdrawal(tokenId); - - // warp to the min lock + start - expect success - vm.warp(atm + expectedTime); - ve.beginWithdrawal(tokenId); - - // enter the queue - assertEq(nftLock.balanceOf(user), 0, "User should have no tokens"); - assertEq(nftLock.balanceOf(address(ve)), 1, "VE should have the NFT"); - - // readjust the cached time - atm = block.timestamp; - - // wait for 1 day - vm.warp(atm + 1 days); - - vm.expectRevert(CannotExit.selector); - ve.withdraw(tokenId); - - // the cooldown is not enough: we snap to the end of the voting period - - // wait for the cooldown - vm.warp(atm + COOLDOWN); - - vm.expectRevert(CannotExit.selector); - ve.withdraw(tokenId); - - // warp to the end of the voting period - vm.warp(atm + 1 weeks); - ve.withdraw(tokenId); - - assertEq(nftLock.balanceOf(user), 0, "User not should have the token"); - assertEq(nftLock.balanceOf(address(ve)), 0, "VE should not have the NFT"); - assertEq(token.balanceOf(user), DEPOSIT, "User should have the tokens"); - } - vm.stopPrank(); - } - - function _checkVoteEpoch() internal { - // warp to the distribution window - vm.warp(block.timestamp + 1 weeks); - assertEq(voter.votingActive(), false, "Voting should not be active"); - - vm.warp(block.timestamp + 1 weeks); - assertEq(voter.votingActive(), true, "Voting should be active again"); - } - - function _vote() internal { - GaugeVote[] memory votes = new GaugeVote[](2); - votes[0] = GaugeVote({gauge: gaugeTheFirst, weight: 25}); - votes[1] = GaugeVote({gauge: gaugeTheSecond, weight: 75}); - - vm.startPrank(user); - { - voter.vote(tokenId, votes); - } - vm.stopPrank(); - - uint maxDeposit = curve.previewMaxBias(DEPOSIT); - - // check, should be 25% of 6*DEPOSIT in the first gauge - // and 75% of 6*DEPOSIT in the second gauge - uint expectedFirst = maxDeposit / 4; - uint expectedSecond = maxDeposit - expectedFirst; - - assertEq(voter.gaugeVotes(gaugeTheFirst), expectedFirst, "First gauge weight incorrect"); - assertEq(voter.gaugeVotes(gaugeTheSecond), expectedSecond, "Second gauge weight incorrect"); - } - - function _createGaugesActivateVoting() internal { - IDAO.Action[] memory actions = new IDAO.Action[](3); - - // action 0: create the first gauge - actions[0] = IDAO.Action({ - to: address(voter), - value: 0, - data: abi.encodeWithSelector(voter.createGauge.selector, gaugeTheFirst, "First Gauge") - }); - - // action 1: create the second gauge - actions[1] = IDAO.Action({ - to: address(voter), - value: 0, - data: abi.encodeWithSelector(voter.createGauge.selector, gaugeTheSecond, "Second Gauge") - }); - - // action 2: activate the voting - actions[2] = IDAO.Action({ - to: address(voter), - value: 0, - data: abi.encodeWithSelector(voter.unpause.selector) - }); - - // create a proposal - vm.startPrank(deployer); - { - multisig.createProposal({ - _metadata: "", - _actions: actions, - _allowFailureMap: 0, - _approveProposal: true, - _tryExecution: true, - _startDate: 0, - _endDate: uint64(block.timestamp + 1) - }); - } - vm.stopPrank(); - - assertEq(voter.votingActive(), false, "Voting should not be active"); - - vm.warp(block.timestamp + 1 weeks + 1 hours + 1); - - assertEq(voter.votingActive(), true, "Voting should be active"); - } - - function _makeDeposit() internal { - // mint tokens - token.mint(user, DEPOSIT); - - vm.startPrank(user); - { - token.approve(address(ve), DEPOSIT); - - // warp to exactly 1 sec before the next epoch so that warmup math is easier - uint expectedStart = clock.epochNextCheckpointTs(); - vm.warp(expectedStart - 1); - - // create the lock - tokenId = ve.createLock(DEPOSIT); - - // fetch the starttime of the lock - depositTime = ve.locked(tokenId).start; - assertEq(depositTime, expectedStart, "Deposit time incorrect"); - - // check the user owns the nft - assertEq(tokenId, 1, "Token ID should be 1"); - assertEq(nftLock.balanceOf(user), 1, "User should have 1 token"); - assertEq(nftLock.ownerOf(tokenId), user, "User should own the token"); - assertEq(token.balanceOf(address(ve)), DEPOSIT, "VE should have the tokens"); - assertEq(token.balanceOf(user), 0, "User should have no tokens"); - } - vm.stopPrank(); - } - - function _checkBalanceOverTime() internal { - uint start = block.timestamp + 1; - // balance now is zero but Warm up - assertEq(curve.votingPowerAt(tokenId, 0), 0, "Balance after deposit before warmup"); - assertEq(curve.isWarm(tokenId), false, "Should not be warm after 0 seconds"); - - // wait for warmup - should be warm 1 second after - vm.warp(block.timestamp + curve.warmupPeriod()); - assertEq(curve.votingPowerAt(tokenId, 0), 0, "Balance after deposit before warmup"); - assertEq(curve.isWarm(tokenId), false, "Should not be warm yet"); - - // warmup complete + 1 - vm.warp(block.timestamp + 1); - // solmate: 1067.784483312193384992 - // python: 1067.784543380942056100 - assertEq( - curve.votingPowerAt(tokenId, block.timestamp), - 1067784196491481600000, - "Balance incorrect after warmup" - ); - assertEq(curve.isWarm(tokenId), true, "Still warming up"); - - // warp to the start of period 2 - vm.warp(start + clock.epochDuration()); - // python: 1428.571428571428683776 - // solmate: 1428.570120419660799763 - // solmate(2): 1428.570120419660800000 - assertEq( - curve.votingPowerAt(tokenId, block.timestamp), - 1428570120419660800000, - "Balance incorrect after p1" - ); - - // warp to the final period - // TECHNICALLY, this should finish at exactly 5 periods but - // 30 seconds off is okay - vm.warp(start + clock.epochDuration() * 5 + 30); - assertEq( - curve.votingPowerAt(tokenId, block.timestamp), - 5999967296216704000000, - "Balance incorrect after p6" - ); - } - - function _deployOSX() internal { - // deploy the mock PSP with the multisig plugin - multisigSetup = new MultisigSetup(); - psp = new MockPluginSetupProcessor(address(multisigSetup)); - daoFactory = new MockDAOFactory(psp); - } - - function _deployDAOAndMSig() internal { - // use the OSx DAO factory with the Plugin - address[] memory members = new address[](1); - members[0] = deployer; - - // encode a 1/1 multisig that can be adjusted later - bytes memory data = abi.encode( - members, - Multisig.MultisigSettings({onlyListed: true, minApprovals: 1}) - ); - - dao = daoFactory.createDao(_mockDAOSettings(), _mockPluginSettings(data)); - - // nonce 0 is something? - // nonce 1 is implementation contract - // nonce 2 is the msig contract behind the proxy - multisig = Multisig(computeAddress(address(multisigSetup), 2)); - } - - function _setupVoterContracts() public { - token = new MockERC20(); - - // deploy setup - voterSetup = new SimpleGaugeVoterSetup( - address(new SimpleGaugeVoter()), - address(new QuadraticIncreasingEscrow()), - address(new ExitQueue()), - address(new VotingEscrow()), - address(new Clock()), - address(new Lock()) - ); - - // push to the PSP - psp.queueSetup(address(voterSetup)); - - // prepare the installation - bytes memory data = abi.encode( - ISimpleGaugeVoterSetupParams({ - isPaused: true, - token: address(token), - veTokenName: "VE Token", - veTokenSymbol: "VE", - warmup: 3 days, - cooldown: 3 days, - feePercent: 0, - minLock: 20 weeks, - minDeposit: 1 ether - }) - ); - (address pluginAddress, IPluginSetup.PreparedSetupData memory preparedSetupData) = psp - .prepareInstallation(address(dao), _mockPrepareInstallationParams(data)); - - // fetch the contracts - voter = SimpleGaugeVoter(pluginAddress); - address[] memory helpers = preparedSetupData.helpers; - curve = QuadraticIncreasingEscrow(helpers[0]); - queue = ExitQueue(helpers[1]); - ve = VotingEscrow(helpers[2]); - clock = Clock(helpers[3]); - nftLock = Lock(helpers[4]); - - // set the permissions - for (uint i = 0; i < preparedSetupData.permissions.length; i++) { - voterSetupPermissions.push(preparedSetupData.permissions[i]); - } - } - - function _actions() internal view returns (IDAO.Action[] memory) { - IDAO.Action[] memory actions = new IDAO.Action[](5); - - // action 0: apply the ve installation - actions[0] = IDAO.Action({ - to: address(psp), - value: 0, - data: abi.encodeCall( - psp.applyInstallation, - (address(dao), _mockApplyInstallationParams(address(ve), voterSetupPermissions)) - ) - }); - - // action 2: activate the curve on the ve - actions[1] = IDAO.Action({ - to: address(ve), - value: 0, - data: abi.encodeWithSelector(ve.setCurve.selector, address(curve)) - }); - - // action 3: activate the queue on the ve - actions[2] = IDAO.Action({ - to: address(ve), - value: 0, - data: abi.encodeWithSelector(ve.setQueue.selector, address(queue)) - }); - - // action 4: set the voter - actions[3] = IDAO.Action({ - to: address(ve), - value: 0, - data: abi.encodeWithSelector(ve.setVoter.selector, address(voter)) - }); - - actions[4] = IDAO.Action({ - to: address(ve), - value: 0, - data: abi.encodeWithSelector(ve.setLockNFT.selector, address(nftLock)) - }); - - return wrapGrantRevokeRoot(DAO(payable(address(dao))), address(psp), actions); - } - - function _applySetup() internal { - IDAO.Action[] memory actions = _actions(); - - // execute the actions - vm.startPrank(deployer); - { - multisig.createProposal({ - _metadata: "", - _actions: actions, - _allowFailureMap: 0, - _approveProposal: true, - _tryExecution: true, - _startDate: 0, - _endDate: uint64(block.timestamp + 1) - }); - } - vm.stopPrank(); - } - - function _addLabels() internal { - vm.label(gaugeTheFirst, "gaugeTheFirst"); - vm.label(gaugeTheSecond, "gaugeTheSecond"); - vm.label(deployer, "deployer"); - vm.label(user, "user"); - } -} diff --git a/test/escrow/curve/QuadraticCurveMath.t.sol b/test/escrow/curve/QuadraticCurveMath.t.sol index 93711bb..e89a880 100644 --- a/test/escrow/curve/QuadraticCurveMath.t.sol +++ b/test/escrow/curve/QuadraticCurveMath.t.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.17; import {console2 as console} from "forge-std/console2.sol"; @@ -8,16 +9,7 @@ import {IVotingEscrowIncreasing, ILockedBalanceIncreasing} from "src/escrow/incr import {QuadraticCurveBase} from "./QuadraticCurveBase.t.sol"; contract TestQuadraticIncreasingCurve is QuadraticCurveBase { - function test_votingPowerComputesCorrect() public { - /** - Period Result - 1 1 - 2 1.428571429 - 3 2.142857143 - 4 3.142857143 - 5 4.428571429 - 6 6 - */ + function test_votingPowerComputesCorrect() public view { uint256 amount = 100e18; int256[3] memory coefficients = curve.getCoefficients(100e18); @@ -30,7 +22,7 @@ contract TestQuadraticIncreasingCurve is QuadraticCurveBase { console.log("Coefficients: %st^2 + %st + %s", quadratic, linear, const); - for (uint i; i <= 6; i++) { + for (uint i; i <= 53; i++) { uint period = 2 weeks * i; console.log( "Period: %d Voting Power : %s", @@ -58,6 +50,35 @@ contract TestQuadraticIncreasingCurve is QuadraticCurveBase { } // write a new checkpoint + /* + * for the 1000 tokens (Python) (extend to 1bn with more zeros) + * 0 Voting Power: 1000000000000000000000 + * 1 minute Voting Power: 1000000953907203932160 + * 1 hour Voting Power: 1000057234432234487808 + * 1 day Voting Power: 1001373626373626396672 + * WARMUP_PERIOD (3 days) Voting Power: 1004120879120879058944 + * WARMUP_PERIOD + 1s Voting Power: 1004120895019332534272 + * 1 week Voting Power: 1009615384615384645632 + * 1 period (2 weeks) Voting Power: 1019230769230769160192 + * 10 periods (10 * PERIOD) Voting Power: 1192307692307692388352 + * 50% periods (26 * PERIOD) Voting Power: 1500000000000000000000 + * 35 periods (35 * PERIOD) Voting Power: 1673076923076923097088 + * PERIOD_END (26 * PERIOD) Voting Power: 2000000000000000000000 + + * for the 420.69 tokens (Python) + * 0 Voting Power: 420690000000000000000 + * 1 minute Voting Power: 420690401299221577728 + * 1 hour Voting Power: 420714077953296695296 + * 1 day Voting Power: 421267870879120883712 + * WARMUP_PERIOD (3 days) Voting Power: 422423612637362651136 + * WARMUP_PERIOD + 1s Voting Power: 422423619325683040256 + * 1 week Voting Power: 424735096153846120448 + * 1 period (2 weeks) Voting Power: 428780192307692306432 + * 10 periods (10 * PERIOD) Voting Power: 501591923076923064320 + * 50% periods (26 * PERIOD) Voting Power: 631035000000000032768 + * 35 periods (35 * PERIOD) Voting Power: 703846730769230856192 + * PERIOD_END (26 * PERIOD) Voting Power: 841380000000000000000 + */ function testWritesCheckpoint() public { uint tokenIdFirst = 1; uint tokenIdSecond = 2; @@ -104,52 +125,43 @@ contract TestQuadraticIncreasingCurve is QuadraticCurveBase { // warmup complete vm.warp(block.timestamp + 1); - // python: 449.206279554928541696 - // solmate (optimized): 449.206254284606635135 assertEq( curve.votingPowerAt(tokenIdFirst, block.timestamp), - 449206254284606635135, + 422423619325633557508, "Balance incorrect after warmup" ); assertEq(curve.isWarm(tokenIdFirst), true, "Still warming up"); - // python: 1067784543380942056100724736 - // solmate: 1067784483312193385000000000 assertEq( curve.votingPowerAt(tokenIdSecond, block.timestamp), - 1067784483312193385000000000, + 1004120895019214998000000000, "Balance incorrect after warmup II" ); // warp to the start of period 2 vm.warp(start + clock.epochDuration()); - // excel: 600.985714300000000000 - // PRB: 600.985163959347100568 - // solmate: 600.985163959347101852 - // python : 600.985714285714341888 - // solmate2: 600.985163959347101952 assertEq( curve.votingPowerAt(tokenIdFirst, block.timestamp), - 600985163959347101952, + 428780192307461588352, "Balance incorrect after p1" ); - uint256 expectedMaxI = 2524126241845405205760; - uint256 expectedMaxII = 5999967296216704000000000000; + uint256 expectedMaxI = 841379999988002594304; + uint256 expectedMaxII = 1999999999971481600000000000; // warp to the final period - // TECHNICALLY, this should finish at exactly 5 periodd and 6 * voting power - // but FP arithmetic has a small rounding error - vm.warp(start + clock.epochDuration() * 5); + // TECHNICALLY, this should round to a whole max + // but FP arithmetic has a small rounding error and it finishes just below + vm.warp(start + clock.epochDuration() * 52); assertEq( curve.votingPowerAt(tokenIdFirst, block.timestamp), expectedMaxI, - "Balance incorrect after p6" + "Balance incorrect after pend" ); assertEq( curve.votingPowerAt(tokenIdSecond, block.timestamp), expectedMaxII, - "Balance incorrect after p6 II " + "Balance incorrect after pend II " ); // warp to the future and balance should be the same diff --git a/test/python/crosscheck.py b/test/python/crosscheck.py index 86f544e..a40b634 100644 --- a/test/python/crosscheck.py +++ b/test/python/crosscheck.py @@ -1,40 +1,39 @@ # time utils HOUR = 60 * 60 -DAY = 24 * HOUR +DAY = 24 * HOUR WEEK = 7 * DAY # Variables -AMOUNT = 1_000_000_000 # example amount to deposit +AMOUNT = 420.69 # example amount to deposit PERIOD_LENGTH = 2 * WEEK # example period length in seconds (1 week) WARMUP_PERIOD = 3 * DAY # warmup period in days -MAX_PERIODS = 5 # maximum periods +MAX_PERIODS = 52 # maximum periods -QUADRATIC_COEFFICIENT = 1/7 -LINEAR_COEFFICIENT = 2/7 +QUADRATIC_COEFFICIENT = 0 +LINEAR_COEFFICIENT = 1 / 52 CONSTANT = 1 # Scale amount amount_scaled = AMOUNT * 1e18 + # Function to evaluate y def evaluate_y(secondsElapsed, PeriodLength, amount_scaled): x = secondsElapsed / PeriodLength y = amount_scaled * ( - QUADRATIC_COEFFICIENT * (x**2) - + LINEAR_COEFFICIENT * x - + CONSTANT + QUADRATIC_COEFFICIENT * (x**2) + LINEAR_COEFFICIENT * x + CONSTANT ) return y + def evaluate_y_v2(secondsElapsed, PeriodLength, amount_scaled): x = secondsElapsed / PeriodLength y = amount_scaled * ( - QUADRATIC_COEFFICIENT * (x*x) - + LINEAR_COEFFICIENT * x - + CONSTANT + QUADRATIC_COEFFICIENT * (x * x) + LINEAR_COEFFICIENT * x + CONSTANT ) return y + # Time points to evaluate, using tuples with optional labels time_points = [ ("0", 0), @@ -42,13 +41,13 @@ def evaluate_y_v2(secondsElapsed, PeriodLength, amount_scaled): ("1 hour", 60 * 60), ("1 day", 60 * 60 * 24), (f"WARMUP_PERIOD ({WARMUP_PERIOD//DAY} days)", WARMUP_PERIOD), - (f"WARMUP_PERIOD + 1s", (WARMUP_PERIOD) + 1), + (f"WARMUP_PERIOD + 1s", (WARMUP_PERIOD) + 1), ("1 week", 60 * 60 * 24 * 7), (f"1 period ({PERIOD_LENGTH // (WEEK)} weeks)", PERIOD_LENGTH), - (f"2 periods (2 * PERIOD)", 2 * PERIOD_LENGTH), - (f"3 periods (3 * PERIOD)", 3 * PERIOD_LENGTH), - (f"4 periods (4 * PERIOD)", 4 * PERIOD_LENGTH), - (f"PERIOD_END (5 * PERIOD)", MAX_PERIODS * PERIOD_LENGTH) + (f"10 periods (10 * PERIOD)", 10 * PERIOD_LENGTH), + (f"50% periods (26 * PERIOD)", 26 * PERIOD_LENGTH), + (f"35 periods (35 * PERIOD)", 35 * PERIOD_LENGTH), + (f"PERIOD_END (26 * PERIOD)", MAX_PERIODS * PERIOD_LENGTH), ] # Evaluate and print results @@ -56,5 +55,3 @@ def evaluate_y_v2(secondsElapsed, PeriodLength, amount_scaled): y_value = evaluate_y(t, PERIOD_LENGTH, amount_scaled) # Avoid scientific notation by formatting with commas and align values vertically print(f"{label:<30} Voting Power: {y_value:>20.0f}") - - From 789002af63d4f69bcd75bd682128f3dad90e7bc8 Mon Sep 17 00:00:00 2001 From: Jordaniza Date: Thu, 3 Oct 2024 20:34:12 +0400 Subject: [PATCH 02/13] halfway through e2e adaptation --- test/e2eV2.t.sol | 51 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/test/e2eV2.t.sol b/test/e2eV2.t.sol index e3ab3ef..118778a 100644 --- a/test/e2eV2.t.sol +++ b/test/e2eV2.t.sol @@ -519,9 +519,9 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke } // carlos goes first and makes the first deposit, it's at the start of the - // week, so we would expect him to be warm by the end of the week if using <6 day + // week, so we would expect him to be warm after 1 week // we wait a couple of days and he makes a deposit for javi - // we expect his warmup to carryover to the next week + // we expect his warmup to carryover also to the next week // we expect both of their locks to start accruing voting power on the same day { goToEpochStartPlus(1 days); @@ -611,11 +611,34 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke // fast forward to the checkpoint interval carlos is warm and has voting power, javi is not goToEpochStartPlus(clock.checkpointInterval()); - assertEq(escrow.votingPower(1), depositCarlos0, "Carlos should have voting power"); - assertTrue(curve.isWarm(1), "Carlos should not be warm"); + assertEq(escrow.votingPower(1), 0, "Carlos should not yet have voting power"); + assertFalse(curve.isWarm(1), "Carlos should not be warm"); assertEq(escrow.votingPower(2), 0, "Javi should not have the correct voting power"); assertFalse(curve.isWarm(2), "Javi should not be warm"); + + // if we move to 1 week after carlos' deposit he should have the correct voting power + goToEpochStartPlus(1 weeks + 1 days); + + assertEq( + escrow.votingPower(1), + 0, + "Carlos should still be waiting after exactly 7 days" + ); + assertFalse(curve.isWarm(1), "Carlos should not be warm after exactly 1 week"); + + // add 1 second + goToEpochStartPlus(1 weeks + 1 days + 1); + + // check the voting power + // he's been accruing 1d + 1s + assertEq( + escrow.votingPower(1), + curve.getBias(1 days + 1, depositCarlos0), + "Carlos should have the correct voting power after 1 week + 1s" + ); + + assertTrue(curve.isWarm(1), "Carlos should be warm after 1 week + 1s"); } // we fast forward 4 weeks and check the expected balances @@ -676,6 +699,7 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke } // we then fast forward 1 week and check that his voting power has increased as expected with the new lock { + // because of the 7d warmup we still will be 1s from warmth goToEpochStartPlus(5 weeks); // calculate elapsed time since we made the first lock @@ -685,8 +709,21 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke // elased time is zero so should be exactly equal to the bias assertEq( escrow.votingPowerForAccount(carlos), - curve.getBias(timeElapsedSinceFirstLock, depositCarlos0) + depositCarlos1, - "Carlos should now have the correct aggregate voting power" + curve.getBias(timeElapsedSinceFirstLock, depositCarlos0), + "Carlos should still not have extra voting power" + ); + + // fast forward 1 second + goToEpochStartPlus(5 weeks + 1); + + timeElapsedSinceFirstLock++; + + // check the voting power + assertEq( + escrow.votingPowerForAccount(carlos), + curve.getBias(timeElapsedSinceFirstLock, depositCarlos0) + + curve.getBias(1, depositCarlos1), + "Carlos should have the correct voting power after 5 weeks + 1s" ); } @@ -1027,7 +1064,7 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke // exit date should be the next checkpoint assertEq( queue.queue(1).exitDate, - epochStartTime + 8 weeks + clock.checkpointInterval(), + epochStartTime + 8 weeks + clock.checkpointInterval() + queue.cooldown(), "Carlos should be able to exit at the next checkpoint" ); From 3e00e4cfd54388e52a76bc6ec02fc57aa3092cc6 Mon Sep 17 00:00:00 2001 From: Jordaniza Date: Fri, 4 Oct 2024 12:25:09 +0400 Subject: [PATCH 03/13] e2e fork test for puffer on holesky --- Makefile | 2 +- test/e2eV2.t.sol | 102 ++++++++++++++++++++++++----------------------- 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/Makefile b/Makefile index cc91ad9..84813c0 100644 --- a/Makefile +++ b/Makefile @@ -64,4 +64,4 @@ ft-mode-fork :; forge test --match-contract TestE2EV2 \ ft-holesky-fork :; forge test --match-contract TestE2EV2 \ --rpc-url https://holesky.drpc.org \ --fork-block-number 2459459 \ - -vvvvv \ No newline at end of file + -vvv \ No newline at end of file diff --git a/test/e2eV2.t.sol b/test/e2eV2.t.sol index 118778a..94fdee5 100644 --- a/test/e2eV2.t.sol +++ b/test/e2eV2.t.sol @@ -53,10 +53,14 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke error VotingInactive(); error OnlyEscrow(); error GaugeDoesNotExist(address _pool); + error AmountTooSmall(); error NotApprovedOrOwner(); error NoVotingPower(); error NotWhitelisted(); error NothingToSweep(); + error MinLockNotReached(uint256 tokenId, uint48 minLock, uint48 earliestExitDate); + + uint constant MONTH = 2592000; GaugesDaoFactory factory; @@ -530,6 +534,10 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke { token.approve(address(escrow), balanceCarlos); + // we also check he can't create too small a lock + vm.expectRevert(AmountTooSmall.selector); + escrow.createLock(100 ether - 1); + escrow.createLock(depositCarlos0); goToEpochStartPlus(6 days); @@ -552,7 +560,7 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke assertEq( tp1_1.checkpointTs, epochStartTime + clock.checkpointInterval(), - "Carlos point should have the correct checkpoint" + "carlos point should have the correct checkpoint" ); assertEq( tp2_1.checkpointTs, @@ -611,34 +619,33 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke // fast forward to the checkpoint interval carlos is warm and has voting power, javi is not goToEpochStartPlus(clock.checkpointInterval()); - assertEq(escrow.votingPower(1), 0, "Carlos should not yet have voting power"); - assertFalse(curve.isWarm(1), "Carlos should not be warm"); + assertEq( + escrow.votingPower(1), + curve.getBias(0, depositCarlos0), + "Carlos should not yet have voting power" + ); + assertTrue(curve.isWarm(1), "Carlos should not be warm"); assertEq(escrow.votingPower(2), 0, "Javi should not have the correct voting power"); assertFalse(curve.isWarm(2), "Javi should not be warm"); + } - // if we move to 1 week after carlos' deposit he should have the correct voting power - goToEpochStartPlus(1 weeks + 1 days); - - assertEq( - escrow.votingPower(1), - 0, - "Carlos should still be waiting after exactly 7 days" - ); - assertFalse(curve.isWarm(1), "Carlos should not be warm after exactly 1 week"); + // carlos can't even begin an exit because of the min lock + { + vm.startPrank(carlos); + { + lock.approve(address(escrow), 1); - // add 1 second - goToEpochStartPlus(1 weeks + 1 days + 1); + TokenPoint memory tp1_1 = curve.tokenPointHistory(1, 1); - // check the voting power - // he's been accruing 1d + 1s - assertEq( - escrow.votingPower(1), - curve.getBias(1 days + 1, depositCarlos0), - "Carlos should have the correct voting power after 1 week + 1s" - ); + uint expectedMinLock = tp1_1.checkpointTs + MONTH; - assertTrue(curve.isWarm(1), "Carlos should be warm after 1 week + 1s"); + vm.expectRevert( + abi.encodeWithSelector(MinLockNotReached.selector, 1, MONTH, expectedMinLock) + ); + escrow.beginWithdrawal(1); + } + vm.stopPrank(); } // we fast forward 4 weeks and check the expected balances @@ -699,7 +706,6 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke } // we then fast forward 1 week and check that his voting power has increased as expected with the new lock { - // because of the 7d warmup we still will be 1s from warmth goToEpochStartPlus(5 weeks); // calculate elapsed time since we made the first lock @@ -709,21 +715,8 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke // elased time is zero so should be exactly equal to the bias assertEq( escrow.votingPowerForAccount(carlos), - curve.getBias(timeElapsedSinceFirstLock, depositCarlos0), - "Carlos should still not have extra voting power" - ); - - // fast forward 1 second - goToEpochStartPlus(5 weeks + 1); - - timeElapsedSinceFirstLock++; - - // check the voting power - assertEq( - escrow.votingPowerForAccount(carlos), - curve.getBias(timeElapsedSinceFirstLock, depositCarlos0) + - curve.getBias(1, depositCarlos1), - "Carlos should have the correct voting power after 5 weeks + 1s" + curve.getBias(timeElapsedSinceFirstLock, depositCarlos0) + depositCarlos1, + "Carlos should have extra voting power" ); } @@ -736,7 +729,13 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke vm.expectRevert(OnlyEscrow.selector); queue.queueExit(i, jordan); - vm.expectRevert(erc721ownererr); + // lingering permissions from carlos' approval + if (i == 1) { + vm.expectRevert(bytes("ERC721: transfer from incorrect owner")); + } else { + vm.expectRevert(erc721ownererr); + } + escrow.beginWithdrawal(i); } } @@ -1061,10 +1060,11 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke assertEq(lock.ownerOf(1), address(escrow), "Carlos should not own the nft"); assertEq(queue.queue(1).holder, carlos, "Carlos should be in the queue"); - // exit date should be the next checkpoint + // expected exit date is: + // now + cooldown given that it crosses the cp boundary assertEq( queue.queue(1).exitDate, - epochStartTime + 8 weeks + clock.checkpointInterval() + queue.cooldown(), + epochStartTime + 8 weeks + 1 hours + queue.cooldown(), "Carlos should be able to exit at the next checkpoint" ); @@ -1089,16 +1089,15 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke vm.expectRevert(CannotExit.selector); escrow.withdraw(1); - // he waits till the end of the week to exit - goToEpochStartPlus(9 weeks); + // go to cooldown end + goToEpochStartPlus(8 weeks + 1 hours + MONTH); // can't exit yet vm.expectRevert(CannotExit.selector); escrow.withdraw(1); - // + 1s he can - - goToEpochStartPlus(9 weeks + 1); + // + 1s he can (1738616401) + goToEpochStartPlus(8 weeks + 1 hours + MONTH + 1); escrow.withdraw(1); } @@ -1117,6 +1116,9 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke depositCarlos1 + depositCarlosJavi + balanceJordi, "Total locked should be the sum of the two deposits" ); + + // there are no fees in our contract + assertEq(token.balanceOf(address(queue)), 0, "Queue should have no fees"); } // governance changes some params: warmup is now one day, cooldown is a week @@ -1283,8 +1285,8 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke // we get all the guys to exit and unwind their positions { - // warp to a voting window - goToEpochStartPlus(12 weeks + 2 hours); + // warp to a voting window - must pass the min lock + goToEpochStartPlus(16 weeks + 2 hours); vm.startPrank(carlos); { @@ -1303,8 +1305,8 @@ contract TestE2EV2 is Test, IWithdrawalQueueErrors, IGaugeVote, IEscrowCurveToke } vm.stopPrank(); - // fast forward like 5 weeks - goToEpochStartPlus(16 weeks); + // fast forward a month + goToEpochStartPlus(16 weeks + 2 hours + MONTH); // carlos exits vm.startPrank(carlos); From b32b889d80d074a2ff3e3e7ed00de127eff79c41 Mon Sep 17 00:00:00 2001 From: Jordaniza Date: Fri, 4 Oct 2024 13:01:22 +0400 Subject: [PATCH 04/13] mainnet fork test and holesky fork test w. holytaco --- Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 84813c0..23b28d0 100644 --- a/Makefile +++ b/Makefile @@ -64,4 +64,9 @@ ft-mode-fork :; forge test --match-contract TestE2EV2 \ ft-holesky-fork :; forge test --match-contract TestE2EV2 \ --rpc-url https://holesky.drpc.org \ --fork-block-number 2459459 \ - -vvv \ No newline at end of file + -vvvvv + +ft-mainnet-fork :; forge test --match-contract TestE2EV2 \ + --rpc-url https://eth.llamarpc.com \ + --fork-block-number 20890902 \ + -vvvvv \ No newline at end of file From 0f34e1eccbc6880b9d317f0a0b66a9af25a35df7 Mon Sep 17 00:00:00 2001 From: Jordaniza Date: Fri, 4 Oct 2024 13:15:33 +0400 Subject: [PATCH 05/13] fork test w. factory --- Makefile | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 23b28d0..81d66ef 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,20 @@ deploy-mode :; forge script script/Deploy.s.sol:Deploy \ --etherscan-api-key $(ETHERSCAN_API_KEY) \ -vvv +deploy-preview-holesky :; forge script script/Deploy.s.sol:Deploy \ + --rpc-url https://holesky.drpc.org \ + --private-key $(DEPLOYMENT_PRIVATE_KEY) \ + -vvvvv + + +deploy-holesky :; forge script script/Deploy.s.sol:Deploy \ + --rpc-url https://holesky.drpc.org \ + --private-key $(DEPLOYMENT_PRIVATE_KEY) \ + --broadcast \ + --verify \ + --etherscan-api-key $(ETHERSCAN_API_KEY) \ + -vvv + # Fork testing ft-mode-sepolia-fork :; forge test --match-contract TestE2EV2 \ --rpc-url https://sepolia.mode.network \ @@ -63,7 +77,7 @@ ft-mode-fork :; forge test --match-contract TestE2EV2 \ ft-holesky-fork :; forge test --match-contract TestE2EV2 \ --rpc-url https://holesky.drpc.org \ - --fork-block-number 2459459 \ + --fork-block-number 2464835 \ -vvvvv ft-mainnet-fork :; forge test --match-contract TestE2EV2 \ From 3a0a583f056001c1ffb272dc9a2f6fad6069207a Mon Sep 17 00:00:00 2001 From: jordaniza Date: Wed, 9 Oct 2024 10:53:15 +0400 Subject: [PATCH 06/13] added sepolia --- Makefile | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 81d66ef..6640e51 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,20 @@ deploy-holesky :; forge script script/Deploy.s.sol:Deploy \ --etherscan-api-key $(ETHERSCAN_API_KEY) \ -vvv +deploy-preview-sepolia :; forge script script/Deploy.s.sol:Deploy \ + --rpc-url https://1rpc.io/sepolia \ + --private-key $(DEPLOYMENT_PRIVATE_KEY) \ + -vvvvv + + +deploy-sepolia :; forge script script/Deploy.s.sol:Deploy \ + --rpc-url https://1rpc.io/sepolia \ + --private-key $(DEPLOYMENT_PRIVATE_KEY) \ + --broadcast \ + --verify \ + --etherscan-api-key $(ETHERSCAN_API_KEY) \ + -vvvvv + # Fork testing ft-mode-sepolia-fork :; forge test --match-contract TestE2EV2 \ --rpc-url https://sepolia.mode.network \ @@ -83,4 +97,4 @@ ft-holesky-fork :; forge test --match-contract TestE2EV2 \ ft-mainnet-fork :; forge test --match-contract TestE2EV2 \ --rpc-url https://eth.llamarpc.com \ --fork-block-number 20890902 \ - -vvvvv \ No newline at end of file + -vvvvv From e2079cfcdfc3c3a523e02c268f6d27bc4e3db265 Mon Sep 17 00:00:00 2001 From: jordaniza Date: Thu, 10 Oct 2024 12:48:18 +0400 Subject: [PATCH 07/13] router --- Makefile | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Makefile b/Makefile index 6640e51..994ee94 100644 --- a/Makefile +++ b/Makefile @@ -62,6 +62,18 @@ deploy-preview-sepolia :; forge script script/Deploy.s.sol:Deploy \ --private-key $(DEPLOYMENT_PRIVATE_KEY) \ -vvvvv +router-preview-sepolia :; forge script DeployRouter \ + --rpc-url https://1rpc.io/sepolia \ + --private-key $(DEPLOYMENT_PRIVATE_KEY) \ + -vvvvv + +router-sepolia :; forge script DeployRouter \ + --rpc-url https://1rpc.io/sepolia \ + --private-key $(DEPLOYMENT_PRIVATE_KEY) \ + --broadcast \ + --verify \ + --etherscan-api-key $(ETHERSCAN_API_KEY) \ + -vvvvv deploy-sepolia :; forge script script/Deploy.s.sol:Deploy \ --rpc-url https://1rpc.io/sepolia \ From 1970910b8ff8468ae1641157fc2f78ea49787f0d Mon Sep 17 00:00:00 2001 From: jordaniza Date: Thu, 10 Oct 2024 21:23:28 +0400 Subject: [PATCH 08/13] tweaks to the makefile --- .env.example | 1 + Makefile | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/.env.example b/.env.example index b0e73bf..d3cc417 100644 --- a/.env.example +++ b/.env.example @@ -10,6 +10,7 @@ FACTORY="0x26afd02483951953B0F8A21123169cf7747CA8e2" # NETWORK AND DEPLOYMENT WALLET DEPLOYMENT_PRIVATE_KEY="..." ALCHEMY_API_KEY="..." +# note - including this can slow down forge ETHERSCAN_API_KEY="..." NETWORK="sepolia" diff --git a/Makefile b/Makefile index 994ee94..8371f5a 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,12 @@ coverage:; ./coverage.sh # init the repo install :; make allow-scripts && make coverage +# tests + +test-unit :; forge test --no-match-contract "TestE2EV2" -w +tu :; make test-unit + + # deployments deploy-preview-mode-sepolia :; forge script script/Deploy.s.sol:Deploy \ --rpc-url https://sepolia.mode.network \ From 5af967dff9e8309af908854c6f28e3598092fe47 Mon Sep 17 00:00:00 2001 From: jordaniza Date: Fri, 11 Oct 2024 17:02:27 +0400 Subject: [PATCH 09/13] deployment addresses --- Makefile | 21 +++++++++++++++++++-- README.md | 23 +++++++++++------------ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 6be48c6..abcfc72 100644 --- a/Makefile +++ b/Makefile @@ -39,12 +39,29 @@ ft-sepolia-fork :; forge test --match-contract TestE2EV2 \ # Fork testing - mainnet ft-mainnet-fork :; forge test --match-contract TestE2EV2 \ - --rpc-url https://eth.llamarpc.com \ - --fork-block-number 20890902 \ + --rpc-url https://eth-mainnet.g.alchemy.com/v2/$(ALCHEMY_API_KEY) \ -vvvvv #### Deployments #### +deploy-preview-mainnet :; forge script script/Deploy.s.sol:Deploy \ + --rpc-url https://eth-mainnet.g.alchemy.com/v2/$(ALCHEMY_API_KEY) \ + --private-key $(DEPLOYMENT_PRIVATE_KEY) \ + -vvvvv + +deploy-mainnet :; forge script script/Deploy.s.sol:Deploy \ + --rpc-url https://eth-mainnet.g.alchemy.com/v2/$(ALCHEMY_API_KEY) \ + --slow \ + --resume \ + --private-key $(DEPLOYMENT_PRIVATE_KEY) \ + --verify \ + --etherscan-api-key $(ETHERSCAN_API_KEY) \ + -vvvvv + +log-mainnet :; forge script Logger \ + --rpc-url https://eth-mainnet.g.alchemy.com/v2/$(ALCHEMY_API_KEY) \ + -vvvvv + deploy-preview-mode-sepolia :; forge script script/Deploy.s.sol:Deploy \ --rpc-url https://sepolia.mode.network \ --private-key $(DEPLOYMENT_PRIVATE_KEY) \ diff --git a/README.md b/README.md index d8092af..0d0272c 100644 --- a/README.md +++ b/README.md @@ -71,19 +71,18 @@ Check the `Makefile` for examples of deployments on different networks. ### Deployment Checklist -- [] I have reviewed the parameters for the veDAO I want to deploy -- [] I have reviewed the multisig file for the correct addresses - - [] I have ensured all multisig members have undergone a proper security review and are aware of the security implications of being on said multisig -- [] I have updated the `.env` with these parameters -- [] I have updated the `CurveConstantLib` and `Clock` with any new constants. -- [] All my unit tests pass -- [] I have run a fork test in `fork-deploy` mode against the OSx contracts on my target testnet -- [] I have deployed my contracts successfully to a target testnet +- [x] I have reviewed the parameters for the veDAO I want to deploy +- [x] I have reviewed the multisig file for the correct addresses + - [x] I have ensured all multisig members have undergone a proper security review and are aware of the security implications of being on said multisig +- [x] I have updated the `.env` with these parameters +- [x] I have updated the `CurveConstantLib` and `Clock` with any new constants. +- [x] All my unit tests pass +- [x] I have run a fork test in `fork-deploy` mode against the OSx contracts on my target testnet +- [x] I have deployed my contracts successfully to a target testnet +- [x] I have previewed my deploy +- [x] My deployer address is a fresh wallet or setup for repeat production deploys in a safe manner. +- [x] My wallet has sufficient native token for gas - [] I have confirmed my tests still work in `fork-existing` mode with the live tokens and the factory. -- [] I have run the same workflow against the mainnet I wish to deploy on -- [] I have previewed my deploy -- [] My deployer address is a fresh wallet or setup for repeat production deploys in a safe manner. -- [] My wallet has sufficient native token for gas **Puffer Only** From 4e63b8a9556d6e067158a0bc0729833c5144513f Mon Sep 17 00:00:00 2001 From: jordaniza Date: Fri, 11 Oct 2024 17:05:24 +0400 Subject: [PATCH 10/13] deployment addresses --- DEPLOYMENT_ADDRESSES.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 DEPLOYMENT_ADDRESSES.md diff --git a/DEPLOYMENT_ADDRESSES.md b/DEPLOYMENT_ADDRESSES.md new file mode 100644 index 0000000..2d2c215 --- /dev/null +++ b/DEPLOYMENT_ADDRESSES.md @@ -0,0 +1,24 @@ +# Deployment Addresses Puffer Mainnet + +```yaml + Deploying from: 0x36b6fE474dAD8e822d3133B76E9adA671E75eC86 + + Chain ID: 1 + Factory: 0xfbF3B5Fa2380C77a6ac255A8e19a142490601767 + + DAO: 0x5dEA8E499b05de8F86E7521F039770268055b23F + + Plugins + - Multisig plugin: 0xA303C435563a4544a84E26501F4666346Ff73a0d + + Gauge voter plugin: 0x69E8D5151d71d4cde35b5076aF3023C7D54d379E + Curve: 0xAaAb5528aFf964CEAc972E39c2357c2D503A9196 + Exit Queue: 0xD9C2d314E29F1940d2a65A691881F0950fE4A455 + Voting Escrow: 0xA55eD5808aeCDF23AE3782C1443185f5D2363ce7 + Clock: 0x8BCDf6291F251cF8eCf5ac06bFc4A2B02Ecc26eB + NFT Lock: 0x1b6ec227ceBeC25118270efbb4b67642fc29965E + + Plugin repositories + - Multisig plugin repository (existing): 0x8c278e37D0817210E18A7958524b7D0a1fAA6F7b + - Gauge voter plugin repository: 0xa10192700F6c3A0ee0deAA2EE72A91916a4CBb70 +``` From 490434fa95a0534da7f3f19b2a7562dd5d7097cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8r=E2=88=82=C2=A1?= <4456749+brickpop@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:06:45 +0200 Subject: [PATCH 11/13] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0d0272c..2b1b9a5 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Welcome to Aragon's veGovernance Plugin - a flexible, modular and secure system which can be used to create custom DAOs that foster a strong alignment between token holders and capital flows. +The mainnet deployment addresses can be found [here](./DEPLOYMENT_ADDRESSES.md). + ## Setup To get started, ensure that [Foundry](https://getfoundry.sh/) is installed on your computer, then copy `.env.example` into `.env` and define the parameters From 63c41af987c8c53a36d025ad09c682f83b08a1d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8r=E2=88=82=C2=A1?= <4456749+brickpop@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:08:53 +0200 Subject: [PATCH 12/13] Update DEPLOYMENT_ADDRESSES.md --- DEPLOYMENT_ADDRESSES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DEPLOYMENT_ADDRESSES.md b/DEPLOYMENT_ADDRESSES.md index 2d2c215..8e970bc 100644 --- a/DEPLOYMENT_ADDRESSES.md +++ b/DEPLOYMENT_ADDRESSES.md @@ -22,3 +22,5 @@ - Multisig plugin repository (existing): 0x8c278e37D0817210E18A7958524b7D0a1fAA6F7b - Gauge voter plugin repository: 0xa10192700F6c3A0ee0deAA2EE72A91916a4CBb70 ``` + +The deployment addresses can also be verified [on the factory contract via Etherscan](https://etherscan.io/address/0xfbf3b5fa2380c77a6ac255a8e19a142490601767#readContract) From d628e68ab6dbc21d14e8701eb6c769021c85a74d Mon Sep 17 00:00:00 2001 From: jordaniza Date: Fri, 11 Oct 2024 17:14:49 +0400 Subject: [PATCH 13/13] add router --- DEPLOYMENT_ADDRESSES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/DEPLOYMENT_ADDRESSES.md b/DEPLOYMENT_ADDRESSES.md index 2d2c215..793a0a6 100644 --- a/DEPLOYMENT_ADDRESSES.md +++ b/DEPLOYMENT_ADDRESSES.md @@ -21,4 +21,9 @@ Plugin repositories - Multisig plugin repository (existing): 0x8c278e37D0817210E18A7958524b7D0a1fAA6F7b - Gauge voter plugin repository: 0xa10192700F6c3A0ee0deAA2EE72A91916a4CBb70 + + Router + - 0xD33340fb9C8c2aEBC6922552bf3bC268a3682696 + + ```