From 8216f44f3938d32dac301e629876e81e2ad24481 Mon Sep 17 00:00:00 2001 From: mejango Date: Thu, 29 Dec 2022 18:37:27 -0300 Subject: [PATCH 01/21] removed trade deadline. added redemption period. mint starts Jan 8 12am EST. 1 day redemption period. game starts Jan 14 12am EST. voting starts the day of the superbowl, scorecards dont have a voting duration. mints are 0.1 ETH. --- contracts/DefifaDeployer.sol | 117 ++++--- contracts/DefifaGovernor.sol | 2 +- contracts/scripts/Deploy.s.sol | 327 +++++++++--------- contracts/structs/DefifaLaunchProjectData.sol | 4 +- contracts/structs/DefifaTimeData.sol | 4 +- 5 files changed, 224 insertions(+), 230 deletions(-) diff --git a/contracts/DefifaDeployer.sol b/contracts/DefifaDeployer.sol index 585772f..4241eea 100644 --- a/contracts/DefifaDeployer.sol +++ b/contracts/DefifaDeployer.sol @@ -126,12 +126,12 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { return _timesFor[_gameId].mintDuration; } - function startOf(uint256 _gameId) external view override returns (uint256) { - return _timesFor[_gameId].start; + function redemptionPeriodDurationOf(uint256 _gameId) external view override returns (uint256) { + return _timesFor[_gameId].redemptionPeriod; } - function tradeDeadlineOf(uint256 _gameId) external view override returns (uint256) { - return _timesFor[_gameId].tradeDeadline; + function startOf(uint256 _gameId) external view override returns (uint256) { + return _timesFor[_gameId].start; } function endOf(uint256 _gameId) external view override returns (uint256) { @@ -227,10 +227,8 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { ) external override returns (uint256 gameId) { // Make sure the provided gameplay timestamps are sequential. if ( - _launchProjectData.start - _launchProjectData.mintDuration < block.timestamp || - _launchProjectData.tradeDeadline < _launchProjectData.start || - _launchProjectData.end < _launchProjectData.start || - _launchProjectData.end < _launchProjectData.tradeDeadline + _launchProjectData.start - _launchProjectData.redemptionPeriod - _launchProjectData.mintDuration < block.timestamp || + _launchProjectData.end < _launchProjectData.start ) revert INVALID_GAME_CONFIGURATION(); // Get the game ID, optimistically knowing it will be one greater than the current count. @@ -243,8 +241,8 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { // Store the timestamps that'll define the game phases. _timesFor[gameId] = DefifaTimeData({ mintDuration: _launchProjectData.mintDuration, + redemptionPeriod: _launchProjectData.redemptionPeriod, start: _launchProjectData.start, - tradeDeadline: _launchProjectData.tradeDeadline, end: _launchProjectData.end }); @@ -328,7 +326,8 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { // Queue the next phase of the game. if (_currentFundingCycle.number == 1) return _queuePhase2(_gameId, _metadata.dataSource); else if (_currentFundingCycle.number == 2) return _queuePhase3(_gameId, _metadata.dataSource); - else return _queuePhase4(_gameId, _metadata.dataSource); + else if (_currentFundingCycle.number == 3) return _queuePhase4(_gameId, _metadata.dataSource); + else return _queuePhase5(_gameId, _metadata.dataSource); } /** @@ -413,6 +412,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { metadata: JBTiered721FundingCycleMetadataResolver.packFundingCycleGlobalMetadata( JBTiered721FundingCycleMetadata({ pauseTransfers: false, + // Reserved tokens can't be minted during this funding cycle. pauseMintingReserves: true }) ) @@ -430,7 +430,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { Gets reconfiguration data for phase 2 of the game. @dev - Phase 2 freezes the treasury and activates the pre-programmed distribution limit to the specified splits. + Phase 2 freezes mints, but continues to allow refund redemptions. @param _gameId The ID of the project that's being reconfigured. @param _dataSource The data source to use. @@ -441,33 +441,6 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { internal returns (uint256 configuration) { - // Get a reference to the terminal being used by the project. - DefifaStoredOpsData memory _ops = _opsFor[_gameId]; - - // Set fund access constraints. - JBFundAccessConstraints[] memory fundAccessConstraints = new JBFundAccessConstraints[](1); - fundAccessConstraints[0] = JBFundAccessConstraints({ - terminal: _ops.terminal, - token: token, - distributionLimit: _ops.distributionLimit, - distributionLimitCurrency: _ops.terminal.currencyForToken(token), - overflowAllowance: 0, - overflowAllowanceCurrency: 0 - }); - - // Fetch splits. - JBSplit[] memory _splits = controller.splitsStore().splitsOf(SPLIT_PROJECT_ID, SPLIT_DOMAIN, _gameId); - - // Make a group split for ETH payouts. - JBGroupedSplits[] memory _groupedSplits; - - if (_splits.length != 0) { - _groupedSplits = new JBGroupedSplits[](1); - _groupedSplits[0] = JBGroupedSplits({group: JBSplitsGroups.ETH_PAYOUT, splits: _splits}); - } - else { - _groupedSplits = new JBGroupedSplits[](0); - } // Get a reference to the time data. DefifaTimeData memory _times = _timesFor[_gameId]; @@ -476,7 +449,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { controller.reconfigureFundingCyclesOf( _gameId, JBFundingCycleData ({ - duration: _times.tradeDeadline - _times.start, + duration: _times.redemptionPeriod, // Don't mint project tokens. weight: 0, discountRate: 0, @@ -489,33 +462,36 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { pauseTransfers: false }), reservedRate: 0, - redemptionRate: 0, - ballotRedemptionRate: 0, + // Full refunds. + redemptionRate: JBConstants.MAX_REDEMPTION_RATE, + ballotRedemptionRate: JBConstants.MAX_REDEMPTION_RATE, // No more payments. pausePay: true, pauseDistributions: false, - // No redemptions. - pauseRedeem: true, + // Allow redemptions. + pauseRedeem: false, pauseBurn: false, allowMinting: false, allowTerminalMigration: false, allowControllerMigration: false, - holdFees: _ops.holdFees, + holdFees: false, preferClaimedTokenOverride: false, useTotalOverflowForRedemptions: false, useDataSourceForPay: true, useDataSourceForRedeem: true, dataSource: _dataSource, + // Set a metadata of 1 to impose token non-transferability. metadata: JBTiered721FundingCycleMetadataResolver.packFundingCycleGlobalMetadata( JBTiered721FundingCycleMetadata({ pauseTransfers: false, - pauseMintingReserves: false + // Reserved tokens can't be minted during this funding cycle. + pauseMintingReserves: true }) ) }), 0, // mustStartAtOrAfter should be ASAP - _groupedSplits, - fundAccessConstraints, + new JBGroupedSplits[](0), + new JBFundAccessConstraints[](0), 'Defifa game phase 2.' ); } @@ -525,14 +501,44 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { Gets reconfiguration data for phase 3 of the game. @dev - Phase 3 imposes a trade deadline. + Phase 3 freezes the treasury and activates the pre-programmed distribution limit to the specified splits. @param _gameId The ID of the project that's being reconfigured. @param _dataSource The data source to use. @return configuration The configuration of the funding cycle that was successfully reconfigured. */ - function _queuePhase3(uint256 _gameId, address _dataSource) internal returns (uint256 configuration) { + function _queuePhase3(uint256 _gameId, address _dataSource) + internal + returns (uint256 configuration) + { + // Get a reference to the terminal being used by the project. + DefifaStoredOpsData memory _ops = _opsFor[_gameId]; + + // Set fund access constraints. + JBFundAccessConstraints[] memory fundAccessConstraints = new JBFundAccessConstraints[](1); + fundAccessConstraints[0] = JBFundAccessConstraints({ + terminal: _ops.terminal, + token: token, + distributionLimit: _ops.distributionLimit, + distributionLimitCurrency: _ops.terminal.currencyForToken(token), + overflowAllowance: 0, + overflowAllowanceCurrency: 0 + }); + + // Fetch splits. + JBSplit[] memory _splits = controller.splitsStore().splitsOf(SPLIT_PROJECT_ID, SPLIT_DOMAIN, _gameId); + + // Make a group split for ETH payouts. + JBGroupedSplits[] memory _groupedSplits; + + if (_splits.length != 0) { + _groupedSplits = new JBGroupedSplits[](1); + _groupedSplits[0] = JBGroupedSplits({group: JBSplitsGroups.ETH_PAYOUT, splits: _splits}); + } + else { + _groupedSplits = new JBGroupedSplits[](0); + } // Get a reference to the time data. DefifaTimeData memory _times = _timesFor[_gameId]; @@ -541,7 +547,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { controller.reconfigureFundingCyclesOf( _gameId, JBFundingCycleData ({ - duration: _times.end - _times.tradeDeadline, + duration: _times.end - _times.start, // Don't mint project tokens. weight: 0, discountRate: 0, @@ -565,23 +571,22 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { allowMinting: false, allowTerminalMigration: false, allowControllerMigration: false, - holdFees: false, + holdFees: _ops.holdFees, preferClaimedTokenOverride: false, useTotalOverflowForRedemptions: false, useDataSourceForPay: true, useDataSourceForRedeem: true, dataSource: _dataSource, - // Set a metadata of 1 to impose token non-transferability. metadata: JBTiered721FundingCycleMetadataResolver.packFundingCycleGlobalMetadata( JBTiered721FundingCycleMetadata({ - pauseTransfers: true, + pauseTransfers: false, pauseMintingReserves: false }) ) }), 0, // mustStartAtOrAfter should be ASAP - new JBGroupedSplits[](0), - new JBFundAccessConstraints[](0), + _groupedSplits, + fundAccessConstraints, 'Defifa game phase 3.' ); } @@ -591,7 +596,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { Gets reconfiguration data for phase 4 of the game. @dev - Phase 4 removes the trade deadline and open up redemptions. + Phase 4 removes the trade deadline and opens up redemptions. @param _gameId The ID of the project that's being reconfigured. @param _dataSource The data source to use. diff --git a/contracts/DefifaGovernor.sol b/contracts/DefifaGovernor.sol index 0af81bc..ea6b674 100644 --- a/contracts/DefifaGovernor.sol +++ b/contracts/DefifaGovernor.sol @@ -284,7 +284,7 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { The amount of time that must go by for voting on a proposal to no longer be allowed. */ function votingPeriod() public pure override(IGovernor) returns (uint256) { - return 45818; // one week + return 420000000000000069; // longtime } /** diff --git a/contracts/scripts/Deploy.s.sol b/contracts/scripts/Deploy.s.sol index 904ff4a..43ef86d 100644 --- a/contracts/scripts/Deploy.s.sol +++ b/contracts/scripts/Deploy.s.sol @@ -11,9 +11,9 @@ contract DeployMainnet is Script { function run() external { vm.startBroadcast(); - // V3 goerli controller. + // V3 mainnet controller. IJBController controller = IJBController(0xFFdD70C318915879d5192e8a0dcbFcB0285b3C98); - // goerli 721 store. + // mainnet 721 store. IJBTiered721DelegateStore store = IJBTiered721DelegateStore( 0xffB2Cd8519439A7ddcf2C933caedd938053067D2 ); @@ -22,10 +22,16 @@ contract DeployMainnet is Script { address _defifaBallcats = 0x11834239698c7336EF232C00a2A9926d3375DF9D; // Game params. - uint48 _start = 1669024800; // 2am PST, Nov 21. - uint48 _mintDuration = 1036800; // 12 days. - uint48 _tradeDeadline = 1670598000; // 7am, Dec 9. - uint48 _end = 1671375600 + 604800; // 7 days after the finals. Dec 25, 7am PST. + uint48 _start = 1642136400; // 12am EST, Jan 14. + uint48 _mintDuration = 432000; // 5 days. + uint48 _redemptionPeriod = 86400; // 1 day. + uint48 _end = 1671375600; // Superbowl. + uint80 _price = 0.1 ether; + string memory _name = 'Defifa: NFL Playoffs 2023'; + string memory _symbol = 'DEFIFA NFL 2023'; + string memory _contractUri = 'QmaK1Hib3Umokija4bRwoPdxHgGY3unRreeeLoJss3vw4Y'; + string memory _projectMetadataUri = 'QmT7VFuF7cPMwMnqh3YruuYcRk2tKMb2xcXSbK2wV82Hdy'; + uint16 _reserved = 9; // 1 reserved NFT mintable to reserved beneficiary for every 9 NFTs minted outwardly. Inclusive, so 1 reserved can be minted as soon as the first token is minted outwardly. JB721TierParams[] memory _tiers = new JB721TierParams[](32); @@ -44,32 +50,14 @@ contract DeployMainnet is Script { _teamEncodedIPFSUris[11] = 0x895646f615fc45358d894014f3d8c15ad020323cf57c6624464bd11a2815a480; _teamEncodedIPFSUris[12] = 0x6388190babc4fd7ad390b545dc0eaf01222355583ce0a5d5496c2bb6f118039b; _teamEncodedIPFSUris[13] = 0x33e06853378f58d42ceb8ab266d25656eded385f82a777ca563c5e38d5241a83; - _teamEncodedIPFSUris[14] = 0x2f4275c8dac582d4718d41315e8406e502f9edc24718508008c9be2120c29718; - _teamEncodedIPFSUris[15] = 0x6ff53e06711936e10bd3ca5786ca9c47cbd42f5b878289c350fa405513cbba39; - _teamEncodedIPFSUris[16] = 0xdaae0d745afe8943fffe0a733b7da605db462162bf0895d069daf8137ded8b0f; - _teamEncodedIPFSUris[17] = 0xba245717d6e4293217d7e94f19b5aef1a84f6902bced1332eb8607aaddd43db2; - _teamEncodedIPFSUris[18] = 0x42a65ae98f0d43856f8d75d645dbe964750f42415e038264813c95e1fd977839; - _teamEncodedIPFSUris[19] = 0x755651ad1de6c43ed4525d761a39c4521445f67c72010544cdbe156928954d2d; - _teamEncodedIPFSUris[20] = 0x6f880ca3d58e8f48a8709d097ead5dda0969f525efacadba9d707fd68578e45f; - _teamEncodedIPFSUris[21] = 0x9ca1e5354a134ff50d36121ccc511ac6a1c42797512aceea4d1e14811359c063; - _teamEncodedIPFSUris[22] = 0x91b2e30c3f239b25f75ea44ca36ddaa616738bd88ecedd67691f22bffe401727; - _teamEncodedIPFSUris[23] = 0xdfb13aa5ab8c607ca1772385ece7dc4213a06ae0e7a09058592556e19b4ef6eb; - _teamEncodedIPFSUris[24] = 0xb587a257c1a625c9b28f3f2c841fe99fdad97d111f94a3f238e1a8f224b48e37; - _teamEncodedIPFSUris[25] = 0xab1d428c4b2594b8232abff414ad259f6748dbe13302dd7d4758c12a79b9ffbf; - _teamEncodedIPFSUris[26] = 0x5756ead1507fa2210f66dd2bf9ed722b27929ccd90fade1a234447dc01cc8ef0; - _teamEncodedIPFSUris[27] = 0x032083c1a27f9e5fed3236e357dca8e7bc205681a9942465adfeca40efcc05a5; - _teamEncodedIPFSUris[28] = 0x60c52313561051352c1d98d9652815b555f95c0ee250b9afd1acddf95dec9578; - _teamEncodedIPFSUris[29] = 0x5b88630af3d5ad16f18c2c8528a41b925233c61e40c8934d7981e21881b062b5; - _teamEncodedIPFSUris[30] = 0x1ba892a008a164359a2b70ef1ab046d90fa3af4ce4815c00cd07a2a9237e9808; - _teamEncodedIPFSUris[31] = 0x193bb548bbf52cf76e00185e24c0eada8f758dfef1927cfaa202207e4beb6cec; for (uint256 _i; _i < 32; ) { _tiers[_i] = JB721TierParams({ - contributionFloor: 0.022 ether, + contributionFloor: _price, lockedUntil: 0, initialQuantity: 1_000_000_000 - 1, // max votingUnits: 1, - reservedRate: 9, + reservedRate: _reserved, reservedTokenBeneficiary: _defifaBallcats, encodedIPFSUri: _teamEncodedIPFSUris[_i], allowManualMint: false, @@ -83,10 +71,10 @@ contract DeployMainnet is Script { } DefifaDelegateData memory _delegateData = DefifaDelegateData({ - name: 'Defifa: FIFA World Cup 2022', - symbol: 'DEFIFA', + name: _name, + symbol: _symbol, baseUri: 'ipfs://', - contractUri: 'QmaK1Hib3Umokija4bRwoPdxHgGY3unRreeeLoJss3vw4Y', + contractUri: _contractUri, tiers: _tiers, store: store, // Set owner will be set to the Governor later on in this script. @@ -95,12 +83,13 @@ contract DeployMainnet is Script { DefifaLaunchProjectData memory _launchProjectData = DefifaLaunchProjectData({ projectMetadata: JBProjectMetadata({ - content: 'QmT7VFuF7cPMwMnqh3YruuYcRk2tKMb2xcXSbK2wV82Hdy', + content: _projectMetadataUri, domain: 0 }), mintDuration: _mintDuration, start: _start, tradeDeadline: _tradeDeadline, + redemptionPeriod: _redemptionPeriod, end: _end, holdFees: false, splits: new JBSplit[](0), @@ -148,143 +137,143 @@ contract DeployMainnet is Script { } } -contract DeployGoerli is Script { - function run() external { - vm.startBroadcast(); - - // V3 goerli controller. - IJBController controller = IJBController(0x7Cb86D43B665196BC719b6974D320bf674AFb395); - // goerli 721 store. - IJBTiered721DelegateStore store = IJBTiered721DelegateStore( - 0x3EA16DeFF07f031e86bd13C55961eB576cd579a6 - ); - // V3 goerli Payment terminal. - IJBPaymentTerminal terminal = IJBPaymentTerminal(0x55d4dfb578daA4d60380995ffF7a706471d7c719); - - address _defifaBallcats = 0x11834239698c7336EF232C00a2A9926d3375DF9D; - // Game params. - uint48 _start = 1669024800; // 2am PST, Nov 21. - uint48 _mintDuration = 1036800; // 12 days. - uint48 _tradeDeadline = 1670598000; // 7am, Dec 9. - uint48 _end = 1671375600 + 604800; // 7 days after the finals. Dec 25, 7am PST. - - JB721TierParams[] memory _tiers = new JB721TierParams[](32); - - bytes32[] memory _teamEncodedIPFSUris = new bytes32[](32); - _teamEncodedIPFSUris[0] = 0xb2cf9b27f33b6b445b31fa13ad93600d35a1bafd27543b313af1e2cd727e213b; - _teamEncodedIPFSUris[1] = 0xbfabff3f158961179837886c91f9e5847a25865b20f1a3c4f13448323284d31f; - _teamEncodedIPFSUris[2] = 0xf526000358a2bb0227db6a0f4c28b8cfb242e0a16f568975b6f7839ef2075761; - _teamEncodedIPFSUris[3] = 0xb514ff48aef786b83f456773af2b432365707b84ca9ec02c0639732279c57f35; - _teamEncodedIPFSUris[4] = 0x816bff580d5d900165c09b953c11cd4a9fe15b41ded825edfc82680eb7cdeaa9; - _teamEncodedIPFSUris[5] = 0x2850e2b55a3fb53a17173d0e91938e2da2d520c3092858ce68a460dad35bbc91; - _teamEncodedIPFSUris[6] = 0x98fa3187e98ad21fcdf43a1e1601e8f8619ceeaf9f3fb0039f2f61f31e35a145; - _teamEncodedIPFSUris[7] = 0xda36dfe50c30ae4e83b4e8ef4cd4ce9e580298a55d31b8d7276e644380ce9ff6; - _teamEncodedIPFSUris[8] = 0x8b3b961de3bacb600488d91dbe9277c50f16311b92455e82ce6c26d078d9503f; - _teamEncodedIPFSUris[9] = 0x0977f77350659d1f8284f1b0a4f0ee447cf32c6ef8c06b7ec5f9295822818111; - _teamEncodedIPFSUris[10] = 0x6198d84d8904f2c89fa6ff3de01ccce8b928cfb6182da65723b70aa1e63a94c8; - _teamEncodedIPFSUris[11] = 0x895646f615fc45358d894014f3d8c15ad020323cf57c6624464bd11a2815a480; - _teamEncodedIPFSUris[12] = 0x6388190babc4fd7ad390b545dc0eaf01222355583ce0a5d5496c2bb6f118039b; - _teamEncodedIPFSUris[13] = 0x33e06853378f58d42ceb8ab266d25656eded385f82a777ca563c5e38d5241a83; - _teamEncodedIPFSUris[14] = 0x2f4275c8dac582d4718d41315e8406e502f9edc24718508008c9be2120c29718; - _teamEncodedIPFSUris[15] = 0x6ff53e06711936e10bd3ca5786ca9c47cbd42f5b878289c350fa405513cbba39; - _teamEncodedIPFSUris[16] = 0xdaae0d745afe8943fffe0a733b7da605db462162bf0895d069daf8137ded8b0f; - _teamEncodedIPFSUris[17] = 0xba245717d6e4293217d7e94f19b5aef1a84f6902bced1332eb8607aaddd43db2; - _teamEncodedIPFSUris[18] = 0x42a65ae98f0d43856f8d75d645dbe964750f42415e038264813c95e1fd977839; - _teamEncodedIPFSUris[19] = 0x755651ad1de6c43ed4525d761a39c4521445f67c72010544cdbe156928954d2d; - _teamEncodedIPFSUris[20] = 0x6f880ca3d58e8f48a8709d097ead5dda0969f525efacadba9d707fd68578e45f; - _teamEncodedIPFSUris[21] = 0x9ca1e5354a134ff50d36121ccc511ac6a1c42797512aceea4d1e14811359c063; - _teamEncodedIPFSUris[22] = 0x91b2e30c3f239b25f75ea44ca36ddaa616738bd88ecedd67691f22bffe401727; - _teamEncodedIPFSUris[23] = 0xdfb13aa5ab8c607ca1772385ece7dc4213a06ae0e7a09058592556e19b4ef6eb; - _teamEncodedIPFSUris[24] = 0xb587a257c1a625c9b28f3f2c841fe99fdad97d111f94a3f238e1a8f224b48e37; - _teamEncodedIPFSUris[25] = 0xab1d428c4b2594b8232abff414ad259f6748dbe13302dd7d4758c12a79b9ffbf; - _teamEncodedIPFSUris[26] = 0x5756ead1507fa2210f66dd2bf9ed722b27929ccd90fade1a234447dc01cc8ef0; - _teamEncodedIPFSUris[27] = 0x032083c1a27f9e5fed3236e357dca8e7bc205681a9942465adfeca40efcc05a5; - _teamEncodedIPFSUris[28] = 0x60c52313561051352c1d98d9652815b555f95c0ee250b9afd1acddf95dec9578; - _teamEncodedIPFSUris[29] = 0x5b88630af3d5ad16f18c2c8528a41b925233c61e40c8934d7981e21881b062b5; - _teamEncodedIPFSUris[30] = 0x1ba892a008a164359a2b70ef1ab046d90fa3af4ce4815c00cd07a2a9237e9808; - _teamEncodedIPFSUris[31] = 0x193bb548bbf52cf76e00185e24c0eada8f758dfef1927cfaa202207e4beb6cec; - - for (uint256 _i; _i < 32; ) { - _tiers[_i] = JB721TierParams({ - contributionFloor: 0.022 ether, - lockedUntil: 0, - initialQuantity: 1_000_000_000 - 1, // max - votingUnits: 1, - reservedRate: 9, - reservedTokenBeneficiary: _defifaBallcats, - encodedIPFSUri: _teamEncodedIPFSUris[_i], - allowManualMint: false, - shouldUseBeneficiaryAsDefault: true, - transfersPausable: true - }); - - unchecked { - ++_i; - } - } - - DefifaDelegateData memory _delegateData = DefifaDelegateData({ - name: 'Defifa: FIFA World Cup 2022', - symbol: 'DEFIFA', - baseUri: 'ipfs://', - contractUri: 'QmaK1Hib3Umokija4bRwoPdxHgGY3unRreeeLoJss3vw4Y', - tiers: _tiers, - store: store, - // Set owner will be set to the Governor later on in this script. - owner: address(0) - }); - - DefifaLaunchProjectData memory _launchProjectData = DefifaLaunchProjectData({ - projectMetadata: JBProjectMetadata({ - content: 'QmT7VFuF7cPMwMnqh3YruuYcRk2tKMb2xcXSbK2wV82Hdy', - domain: 0 - }), - mintDuration: _mintDuration, - start: _start, - tradeDeadline: _tradeDeadline, - end: _end, - holdFees: false, - splits: new JBSplit[](0), - distributionLimit: 0, - terminal: terminal - }); - - // Deploy the codeOrigin for the delegate - DefifaDelegate _defifaDelegateCodeOrigin = new DefifaDelegate(); - - // Deploy the deployer. - DefifaDeployer defifaDeployer = new DefifaDeployer( - address(_defifaDelegateCodeOrigin), - controller, - JBTokens.ETH, - _defifaBallcats - ); - - // Set the owner as the governor (done here to easily count future nonces) - _delegateData.owner = computeCreateAddress(tx.origin, vm.getNonce(tx.origin) + 1); - - // Launch the game - initialNonce - uint256 _projectId = defifaDeployer.launchGameWith(_delegateData, _launchProjectData); - // initialNonce + 1 - - // Get a reference to the latest configured funding cycle's data source, which should be the delegate that was deployed and attached to the project. - (, JBFundingCycleMetadata memory _metadata, ) = controller.latestConfiguredFundingCycleOf( - _projectId - ); - // initialNonce + 1 (view function) - - // Deploy the governor - { - address _governor = address(new DefifaGovernor(DefifaDelegate(_metadata.dataSource), _end)); +// contract DeployGoerli is Script { +// function run() external { +// vm.startBroadcast(); + +// // V3 goerli controller. +// IJBController controller = IJBController(0x7Cb86D43B665196BC719b6974D320bf674AFb395); +// // goerli 721 store. +// IJBTiered721DelegateStore store = IJBTiered721DelegateStore( +// 0x3EA16DeFF07f031e86bd13C55961eB576cd579a6 +// ); +// // V3 goerli Payment terminal. +// IJBPaymentTerminal terminal = IJBPaymentTerminal(0x55d4dfb578daA4d60380995ffF7a706471d7c719); + +// address _defifaBallcats = 0x11834239698c7336EF232C00a2A9926d3375DF9D; +// // Game params. +// uint48 _start = 1669024800; // 2am PST, Nov 21. +// uint48 _mintDuration = 1036800; // 12 days. +// uint48 _tradeDeadline = 1670598000; // 7am, Dec 9. +// uint48 _end = 1671375600 + 604800; // 7 days after the finals. Dec 25, 7am PST. + +// JB721TierParams[] memory _tiers = new JB721TierParams[](32); + +// bytes32[] memory _teamEncodedIPFSUris = new bytes32[](32); +// _teamEncodedIPFSUris[0] = 0xb2cf9b27f33b6b445b31fa13ad93600d35a1bafd27543b313af1e2cd727e213b; +// _teamEncodedIPFSUris[1] = 0xbfabff3f158961179837886c91f9e5847a25865b20f1a3c4f13448323284d31f; +// _teamEncodedIPFSUris[2] = 0xf526000358a2bb0227db6a0f4c28b8cfb242e0a16f568975b6f7839ef2075761; +// _teamEncodedIPFSUris[3] = 0xb514ff48aef786b83f456773af2b432365707b84ca9ec02c0639732279c57f35; +// _teamEncodedIPFSUris[4] = 0x816bff580d5d900165c09b953c11cd4a9fe15b41ded825edfc82680eb7cdeaa9; +// _teamEncodedIPFSUris[5] = 0x2850e2b55a3fb53a17173d0e91938e2da2d520c3092858ce68a460dad35bbc91; +// _teamEncodedIPFSUris[6] = 0x98fa3187e98ad21fcdf43a1e1601e8f8619ceeaf9f3fb0039f2f61f31e35a145; +// _teamEncodedIPFSUris[7] = 0xda36dfe50c30ae4e83b4e8ef4cd4ce9e580298a55d31b8d7276e644380ce9ff6; +// _teamEncodedIPFSUris[8] = 0x8b3b961de3bacb600488d91dbe9277c50f16311b92455e82ce6c26d078d9503f; +// _teamEncodedIPFSUris[9] = 0x0977f77350659d1f8284f1b0a4f0ee447cf32c6ef8c06b7ec5f9295822818111; +// _teamEncodedIPFSUris[10] = 0x6198d84d8904f2c89fa6ff3de01ccce8b928cfb6182da65723b70aa1e63a94c8; +// _teamEncodedIPFSUris[11] = 0x895646f615fc45358d894014f3d8c15ad020323cf57c6624464bd11a2815a480; +// _teamEncodedIPFSUris[12] = 0x6388190babc4fd7ad390b545dc0eaf01222355583ce0a5d5496c2bb6f118039b; +// _teamEncodedIPFSUris[13] = 0x33e06853378f58d42ceb8ab266d25656eded385f82a777ca563c5e38d5241a83; +// _teamEncodedIPFSUris[14] = 0x2f4275c8dac582d4718d41315e8406e502f9edc24718508008c9be2120c29718; +// _teamEncodedIPFSUris[15] = 0x6ff53e06711936e10bd3ca5786ca9c47cbd42f5b878289c350fa405513cbba39; +// _teamEncodedIPFSUris[16] = 0xdaae0d745afe8943fffe0a733b7da605db462162bf0895d069daf8137ded8b0f; +// _teamEncodedIPFSUris[17] = 0xba245717d6e4293217d7e94f19b5aef1a84f6902bced1332eb8607aaddd43db2; +// _teamEncodedIPFSUris[18] = 0x42a65ae98f0d43856f8d75d645dbe964750f42415e038264813c95e1fd977839; +// _teamEncodedIPFSUris[19] = 0x755651ad1de6c43ed4525d761a39c4521445f67c72010544cdbe156928954d2d; +// _teamEncodedIPFSUris[20] = 0x6f880ca3d58e8f48a8709d097ead5dda0969f525efacadba9d707fd68578e45f; +// _teamEncodedIPFSUris[21] = 0x9ca1e5354a134ff50d36121ccc511ac6a1c42797512aceea4d1e14811359c063; +// _teamEncodedIPFSUris[22] = 0x91b2e30c3f239b25f75ea44ca36ddaa616738bd88ecedd67691f22bffe401727; +// _teamEncodedIPFSUris[23] = 0xdfb13aa5ab8c607ca1772385ece7dc4213a06ae0e7a09058592556e19b4ef6eb; +// _teamEncodedIPFSUris[24] = 0xb587a257c1a625c9b28f3f2c841fe99fdad97d111f94a3f238e1a8f224b48e37; +// _teamEncodedIPFSUris[25] = 0xab1d428c4b2594b8232abff414ad259f6748dbe13302dd7d4758c12a79b9ffbf; +// _teamEncodedIPFSUris[26] = 0x5756ead1507fa2210f66dd2bf9ed722b27929ccd90fade1a234447dc01cc8ef0; +// _teamEncodedIPFSUris[27] = 0x032083c1a27f9e5fed3236e357dca8e7bc205681a9942465adfeca40efcc05a5; +// _teamEncodedIPFSUris[28] = 0x60c52313561051352c1d98d9652815b555f95c0ee250b9afd1acddf95dec9578; +// _teamEncodedIPFSUris[29] = 0x5b88630af3d5ad16f18c2c8528a41b925233c61e40c8934d7981e21881b062b5; +// _teamEncodedIPFSUris[30] = 0x1ba892a008a164359a2b70ef1ab046d90fa3af4ce4815c00cd07a2a9237e9808; +// _teamEncodedIPFSUris[31] = 0x193bb548bbf52cf76e00185e24c0eada8f758dfef1927cfaa202207e4beb6cec; + +// for (uint256 _i; _i < 32; ) { +// _tiers[_i] = JB721TierParams({ +// contributionFloor: 0.022 ether, +// lockedUntil: 0, +// initialQuantity: 1_000_000_000 - 1, // max +// votingUnits: 1, +// reservedRate: 9, +// reservedTokenBeneficiary: _defifaBallcats, +// encodedIPFSUri: _teamEncodedIPFSUris[_i], +// allowManualMint: false, +// shouldUseBeneficiaryAsDefault: true, +// transfersPausable: true +// }); + +// unchecked { +// ++_i; +// } +// } + +// DefifaDelegateData memory _delegateData = DefifaDelegateData({ +// name: 'Defifa: FIFA World Cup 2022', +// symbol: 'DEFIFA', +// baseUri: 'ipfs://', +// contractUri: 'QmaK1Hib3Umokija4bRwoPdxHgGY3unRreeeLoJss3vw4Y', +// tiers: _tiers, +// store: store, +// // Set owner will be set to the Governor later on in this script. +// owner: address(0) +// }); + +// DefifaLaunchProjectData memory _launchProjectData = DefifaLaunchProjectData({ +// projectMetadata: JBProjectMetadata({ +// content: 'QmT7VFuF7cPMwMnqh3YruuYcRk2tKMb2xcXSbK2wV82Hdy', +// domain: 0 +// }), +// mintDuration: _mintDuration, +// start: _start, +// tradeDeadline: _tradeDeadline, +// end: _end, +// holdFees: false, +// splits: new JBSplit[](0), +// distributionLimit: 0, +// terminal: terminal +// }); + +// // Deploy the codeOrigin for the delegate +// DefifaDelegate _defifaDelegateCodeOrigin = new DefifaDelegate(); + +// // Deploy the deployer. +// DefifaDeployer defifaDeployer = new DefifaDeployer( +// address(_defifaDelegateCodeOrigin), +// controller, +// JBTokens.ETH, +// _defifaBallcats +// ); + +// // Set the owner as the governor (done here to easily count future nonces) +// _delegateData.owner = computeCreateAddress(tx.origin, vm.getNonce(tx.origin) + 1); + +// // Launch the game - initialNonce +// uint256 _projectId = defifaDeployer.launchGameWith(_delegateData, _launchProjectData); +// // initialNonce + 1 + +// // Get a reference to the latest configured funding cycle's data source, which should be the delegate that was deployed and attached to the project. +// (, JBFundingCycleMetadata memory _metadata, ) = controller.latestConfiguredFundingCycleOf( +// _projectId +// ); +// // initialNonce + 1 (view function) + +// // Deploy the governor +// { +// address _governor = address(new DefifaGovernor(DefifaDelegate(_metadata.dataSource), _end)); - // These 3 should be the same: - console.log(_delegateData.owner); - console.log(_governor); - console.log(Ownable(_metadata.dataSource).owner()); - } - - console.log(address(defifaDeployer)); - console.log(address(store)); - console.log(_metadata.dataSource); - } -} +// // These 3 should be the same: +// console.log(_delegateData.owner); +// console.log(_governor); +// console.log(Ownable(_metadata.dataSource).owner()); +// } + +// console.log(address(defifaDeployer)); +// console.log(address(store)); +// console.log(_metadata.dataSource); +// } +// } diff --git a/contracts/structs/DefifaLaunchProjectData.sol b/contracts/structs/DefifaLaunchProjectData.sol index 0ce23dc..9957cb9 100644 --- a/contracts/structs/DefifaLaunchProjectData.sol +++ b/contracts/structs/DefifaLaunchProjectData.sol @@ -9,8 +9,8 @@ import './DefifaTimeData.sol'; /** @member projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project. @member mintDuration The duration of the game's first phase. + @member redemptionPeriod The time between the mint period and the start time where mint's are no longer open but refunds are still allowed. @member start The timestamp at which the game should start. - @member tradeDeadline The timestamp at which the game's trade deadline should begin. @member end The timestamp at which the game should end. @member holdFees A flag indicating if fees should be held when distributing funds during the second funding cycle. @member splits Splits to distribute funds between during the game's second phase. @@ -20,8 +20,8 @@ import './DefifaTimeData.sol'; struct DefifaLaunchProjectData { JBProjectMetadata projectMetadata; uint48 mintDuration; + uint48 redemptionPeriod; uint48 start; - uint48 tradeDeadline; uint48 end; bool holdFees; JBSplit[] splits; diff --git a/contracts/structs/DefifaTimeData.sol b/contracts/structs/DefifaTimeData.sol index 40395b6..758389f 100644 --- a/contracts/structs/DefifaTimeData.sol +++ b/contracts/structs/DefifaTimeData.sol @@ -5,13 +5,13 @@ import '@jbx-protocol/juice-721-delegate/contracts/structs/JB721TierParams.sol'; /** @member mintDuration The amount of time mints will be open for before the game's start. + @member redemptionPeriod The time between the mint period and the start time where mint's are no longer open but refunds are still allowed. @member start The timestamp at which the game should start. - @member tradeDeadline The timestamp at which the game's trade deadline should begin. @member end The timestamp at which the game should end. */ struct DefifaTimeData { uint48 mintDuration; + uint48 redemptionPeriod; uint48 start; - uint48 tradeDeadline; uint48 end; } From 5f1543e94ef1e15a36d0a08e98cb06831a951fd2 Mon Sep 17 00:00:00 2001 From: mejango Date: Thu, 29 Dec 2022 18:42:07 -0300 Subject: [PATCH 02/21] fixed dates --- contracts/DefifaDeployer.sol | 8 ++++---- contracts/scripts/Deploy.s.sol | 8 ++++---- contracts/structs/DefifaLaunchProjectData.sol | 4 ++-- contracts/structs/DefifaTimeData.sol | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/contracts/DefifaDeployer.sol b/contracts/DefifaDeployer.sol index 4241eea..55a340e 100644 --- a/contracts/DefifaDeployer.sol +++ b/contracts/DefifaDeployer.sol @@ -127,7 +127,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { } function redemptionPeriodDurationOf(uint256 _gameId) external view override returns (uint256) { - return _timesFor[_gameId].redemptionPeriod; + return _timesFor[_gameId].redemptionPeriodDuration; } function startOf(uint256 _gameId) external view override returns (uint256) { @@ -227,7 +227,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { ) external override returns (uint256 gameId) { // Make sure the provided gameplay timestamps are sequential. if ( - _launchProjectData.start - _launchProjectData.redemptionPeriod - _launchProjectData.mintDuration < block.timestamp || + _launchProjectData.start - _launchProjectData.redemptionPeriodDuration - _launchProjectData.mintDuration < block.timestamp || _launchProjectData.end < _launchProjectData.start ) revert INVALID_GAME_CONFIGURATION(); @@ -241,7 +241,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { // Store the timestamps that'll define the game phases. _timesFor[gameId] = DefifaTimeData({ mintDuration: _launchProjectData.mintDuration, - redemptionPeriod: _launchProjectData.redemptionPeriod, + redemptionPeriodDuration: _launchProjectData.redemptionPeriodDuration, start: _launchProjectData.start, end: _launchProjectData.end }); @@ -449,7 +449,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { controller.reconfigureFundingCyclesOf( _gameId, JBFundingCycleData ({ - duration: _times.redemptionPeriod, + duration: _times.redemptionPeriodDuration, // Don't mint project tokens. weight: 0, discountRate: 0, diff --git a/contracts/scripts/Deploy.s.sol b/contracts/scripts/Deploy.s.sol index 43ef86d..efd5f1d 100644 --- a/contracts/scripts/Deploy.s.sol +++ b/contracts/scripts/Deploy.s.sol @@ -22,10 +22,10 @@ contract DeployMainnet is Script { address _defifaBallcats = 0x11834239698c7336EF232C00a2A9926d3375DF9D; // Game params. - uint48 _start = 1642136400; // 12am EST, Jan 14. + uint48 _start = 1673672400; // 12am EST, Jan 14. uint48 _mintDuration = 432000; // 5 days. - uint48 _redemptionPeriod = 86400; // 1 day. - uint48 _end = 1671375600; // Superbowl. + uint48 _redemptionPeriodDuration = 86400; // 1 day. + uint48 _end = 1676178000; // 12am EST, Feb 12. uint80 _price = 0.1 ether; string memory _name = 'Defifa: NFL Playoffs 2023'; string memory _symbol = 'DEFIFA NFL 2023'; @@ -89,7 +89,7 @@ contract DeployMainnet is Script { mintDuration: _mintDuration, start: _start, tradeDeadline: _tradeDeadline, - redemptionPeriod: _redemptionPeriod, + redemptionPeriodDuration: _redemptionPeriodDuration, end: _end, holdFees: false, splits: new JBSplit[](0), diff --git a/contracts/structs/DefifaLaunchProjectData.sol b/contracts/structs/DefifaLaunchProjectData.sol index 9957cb9..4b45356 100644 --- a/contracts/structs/DefifaLaunchProjectData.sol +++ b/contracts/structs/DefifaLaunchProjectData.sol @@ -9,7 +9,7 @@ import './DefifaTimeData.sol'; /** @member projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project. @member mintDuration The duration of the game's first phase. - @member redemptionPeriod The time between the mint period and the start time where mint's are no longer open but refunds are still allowed. + @member redemptionPeriodDuration The time between the mint period and the start time where mint's are no longer open but refunds are still allowed. @member start The timestamp at which the game should start. @member end The timestamp at which the game should end. @member holdFees A flag indicating if fees should be held when distributing funds during the second funding cycle. @@ -20,7 +20,7 @@ import './DefifaTimeData.sol'; struct DefifaLaunchProjectData { JBProjectMetadata projectMetadata; uint48 mintDuration; - uint48 redemptionPeriod; + uint48 redemptionPeriodDuration; uint48 start; uint48 end; bool holdFees; diff --git a/contracts/structs/DefifaTimeData.sol b/contracts/structs/DefifaTimeData.sol index 758389f..77f433a 100644 --- a/contracts/structs/DefifaTimeData.sol +++ b/contracts/structs/DefifaTimeData.sol @@ -5,13 +5,13 @@ import '@jbx-protocol/juice-721-delegate/contracts/structs/JB721TierParams.sol'; /** @member mintDuration The amount of time mints will be open for before the game's start. - @member redemptionPeriod The time between the mint period and the start time where mint's are no longer open but refunds are still allowed. + @member redemptionPeriodDuration The time between the mint period and the start time where mint's are no longer open but refunds are still allowed. @member start The timestamp at which the game should start. @member end The timestamp at which the game should end. */ struct DefifaTimeData { uint48 mintDuration; - uint48 redemptionPeriod; + uint48 redemptionPeriodDuration; uint48 start; uint48 end; } From a11c1f7c17a0c1cd343d5716f898f7a37b6e0cf8 Mon Sep 17 00:00:00 2001 From: mejango Date: Thu, 29 Dec 2022 18:43:29 -0300 Subject: [PATCH 03/21] fixed ref --- contracts/DefifaDeployer.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/DefifaDeployer.sol b/contracts/DefifaDeployer.sol index 55a340e..93e771e 100644 --- a/contracts/DefifaDeployer.sol +++ b/contracts/DefifaDeployer.sol @@ -326,8 +326,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { // Queue the next phase of the game. if (_currentFundingCycle.number == 1) return _queuePhase2(_gameId, _metadata.dataSource); else if (_currentFundingCycle.number == 2) return _queuePhase3(_gameId, _metadata.dataSource); - else if (_currentFundingCycle.number == 3) return _queuePhase4(_gameId, _metadata.dataSource); - else return _queuePhase5(_gameId, _metadata.dataSource); + else return _queuePhase4(_gameId, _metadata.dataSource); } /** From 453fe0b651515635144362e51772328e982fa582 Mon Sep 17 00:00:00 2001 From: mejango Date: Thu, 29 Dec 2022 18:44:23 -0300 Subject: [PATCH 04/21] fixed interface --- contracts/interfaces/IDefifaDeployer.sol | 2 +- contracts/scripts/Deploy.s.sol | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/interfaces/IDefifaDeployer.sol b/contracts/interfaces/IDefifaDeployer.sol index 4063978..338b553 100644 --- a/contracts/interfaces/IDefifaDeployer.sol +++ b/contracts/interfaces/IDefifaDeployer.sol @@ -24,7 +24,7 @@ interface IDefifaDeployer { function startOf(uint256 _gameId) external view returns (uint256); - function tradeDeadlineOf(uint256 _gameId) external view returns (uint256); + function redemptionPeriodDurationOf(uint256 _gameId) external view returns (uint256); function endOf(uint256 _gameId) external view returns (uint256); diff --git a/contracts/scripts/Deploy.s.sol b/contracts/scripts/Deploy.s.sol index efd5f1d..0090959 100644 --- a/contracts/scripts/Deploy.s.sol +++ b/contracts/scripts/Deploy.s.sol @@ -88,7 +88,6 @@ contract DeployMainnet is Script { }), mintDuration: _mintDuration, start: _start, - tradeDeadline: _tradeDeadline, redemptionPeriodDuration: _redemptionPeriodDuration, end: _end, holdFees: false, From 673e2952c76a125d92c5a48c3711e3294b4afd39 Mon Sep 17 00:00:00 2001 From: mejango Date: Thu, 29 Dec 2022 18:46:57 -0300 Subject: [PATCH 05/21] redemptionPeriod => refundPeriod --- contracts/DefifaDeployer.sol | 10 +++++----- contracts/interfaces/IDefifaDeployer.sol | 2 +- contracts/scripts/Deploy.s.sol | 4 ++-- contracts/structs/DefifaLaunchProjectData.sol | 4 ++-- contracts/structs/DefifaTimeData.sol | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/contracts/DefifaDeployer.sol b/contracts/DefifaDeployer.sol index 93e771e..1346b38 100644 --- a/contracts/DefifaDeployer.sol +++ b/contracts/DefifaDeployer.sol @@ -126,8 +126,8 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { return _timesFor[_gameId].mintDuration; } - function redemptionPeriodDurationOf(uint256 _gameId) external view override returns (uint256) { - return _timesFor[_gameId].redemptionPeriodDuration; + function refundPeriodDurationOf(uint256 _gameId) external view override returns (uint256) { + return _timesFor[_gameId].refundPeriodDuration; } function startOf(uint256 _gameId) external view override returns (uint256) { @@ -227,7 +227,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { ) external override returns (uint256 gameId) { // Make sure the provided gameplay timestamps are sequential. if ( - _launchProjectData.start - _launchProjectData.redemptionPeriodDuration - _launchProjectData.mintDuration < block.timestamp || + _launchProjectData.start - _launchProjectData.refundPeriodDuration - _launchProjectData.mintDuration < block.timestamp || _launchProjectData.end < _launchProjectData.start ) revert INVALID_GAME_CONFIGURATION(); @@ -241,7 +241,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { // Store the timestamps that'll define the game phases. _timesFor[gameId] = DefifaTimeData({ mintDuration: _launchProjectData.mintDuration, - redemptionPeriodDuration: _launchProjectData.redemptionPeriodDuration, + refundPeriodDuration: _launchProjectData.refundPeriodDuration, start: _launchProjectData.start, end: _launchProjectData.end }); @@ -448,7 +448,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { controller.reconfigureFundingCyclesOf( _gameId, JBFundingCycleData ({ - duration: _times.redemptionPeriodDuration, + duration: _times.refundPeriodDuration, // Don't mint project tokens. weight: 0, discountRate: 0, diff --git a/contracts/interfaces/IDefifaDeployer.sol b/contracts/interfaces/IDefifaDeployer.sol index 338b553..7924442 100644 --- a/contracts/interfaces/IDefifaDeployer.sol +++ b/contracts/interfaces/IDefifaDeployer.sol @@ -24,7 +24,7 @@ interface IDefifaDeployer { function startOf(uint256 _gameId) external view returns (uint256); - function redemptionPeriodDurationOf(uint256 _gameId) external view returns (uint256); + function refundPeriodDurationOf(uint256 _gameId) external view returns (uint256); function endOf(uint256 _gameId) external view returns (uint256); diff --git a/contracts/scripts/Deploy.s.sol b/contracts/scripts/Deploy.s.sol index 0090959..7ae1f7a 100644 --- a/contracts/scripts/Deploy.s.sol +++ b/contracts/scripts/Deploy.s.sol @@ -24,7 +24,7 @@ contract DeployMainnet is Script { // Game params. uint48 _start = 1673672400; // 12am EST, Jan 14. uint48 _mintDuration = 432000; // 5 days. - uint48 _redemptionPeriodDuration = 86400; // 1 day. + uint48 _refundPeriodDuration = 86400; // 1 day. uint48 _end = 1676178000; // 12am EST, Feb 12. uint80 _price = 0.1 ether; string memory _name = 'Defifa: NFL Playoffs 2023'; @@ -88,7 +88,7 @@ contract DeployMainnet is Script { }), mintDuration: _mintDuration, start: _start, - redemptionPeriodDuration: _redemptionPeriodDuration, + refundPeriodDuration: _refundPeriodDuration, end: _end, holdFees: false, splits: new JBSplit[](0), diff --git a/contracts/structs/DefifaLaunchProjectData.sol b/contracts/structs/DefifaLaunchProjectData.sol index 4b45356..16574a6 100644 --- a/contracts/structs/DefifaLaunchProjectData.sol +++ b/contracts/structs/DefifaLaunchProjectData.sol @@ -9,7 +9,7 @@ import './DefifaTimeData.sol'; /** @member projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project. @member mintDuration The duration of the game's first phase. - @member redemptionPeriodDuration The time between the mint period and the start time where mint's are no longer open but refunds are still allowed. + @member refundPeriodDuration The time between the mint period and the start time where mint's are no longer open but refunds are still allowed. @member start The timestamp at which the game should start. @member end The timestamp at which the game should end. @member holdFees A flag indicating if fees should be held when distributing funds during the second funding cycle. @@ -20,7 +20,7 @@ import './DefifaTimeData.sol'; struct DefifaLaunchProjectData { JBProjectMetadata projectMetadata; uint48 mintDuration; - uint48 redemptionPeriodDuration; + uint48 refundPeriodDuration; uint48 start; uint48 end; bool holdFees; diff --git a/contracts/structs/DefifaTimeData.sol b/contracts/structs/DefifaTimeData.sol index 77f433a..0c7ccd7 100644 --- a/contracts/structs/DefifaTimeData.sol +++ b/contracts/structs/DefifaTimeData.sol @@ -5,13 +5,13 @@ import '@jbx-protocol/juice-721-delegate/contracts/structs/JB721TierParams.sol'; /** @member mintDuration The amount of time mints will be open for before the game's start. - @member redemptionPeriodDuration The time between the mint period and the start time where mint's are no longer open but refunds are still allowed. + @member refundPeriodDuration The time between the mint period and the start time where mint's are no longer open but refunds are still allowed. @member start The timestamp at which the game should start. @member end The timestamp at which the game should end. */ struct DefifaTimeData { uint48 mintDuration; - uint48 redemptionPeriodDuration; + uint48 refundPeriodDuration; uint48 start; uint48 end; } From 193d895c9d31732211067525433d40e1a7009486 Mon Sep 17 00:00:00 2001 From: viraj124 Date: Fri, 30 Dec 2022 10:40:16 +0700 Subject: [PATCH 06/21] chore: no voting delay & voting duration is max --- contracts/DefifaGovernor.sol | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/contracts/DefifaGovernor.sol b/contracts/DefifaGovernor.sol index ea6b674..5612d6d 100644 --- a/contracts/DefifaGovernor.sol +++ b/contracts/DefifaGovernor.sol @@ -272,10 +272,6 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { @return The delay in number of blocks. */ function votingDelay() public view override(IGovernor) returns (uint256) { - if (votingStartTime > block.timestamp) - return (votingStartTime - block.timestamp) / _BLOCKTIME_SECONDS; - - // no voting delay once voting is active return 0; } @@ -284,7 +280,8 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { The amount of time that must go by for voting on a proposal to no longer be allowed. */ function votingPeriod() public pure override(IGovernor) returns (uint256) { - return 420000000000000069; // longtime + // the max value i.e 2**64 - 1 + return 18446744073709551615; // longtime } /** From 980401167df7098d366c3e68770747e6c6fda371 Mon Sep 17 00:00:00 2001 From: viraj124 Date: Sat, 31 Dec 2022 10:19:37 +0700 Subject: [PATCH 07/21] chore: remove votingStartTime --- contracts/DefifaGovernor.sol | 18 ++---------------- contracts/interfaces/IDefifaGovernor.sol | 2 -- contracts/scripts/Deploy.s.sol | 2 +- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/contracts/DefifaGovernor.sol b/contracts/DefifaGovernor.sol index 5612d6d..b6934f1 100644 --- a/contracts/DefifaGovernor.sol +++ b/contracts/DefifaGovernor.sol @@ -34,12 +34,6 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { // -------------------- private constant properties ------------------ // //*********************************************************************// - /** - @notice - The duration of one block. - */ - uint256 internal constant _BLOCKTIME_SECONDS = 12; - //*********************************************************************// // ------------------------ public constants ------------------------- // //*********************************************************************// @@ -60,25 +54,17 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { */ IDefifaDelegate public immutable override defifaDelegate; - /** - @notice - Voting start timestamp after which voting can begin. - */ - uint256 public immutable override votingStartTime; - //*********************************************************************// // -------------------------- constructor ---------------------------- // //*********************************************************************// /** @param _defifaDelegate The Defifa delegate contract that this contract is Governing. - @param _votingStartTime Voting start time . */ - constructor(IDefifaDelegate _defifaDelegate, uint256 _votingStartTime) + constructor(IDefifaDelegate _defifaDelegate) Governor('DefifaGovernor') { defifaDelegate = _defifaDelegate; - votingStartTime = _votingStartTime; } //*********************************************************************// @@ -271,7 +257,7 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { @return The delay in number of blocks. */ - function votingDelay() public view override(IGovernor) returns (uint256) { + function votingDelay() public pure override(IGovernor) returns (uint256) { return 0; } diff --git a/contracts/interfaces/IDefifaGovernor.sol b/contracts/interfaces/IDefifaGovernor.sol index 52f9c3e..ee717b1 100644 --- a/contracts/interfaces/IDefifaGovernor.sol +++ b/contracts/interfaces/IDefifaGovernor.sol @@ -9,8 +9,6 @@ interface IDefifaGovernor { function defifaDelegate() external view returns (IDefifaDelegate); - function votingStartTime() external view returns (uint256); - function submitScorecards(DefifaTierRedemptionWeight[] calldata _tierWeights) external returns (uint256); diff --git a/contracts/scripts/Deploy.s.sol b/contracts/scripts/Deploy.s.sol index 7ae1f7a..697ca15 100644 --- a/contracts/scripts/Deploy.s.sol +++ b/contracts/scripts/Deploy.s.sol @@ -122,7 +122,7 @@ contract DeployMainnet is Script { // Deploy the governor { - address _governor = address(new DefifaGovernor(DefifaDelegate(_metadata.dataSource), _end)); + address _governor = address(new DefifaGovernor(DefifaDelegate(_metadata.dataSource))); // These 3 should be the same: console.log(_delegateData.owner); From 4d11674d2bfc85659f788e9d5b6bc3e990c331f8 Mon Sep 17 00:00:00 2001 From: mejango Date: Sat, 31 Dec 2022 10:52:56 -0300 Subject: [PATCH 08/21] attest call --- contracts/DefifaGovernor.sol | 11 +++++++++++ contracts/interfaces/IDefifaGovernor.sol | 2 ++ 2 files changed, 13 insertions(+) diff --git a/contracts/DefifaGovernor.sol b/contracts/DefifaGovernor.sol index b6934f1..682679a 100644 --- a/contracts/DefifaGovernor.sol +++ b/contracts/DefifaGovernor.sol @@ -95,6 +95,17 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { return propose(_targets, _values, _calldatas, ''); } + /** + @notice + Attests to a scorecard. + + @param _scorecardId The scorecard ID. + */ + function attestToScorecard(uint256 _scorecardId) external override { + // Vote. + super._castVote(_scorecardId, msg.sender, 1, ''); + } + /** @notice Ratifies a scorecard that has been approved. diff --git a/contracts/interfaces/IDefifaGovernor.sol b/contracts/interfaces/IDefifaGovernor.sol index ee717b1..2dffb1f 100644 --- a/contracts/interfaces/IDefifaGovernor.sol +++ b/contracts/interfaces/IDefifaGovernor.sol @@ -13,6 +13,8 @@ interface IDefifaGovernor { external returns (uint256); + function attestToScorecard(uint256 _scorecardId) external; + function ratifyScorecard(DefifaTierRedemptionWeight[] calldata _tierWeights) external returns (uint256); From 16607fda640c0f91af4f4750a6c663c53251f4c4 Mon Sep 17 00:00:00 2001 From: viraj124 Date: Sun, 1 Jan 2023 12:22:15 +0700 Subject: [PATCH 09/21] chore: updated voting period to 2 weeks --- contracts/DefifaGovernor.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/DefifaGovernor.sol b/contracts/DefifaGovernor.sol index 682679a..9b16ffc 100644 --- a/contracts/DefifaGovernor.sol +++ b/contracts/DefifaGovernor.sol @@ -277,8 +277,8 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { The amount of time that must go by for voting on a proposal to no longer be allowed. */ function votingPeriod() public pure override(IGovernor) returns (uint256) { - // the max value i.e 2**64 - 1 - return 18446744073709551615; // longtime + // blocks worth 2 weeks + return 100381; } /** From 934eb8d170d2bb8c41decced4fe27bedb51dff2a Mon Sep 17 00:00:00 2001 From: xBA5ED <0xBA5ED@protonmail.com> Date: Tue, 3 Jan 2023 23:00:09 +0100 Subject: [PATCH 10/21] Small fix to make tests compile --- contracts/forge-test/DefifaGovernor.t.sol | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/contracts/forge-test/DefifaGovernor.t.sol b/contracts/forge-test/DefifaGovernor.t.sol index 87b0b95..c3fe86f 100644 --- a/contracts/forge-test/DefifaGovernor.t.sol +++ b/contracts/forge-test/DefifaGovernor.t.sol @@ -1085,7 +1085,8 @@ contract DefifaGovernorTest is TestBaseWorkflow { projectMetadata: JBProjectMetadata({content: '', domain: 0}), mintDuration: _mintDuration, start: _launchProjectAt + uint48(_mintDuration), - tradeDeadline: _launchProjectAt + uint48(_mintDuration) + uint48(_inBetweenMintAndFifa), + refundPeriodDuration: 1 days, + //tradeDeadline: _launchProjectAt + uint48(_mintDuration) + uint48(_inBetweenMintAndFifa), end: _end, holdFees: false, splits: new JBSplit[](0), @@ -1412,9 +1413,10 @@ contract DefifaGovernorTest is TestBaseWorkflow { DefifaLaunchProjectData({ projectMetadata: JBProjectMetadata({content: '', domain: 0}), mintDuration: 1 days, - start: uint48(block.timestamp + 1 days), - tradeDeadline: uint48(block.timestamp + 1 days), - end: uint48(block.timestamp + 1 weeks), + start: uint48(block.timestamp + 10 days), + refundPeriodDuration: 1 days, + //tradeDeadline: uint48(block.timestamp + 1 days), + end: uint48(block.timestamp + 10 days + 1 weeks), holdFees: false, splits: new JBSplit[](0), distributionLimit: 0, @@ -1454,7 +1456,7 @@ contract DefifaGovernorTest is TestBaseWorkflow { JBFundingCycle memory _fc = _jbFundingCycleStore.currentOf(projectId); // Deploy the governor - governor = new DefifaGovernor(DefifaDelegate(_fc.dataSource()), defifaLaunchData.tradeDeadline); + governor = new DefifaGovernor(DefifaDelegate(_fc.dataSource())); // making sure the addresses match assertEq(address(governor), _owner); From 4b9e97412c79f758da4dd068dff8aee1a86f6e40 Mon Sep 17 00:00:00 2001 From: mejango Date: Wed, 4 Jan 2023 12:56:28 -0300 Subject: [PATCH 11/21] Better attest --- contracts/DefifaGovernor.sol | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/contracts/DefifaGovernor.sol b/contracts/DefifaGovernor.sol index 9b16ffc..73df8b2 100644 --- a/contracts/DefifaGovernor.sol +++ b/contracts/DefifaGovernor.sol @@ -61,9 +61,7 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { /** @param _defifaDelegate The Defifa delegate contract that this contract is Governing. */ - constructor(IDefifaDelegate _defifaDelegate) - Governor('DefifaGovernor') - { + constructor(IDefifaDelegate _defifaDelegate) Governor('DefifaGovernor') { defifaDelegate = _defifaDelegate; } @@ -103,7 +101,7 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { */ function attestToScorecard(uint256 _scorecardId) external override { // Vote. - super._castVote(_scorecardId, msg.sender, 1, ''); + super._castVote(_scorecardId, msg.sender, 1, '', _defaultParams()); } /** From d311d1ec94a76089f3f16d5e0c35276c04ab832f Mon Sep 17 00:00:00 2001 From: xBA5ED <0xBA5ED@protonmail.com> Date: Wed, 4 Jan 2023 17:06:21 +0100 Subject: [PATCH 12/21] Fix for phase-1 start timestamp calculation --- contracts/DefifaDeployer.sol | 2 +- contracts/forge-test/DefifaGovernor.t.sol | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/DefifaDeployer.sol b/contracts/DefifaDeployer.sol index 1346b38..a21961a 100644 --- a/contracts/DefifaDeployer.sol +++ b/contracts/DefifaDeployer.sol @@ -416,7 +416,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { }) ) }), - _launchProjectData.start - _launchProjectData.mintDuration, + _launchProjectData.start - _launchProjectData.mintDuration - _launchProjectData.refundPeriodDuration, new JBGroupedSplits[](0), new JBFundAccessConstraints[](0), _terminals, diff --git a/contracts/forge-test/DefifaGovernor.t.sol b/contracts/forge-test/DefifaGovernor.t.sol index c3fe86f..75d0539 100644 --- a/contracts/forge-test/DefifaGovernor.t.sol +++ b/contracts/forge-test/DefifaGovernor.t.sol @@ -1413,10 +1413,10 @@ contract DefifaGovernorTest is TestBaseWorkflow { DefifaLaunchProjectData({ projectMetadata: JBProjectMetadata({content: '', domain: 0}), mintDuration: 1 days, - start: uint48(block.timestamp + 10 days), + start: uint48(block.timestamp + 2 days), refundPeriodDuration: 1 days, //tradeDeadline: uint48(block.timestamp + 1 days), - end: uint48(block.timestamp + 10 days + 1 weeks), + end: uint48(block.timestamp + 2 days + 1 weeks), holdFees: false, splits: new JBSplit[](0), distributionLimit: 0, From 9e161e0a2a9542a8b86ce271e163f47e3be4daf3 Mon Sep 17 00:00:00 2001 From: xBA5ED <0xBA5ED@protonmail.com> Date: Wed, 4 Jan 2023 17:23:29 +0100 Subject: [PATCH 13/21] Small change to allow compiling without '--via-ir' --- contracts/forge-test/DefifaGovernor.t.sol | 2 +- contracts/scripts/Deploy.s.sol | 54 +++++++++++------------ 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/contracts/forge-test/DefifaGovernor.t.sol b/contracts/forge-test/DefifaGovernor.t.sol index 75d0539..12b92fe 100644 --- a/contracts/forge-test/DefifaGovernor.t.sol +++ b/contracts/forge-test/DefifaGovernor.t.sol @@ -249,7 +249,7 @@ contract DefifaGovernorTest is TestBaseWorkflow { uint8 nTiers = 10; address[] memory _users = new address[](nTiers); - (uint256 _projectId, DefifaDelegate _nft, ) = createDefifaProject( + (uint256 _projectId,, ) = createDefifaProject( uint256(nTiers), getBasicDefifaLaunchData() ); diff --git a/contracts/scripts/Deploy.s.sol b/contracts/scripts/Deploy.s.sol index 697ca15..dce5da6 100644 --- a/contracts/scripts/Deploy.s.sol +++ b/contracts/scripts/Deploy.s.sol @@ -8,31 +8,32 @@ import '../DefifaGovernor.sol'; import 'forge-std/Script.sol'; contract DeployMainnet is Script { - function run() external { - vm.startBroadcast(); + // V3 mainnet controller. + IJBController controller = IJBController(0xFFdD70C318915879d5192e8a0dcbFcB0285b3C98); + // mainnet 721 store. + IJBTiered721DelegateStore store = + IJBTiered721DelegateStore(0xffB2Cd8519439A7ddcf2C933caedd938053067D2); + // V3 goerli Payment terminal. + IJBPaymentTerminal terminal = IJBPaymentTerminal(0x594Cb208b5BB48db1bcbC9354d1694998864ec63); + + address _defifaBallcats = 0x11834239698c7336EF232C00a2A9926d3375DF9D; + // Game params. + uint48 _start = 1673672400; // 12am EST, Jan 14. + uint48 _mintDuration = 432000; // 5 days. + uint48 _refundPeriodDuration = 86400; // 1 day. + uint48 _end = 1676178000; // 12am EST, Feb 12. + uint80 _price = 0.1 ether; + // We don't have to do this effenciently since this contract never gets deployed, its just used to build the broadcast txs + string _name = 'Defifa: NFL Playoffs 2023'; + string _symbol = 'DEFIFA NFL 2023'; + string _contractUri = 'QmaK1Hib3Umokija4bRwoPdxHgGY3unRreeeLoJss3vw4Y'; + string _projectMetadataUri = 'QmT7VFuF7cPMwMnqh3YruuYcRk2tKMb2xcXSbK2wV82Hdy'; + uint16 _reserved = 9; // 1 reserved NFT mintable to reserved beneficiary for every 9 NFTs minted outwardly. Inclusive, so 1 reserved can be minted as soon as the first token is minted outwardly. - // V3 mainnet controller. - IJBController controller = IJBController(0xFFdD70C318915879d5192e8a0dcbFcB0285b3C98); - // mainnet 721 store. - IJBTiered721DelegateStore store = IJBTiered721DelegateStore( - 0xffB2Cd8519439A7ddcf2C933caedd938053067D2 - ); - // V3 goerli Payment terminal. - IJBPaymentTerminal terminal = IJBPaymentTerminal(0x594Cb208b5BB48db1bcbC9354d1694998864ec63); - - address _defifaBallcats = 0x11834239698c7336EF232C00a2A9926d3375DF9D; - // Game params. - uint48 _start = 1673672400; // 12am EST, Jan 14. - uint48 _mintDuration = 432000; // 5 days. - uint48 _refundPeriodDuration = 86400; // 1 day. - uint48 _end = 1676178000; // 12am EST, Feb 12. - uint80 _price = 0.1 ether; - string memory _name = 'Defifa: NFL Playoffs 2023'; - string memory _symbol = 'DEFIFA NFL 2023'; - string memory _contractUri = 'QmaK1Hib3Umokija4bRwoPdxHgGY3unRreeeLoJss3vw4Y'; - string memory _projectMetadataUri = 'QmT7VFuF7cPMwMnqh3YruuYcRk2tKMb2xcXSbK2wV82Hdy'; - uint16 _reserved = 9; // 1 reserved NFT mintable to reserved beneficiary for every 9 NFTs minted outwardly. Inclusive, so 1 reserved can be minted as soon as the first token is minted outwardly. + function run() external { + vm.startBroadcast(); + JB721TierParams[] memory _tiers = new JB721TierParams[](32); bytes32[] memory _teamEncodedIPFSUris = new bytes32[](32); @@ -82,10 +83,7 @@ contract DeployMainnet is Script { }); DefifaLaunchProjectData memory _launchProjectData = DefifaLaunchProjectData({ - projectMetadata: JBProjectMetadata({ - content: _projectMetadataUri, - domain: 0 - }), + projectMetadata: JBProjectMetadata({content: _projectMetadataUri, domain: 0}), mintDuration: _mintDuration, start: _start, refundPeriodDuration: _refundPeriodDuration, @@ -264,7 +262,7 @@ contract DeployMainnet is Script { // // Deploy the governor // { // address _governor = address(new DefifaGovernor(DefifaDelegate(_metadata.dataSource), _end)); - + // // These 3 should be the same: // console.log(_delegateData.owner); // console.log(_governor); From 1b1cee7bea84af3a444a731372957d7d05e504b4 Mon Sep 17 00:00:00 2001 From: mejango Date: Wed, 4 Jan 2023 15:42:17 -0300 Subject: [PATCH 14/21] votingStartTime --- contracts/DefifaGovernor.sol | 24 +- contracts/abstract/Governor.sol | 617 ++++++++++++++++++++++ contracts/forge-test/DefifaGovernor.t.sol | 2 +- contracts/interfaces/IDefifaGovernor.sol | 2 + contracts/interfaces/IGovernor.sol | 282 ++++++++++ contracts/scripts/Deploy.s.sol | 2 +- package.json | 2 +- 7 files changed, 925 insertions(+), 6 deletions(-) create mode 100644 contracts/abstract/Governor.sol create mode 100644 contracts/interfaces/IGovernor.sol diff --git a/contracts/DefifaGovernor.sol b/contracts/DefifaGovernor.sol index 73df8b2..49e070a 100644 --- a/contracts/DefifaGovernor.sol +++ b/contracts/DefifaGovernor.sol @@ -33,6 +33,11 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { //*********************************************************************// // -------------------- private constant properties ------------------ // //*********************************************************************// + /** + @notice + The duration of one block. + */ + uint256 internal constant _BLOCKTIME_SECONDS = 12; //*********************************************************************// // ------------------------ public constants ------------------------- // @@ -54,15 +59,25 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { */ IDefifaDelegate public immutable override defifaDelegate; + /** + @notice + Voting start timestamp after which voting can begin. + */ + uint256 public immutable override votingStartTime; + //*********************************************************************// // -------------------------- constructor ---------------------------- // //*********************************************************************// /** @param _defifaDelegate The Defifa delegate contract that this contract is Governing. + @param _votingStartTime Voting start time . */ - constructor(IDefifaDelegate _defifaDelegate) Governor('DefifaGovernor') { + constructor(IDefifaDelegate _defifaDelegate, uint256 _votingStartTime) + Governor('DefifaGovernor') + { defifaDelegate = _defifaDelegate; + votingStartTime = _votingStartTime; } //*********************************************************************// @@ -266,8 +281,11 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { @return The delay in number of blocks. */ - function votingDelay() public pure override(IGovernor) returns (uint256) { - return 0; + function votingDelay() public view override(IGovernor) returns (uint256) { + return + votingStartTime > block.timestamp + ? (votingStartTime - block.timestamp) / _BLOCKTIME_SECONDS + : 0; } /** diff --git a/contracts/abstract/Governor.sol b/contracts/abstract/Governor.sol new file mode 100644 index 0000000..1879c63 --- /dev/null +++ b/contracts/abstract/Governor.sol @@ -0,0 +1,617 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.2) (governance/Governor.sol) + +pragma solidity ^0.8.0; + +import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol'; +import '@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol'; +import '@openzeppelin/contracts/utils/cryptography/ECDSA.sol'; +import '@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol'; +import '@openzeppelin/contracts/utils/introspection/ERC165.sol'; +import '@openzeppelin/contracts/utils/math/SafeCast.sol'; +import '@openzeppelin/contracts/utils/structs/DoubleEndedQueue.sol'; +import '@openzeppelin/contracts/utils/Address.sol'; +import '@openzeppelin/contracts/utils/Context.sol'; +import '@openzeppelin/contracts/utils/Timers.sol'; +import '@openzeppelin/contracts/governance/IGovernor.sol'; + +/** + * @dev Core of the governance system, designed to be extended though various modules. + * + * This contract is abstract and requires several function to be implemented in various modules: + * + * - A counting module must implement {quorum}, {_quorumReached}, {_voteSucceeded} and {_countVote} + * - A voting module must implement {_getVotes} + * - Additionanly, the {votingPeriod} must also be implemented + * + * _Available since v4.3._ + */ +abstract contract Governor is + Context, + ERC165, + EIP712, + IGovernor, + IERC721Receiver, + IERC1155Receiver +{ + using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; + using SafeCast for uint256; + using Timers for Timers.BlockNumber; + + bytes32 public constant BALLOT_TYPEHASH = keccak256('Ballot(uint256 proposalId,uint8 support)'); + bytes32 public constant EXTENDED_BALLOT_TYPEHASH = + keccak256('ExtendedBallot(uint256 proposalId,uint8 support,string reason,bytes params)'); + + struct ProposalCore { + Timers.BlockNumber voteStart; + Timers.BlockNumber voteEnd; + bool executed; + bool canceled; + } + + string private _name; + + mapping(uint256 => ProposalCore) private _proposals; + + // This queue keeps track of the governor operating on itself. Calls to functions protected by the + // {onlyGovernance} modifier needs to be whitelisted in this queue. Whitelisting is set in {_beforeExecute}, + // consumed by the {onlyGovernance} modifier and eventually reset in {_afterExecute}. This ensures that the + // execution of {onlyGovernance} protected calls can only be achieved through successful proposals. + DoubleEndedQueue.Bytes32Deque private _governanceCall; + + /** + * @dev Restricts a function so it can only be executed through governance proposals. For example, governance + * parameter setters in {GovernorSettings} are protected using this modifier. + * + * The governance executing address may be different from the Governor's own address, for example it could be a + * timelock. This can be customized by modules by overriding {_executor}. The executor is only able to invoke these + * functions during the execution of the governor's {execute} function, and not under any other circumstances. Thus, + * for example, additional timelock proposers are not able to change governance parameters without going through the + * governance protocol (since v4.6). + */ + modifier onlyGovernance() { + require(_msgSender() == _executor(), 'Governor: onlyGovernance'); + if (_executor() != address(this)) { + bytes32 msgDataHash = keccak256(_msgData()); + // loop until popping the expected operation - throw if deque is empty (operation not authorized) + while (_governanceCall.popFront() != msgDataHash) {} + } + _; + } + + /** + * @dev Sets the value for {name} and {version} + */ + constructor(string memory name_) EIP712(name_, version()) { + _name = name_; + } + + /** + * @dev Function to receive ETH that will be handled by the governor (disabled if executor is a third party contract) + */ + receive() external payable virtual { + require(_executor() == address(this)); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(IERC165, ERC165) + returns (bool) + { + // In addition to the current interfaceId, also support previous version of the interfaceId that did not + // include the castVoteWithReasonAndParams() function as standard + return + interfaceId == + (type(IGovernor).interfaceId ^ + this.castVoteWithReasonAndParams.selector ^ + this.castVoteWithReasonAndParamsBySig.selector ^ + this.getVotesWithParams.selector) || + interfaceId == type(IGovernor).interfaceId || + interfaceId == type(IERC1155Receiver).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IGovernor-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IGovernor-version}. + */ + function version() public view virtual override returns (string memory) { + return '1'; + } + + /** + * @dev See {IGovernor-hashProposal}. + * + * The proposal id is produced by hashing the ABI encoded `targets` array, the `values` array, the `calldatas` array + * and the descriptionHash (bytes32 which itself is the keccak256 hash of the description string). This proposal id + * can be produced from the proposal data which is part of the {ProposalCreated} event. It can even be computed in + * advance, before the proposal is submitted. + * + * Note that the chainId and the governor address are not part of the proposal id computation. Consequently, the + * same proposal (with same operation and same description) will have the same id if submitted on multiple governors + * across multiple networks. This also means that in order to execute the same operation twice (on the same + * governor) the proposer will have to change the description in order to avoid proposal id conflicts. + */ + function hashProposal( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public pure virtual override returns (uint256) { + return uint256(keccak256(abi.encode(targets, values, calldatas, descriptionHash))); + } + + /** + * @dev See {IGovernor-state}. + */ + function state(uint256 proposalId) public view virtual override returns (ProposalState) { + ProposalCore storage proposal = _proposals[proposalId]; + + if (proposal.executed) { + return ProposalState.Executed; + } + + if (proposal.canceled) { + return ProposalState.Canceled; + } + + uint256 snapshot = proposalSnapshot(proposalId); + + if (snapshot == 0) { + revert('Governor: unknown proposal id'); + } + + if (snapshot >= block.number) { + return ProposalState.Pending; + } + + uint256 deadline = proposalDeadline(proposalId); + + if (deadline >= block.number) { + return ProposalState.Active; + } + + if (_quorumReached(proposalId) && _voteSucceeded(proposalId)) { + return ProposalState.Succeeded; + } else { + return ProposalState.Defeated; + } + } + + /** + * @dev See {IGovernor-proposalSnapshot}. + */ + function proposalSnapshot(uint256 proposalId) public view virtual override returns (uint256) { + return _proposals[proposalId].voteStart.getDeadline(); + } + + /** + * @dev See {IGovernor-proposalDeadline}. + */ + function proposalDeadline(uint256 proposalId) public view virtual override returns (uint256) { + return _proposals[proposalId].voteEnd.getDeadline(); + } + + /** + * @dev Part of the Governor Bravo's interface: _"The number of votes required in order for a voter to become a proposer"_. + */ + function proposalThreshold() public view virtual returns (uint256) { + return 0; + } + + /** + * @dev Amount of votes already cast passes the threshold limit. + */ + function _quorumReached(uint256 proposalId) internal view virtual returns (bool); + + /** + * @dev Is the proposal successful or not. + */ + function _voteSucceeded(uint256 proposalId) internal view virtual returns (bool); + + /** + * @dev Get the voting weight of `account` at a specific `blockNumber`, for a vote as described by `params`. + */ + function _getVotes( + address account, + uint256 blockNumber, + bytes memory params + ) internal view virtual returns (uint256); + + /** + * @dev Register a vote for `proposalId` by `account` with a given `support`, voting `weight` and voting `params`. + * + * Note: Support is generic and can represent various things depending on the voting system used. + */ + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory params + ) internal virtual; + + /** + * @dev Default additional encoded parameters used by castVote methods that don't include them + * + * Note: Should be overridden by specific implementations to use an appropriate value, the + * meaning of the additional params, in the context of that implementation + */ + function _defaultParams() internal view virtual returns (bytes memory) { + return ''; + } + + /** + * @dev See {IGovernor-propose}. + */ + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public virtual override returns (uint256) { + require( + getVotes(_msgSender(), block.number - 1) >= proposalThreshold(), + 'Governor: proposer votes below proposal threshold' + ); + + uint256 proposalId = hashProposal(targets, values, calldatas, keccak256(bytes(description))); + + require(targets.length == values.length, 'Governor: invalid proposal length'); + require(targets.length == calldatas.length, 'Governor: invalid proposal length'); + require(targets.length > 0, 'Governor: empty proposal'); + + ProposalCore storage proposal = _proposals[proposalId]; + require(proposal.voteStart.isUnset(), 'Governor: proposal already exists'); + + uint64 snapshot = block.number.toUint64() + votingDelay().toUint64(); + uint64 deadline = snapshot + votingPeriod().toUint64(); + + proposal.voteStart.setDeadline(snapshot); + proposal.voteEnd.setDeadline(deadline); + + emit ProposalCreated( + proposalId, + _msgSender(), + targets, + values, + new string[](targets.length), + calldatas, + snapshot, + deadline, + description + ); + + return proposalId; + } + + /** + * @dev See {IGovernor-execute}. + */ + function execute( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public payable virtual override returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + + ProposalState status = state(proposalId); + require( + status == ProposalState.Succeeded || status == ProposalState.Queued, + 'Governor: proposal not successful' + ); + _proposals[proposalId].executed = true; + + emit ProposalExecuted(proposalId); + + _beforeExecute(proposalId, targets, values, calldatas, descriptionHash); + _execute(proposalId, targets, values, calldatas, descriptionHash); + _afterExecute(proposalId, targets, values, calldatas, descriptionHash); + + return proposalId; + } + + /** + * @dev Internal execution mechanism. Can be overridden to implement different execution mechanism + */ + function _execute( + uint256, /* proposalId */ + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual { + string memory errorMessage = 'Governor: call reverted without message'; + for (uint256 i = 0; i < targets.length; ++i) { + (bool success, bytes memory returndata) = targets[i].call{value: values[i]}(calldatas[i]); + Address.verifyCallResult(success, returndata, errorMessage); + } + } + + /** + * @dev Hook before execution is triggered. + */ + function _beforeExecute( + uint256, /* proposalId */ + address[] memory targets, + uint256[] memory, /* values */ + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual { + if (_executor() != address(this)) { + for (uint256 i = 0; i < targets.length; ++i) { + if (targets[i] == address(this)) { + _governanceCall.pushBack(keccak256(calldatas[i])); + } + } + } + } + + /** + * @dev Hook after execution is triggered. + */ + function _afterExecute( + uint256, /* proposalId */ + address[] memory, /* targets */ + uint256[] memory, /* values */ + bytes[] memory, /* calldatas */ + bytes32 /*descriptionHash*/ + ) internal virtual { + if (_executor() != address(this)) { + if (!_governanceCall.empty()) { + _governanceCall.clear(); + } + } + } + + /** + * @dev Internal cancel mechanism: locks up the proposal timer, preventing it from being re-submitted. Marks it as + * canceled to allow distinguishing it from executed proposals. + * + * Emits a {IGovernor-ProposalCanceled} event. + */ + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + ProposalState status = state(proposalId); + + require( + status != ProposalState.Canceled && + status != ProposalState.Expired && + status != ProposalState.Executed, + 'Governor: proposal not active' + ); + _proposals[proposalId].canceled = true; + + emit ProposalCanceled(proposalId); + + return proposalId; + } + + /** + * @dev See {IGovernor-getVotes}. + */ + function getVotes(address account, uint256 blockNumber) + public + view + virtual + override + returns (uint256) + { + return _getVotes(account, blockNumber, _defaultParams()); + } + + /** + * @dev See {IGovernor-getVotesWithParams}. + */ + function getVotesWithParams( + address account, + uint256 blockNumber, + bytes memory params + ) public view virtual override returns (uint256) { + return _getVotes(account, blockNumber, params); + } + + /** + * @dev See {IGovernor-castVote}. + */ + function castVote(uint256 proposalId, uint8 support) public virtual override returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, ''); + } + + /** + * @dev See {IGovernor-castVoteWithReason}. + */ + function castVoteWithReason( + uint256 proposalId, + uint8 support, + string calldata reason + ) public virtual override returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, reason); + } + + /** + * @dev See {IGovernor-castVoteWithReasonAndParams}. + */ + function castVoteWithReasonAndParams( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params + ) public virtual override returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, reason, params); + } + + /** + * @dev See {IGovernor-castVoteBySig}. + */ + function castVoteBySig( + uint256 proposalId, + uint8 support, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual override returns (uint256) { + address voter = ECDSA.recover( + _hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support))), + v, + r, + s + ); + return _castVote(proposalId, voter, support, ''); + } + + /** + * @dev See {IGovernor-castVoteWithReasonAndParamsBySig}. + */ + function castVoteWithReasonAndParamsBySig( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual override returns (uint256) { + address voter = ECDSA.recover( + _hashTypedDataV4( + keccak256( + abi.encode( + EXTENDED_BALLOT_TYPEHASH, + proposalId, + support, + keccak256(bytes(reason)), + keccak256(params) + ) + ) + ), + v, + r, + s + ); + + return _castVote(proposalId, voter, support, reason, params); + } + + /** + * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve + * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. Uses the _defaultParams(). + * + * Emits a {IGovernor-VoteCast} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason + ) internal virtual returns (uint256) { + return _castVote(proposalId, account, support, reason, _defaultParams()); + } + + /** + * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve + * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. + * + * Emits a {IGovernor-VoteCast} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason, + bytes memory params + ) internal virtual returns (uint256) { + ProposalCore storage proposal = _proposals[proposalId]; + require(state(proposalId) == ProposalState.Active, 'Governor: vote not currently active'); + + uint256 weight = _getVotes(account, proposal.voteStart.getDeadline(), params); + _countVote(proposalId, account, support, weight, params); + + if (params.length == 0) { + emit VoteCast(account, proposalId, support, weight, reason); + } else { + emit VoteCastWithParams(account, proposalId, support, weight, reason, params); + } + + return weight; + } + + /** + * @dev Relays a transaction or function call to an arbitrary target. In cases where the governance executor + * is some contract other than the governor itself, like when using a timelock, this function can be invoked + * in a governance proposal to recover tokens or Ether that was sent to the governor contract by mistake. + * Note that if the executor is simply the governor itself, use of `relay` is redundant. + */ + function relay( + address target, + uint256 value, + bytes calldata data + ) external virtual onlyGovernance { + Address.functionCallWithValue(target, data, value); + } + + /** + * @dev Address through which the governor executes action. Will be overloaded by module that execute actions + * through another contract such as a timelock. + */ + function _executor() internal view virtual returns (address) { + return address(this); + } + + /** + * @dev See {IERC721Receiver-onERC721Received}. + */ + function onERC721Received( + address, + address, + uint256, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC721Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155Received}. + */ + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155BatchReceived}. + */ + function onERC1155BatchReceived( + address, + address, + uint256[] memory, + uint256[] memory, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155BatchReceived.selector; + } +} diff --git a/contracts/forge-test/DefifaGovernor.t.sol b/contracts/forge-test/DefifaGovernor.t.sol index 12b92fe..45754f9 100644 --- a/contracts/forge-test/DefifaGovernor.t.sol +++ b/contracts/forge-test/DefifaGovernor.t.sol @@ -1456,7 +1456,7 @@ contract DefifaGovernorTest is TestBaseWorkflow { JBFundingCycle memory _fc = _jbFundingCycleStore.currentOf(projectId); // Deploy the governor - governor = new DefifaGovernor(DefifaDelegate(_fc.dataSource())); + governor = new DefifaGovernor(DefifaDelegate(_fc.dataSource()), uint48(block.timestamp + 10 days + 1 weeks)); // making sure the addresses match assertEq(address(governor), _owner); diff --git a/contracts/interfaces/IDefifaGovernor.sol b/contracts/interfaces/IDefifaGovernor.sol index 2dffb1f..a1efe74 100644 --- a/contracts/interfaces/IDefifaGovernor.sol +++ b/contracts/interfaces/IDefifaGovernor.sol @@ -9,6 +9,8 @@ interface IDefifaGovernor { function defifaDelegate() external view returns (IDefifaDelegate); + function votingStartTime() external view returns (uint256); + function submitScorecards(DefifaTierRedemptionWeight[] calldata _tierWeights) external returns (uint256); diff --git a/contracts/interfaces/IGovernor.sol b/contracts/interfaces/IGovernor.sol new file mode 100644 index 0000000..e1265a0 --- /dev/null +++ b/contracts/interfaces/IGovernor.sol @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.2) (governance/IGovernor.sol) + +pragma solidity ^0.8.0; + +import '@openzeppelin/contracts/utils/introspection/ERC165.sol'; + +/** + * @dev Interface of the {Governor} core. + * + * _Available since v4.3._ + */ +abstract contract IGovernor is IERC165 { + enum ProposalState { + Pending, + Active, + Canceled, + Defeated, + Succeeded, + Queued, + Expired, + Executed + } + + /** + * @dev Emitted when a proposal is created. + */ + event ProposalCreated( + uint256 proposalId, + address proposer, + address[] targets, + uint256[] values, + string[] signatures, + bytes[] calldatas, + uint256 startBlock, + uint256 endBlock, + string description + ); + + /** + * @dev Emitted when a proposal is canceled. + */ + event ProposalCanceled(uint256 proposalId); + + /** + * @dev Emitted when a proposal is executed. + */ + event ProposalExecuted(uint256 proposalId); + + /** + * @dev Emitted when a vote is cast without params. + * + * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used. + */ + event VoteCast( + address indexed voter, + uint256 proposalId, + uint8 support, + uint256 weight, + string reason + ); + + /** + * @dev Emitted when a vote is cast with params. + * + * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used. + * `params` are additional encoded parameters. Their intepepretation also depends on the voting module used. + */ + event VoteCastWithParams( + address indexed voter, + uint256 proposalId, + uint8 support, + uint256 weight, + string reason, + bytes params + ); + + /** + * @notice module:core + * @dev Name of the governor instance (used in building the ERC712 domain separator). + */ + function name() public view virtual returns (string memory); + + /** + * @notice module:core + * @dev Version of the governor instance (used in building the ERC712 domain separator). Default: "1" + */ + function version() public view virtual returns (string memory); + + /** + * @notice module:voting + * @dev A description of the possible `support` values for {castVote} and the way these votes are counted, meant to + * be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of + * key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`. + * + * There are 2 standard keys: `support` and `quorum`. + * + * - `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`. + * - `quorum=bravo` means that only For votes are counted towards quorum. + * - `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum. + * + * If a counting module makes use of encoded `params`, it should include this under a `params` key with a unique + * name that describes the behavior. For example: + * + * - `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain. + * - `params=erc721` might refer to a scheme where specific NFTs are delegated to vote. + * + * NOTE: The string can be decoded by the standard + * https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams[`URLSearchParams`] + * JavaScript class. + */ + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public pure virtual returns (string memory); + + /** + * @notice module:core + * @dev Hashing function used to (re)build the proposal id from the proposal details.. + */ + function hashProposal( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public pure virtual returns (uint256); + + /** + * @notice module:core + * @dev Current state of a proposal, following Compound's convention + */ + function state(uint256 proposalId) public view virtual returns (ProposalState); + + /** + * @notice module:core + * @dev Block number used to retrieve user's votes and quorum. As per Compound's Comp and OpenZeppelin's + * ERC20Votes, the snapshot is performed at the end of this block. Hence, voting for this proposal starts at the + * beginning of the following block. + */ + function proposalSnapshot(uint256 proposalId) public view virtual returns (uint256); + + /** + * @notice module:core + * @dev Block number at which votes close. Votes close at the end of this block, so it is possible to cast a vote + * during this block. + */ + function proposalDeadline(uint256 proposalId) public view virtual returns (uint256); + + /** + * @notice module:user-config + * @dev Delay, in number of block, between the proposal is created and the vote starts. This can be increassed to + * leave time for users to buy voting power, or delegate it, before the voting of a proposal starts. + */ + function votingDelay() public view virtual returns (uint256); + + /** + * @notice module:user-config + * @dev Delay, in number of blocks, between the vote start and vote ends. + * + * NOTE: The {votingDelay} can delay the start of the vote. This must be considered when setting the voting + * duration compared to the voting delay. + */ + function votingPeriod() public view virtual returns (uint256); + + /** + * @notice module:user-config + * @dev Minimum number of cast voted required for a proposal to be successful. + * + * Note: The `blockNumber` parameter corresponds to the snapshot used for counting vote. This allows to scale the + * quorum depending on values such as the totalSupply of a token at this block (see {ERC20Votes}). + */ + function quorum(uint256 blockNumber) public view virtual returns (uint256); + + /** + * @notice module:reputation + * @dev Voting power of an `account` at a specific `blockNumber`. + * + * Note: this can be implemented in a number of ways, for example by reading the delegated balance from one (or + * multiple), {ERC20Votes} tokens. + */ + function getVotes(address account, uint256 blockNumber) public view virtual returns (uint256); + + /** + * @notice module:reputation + * @dev Voting power of an `account` at a specific `blockNumber` given additional encoded parameters. + */ + function getVotesWithParams( + address account, + uint256 blockNumber, + bytes memory params + ) public view virtual returns (uint256); + + /** + * @notice module:voting + * @dev Returns weither `account` has cast a vote on `proposalId`. + */ + function hasVoted(uint256 proposalId, address account) public view virtual returns (bool); + + /** + * @dev Create a new proposal. Vote start {IGovernor-votingDelay} blocks after the proposal is created and ends + * {IGovernor-votingPeriod} blocks after the voting starts. + * + * Emits a {ProposalCreated} event. + */ + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public virtual returns (uint256 proposalId); + + /** + * @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the + * deadline to be reached. + * + * Emits a {ProposalExecuted} event. + * + * Note: some module can modify the requirements for execution, for example by adding an additional timelock. + */ + function execute( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public payable virtual returns (uint256 proposalId); + + /** + * @dev Cast a vote + * + * Emits a {VoteCast} event. + */ + function castVote(uint256 proposalId, uint8 support) public virtual returns (uint256 balance); + + /** + * @dev Cast a vote with a reason + * + * Emits a {VoteCast} event. + */ + function castVoteWithReason( + uint256 proposalId, + uint8 support, + string calldata reason + ) public virtual returns (uint256 balance); + + /** + * @dev Cast a vote with a reason and additional encoded parameters + * + * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. + */ + function castVoteWithReasonAndParams( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params + ) public virtual returns (uint256 balance); + + /** + * @dev Cast a vote using the user's cryptographic signature. + * + * Emits a {VoteCast} event. + */ + function castVoteBySig( + uint256 proposalId, + uint8 support, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual returns (uint256 balance); + + /** + * @dev Cast a vote with a reason and additional encoded parameters using the user's cryptographic signature. + * + * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. + */ + function castVoteWithReasonAndParamsBySig( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual returns (uint256 balance); +} diff --git a/contracts/scripts/Deploy.s.sol b/contracts/scripts/Deploy.s.sol index dce5da6..0b98fbc 100644 --- a/contracts/scripts/Deploy.s.sol +++ b/contracts/scripts/Deploy.s.sol @@ -120,7 +120,7 @@ contract DeployMainnet is Script { // Deploy the governor { - address _governor = address(new DefifaGovernor(DefifaDelegate(_metadata.dataSource))); + address _governor = address(new DefifaGovernor(DefifaDelegate(_metadata.dataSource), _end)); // These 3 should be the same: console.log(_delegateData.owner); diff --git a/package.json b/package.json index 702462e..b982daf 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "version": "6.0.0", "license": "MIT", "dependencies": { - "@jbx-protocol/juice-721-delegate": "^3.0.2", + "@jbx-protocol/juice-721-delegate": "^3.0.3", "@openzeppelin/contracts": "^4.7.3", "@prb/math": "^2.5.0" }, From e118210ad1edeac5da52ad4f7f3fa9eb4bb61924 Mon Sep 17 00:00:00 2001 From: mejango Date: Wed, 4 Jan 2023 15:47:52 -0300 Subject: [PATCH 15/21] NFT on 1.1 --- contracts/DefifaDelegate.sol | 120 +++++++++++++++++------------------ yarn.lock | 8 +-- 2 files changed, 64 insertions(+), 64 deletions(-) diff --git a/contracts/DefifaDelegate.sol b/contracts/DefifaDelegate.sol index b084726..62e45df 100644 --- a/contracts/DefifaDelegate.sol +++ b/contracts/DefifaDelegate.sol @@ -158,14 +158,72 @@ contract DefifaDelegate is IDefifaDelegate, JB721TieredGovernance { return ( PRBMath.mulDiv( _data.overflow + _amountRedeemed, - _redemptionWeightOf(_decodedTokenIds, _data), - _totalRedemptionWeight(_data) + redemptionWeightOf(_decodedTokenIds, _data), + totalRedemptionWeight(_data) ), _data.memo, delegateAllocations ); } + /** + @notice + The cumulative weight the given token IDs have in redemptions compared to the `_totalRedemptionWeight`. + + @param _tokenIds The IDs of the tokens to get the cumulative redemption weight of. + + @return cumulativeWeight The weight. + */ + function redemptionWeightOf(uint256[] memory _tokenIds, JBRedeemParamsData calldata) + public + view + virtual + override + returns (uint256 cumulativeWeight) + { + // If the game is over, set the weight based on the scorecard results. + // Keep a reference to the number of tokens being redeemed. + uint256 _tokenCount = _tokenIds.length; + + for (uint256 _i; _i < _tokenCount; ) { + // Keep a reference to the token's tier ID. + uint256 _tierId = store.tierIdOfToken(_tokenIds[_i]); + + // Keep a reference to the tier. + JB721Tier memory _tier = store.tier(address(this), _tierId); + + // Calculate what percentage of the tier redemption amount a single token counts for. + cumulativeWeight += + // Tier's are 1 indexed and are stored 0 indexed. + _tierRedemptionWeights[_tierId - 1] / + (_tier.initialQuantity - _tier.remainingQuantity + _redeemedFromTier[_tierId]); + + unchecked { + ++_i; + } + } + + // If there's nothing to claim, revert to prevent burning for nothing. + if (cumulativeWeight == 0) revert NOTHING_TO_CLAIM(); + } + + /** + @notice + The cumulative weight that all token IDs have in redemptions. + + @return The total weight. + */ + function totalRedemptionWeight(JBRedeemParamsData calldata) + public + view + virtual + override + returns (uint256) + { + // Set the total weight as the total scorecard weight. + return TOTAL_REDEMPTION_WEIGHT; + } + //*********************************************************************// // ---------------------- external transactions ---------------------- // //*********************************************************************// @@ -316,62 +374,4 @@ contract DefifaDelegate is IDefifaDelegate, JB721TieredGovernance { _transferTierVotingUnits(_from, _to, _tier.id, _tier.votingUnits); } } - - /** - @notice - The cumulative weight the given token IDs have in redemptions compared to the `_totalRedemptionWeight`. - - @param _tokenIds The IDs of the tokens to get the cumulative redemption weight of. - - @return cumulativeWeight The weight. - */ - function _redemptionWeightOf(uint256[] memory _tokenIds, JBRedeemParamsData calldata) - internal - view - virtual - override - returns (uint256 cumulativeWeight) - { - // If the game is over, set the weight based on the scorecard results. - // Keep a reference to the number of tokens being redeemed. - uint256 _tokenCount = _tokenIds.length; - - for (uint256 _i; _i < _tokenCount; ) { - // Keep a reference to the token's tier ID. - uint256 _tierId = store.tierIdOfToken(_tokenIds[_i]); - - // Keep a reference to the tier. - JB721Tier memory _tier = store.tier(address(this), _tierId); - - // Calculate what percentage of the tier redemption amount a single token counts for. - cumulativeWeight += - // Tier's are 1 indexed and are stored 0 indexed. - _tierRedemptionWeights[_tierId - 1] / - (_tier.initialQuantity - _tier.remainingQuantity + _redeemedFromTier[_tierId]); - - unchecked { - ++_i; - } - } - - // If there's nothing to claim, revert to prevent burning for nothing. - if (cumulativeWeight == 0) revert NOTHING_TO_CLAIM(); - } - - /** - @notice - The cumulative weight that all token IDs have in redemptions. - - @return The total weight. - */ - function _totalRedemptionWeight(JBRedeemParamsData calldata) - internal - view - virtual - override - returns (uint256) - { - // Set the total weight as the total scorecard weight. - return TOTAL_REDEMPTION_WEIGHT; - } } diff --git a/yarn.lock b/yarn.lock index cca439e..5ed6d47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -51,10 +51,10 @@ resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== -"@jbx-protocol/juice-721-delegate@^3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@jbx-protocol/juice-721-delegate/-/juice-721-delegate-3.0.2.tgz#da6de37cbb024cc3799f7221ec206e1a11e115e7" - integrity sha512-d0FoHLCQt5fHKuu7tUs1DelAQgYFAyA6FWPOie6kpQqoVNilAtU5njGv+/eATJSVhnIPriXI5cSmssekob1j4g== +"@jbx-protocol/juice-721-delegate@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@jbx-protocol/juice-721-delegate/-/juice-721-delegate-3.0.3.tgz#ede21a641267dd7c6c3338206221eac168edad56" + integrity sha512-0W/tJcjEmETCLJ6gSDl0ROJ1wp3fJjVtGoA7KfbLNUpKEC+m4I6BwlrYsuIBhWSqvBaYleTqL87lnd4jYEIbaA== dependencies: "@jbx-protocol/juice-contracts-v3" "^2.0.0" "@openzeppelin/contracts" "^4.6.0" From 3fda244239f586a8706ac655faaf7811a9b23d72 Mon Sep 17 00:00:00 2001 From: mejango Date: Wed, 4 Jan 2023 15:52:24 -0300 Subject: [PATCH 16/21] removed Governor abstract for now --- contracts/abstract/Governor.sol | 617 ----------------------------- contracts/interfaces/IGovernor.sol | 86 ---- 2 files changed, 703 deletions(-) delete mode 100644 contracts/abstract/Governor.sol diff --git a/contracts/abstract/Governor.sol b/contracts/abstract/Governor.sol deleted file mode 100644 index 1879c63..0000000 --- a/contracts/abstract/Governor.sol +++ /dev/null @@ -1,617 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.7.2) (governance/Governor.sol) - -pragma solidity ^0.8.0; - -import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol'; -import '@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol'; -import '@openzeppelin/contracts/utils/cryptography/ECDSA.sol'; -import '@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol'; -import '@openzeppelin/contracts/utils/introspection/ERC165.sol'; -import '@openzeppelin/contracts/utils/math/SafeCast.sol'; -import '@openzeppelin/contracts/utils/structs/DoubleEndedQueue.sol'; -import '@openzeppelin/contracts/utils/Address.sol'; -import '@openzeppelin/contracts/utils/Context.sol'; -import '@openzeppelin/contracts/utils/Timers.sol'; -import '@openzeppelin/contracts/governance/IGovernor.sol'; - -/** - * @dev Core of the governance system, designed to be extended though various modules. - * - * This contract is abstract and requires several function to be implemented in various modules: - * - * - A counting module must implement {quorum}, {_quorumReached}, {_voteSucceeded} and {_countVote} - * - A voting module must implement {_getVotes} - * - Additionanly, the {votingPeriod} must also be implemented - * - * _Available since v4.3._ - */ -abstract contract Governor is - Context, - ERC165, - EIP712, - IGovernor, - IERC721Receiver, - IERC1155Receiver -{ - using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; - using SafeCast for uint256; - using Timers for Timers.BlockNumber; - - bytes32 public constant BALLOT_TYPEHASH = keccak256('Ballot(uint256 proposalId,uint8 support)'); - bytes32 public constant EXTENDED_BALLOT_TYPEHASH = - keccak256('ExtendedBallot(uint256 proposalId,uint8 support,string reason,bytes params)'); - - struct ProposalCore { - Timers.BlockNumber voteStart; - Timers.BlockNumber voteEnd; - bool executed; - bool canceled; - } - - string private _name; - - mapping(uint256 => ProposalCore) private _proposals; - - // This queue keeps track of the governor operating on itself. Calls to functions protected by the - // {onlyGovernance} modifier needs to be whitelisted in this queue. Whitelisting is set in {_beforeExecute}, - // consumed by the {onlyGovernance} modifier and eventually reset in {_afterExecute}. This ensures that the - // execution of {onlyGovernance} protected calls can only be achieved through successful proposals. - DoubleEndedQueue.Bytes32Deque private _governanceCall; - - /** - * @dev Restricts a function so it can only be executed through governance proposals. For example, governance - * parameter setters in {GovernorSettings} are protected using this modifier. - * - * The governance executing address may be different from the Governor's own address, for example it could be a - * timelock. This can be customized by modules by overriding {_executor}. The executor is only able to invoke these - * functions during the execution of the governor's {execute} function, and not under any other circumstances. Thus, - * for example, additional timelock proposers are not able to change governance parameters without going through the - * governance protocol (since v4.6). - */ - modifier onlyGovernance() { - require(_msgSender() == _executor(), 'Governor: onlyGovernance'); - if (_executor() != address(this)) { - bytes32 msgDataHash = keccak256(_msgData()); - // loop until popping the expected operation - throw if deque is empty (operation not authorized) - while (_governanceCall.popFront() != msgDataHash) {} - } - _; - } - - /** - * @dev Sets the value for {name} and {version} - */ - constructor(string memory name_) EIP712(name_, version()) { - _name = name_; - } - - /** - * @dev Function to receive ETH that will be handled by the governor (disabled if executor is a third party contract) - */ - receive() external payable virtual { - require(_executor() == address(this)); - } - - /** - * @dev See {IERC165-supportsInterface}. - */ - function supportsInterface(bytes4 interfaceId) - public - view - virtual - override(IERC165, ERC165) - returns (bool) - { - // In addition to the current interfaceId, also support previous version of the interfaceId that did not - // include the castVoteWithReasonAndParams() function as standard - return - interfaceId == - (type(IGovernor).interfaceId ^ - this.castVoteWithReasonAndParams.selector ^ - this.castVoteWithReasonAndParamsBySig.selector ^ - this.getVotesWithParams.selector) || - interfaceId == type(IGovernor).interfaceId || - interfaceId == type(IERC1155Receiver).interfaceId || - super.supportsInterface(interfaceId); - } - - /** - * @dev See {IGovernor-name}. - */ - function name() public view virtual override returns (string memory) { - return _name; - } - - /** - * @dev See {IGovernor-version}. - */ - function version() public view virtual override returns (string memory) { - return '1'; - } - - /** - * @dev See {IGovernor-hashProposal}. - * - * The proposal id is produced by hashing the ABI encoded `targets` array, the `values` array, the `calldatas` array - * and the descriptionHash (bytes32 which itself is the keccak256 hash of the description string). This proposal id - * can be produced from the proposal data which is part of the {ProposalCreated} event. It can even be computed in - * advance, before the proposal is submitted. - * - * Note that the chainId and the governor address are not part of the proposal id computation. Consequently, the - * same proposal (with same operation and same description) will have the same id if submitted on multiple governors - * across multiple networks. This also means that in order to execute the same operation twice (on the same - * governor) the proposer will have to change the description in order to avoid proposal id conflicts. - */ - function hashProposal( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) public pure virtual override returns (uint256) { - return uint256(keccak256(abi.encode(targets, values, calldatas, descriptionHash))); - } - - /** - * @dev See {IGovernor-state}. - */ - function state(uint256 proposalId) public view virtual override returns (ProposalState) { - ProposalCore storage proposal = _proposals[proposalId]; - - if (proposal.executed) { - return ProposalState.Executed; - } - - if (proposal.canceled) { - return ProposalState.Canceled; - } - - uint256 snapshot = proposalSnapshot(proposalId); - - if (snapshot == 0) { - revert('Governor: unknown proposal id'); - } - - if (snapshot >= block.number) { - return ProposalState.Pending; - } - - uint256 deadline = proposalDeadline(proposalId); - - if (deadline >= block.number) { - return ProposalState.Active; - } - - if (_quorumReached(proposalId) && _voteSucceeded(proposalId)) { - return ProposalState.Succeeded; - } else { - return ProposalState.Defeated; - } - } - - /** - * @dev See {IGovernor-proposalSnapshot}. - */ - function proposalSnapshot(uint256 proposalId) public view virtual override returns (uint256) { - return _proposals[proposalId].voteStart.getDeadline(); - } - - /** - * @dev See {IGovernor-proposalDeadline}. - */ - function proposalDeadline(uint256 proposalId) public view virtual override returns (uint256) { - return _proposals[proposalId].voteEnd.getDeadline(); - } - - /** - * @dev Part of the Governor Bravo's interface: _"The number of votes required in order for a voter to become a proposer"_. - */ - function proposalThreshold() public view virtual returns (uint256) { - return 0; - } - - /** - * @dev Amount of votes already cast passes the threshold limit. - */ - function _quorumReached(uint256 proposalId) internal view virtual returns (bool); - - /** - * @dev Is the proposal successful or not. - */ - function _voteSucceeded(uint256 proposalId) internal view virtual returns (bool); - - /** - * @dev Get the voting weight of `account` at a specific `blockNumber`, for a vote as described by `params`. - */ - function _getVotes( - address account, - uint256 blockNumber, - bytes memory params - ) internal view virtual returns (uint256); - - /** - * @dev Register a vote for `proposalId` by `account` with a given `support`, voting `weight` and voting `params`. - * - * Note: Support is generic and can represent various things depending on the voting system used. - */ - function _countVote( - uint256 proposalId, - address account, - uint8 support, - uint256 weight, - bytes memory params - ) internal virtual; - - /** - * @dev Default additional encoded parameters used by castVote methods that don't include them - * - * Note: Should be overridden by specific implementations to use an appropriate value, the - * meaning of the additional params, in the context of that implementation - */ - function _defaultParams() internal view virtual returns (bytes memory) { - return ''; - } - - /** - * @dev See {IGovernor-propose}. - */ - function propose( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - string memory description - ) public virtual override returns (uint256) { - require( - getVotes(_msgSender(), block.number - 1) >= proposalThreshold(), - 'Governor: proposer votes below proposal threshold' - ); - - uint256 proposalId = hashProposal(targets, values, calldatas, keccak256(bytes(description))); - - require(targets.length == values.length, 'Governor: invalid proposal length'); - require(targets.length == calldatas.length, 'Governor: invalid proposal length'); - require(targets.length > 0, 'Governor: empty proposal'); - - ProposalCore storage proposal = _proposals[proposalId]; - require(proposal.voteStart.isUnset(), 'Governor: proposal already exists'); - - uint64 snapshot = block.number.toUint64() + votingDelay().toUint64(); - uint64 deadline = snapshot + votingPeriod().toUint64(); - - proposal.voteStart.setDeadline(snapshot); - proposal.voteEnd.setDeadline(deadline); - - emit ProposalCreated( - proposalId, - _msgSender(), - targets, - values, - new string[](targets.length), - calldatas, - snapshot, - deadline, - description - ); - - return proposalId; - } - - /** - * @dev See {IGovernor-execute}. - */ - function execute( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) public payable virtual override returns (uint256) { - uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); - - ProposalState status = state(proposalId); - require( - status == ProposalState.Succeeded || status == ProposalState.Queued, - 'Governor: proposal not successful' - ); - _proposals[proposalId].executed = true; - - emit ProposalExecuted(proposalId); - - _beforeExecute(proposalId, targets, values, calldatas, descriptionHash); - _execute(proposalId, targets, values, calldatas, descriptionHash); - _afterExecute(proposalId, targets, values, calldatas, descriptionHash); - - return proposalId; - } - - /** - * @dev Internal execution mechanism. Can be overridden to implement different execution mechanism - */ - function _execute( - uint256, /* proposalId */ - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 /*descriptionHash*/ - ) internal virtual { - string memory errorMessage = 'Governor: call reverted without message'; - for (uint256 i = 0; i < targets.length; ++i) { - (bool success, bytes memory returndata) = targets[i].call{value: values[i]}(calldatas[i]); - Address.verifyCallResult(success, returndata, errorMessage); - } - } - - /** - * @dev Hook before execution is triggered. - */ - function _beforeExecute( - uint256, /* proposalId */ - address[] memory targets, - uint256[] memory, /* values */ - bytes[] memory calldatas, - bytes32 /*descriptionHash*/ - ) internal virtual { - if (_executor() != address(this)) { - for (uint256 i = 0; i < targets.length; ++i) { - if (targets[i] == address(this)) { - _governanceCall.pushBack(keccak256(calldatas[i])); - } - } - } - } - - /** - * @dev Hook after execution is triggered. - */ - function _afterExecute( - uint256, /* proposalId */ - address[] memory, /* targets */ - uint256[] memory, /* values */ - bytes[] memory, /* calldatas */ - bytes32 /*descriptionHash*/ - ) internal virtual { - if (_executor() != address(this)) { - if (!_governanceCall.empty()) { - _governanceCall.clear(); - } - } - } - - /** - * @dev Internal cancel mechanism: locks up the proposal timer, preventing it from being re-submitted. Marks it as - * canceled to allow distinguishing it from executed proposals. - * - * Emits a {IGovernor-ProposalCanceled} event. - */ - function _cancel( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) internal virtual returns (uint256) { - uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); - ProposalState status = state(proposalId); - - require( - status != ProposalState.Canceled && - status != ProposalState.Expired && - status != ProposalState.Executed, - 'Governor: proposal not active' - ); - _proposals[proposalId].canceled = true; - - emit ProposalCanceled(proposalId); - - return proposalId; - } - - /** - * @dev See {IGovernor-getVotes}. - */ - function getVotes(address account, uint256 blockNumber) - public - view - virtual - override - returns (uint256) - { - return _getVotes(account, blockNumber, _defaultParams()); - } - - /** - * @dev See {IGovernor-getVotesWithParams}. - */ - function getVotesWithParams( - address account, - uint256 blockNumber, - bytes memory params - ) public view virtual override returns (uint256) { - return _getVotes(account, blockNumber, params); - } - - /** - * @dev See {IGovernor-castVote}. - */ - function castVote(uint256 proposalId, uint8 support) public virtual override returns (uint256) { - address voter = _msgSender(); - return _castVote(proposalId, voter, support, ''); - } - - /** - * @dev See {IGovernor-castVoteWithReason}. - */ - function castVoteWithReason( - uint256 proposalId, - uint8 support, - string calldata reason - ) public virtual override returns (uint256) { - address voter = _msgSender(); - return _castVote(proposalId, voter, support, reason); - } - - /** - * @dev See {IGovernor-castVoteWithReasonAndParams}. - */ - function castVoteWithReasonAndParams( - uint256 proposalId, - uint8 support, - string calldata reason, - bytes memory params - ) public virtual override returns (uint256) { - address voter = _msgSender(); - return _castVote(proposalId, voter, support, reason, params); - } - - /** - * @dev See {IGovernor-castVoteBySig}. - */ - function castVoteBySig( - uint256 proposalId, - uint8 support, - uint8 v, - bytes32 r, - bytes32 s - ) public virtual override returns (uint256) { - address voter = ECDSA.recover( - _hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support))), - v, - r, - s - ); - return _castVote(proposalId, voter, support, ''); - } - - /** - * @dev See {IGovernor-castVoteWithReasonAndParamsBySig}. - */ - function castVoteWithReasonAndParamsBySig( - uint256 proposalId, - uint8 support, - string calldata reason, - bytes memory params, - uint8 v, - bytes32 r, - bytes32 s - ) public virtual override returns (uint256) { - address voter = ECDSA.recover( - _hashTypedDataV4( - keccak256( - abi.encode( - EXTENDED_BALLOT_TYPEHASH, - proposalId, - support, - keccak256(bytes(reason)), - keccak256(params) - ) - ) - ), - v, - r, - s - ); - - return _castVote(proposalId, voter, support, reason, params); - } - - /** - * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve - * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. Uses the _defaultParams(). - * - * Emits a {IGovernor-VoteCast} event. - */ - function _castVote( - uint256 proposalId, - address account, - uint8 support, - string memory reason - ) internal virtual returns (uint256) { - return _castVote(proposalId, account, support, reason, _defaultParams()); - } - - /** - * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve - * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. - * - * Emits a {IGovernor-VoteCast} event. - */ - function _castVote( - uint256 proposalId, - address account, - uint8 support, - string memory reason, - bytes memory params - ) internal virtual returns (uint256) { - ProposalCore storage proposal = _proposals[proposalId]; - require(state(proposalId) == ProposalState.Active, 'Governor: vote not currently active'); - - uint256 weight = _getVotes(account, proposal.voteStart.getDeadline(), params); - _countVote(proposalId, account, support, weight, params); - - if (params.length == 0) { - emit VoteCast(account, proposalId, support, weight, reason); - } else { - emit VoteCastWithParams(account, proposalId, support, weight, reason, params); - } - - return weight; - } - - /** - * @dev Relays a transaction or function call to an arbitrary target. In cases where the governance executor - * is some contract other than the governor itself, like when using a timelock, this function can be invoked - * in a governance proposal to recover tokens or Ether that was sent to the governor contract by mistake. - * Note that if the executor is simply the governor itself, use of `relay` is redundant. - */ - function relay( - address target, - uint256 value, - bytes calldata data - ) external virtual onlyGovernance { - Address.functionCallWithValue(target, data, value); - } - - /** - * @dev Address through which the governor executes action. Will be overloaded by module that execute actions - * through another contract such as a timelock. - */ - function _executor() internal view virtual returns (address) { - return address(this); - } - - /** - * @dev See {IERC721Receiver-onERC721Received}. - */ - function onERC721Received( - address, - address, - uint256, - bytes memory - ) public virtual override returns (bytes4) { - return this.onERC721Received.selector; - } - - /** - * @dev See {IERC1155Receiver-onERC1155Received}. - */ - function onERC1155Received( - address, - address, - uint256, - uint256, - bytes memory - ) public virtual override returns (bytes4) { - return this.onERC1155Received.selector; - } - - /** - * @dev See {IERC1155Receiver-onERC1155BatchReceived}. - */ - function onERC1155BatchReceived( - address, - address, - uint256[] memory, - uint256[] memory, - bytes memory - ) public virtual override returns (bytes4) { - return this.onERC1155BatchReceived.selector; - } -} diff --git a/contracts/interfaces/IGovernor.sol b/contracts/interfaces/IGovernor.sol index e1265a0..6bd6009 100644 --- a/contracts/interfaces/IGovernor.sol +++ b/contracts/interfaces/IGovernor.sol @@ -193,90 +193,4 @@ abstract contract IGovernor is IERC165 { * @dev Returns weither `account` has cast a vote on `proposalId`. */ function hasVoted(uint256 proposalId, address account) public view virtual returns (bool); - - /** - * @dev Create a new proposal. Vote start {IGovernor-votingDelay} blocks after the proposal is created and ends - * {IGovernor-votingPeriod} blocks after the voting starts. - * - * Emits a {ProposalCreated} event. - */ - function propose( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - string memory description - ) public virtual returns (uint256 proposalId); - - /** - * @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the - * deadline to be reached. - * - * Emits a {ProposalExecuted} event. - * - * Note: some module can modify the requirements for execution, for example by adding an additional timelock. - */ - function execute( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) public payable virtual returns (uint256 proposalId); - - /** - * @dev Cast a vote - * - * Emits a {VoteCast} event. - */ - function castVote(uint256 proposalId, uint8 support) public virtual returns (uint256 balance); - - /** - * @dev Cast a vote with a reason - * - * Emits a {VoteCast} event. - */ - function castVoteWithReason( - uint256 proposalId, - uint8 support, - string calldata reason - ) public virtual returns (uint256 balance); - - /** - * @dev Cast a vote with a reason and additional encoded parameters - * - * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. - */ - function castVoteWithReasonAndParams( - uint256 proposalId, - uint8 support, - string calldata reason, - bytes memory params - ) public virtual returns (uint256 balance); - - /** - * @dev Cast a vote using the user's cryptographic signature. - * - * Emits a {VoteCast} event. - */ - function castVoteBySig( - uint256 proposalId, - uint8 support, - uint8 v, - bytes32 r, - bytes32 s - ) public virtual returns (uint256 balance); - - /** - * @dev Cast a vote with a reason and additional encoded parameters using the user's cryptographic signature. - * - * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. - */ - function castVoteWithReasonAndParamsBySig( - uint256 proposalId, - uint8 support, - string calldata reason, - bytes memory params, - uint8 v, - bytes32 r, - bytes32 s - ) public virtual returns (uint256 balance); } From f55e615ade61e34a3613f64ee71d9822377ca9ed Mon Sep 17 00:00:00 2001 From: mejango Date: Wed, 4 Jan 2023 15:59:01 -0300 Subject: [PATCH 17/21] goerli script --- contracts/DefifaDeployer.sol | 1 + contracts/forge-test/DefifaGovernor.t.sol | 1 + contracts/scripts/Deploy.s.sol | 266 ++++++++++------------ 3 files changed, 128 insertions(+), 140 deletions(-) diff --git a/contracts/DefifaDeployer.sol b/contracts/DefifaDeployer.sol index a21961a..2b431c4 100644 --- a/contracts/DefifaDeployer.sol +++ b/contracts/DefifaDeployer.sol @@ -283,6 +283,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { _pricingParams, _delegateData.store, JBTiered721Flags({ + preventOverspending: false, lockReservedTokenChanges: false, lockVotingUnitChanges: false, lockManualMintingChanges: false diff --git a/contracts/forge-test/DefifaGovernor.t.sol b/contracts/forge-test/DefifaGovernor.t.sol index 45754f9..dade39e 100644 --- a/contracts/forge-test/DefifaGovernor.t.sol +++ b/contracts/forge-test/DefifaGovernor.t.sol @@ -1602,6 +1602,7 @@ contract DefifaGovernorTest is TestBaseWorkflow { reservedTokenBeneficiary: reserveBeneficiary, store: new JBTiered721DelegateStore(), flags: JBTiered721Flags({ + preventOverspending: false, lockReservedTokenChanges: false, lockVotingUnitChanges: false, lockManualMintingChanges: false diff --git a/contracts/scripts/Deploy.s.sol b/contracts/scripts/Deploy.s.sol index 0b98fbc..7069d9d 100644 --- a/contracts/scripts/Deploy.s.sol +++ b/contracts/scripts/Deploy.s.sol @@ -134,143 +134,129 @@ contract DeployMainnet is Script { } } -// contract DeployGoerli is Script { -// function run() external { -// vm.startBroadcast(); - -// // V3 goerli controller. -// IJBController controller = IJBController(0x7Cb86D43B665196BC719b6974D320bf674AFb395); -// // goerli 721 store. -// IJBTiered721DelegateStore store = IJBTiered721DelegateStore( -// 0x3EA16DeFF07f031e86bd13C55961eB576cd579a6 -// ); -// // V3 goerli Payment terminal. -// IJBPaymentTerminal terminal = IJBPaymentTerminal(0x55d4dfb578daA4d60380995ffF7a706471d7c719); - -// address _defifaBallcats = 0x11834239698c7336EF232C00a2A9926d3375DF9D; -// // Game params. -// uint48 _start = 1669024800; // 2am PST, Nov 21. -// uint48 _mintDuration = 1036800; // 12 days. -// uint48 _tradeDeadline = 1670598000; // 7am, Dec 9. -// uint48 _end = 1671375600 + 604800; // 7 days after the finals. Dec 25, 7am PST. - -// JB721TierParams[] memory _tiers = new JB721TierParams[](32); - -// bytes32[] memory _teamEncodedIPFSUris = new bytes32[](32); -// _teamEncodedIPFSUris[0] = 0xb2cf9b27f33b6b445b31fa13ad93600d35a1bafd27543b313af1e2cd727e213b; -// _teamEncodedIPFSUris[1] = 0xbfabff3f158961179837886c91f9e5847a25865b20f1a3c4f13448323284d31f; -// _teamEncodedIPFSUris[2] = 0xf526000358a2bb0227db6a0f4c28b8cfb242e0a16f568975b6f7839ef2075761; -// _teamEncodedIPFSUris[3] = 0xb514ff48aef786b83f456773af2b432365707b84ca9ec02c0639732279c57f35; -// _teamEncodedIPFSUris[4] = 0x816bff580d5d900165c09b953c11cd4a9fe15b41ded825edfc82680eb7cdeaa9; -// _teamEncodedIPFSUris[5] = 0x2850e2b55a3fb53a17173d0e91938e2da2d520c3092858ce68a460dad35bbc91; -// _teamEncodedIPFSUris[6] = 0x98fa3187e98ad21fcdf43a1e1601e8f8619ceeaf9f3fb0039f2f61f31e35a145; -// _teamEncodedIPFSUris[7] = 0xda36dfe50c30ae4e83b4e8ef4cd4ce9e580298a55d31b8d7276e644380ce9ff6; -// _teamEncodedIPFSUris[8] = 0x8b3b961de3bacb600488d91dbe9277c50f16311b92455e82ce6c26d078d9503f; -// _teamEncodedIPFSUris[9] = 0x0977f77350659d1f8284f1b0a4f0ee447cf32c6ef8c06b7ec5f9295822818111; -// _teamEncodedIPFSUris[10] = 0x6198d84d8904f2c89fa6ff3de01ccce8b928cfb6182da65723b70aa1e63a94c8; -// _teamEncodedIPFSUris[11] = 0x895646f615fc45358d894014f3d8c15ad020323cf57c6624464bd11a2815a480; -// _teamEncodedIPFSUris[12] = 0x6388190babc4fd7ad390b545dc0eaf01222355583ce0a5d5496c2bb6f118039b; -// _teamEncodedIPFSUris[13] = 0x33e06853378f58d42ceb8ab266d25656eded385f82a777ca563c5e38d5241a83; -// _teamEncodedIPFSUris[14] = 0x2f4275c8dac582d4718d41315e8406e502f9edc24718508008c9be2120c29718; -// _teamEncodedIPFSUris[15] = 0x6ff53e06711936e10bd3ca5786ca9c47cbd42f5b878289c350fa405513cbba39; -// _teamEncodedIPFSUris[16] = 0xdaae0d745afe8943fffe0a733b7da605db462162bf0895d069daf8137ded8b0f; -// _teamEncodedIPFSUris[17] = 0xba245717d6e4293217d7e94f19b5aef1a84f6902bced1332eb8607aaddd43db2; -// _teamEncodedIPFSUris[18] = 0x42a65ae98f0d43856f8d75d645dbe964750f42415e038264813c95e1fd977839; -// _teamEncodedIPFSUris[19] = 0x755651ad1de6c43ed4525d761a39c4521445f67c72010544cdbe156928954d2d; -// _teamEncodedIPFSUris[20] = 0x6f880ca3d58e8f48a8709d097ead5dda0969f525efacadba9d707fd68578e45f; -// _teamEncodedIPFSUris[21] = 0x9ca1e5354a134ff50d36121ccc511ac6a1c42797512aceea4d1e14811359c063; -// _teamEncodedIPFSUris[22] = 0x91b2e30c3f239b25f75ea44ca36ddaa616738bd88ecedd67691f22bffe401727; -// _teamEncodedIPFSUris[23] = 0xdfb13aa5ab8c607ca1772385ece7dc4213a06ae0e7a09058592556e19b4ef6eb; -// _teamEncodedIPFSUris[24] = 0xb587a257c1a625c9b28f3f2c841fe99fdad97d111f94a3f238e1a8f224b48e37; -// _teamEncodedIPFSUris[25] = 0xab1d428c4b2594b8232abff414ad259f6748dbe13302dd7d4758c12a79b9ffbf; -// _teamEncodedIPFSUris[26] = 0x5756ead1507fa2210f66dd2bf9ed722b27929ccd90fade1a234447dc01cc8ef0; -// _teamEncodedIPFSUris[27] = 0x032083c1a27f9e5fed3236e357dca8e7bc205681a9942465adfeca40efcc05a5; -// _teamEncodedIPFSUris[28] = 0x60c52313561051352c1d98d9652815b555f95c0ee250b9afd1acddf95dec9578; -// _teamEncodedIPFSUris[29] = 0x5b88630af3d5ad16f18c2c8528a41b925233c61e40c8934d7981e21881b062b5; -// _teamEncodedIPFSUris[30] = 0x1ba892a008a164359a2b70ef1ab046d90fa3af4ce4815c00cd07a2a9237e9808; -// _teamEncodedIPFSUris[31] = 0x193bb548bbf52cf76e00185e24c0eada8f758dfef1927cfaa202207e4beb6cec; - -// for (uint256 _i; _i < 32; ) { -// _tiers[_i] = JB721TierParams({ -// contributionFloor: 0.022 ether, -// lockedUntil: 0, -// initialQuantity: 1_000_000_000 - 1, // max -// votingUnits: 1, -// reservedRate: 9, -// reservedTokenBeneficiary: _defifaBallcats, -// encodedIPFSUri: _teamEncodedIPFSUris[_i], -// allowManualMint: false, -// shouldUseBeneficiaryAsDefault: true, -// transfersPausable: true -// }); - -// unchecked { -// ++_i; -// } -// } - -// DefifaDelegateData memory _delegateData = DefifaDelegateData({ -// name: 'Defifa: FIFA World Cup 2022', -// symbol: 'DEFIFA', -// baseUri: 'ipfs://', -// contractUri: 'QmaK1Hib3Umokija4bRwoPdxHgGY3unRreeeLoJss3vw4Y', -// tiers: _tiers, -// store: store, -// // Set owner will be set to the Governor later on in this script. -// owner: address(0) -// }); - -// DefifaLaunchProjectData memory _launchProjectData = DefifaLaunchProjectData({ -// projectMetadata: JBProjectMetadata({ -// content: 'QmT7VFuF7cPMwMnqh3YruuYcRk2tKMb2xcXSbK2wV82Hdy', -// domain: 0 -// }), -// mintDuration: _mintDuration, -// start: _start, -// tradeDeadline: _tradeDeadline, -// end: _end, -// holdFees: false, -// splits: new JBSplit[](0), -// distributionLimit: 0, -// terminal: terminal -// }); - -// // Deploy the codeOrigin for the delegate -// DefifaDelegate _defifaDelegateCodeOrigin = new DefifaDelegate(); - -// // Deploy the deployer. -// DefifaDeployer defifaDeployer = new DefifaDeployer( -// address(_defifaDelegateCodeOrigin), -// controller, -// JBTokens.ETH, -// _defifaBallcats -// ); - -// // Set the owner as the governor (done here to easily count future nonces) -// _delegateData.owner = computeCreateAddress(tx.origin, vm.getNonce(tx.origin) + 1); - -// // Launch the game - initialNonce -// uint256 _projectId = defifaDeployer.launchGameWith(_delegateData, _launchProjectData); -// // initialNonce + 1 - -// // Get a reference to the latest configured funding cycle's data source, which should be the delegate that was deployed and attached to the project. -// (, JBFundingCycleMetadata memory _metadata, ) = controller.latestConfiguredFundingCycleOf( -// _projectId -// ); -// // initialNonce + 1 (view function) - -// // Deploy the governor -// { -// address _governor = address(new DefifaGovernor(DefifaDelegate(_metadata.dataSource), _end)); - -// // These 3 should be the same: -// console.log(_delegateData.owner); -// console.log(_governor); -// console.log(Ownable(_metadata.dataSource).owner()); -// } - -// console.log(address(defifaDeployer)); -// console.log(address(store)); -// console.log(_metadata.dataSource); -// } -// } +contract DeployGoerli is Script { + // V3 goerli controller. + IJBController controller = IJBController(0x7Cb86D43B665196BC719b6974D320bf674AFb395); + // goerli 721 store. + IJBTiered721DelegateStore store = IJBTiered721DelegateStore( + 0x3EA16DeFF07f031e86bd13C55961eB576cd579a6 + ); + // V3 goerli Payment terminal. + IJBPaymentTerminal terminal = IJBPaymentTerminal(0x55d4dfb578daA4d60380995ffF7a706471d7c719); + + address _defifaBallcats = 0x11834239698c7336EF232C00a2A9926d3375DF9D; + // Game params. + uint48 _start = 1673672400; // 12am EST, Jan 14. + uint48 _mintDuration = 432000; // 5 days. + uint48 _refundPeriodDuration = 86400; // 1 day. + uint48 _end = 1676178000; // 12am EST, Feb 12. + uint80 _price = 0.1 ether; + // We don't have to do this effenciently since this contract never gets deployed, its just used to build the broadcast txs + string _name = 'Defifa: NFL Playoffs 2023'; + string _symbol = 'DEFIFA NFL 2023'; + string _contractUri = 'QmaK1Hib3Umokija4bRwoPdxHgGY3unRreeeLoJss3vw4Y'; + string _projectMetadataUri = 'QmT7VFuF7cPMwMnqh3YruuYcRk2tKMb2xcXSbK2wV82Hdy'; + uint16 _reserved = 9; // 1 reserved NFT mintable to reserved beneficiary for every 9 NFTs minted outwardly. Inclusive, so 1 reserved can be minted as soon as the first token is minted outwardly. + + function run() external { + vm.startBroadcast(); + + JB721TierParams[] memory _tiers = new JB721TierParams[](32); + + bytes32[] memory _teamEncodedIPFSUris = new bytes32[](32); + _teamEncodedIPFSUris[0] = 0xb2cf9b27f33b6b445b31fa13ad93600d35a1bafd27543b313af1e2cd727e213b; + _teamEncodedIPFSUris[1] = 0xbfabff3f158961179837886c91f9e5847a25865b20f1a3c4f13448323284d31f; + _teamEncodedIPFSUris[2] = 0xf526000358a2bb0227db6a0f4c28b8cfb242e0a16f568975b6f7839ef2075761; + _teamEncodedIPFSUris[3] = 0xb514ff48aef786b83f456773af2b432365707b84ca9ec02c0639732279c57f35; + _teamEncodedIPFSUris[4] = 0x816bff580d5d900165c09b953c11cd4a9fe15b41ded825edfc82680eb7cdeaa9; + _teamEncodedIPFSUris[5] = 0x2850e2b55a3fb53a17173d0e91938e2da2d520c3092858ce68a460dad35bbc91; + _teamEncodedIPFSUris[6] = 0x98fa3187e98ad21fcdf43a1e1601e8f8619ceeaf9f3fb0039f2f61f31e35a145; + _teamEncodedIPFSUris[7] = 0xda36dfe50c30ae4e83b4e8ef4cd4ce9e580298a55d31b8d7276e644380ce9ff6; + _teamEncodedIPFSUris[8] = 0x8b3b961de3bacb600488d91dbe9277c50f16311b92455e82ce6c26d078d9503f; + _teamEncodedIPFSUris[9] = 0x0977f77350659d1f8284f1b0a4f0ee447cf32c6ef8c06b7ec5f9295822818111; + _teamEncodedIPFSUris[10] = 0x6198d84d8904f2c89fa6ff3de01ccce8b928cfb6182da65723b70aa1e63a94c8; + _teamEncodedIPFSUris[11] = 0x895646f615fc45358d894014f3d8c15ad020323cf57c6624464bd11a2815a480; + _teamEncodedIPFSUris[12] = 0x6388190babc4fd7ad390b545dc0eaf01222355583ce0a5d5496c2bb6f118039b; + _teamEncodedIPFSUris[13] = 0x33e06853378f58d42ceb8ab266d25656eded385f82a777ca563c5e38d5241a83; + + for (uint256 _i; _i < 32; ) { + _tiers[_i] = JB721TierParams({ + contributionFloor: _price, + lockedUntil: 0, + initialQuantity: 1_000_000_000 - 1, // max + votingUnits: 1, + reservedRate: _reserved, + reservedTokenBeneficiary: _defifaBallcats, + encodedIPFSUri: _teamEncodedIPFSUris[_i], + allowManualMint: false, + shouldUseBeneficiaryAsDefault: true, + transfersPausable: true + }); + + unchecked { + ++_i; + } + } + + DefifaDelegateData memory _delegateData = DefifaDelegateData({ + name: _name, + symbol: _symbol, + baseUri: 'ipfs://', + contractUri: _contractUri, + tiers: _tiers, + store: store, + // Set owner will be set to the Governor later on in this script. + owner: address(0) + }); + + DefifaLaunchProjectData memory _launchProjectData = DefifaLaunchProjectData({ + projectMetadata: JBProjectMetadata({content: _projectMetadataUri, domain: 0}), + mintDuration: _mintDuration, + start: _start, + refundPeriodDuration: _refundPeriodDuration, + end: _end, + holdFees: false, + splits: new JBSplit[](0), + distributionLimit: 0, + terminal: terminal + }); + + // Deploy the codeOrigin for the delegate + DefifaDelegate _defifaDelegateCodeOrigin = new DefifaDelegate(); + + // Deploy the deployer. + DefifaDeployer defifaDeployer = new DefifaDeployer( + address(_defifaDelegateCodeOrigin), + controller, + JBTokens.ETH, + _defifaBallcats + ); + + // Set the owner as the governor (done here to easily count future nonces) + _delegateData.owner = computeCreateAddress(tx.origin, vm.getNonce(tx.origin) + 1); + + // Launch the game - initialNonce + uint256 _projectId = defifaDeployer.launchGameWith(_delegateData, _launchProjectData); + // initialNonce + 1 + + // Get a reference to the latest configured funding cycle's data source, which should be the delegate that was deployed and attached to the project. + (, JBFundingCycleMetadata memory _metadata, ) = controller.latestConfiguredFundingCycleOf( + _projectId + ); + // initialNonce + 1 (view function) + + // Deploy the governor + { + address _governor = address(new DefifaGovernor(DefifaDelegate(_metadata.dataSource), _end)); + + // These 3 should be the same: + console.log(_delegateData.owner); + console.log(_governor); + console.log(Ownable(_metadata.dataSource).owner()); + } + + console.log(address(defifaDeployer)); + console.log(address(store)); + console.log(_metadata.dataSource); + } +} From f51bcd82093ba3d0fa6630443450e7f30d516df8 Mon Sep 17 00:00:00 2001 From: mejango Date: Wed, 4 Jan 2023 17:33:08 -0300 Subject: [PATCH 18/21] prevent overspending --- contracts/DefifaDeployer.sol | 2 +- contracts/forge-test/DefifaGovernor.t.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/DefifaDeployer.sol b/contracts/DefifaDeployer.sol index 2b431c4..3c760fa 100644 --- a/contracts/DefifaDeployer.sol +++ b/contracts/DefifaDeployer.sol @@ -283,7 +283,7 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { _pricingParams, _delegateData.store, JBTiered721Flags({ - preventOverspending: false, + preventOverspending: true, lockReservedTokenChanges: false, lockVotingUnitChanges: false, lockManualMintingChanges: false diff --git a/contracts/forge-test/DefifaGovernor.t.sol b/contracts/forge-test/DefifaGovernor.t.sol index dade39e..a564f91 100644 --- a/contracts/forge-test/DefifaGovernor.t.sol +++ b/contracts/forge-test/DefifaGovernor.t.sol @@ -1602,7 +1602,7 @@ contract DefifaGovernorTest is TestBaseWorkflow { reservedTokenBeneficiary: reserveBeneficiary, store: new JBTiered721DelegateStore(), flags: JBTiered721Flags({ - preventOverspending: false, + preventOverspending: true, lockReservedTokenChanges: false, lockVotingUnitChanges: false, lockManualMintingChanges: false From 6fb40e2c6a1284d8d9f710a49fc5809f8559c1fc Mon Sep 17 00:00:00 2001 From: xBA5ED <0xBA5ED@protonmail.com> Date: Wed, 4 Jan 2023 23:36:52 +0100 Subject: [PATCH 19/21] Fix tests, disable proposing custom calls (only allow setting scorecard redemptions) --- contracts/DefifaDelegate.sol | 2 - contracts/DefifaDeployer.sol | 1 - contracts/DefifaGovernor.sol | 7 +- contracts/forge-test/DefifaGovernor.t.sol | 434 +++++++++++----------- 4 files changed, 221 insertions(+), 223 deletions(-) diff --git a/contracts/DefifaDelegate.sol b/contracts/DefifaDelegate.sol index 62e45df..f2edf91 100644 --- a/contracts/DefifaDelegate.sol +++ b/contracts/DefifaDelegate.sol @@ -178,7 +178,6 @@ contract DefifaDelegate is IDefifaDelegate, JB721TieredGovernance { public view virtual - override returns (uint256 cumulativeWeight) { // If the game is over, set the weight based on the scorecard results. @@ -217,7 +216,6 @@ contract DefifaDelegate is IDefifaDelegate, JB721TieredGovernance { public view virtual - override returns (uint256) { // Set the total weight as the total scorecard weight. diff --git a/contracts/DefifaDeployer.sol b/contracts/DefifaDeployer.sol index 2b431c4..a21961a 100644 --- a/contracts/DefifaDeployer.sol +++ b/contracts/DefifaDeployer.sol @@ -283,7 +283,6 @@ contract DefifaDeployer is IDefifaDeployer, IERC721Receiver { _pricingParams, _delegateData.store, JBTiered721Flags({ - preventOverspending: false, lockReservedTokenChanges: false, lockVotingUnitChanges: false, lockManualMintingChanges: false diff --git a/contracts/DefifaGovernor.sol b/contracts/DefifaGovernor.sol index 49e070a..06e0230 100644 --- a/contracts/DefifaGovernor.sol +++ b/contracts/DefifaGovernor.sol @@ -29,6 +29,7 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { // --------------------------- custom errors ------------------------- // //*********************************************************************// error INCORRECT_TIER_ORDER(); + error DISABLED(); //*********************************************************************// // -------------------- private constant properties ------------------ // @@ -105,7 +106,7 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { ) = _buildScorecardCalldata(_tierWeights); // Submit the proposal. - return propose(_targets, _values, _calldatas, ''); + return this.propose(_targets, _values, _calldatas, ''); } /** @@ -318,6 +319,10 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { bytes[] memory calldatas, string memory description ) public override(Governor) returns (uint256) { + // We don't allow submitting proposals other than scorecards + if (_msgSender() != address(this)) + revert DISABLED(); + return super.propose(targets, values, calldatas, description); } diff --git a/contracts/forge-test/DefifaGovernor.t.sol b/contracts/forge-test/DefifaGovernor.t.sol index dade39e..48bc6b3 100644 --- a/contracts/forge-test/DefifaGovernor.t.sol +++ b/contracts/forge-test/DefifaGovernor.t.sol @@ -39,10 +39,15 @@ contract DefifaGovernorTest is TestBaseWorkflow { address _user = address(bytes20(keccak256('user'))); + DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(); (uint256 _projectId, DefifaDelegate _nft, DefifaGovernor _governor) = createDefifaProject( uint256(nTiers), - getBasicDefifaLaunchData() + defifaData ); + + // Phase 1: Mint + vm.warp(defifaData.start - defifaData.mintDuration - defifaData.refundPeriodDuration); + deployer.queueNextPhaseOf(_projectId); // User should have no voting power (yet) assertEq(_governor.getVotes(_user, block.number - 1), 0); @@ -100,11 +105,16 @@ contract DefifaGovernorTest is TestBaseWorkflow { uint8 nTiers = 10; address[] memory _users = new address[](nTiers); + DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(); (uint256 _projectId, DefifaDelegate _nft, ) = createDefifaProject( uint256(nTiers), - getBasicDefifaLaunchData() + defifaData ); + // Phase 1: Mint + vm.warp(defifaData.start - defifaData.mintDuration - defifaData.refundPeriodDuration); + deployer.queueNextPhaseOf(_projectId); + for (uint256 i = 0; i < nTiers; i++) { // Generate a new address for each tier _users[i] = address(bytes20(keccak256(abi.encode('user', Strings.toString(i))))); @@ -149,40 +159,12 @@ contract DefifaGovernorTest is TestBaseWorkflow { _nft.setTierDelegates(tiered721SetDelegatesData); } - // Phase 2 - vm.warp(block.timestamp + 1 days); + // Phase 2: Redeem + vm.warp(block.timestamp + defifaData.mintDuration); deployer.queueNextPhaseOf(_projectId); - // Make sure this is actually Phase 2 - assertEq(_jbFundingCycleStore.currentOf(_projectId).number, 2); - - for (uint256 i = 0; i < _users.length; i++) { - address _user = _users[i]; - - // Craft the metadata: redeem the tokenId - bytes memory redemptionMetadata; - { - uint256[] memory redemptionId = new uint256[](1); - redemptionId[0] = _generateTokenId(i + 1, 1); - redemptionMetadata = abi.encode(bytes32(0), type(IJB721Delegate).interfaceId, redemptionId); - } - - vm.expectRevert(abi.encodeWithSignature('FUNDING_CYCLE_REDEEM_PAUSED()')); - vm.prank(_user); - JBETHPaymentTerminal(address(_terminals[0])).redeemTokensOf({ - _holder: _user, - _projectId: _projectId, - _tokenCount: 0, - _token: address(0), - _minReturnedTokens: 0, - _beneficiary: payable(_user), - _memo: 'Refund plz', - _metadata: redemptionMetadata - }); - } - - // Phase 3 - vm.warp(block.timestamp + 1 weeks); + // Phase 3: Start + vm.warp(defifaData.start + 1); deployer.queueNextPhaseOf(_projectId); // Make sure this is actually Phase 3 @@ -213,7 +195,10 @@ contract DefifaGovernorTest is TestBaseWorkflow { }); } - // Phase 4 + // Phase 4: End + vm.warp(deployer.endOf(_projectId)); + // Forward the amount of blocks needed to reach the end (and round up) + vm.roll(deployer.endOf(_projectId) - block.timestamp / 12 + 1); vm.warp(block.timestamp + 1 weeks); assertEq(_jbFundingCycleStore.currentOf(_projectId).number, 4); @@ -249,13 +234,18 @@ contract DefifaGovernorTest is TestBaseWorkflow { uint8 nTiers = 10; address[] memory _users = new address[](nTiers); - (uint256 _projectId,, ) = createDefifaProject( + DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(); + (uint256 _projectId, DefifaDelegate _nft, DefifaGovernor _governor) = createDefifaProject( uint256(nTiers), - getBasicDefifaLaunchData() + defifaData ); - // Phase 2 - vm.warp(block.timestamp + 1 days); + // Phase 1: minting + vm.warp(defifaData.start - defifaData.mintDuration - defifaData.refundPeriodDuration); + deployer.queueNextPhaseOf(_projectId); + + // Phase 2: Redeem + vm.warp(block.timestamp + defifaData.mintDuration); deployer.queueNextPhaseOf(_projectId); // Make sure this is actually Phase 2 @@ -296,8 +286,8 @@ contract DefifaGovernorTest is TestBaseWorkflow { ); } - // Phase 3 - vm.warp(block.timestamp + 1 weeks); + // Phase 3: Start + vm.warp(defifaData.start + 1); deployer.queueNextPhaseOf(_projectId); // Make sure this is actually Phase 3 @@ -338,8 +328,10 @@ contract DefifaGovernorTest is TestBaseWorkflow { ); } - // Phase 4 - vm.warp(block.timestamp + 1 weeks); + // Phase 4: End + vm.warp(deployer.endOf(_projectId)); + // Forward the amount of blocks needed to reach the end (and round up) + vm.roll(deployer.endOf(_projectId) - block.timestamp / 12 + 1); // Make sure this is actually Phase 4 assertEq(_jbFundingCycleStore.currentOf(_projectId).number, 4); @@ -379,79 +371,89 @@ contract DefifaGovernorTest is TestBaseWorkflow { } } - function testTransfer_fails_afterTradeDeadline() external { + // Transfers are no longer disabled + // function testTransfer_fails_afterTradeDeadline() external { + // uint8 nTiers = 10; + // address[] memory _users = new address[](nTiers); + + // DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(); + // (uint256 _projectId, DefifaDelegate _nft, ) = createDefifaProject( + // uint256(nTiers), + // getBasicDefifaLaunchData() + // ); + + // // Phase 1: minting + // vm.warp(defifaData.start - defifaData.mintDuration - defifaData.refundPeriodDuration); + + // for (uint256 i = 0; i < nTiers; i++) { + // // Generate a new address for each tier + // _users[i] = address(bytes20(keccak256(abi.encode('user', Strings.toString(i))))); + + // // fund user + // vm.deal(_users[i], 1 ether); + + // // Build metadata to buy specific NFT + // uint16[] memory rawMetadata = new uint16[](1); + // rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed + // bytes memory metadata = abi.encode( + // bytes32(0), + // bytes32(0), + // type(IJB721Delegate).interfaceId, + // false, + // false, + // false, + // rawMetadata + // ); + + // // Pay to the project and mint an NFT + // vm.prank(_users[i]); + // _terminals[0].pay{value: 1 ether}( + // _projectId, + // 1 ether, + // address(0), + // _users[i], + // 0, + // true, + // '', + // metadata + // ); + // } + + // // Phase 2: Redeem + // vm.warp(block.timestamp + defifaData.mintDuration); + // deployer.queueNextPhaseOf(_projectId); + + // // Make sure this is actually Phase 2 + // assertEq(_jbFundingCycleStore.currentOf(_projectId).number, 2); + + // // Phase 3: Start + // vm.warp(defifaData.start + 1); + // deployer.queueNextPhaseOf(_projectId); + + // // Make sure this is actually Phase 3 + // assertEq(_jbFundingCycleStore.currentOf(_projectId).number, 3); + + // uint256 _tokenIdToTransfer = _generateTokenId(1, 1); + // vm.prank(_users[0]); + // // trasnfers not possible in phase 3 + // vm.expectRevert(abi.encodeWithSignature('TRANSFERS_PAUSED()')); + // _nft.transferFrom(_users[0], _users[1], _tokenIdToTransfer); + // } + + function testSetRedemptionRates_fails_unmetQuorum() external { uint8 nTiers = 10; address[] memory _users = new address[](nTiers); - (uint256 _projectId, DefifaDelegate _nft, ) = createDefifaProject( + DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(); + (uint256 _projectId, DefifaDelegate _nft, DefifaGovernor _governor) = createDefifaProject( uint256(nTiers), - getBasicDefifaLaunchData() + defifaData ); - for (uint256 i = 0; i < nTiers; i++) { - // Generate a new address for each tier - _users[i] = address(bytes20(keccak256(abi.encode('user', Strings.toString(i))))); - - // fund user - vm.deal(_users[i], 1 ether); - - // Build metadata to buy specific NFT - uint16[] memory rawMetadata = new uint16[](1); - rawMetadata[0] = uint16(i + 1); // reward tier, 1 indexed - bytes memory metadata = abi.encode( - bytes32(0), - bytes32(0), - type(IJB721Delegate).interfaceId, - false, - false, - false, - rawMetadata - ); - - // Pay to the project and mint an NFT - vm.prank(_users[i]); - _terminals[0].pay{value: 1 ether}( - _projectId, - 1 ether, - address(0), - _users[i], - 0, - true, - '', - metadata - ); - } - - // Phase 2 - vm.warp(block.timestamp + 1 days); + // Phase 1: minting + vm.warp(defifaData.start - defifaData.mintDuration - defifaData.refundPeriodDuration); deployer.queueNextPhaseOf(_projectId); - // Make sure this is actually Phase 2 - assertEq(_jbFundingCycleStore.currentOf(_projectId).number, 2); - - // Phase 3 - vm.warp(block.timestamp + 1 weeks); - deployer.queueNextPhaseOf(_projectId); - - // Make sure this is actually Phase 3 - assertEq(_jbFundingCycleStore.currentOf(_projectId).number, 3); - - uint256 _tokenIdToTransfer = _generateTokenId(1, 1); - vm.prank(_users[0]); - // trasnfers not possible in phase 3 - vm.expectRevert(abi.encodeWithSignature('TRANSFERS_PAUSED()')); - _nft.transferFrom(_users[0], _users[1], _tokenIdToTransfer); - } - - function testSetRedemptionRates_fails_unmetQuorum(bool _useHelper) external { - uint8 nTiers = 10; - address[] memory _users = new address[](nTiers); - - (uint256 _projectId, DefifaDelegate _nft, DefifaGovernor _governor) = createDefifaProject( - uint256(nTiers), - getBasicDefifaLaunchData() - ); - for (uint256 i = 0; i < nTiers; i++) { // Generate a new address for each tier _users[i] = address(bytes20(keccak256(abi.encode('user', Strings.toString(i))))); @@ -500,18 +502,14 @@ contract DefifaGovernorTest is TestBaseWorkflow { assertEq(_governor.MAX_VOTING_POWER_TIER(), _governor.getVotes(_users[i], block.number - 1)); } - // Phase 2 - vm.warp(block.timestamp + 1 days); + // Phase 2: Redeem + vm.warp(block.timestamp + defifaData.mintDuration); deployer.queueNextPhaseOf(_projectId); - // Phase 3 - vm.warp(block.timestamp + 1 days); + // Phase 3: Start + vm.warp(defifaData.start + 1); deployer.queueNextPhaseOf(_projectId); - address[] memory targets = new address[](1); - uint256[] memory values = new uint256[](1); - bytes[] memory calldatas = new bytes[](1); - // Generate the scorecards DefifaTierRedemptionWeight[] memory scorecards = new DefifaTierRedemptionWeight[](nTiers); @@ -522,17 +520,7 @@ contract DefifaGovernorTest is TestBaseWorkflow { } // Forward time so proposals can be created - uint256 _proposalId; - if (_useHelper) { - _proposalId = _governor.submitScorecards(scorecards); - } else { - targets[0] = address(_nft); - calldatas[0] = abi.encodeCall(_nft.setTierRedemptionWeights, scorecards); - - // Create the proposal - _proposalId = _governor.propose(targets, values, calldatas, 'Governance!'); - } - + uint256 _proposalId = _governor.submitScorecards(scorecards); // Forward time so voting becomes active vm.roll(block.number + _governor.votingDelay() + 1); // '_governor.votingDelay()' internally uses the timestamp and not the block number, so we have to modify it for the next assert @@ -548,30 +536,31 @@ contract DefifaGovernorTest is TestBaseWorkflow { _governor.castVote(_proposalId, 0); } - // Phase 4 - vm.warp(block.timestamp + 1 weeks); - vm.roll(deployer.endOf(_projectId)); - deployer.queueNextPhaseOf(_projectId); + // Phase 4: End + vm.warp(deployer.endOf(_projectId)); + // Forward the amount of blocks needed to reach the end (and round up) + vm.roll(deployer.endOf(_projectId) - block.timestamp / 12 + 1); vm.warp(block.timestamp + 1 weeks); // Execute the proposal vm.expectRevert('Governor: proposal not successful'); - if (_useHelper) { - _governor.ratifyScorecard(scorecards); - } else { - _governor.execute(targets, values, calldatas, keccak256('Governance!')); - } + _governor.ratifyScorecard(scorecards); } - function testSetRedemptionRates_fails_declined(bool _useHelper) external { + function testSetRedemptionRates_fails_declined() external { uint8 nTiers = 10; address[] memory _users = new address[](nTiers); + DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(); (uint256 _projectId, DefifaDelegate _nft, DefifaGovernor _governor) = createDefifaProject( uint256(nTiers), - getBasicDefifaLaunchData() + defifaData ); + // Phase 1: minting + vm.warp(defifaData.start - defifaData.mintDuration - defifaData.refundPeriodDuration); + deployer.queueNextPhaseOf(_projectId); + for (uint256 i = 0; i < nTiers; i++) { // Generate a new address for each tier _users[i] = address(bytes20(keccak256(abi.encode('user', Strings.toString(i))))); @@ -620,18 +609,14 @@ contract DefifaGovernorTest is TestBaseWorkflow { assertEq(_governor.MAX_VOTING_POWER_TIER(), _governor.getVotes(_users[i], block.number - 1)); } - // Phase 2 - vm.warp(block.timestamp + 1 days); + // Phase 2: Redeem + vm.warp(block.timestamp + defifaData.mintDuration); deployer.queueNextPhaseOf(_projectId); - // Phase 3 - vm.warp(block.timestamp + 1 days); + // Phase 3: Start + vm.warp(defifaData.start + 1); deployer.queueNextPhaseOf(_projectId); - address[] memory targets = new address[](1); - uint256[] memory values = new uint256[](1); - bytes[] memory calldatas = new bytes[](1); - // Generate the scorecards DefifaTierRedemptionWeight[] memory scorecards = new DefifaTierRedemptionWeight[](nTiers); @@ -642,17 +627,7 @@ contract DefifaGovernorTest is TestBaseWorkflow { } // Forward time so proposals can be created - uint256 _proposalId; - if (_useHelper) { - _proposalId = _governor.submitScorecards(scorecards); - } else { - targets[0] = address(_nft); - calldatas[0] = abi.encodeCall(_nft.setTierRedemptionWeights, scorecards); - - // Create the proposal - _proposalId = _governor.propose(targets, values, calldatas, 'Governance!'); - } - + uint256 _proposalId = _governor.submitScorecards(scorecards); // Forward time so voting becomes active vm.roll(block.number + _governor.votingDelay() + 1); // '_governor.votingDelay()' internally uses the timestamp and not the block number, so we have to modify it for the next assert @@ -668,19 +643,14 @@ contract DefifaGovernorTest is TestBaseWorkflow { _governor.castVote(_proposalId, 0); } - // Phase 4 - vm.warp(block.timestamp + 1 weeks); + // Phase 4: End + vm.warp(deployer.endOf(_projectId)); vm.roll(deployer.endOf(_projectId)); - deployer.queueNextPhaseOf(_projectId); vm.warp(block.timestamp + 1 weeks); // Execute the proposal vm.expectRevert('Governor: proposal not successful'); - if (_useHelper) { - _governor.ratifyScorecard(scorecards); - } else { - _governor.execute(targets, values, calldatas, keccak256('Governance!')); - } + _governor.ratifyScorecard(scorecards); } function testSetRedemptionRatesAndRedeem_multipleTiers( @@ -699,11 +669,16 @@ contract DefifaGovernorTest is TestBaseWorkflow { address[] memory _users = new address[](nTiers); + DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(); (uint256 _projectId, DefifaDelegate _nft, DefifaGovernor _governor) = createDefifaProject( uint256(nTiers), - getBasicDefifaLaunchData() + defifaData ); + // Phase 1: minting + vm.warp(defifaData.start - defifaData.mintDuration - defifaData.refundPeriodDuration); + deployer.queueNextPhaseOf(_projectId); + for (uint256 i = 0; i < nTiers; i++) { // Generate a new address for each tier _users[i] = address(bytes20(keccak256(abi.encode('user', Strings.toString(i))))); @@ -748,12 +723,12 @@ contract DefifaGovernorTest is TestBaseWorkflow { // Have a user mint and refund the tier mintAndRefund(_nft, _projectId, 1); - // Phase 2 - vm.warp(block.timestamp + 1 days); + // Phase 2: Redeem + vm.warp(block.timestamp + defifaData.mintDuration); deployer.queueNextPhaseOf(_projectId); - // Phase 3 - vm.warp(block.timestamp + 1 days); + // Phase 3: Start + vm.warp(defifaData.start + 1); deployer.queueNextPhaseOf(_projectId); // Generate the scorecards @@ -790,10 +765,10 @@ contract DefifaGovernorTest is TestBaseWorkflow { _governor.castVote(_proposalId, 1); } - // Phase 4 - vm.warp(block.timestamp + 1 weeks); - vm.roll(deployer.endOf(_projectId)); - deployer.queueNextPhaseOf(_projectId); + // Phase 4: End + vm.warp(deployer.endOf(_projectId)); + // Forward the amount of blocks needed to reach the end (and round up) + vm.roll(deployer.endOf(_projectId) - block.timestamp / 12 + 1); vm.warp(block.timestamp + 1 weeks); _governor.ratifyScorecard(scorecards); @@ -859,11 +834,15 @@ contract DefifaGovernorTest is TestBaseWorkflow { address[] memory _users = new address[](nOfOtherTiers + nUsersWithWinningTier); + DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(); (uint256 _projectId, DefifaDelegate _nft, DefifaGovernor _governor) = createDefifaProject( uint256(nOfOtherTiers + 1), // All users will buying the same tier - getBasicDefifaLaunchData() + defifaData ); + // Phase 1: minting + vm.warp(defifaData.start - defifaData.mintDuration - defifaData.refundPeriodDuration); + for (uint256 i = 0; i < nOfOtherTiers + nUsersWithWinningTier; i++) { // Generate a new address for each tier _users[i] = address(bytes20(keccak256(abi.encode('user', Strings.toString(i))))); @@ -946,12 +925,12 @@ contract DefifaGovernorTest is TestBaseWorkflow { // Have a user mint and refund the tier mintAndRefund(_nft, _projectId, 1); - // Phase 2 - vm.warp(block.timestamp + 1 days); + // Phase 2: Redeem + vm.warp(block.timestamp + defifaData.mintDuration); deployer.queueNextPhaseOf(_projectId); - // Phase 3 - vm.warp(block.timestamp + 1 days); + // Phase 3: Start + vm.warp(defifaData.start + 1); deployer.queueNextPhaseOf(_projectId); // Generate the scorecards @@ -996,9 +975,10 @@ contract DefifaGovernorTest is TestBaseWorkflow { } } - // Phase 4 - vm.warp(block.timestamp + 1 weeks); - vm.roll(deployer.endOf(_projectId)); + // Phase 4: End + // Forward the amount of blocks needed to reach the end (and round up) + vm.roll(deployer.endOf(_projectId) - block.timestamp / 12 + 1); + vm.warp(deployer.endOf(_projectId)); deployer.queueNextPhaseOf(_projectId); vm.warp(block.timestamp + 1 weeks); @@ -1041,18 +1021,19 @@ contract DefifaGovernorTest is TestBaseWorkflow { _metadata: redemptionMetadata }); - // We calculate the expected output based on the given distribution and how much is in the pot - uint256 _expectedTierRedemption = (uint256(_users.length) * 1 ether * _tierWeight) / - totalWeight; - { - // If this is the winning tier then the amount is divided among the nUsersWithWinningTier - if (_tier == nOfOtherTiers + 1) - _expectedTierRedemption = _expectedTierRedemption / nUsersWithWinningTier; - } - - // Assert that our expected tier redemption is ~equal to the actual amount - // Allowing for some rounding errors, max allowed error is 0.000001 ether - assertLt(_expectedTierRedemption - _user.balance, 10**12); + // TODO: Uncomment below code and optimize to allow compiling without '--via-ir', had to temp comment this because compiltion is taking way too long + // // We calculate the expected output based on the given distribution and how much is in the pot + // uint256 _expectedTierRedemption = (uint256(_users.length) * 1 ether * _tierWeight) / + // totalWeight; + // { + // // If this is the winning tier then the amount is divided among the nUsersWithWinningTier + // if (_tier == nOfOtherTiers + 1) + // _expectedTierRedemption = _expectedTierRedemption / nUsersWithWinningTier; + // } + + // // Assert that our expected tier redemption is ~equal to the actual amount + // // Allowing for some rounding errors, max allowed error is 0.000001 ether + // assertLt(_expectedTierRedemption - _user.balance, 10**12); } // All NFTs should have been redeemed, only some dust should be left @@ -1084,9 +1065,8 @@ contract DefifaGovernorTest is TestBaseWorkflow { DefifaLaunchProjectData memory _launchData = DefifaLaunchProjectData({ projectMetadata: JBProjectMetadata({content: '', domain: 0}), mintDuration: _mintDuration, - start: _launchProjectAt + uint48(_mintDuration), - refundPeriodDuration: 1 days, - //tradeDeadline: _launchProjectAt + uint48(_mintDuration) + uint48(_inBetweenMintAndFifa), + start: _launchProjectAt + uint48(_mintDuration) + _inBetweenMintAndFifa, + refundPeriodDuration: _inBetweenMintAndFifa, end: _end, holdFees: false, splits: new JBSplit[](0), @@ -1141,10 +1121,15 @@ contract DefifaGovernorTest is TestBaseWorkflow { uint8 nTiers = 10; address[] memory _users = new address[](nTiers); + DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(); (uint256 _projectId, DefifaDelegate _nft, DefifaGovernor _governor) = createDefifaProject( uint256(nTiers), - getBasicDefifaLaunchData() + defifaData ); + + // Phase 1: Mint + vm.warp(defifaData.start - defifaData.mintDuration - defifaData.refundPeriodDuration); + deployer.queueNextPhaseOf(_projectId); for (uint256 i = 0; i < nTiers; i++) { // Generate a new address for each tier @@ -1194,13 +1179,12 @@ contract DefifaGovernorTest is TestBaseWorkflow { assertEq(_governor.MAX_VOTING_POWER_TIER(), _governor.getVotes(_users[i], block.number - 1)); } - // Phase 2 - vm.roll(block.number + 5); - vm.warp(block.timestamp + 600); + // Phase 2: Redeem + vm.warp(block.timestamp + defifaData.mintDuration); deployer.queueNextPhaseOf(_projectId); - vm.roll(block.number + 5); - vm.warp(block.timestamp + 600); + // Right at the end of Phase 2 + vm.warp(defifaData.start - 1); vm.expectRevert(abi.encodeWithSignature('PHASE_ALREADY_QUEUED()')); deployer.queueNextPhaseOf(_projectId); } @@ -1209,10 +1193,15 @@ contract DefifaGovernorTest is TestBaseWorkflow { uint8 nTiers = 10; address[] memory _users = new address[](nTiers); + DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(); (uint256 _projectId, DefifaDelegate _nft, DefifaGovernor _governor) = createDefifaProject( uint256(nTiers), - getBasicDefifaLaunchData() + defifaData ); + + // Phase 1: Mint + vm.warp(defifaData.start - defifaData.mintDuration - defifaData.refundPeriodDuration); + deployer.queueNextPhaseOf(_projectId); for (uint256 i = 0; i < nTiers; i++) { // Generate a new address for each tier @@ -1262,12 +1251,12 @@ contract DefifaGovernorTest is TestBaseWorkflow { assertEq(_governor.MAX_VOTING_POWER_TIER(), _governor.getVotes(_users[i], block.number - 1)); } - // Phase 2 - vm.warp(block.timestamp + 1 days); + // Phase 2: Redeem + vm.warp(block.timestamp + defifaData.mintDuration); deployer.queueNextPhaseOf(_projectId); - // Phase 3 - vm.warp(block.timestamp + 1 days); + // Phase 3: Start + vm.warp(defifaData.start + 1); deployer.queueNextPhaseOf(_projectId); // Generate the scorecards @@ -1306,10 +1295,15 @@ contract DefifaGovernorTest is TestBaseWorkflow { uint8 nTiers = 10; address[] memory _users = new address[](nTiers); + DefifaLaunchProjectData memory defifaData = getBasicDefifaLaunchData(); (uint256 _projectId, DefifaDelegate _nft, DefifaGovernor _governor) = createDefifaProject( uint256(nTiers), - getBasicDefifaLaunchData() + defifaData ); + + // Phase 1: Mint + vm.warp(defifaData.start - defifaData.mintDuration - defifaData.refundPeriodDuration); + deployer.queueNextPhaseOf(_projectId); for (uint256 i = 0; i < nTiers; i++) { // Generate a new address for each tier @@ -1359,12 +1353,12 @@ contract DefifaGovernorTest is TestBaseWorkflow { assertEq(_governor.MAX_VOTING_POWER_TIER(), _governor.getVotes(_users[i], block.number - 1)); } - // Phase 2 - vm.warp(block.timestamp + 1 days); + // Phase 2: Redeem + vm.warp(block.timestamp + defifaData.mintDuration); deployer.queueNextPhaseOf(_projectId); - // Phase 3 - vm.warp(block.timestamp + 1 days); + // Phase 3: Start + vm.warp(defifaData.start + 1); deployer.queueNextPhaseOf(_projectId); // Generate the scorecards @@ -1397,10 +1391,9 @@ contract DefifaGovernorTest is TestBaseWorkflow { _governor.castVote(_proposalId, 1); } - // Phase 4 - vm.warp(block.timestamp + 1 weeks); + // Phase 4: End + vm.warp(deployer.endOf(_projectId)); vm.roll(deployer.endOf(_projectId)); - deployer.queueNextPhaseOf(_projectId); vm.warp(block.timestamp + 1 weeks); // Execute the proposal @@ -1413,10 +1406,10 @@ contract DefifaGovernorTest is TestBaseWorkflow { DefifaLaunchProjectData({ projectMetadata: JBProjectMetadata({content: '', domain: 0}), mintDuration: 1 days, - start: uint48(block.timestamp + 2 days), + start: uint48(block.timestamp + 3 days), refundPeriodDuration: 1 days, //tradeDeadline: uint48(block.timestamp + 1 days), - end: uint48(block.timestamp + 2 days + 1 weeks), + end: uint48(block.timestamp + 3 days + 1 weeks), holdFees: false, splits: new JBSplit[](0), distributionLimit: 0, @@ -1455,6 +1448,10 @@ contract DefifaGovernorTest is TestBaseWorkflow { // Get a reference to the latest configured funding cycle's data source, which should be the delegate that was deployed and attached to the project. JBFundingCycle memory _fc = _jbFundingCycleStore.currentOf(projectId); + if (_fc.dataSource() == address(0)) { + _fc = _jbFundingCycleStore.queuedOf(projectId); + } + // Deploy the governor governor = new DefifaGovernor(DefifaDelegate(_fc.dataSource()), uint48(block.timestamp + 10 days + 1 weeks)); @@ -1602,7 +1599,6 @@ contract DefifaGovernorTest is TestBaseWorkflow { reservedTokenBeneficiary: reserveBeneficiary, store: new JBTiered721DelegateStore(), flags: JBTiered721Flags({ - preventOverspending: false, lockReservedTokenChanges: false, lockVotingUnitChanges: false, lockManualMintingChanges: false From cca0102c97884445011d24649c2bc7ac6e23dc32 Mon Sep 17 00:00:00 2001 From: viraj124 Date: Thu, 5 Jan 2023 09:35:13 +0530 Subject: [PATCH 20/21] fix: stack too deep in tests --- contracts/forge-test/DefifaGovernor.t.sol | 29 ++++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/contracts/forge-test/DefifaGovernor.t.sol b/contracts/forge-test/DefifaGovernor.t.sol index 74511f7..68f28fc 100644 --- a/contracts/forge-test/DefifaGovernor.t.sol +++ b/contracts/forge-test/DefifaGovernor.t.sol @@ -980,7 +980,8 @@ contract DefifaGovernorTest is TestBaseWorkflow { ); redemptionMetadata = abi.encode(bytes32(0), type(IJB721Delegate).interfaceId, redemptionId); } - + uint256 _expectedTierRedemption; + { // Calculate how much weight his tier has uint256 _tierWeight = _tier == nOfOtherTiers + 1 ? uint256(baseRedemptionWeight) + uint256(winningTierExtraWeight) @@ -1001,19 +1002,19 @@ contract DefifaGovernorTest is TestBaseWorkflow { _metadata: redemptionMetadata }); - // TODO: Uncomment below code and optimize to allow compiling without '--via-ir', had to temp comment this because compiltion is taking way too long - // // We calculate the expected output based on the given distribution and how much is in the pot - // uint256 _expectedTierRedemption = (uint256(_users.length) * 1 ether * _tierWeight) / - // totalWeight; - // { - // // If this is the winning tier then the amount is divided among the nUsersWithWinningTier - // if (_tier == nOfOtherTiers + 1) - // _expectedTierRedemption = _expectedTierRedemption / nUsersWithWinningTier; - // } - - // // Assert that our expected tier redemption is ~equal to the actual amount - // // Allowing for some rounding errors, max allowed error is 0.000001 ether - // assertLt(_expectedTierRedemption - _user.balance, 10**12); + // We calculate the expected output based on the given distribution and how much is in the pot + _expectedTierRedemption = (uint256(_users.length) * 1 ether * _tierWeight) / + totalWeight; + } + { + // If this is the winning tier then the amount is divided among the nUsersWithWinningTier + if (_tier == nOfOtherTiers + 1) + _expectedTierRedemption = _expectedTierRedemption / nUsersWithWinningTier; + } + + // Assert that our expected tier redemption is ~equal to the actual amount + // Allowing for some rounding errors, max allowed error is 0.000001 ether + assertLt(_expectedTierRedemption - _user.balance, 10**12); } // All NFTs should have been redeemed, only some dust should be left From 7bd6fb5d92a6a71446752310791ae068ee02b99e Mon Sep 17 00:00:00 2001 From: viraj124 Date: Thu, 5 Jan 2023 10:49:23 +0530 Subject: [PATCH 21/21] chore: attest with a fixed set of tier id's --- contracts/DefifaGovernor.sol | 11 +++++++++++ contracts/interfaces/IDefifaGovernor.sol | 2 ++ 2 files changed, 13 insertions(+) diff --git a/contracts/DefifaGovernor.sol b/contracts/DefifaGovernor.sol index 06e0230..9156c3a 100644 --- a/contracts/DefifaGovernor.sol +++ b/contracts/DefifaGovernor.sol @@ -120,6 +120,17 @@ contract DefifaGovernor is Governor, GovernorCountingSimple, IDefifaGovernor { super._castVote(_scorecardId, msg.sender, 1, '', _defaultParams()); } + /** + @notice + Attests to a scorecard with the set of ordered tier id's. + + @param _scorecardId The scorecard ID. + */ + function attestToScorecardWithReasonAndParams(uint256 _scorecardId, bytes memory params) external override { + // Vote. + super._castVote(_scorecardId, msg.sender, 1, '', params); + } + /** @notice Ratifies a scorecard that has been approved. diff --git a/contracts/interfaces/IDefifaGovernor.sol b/contracts/interfaces/IDefifaGovernor.sol index a1efe74..965449e 100644 --- a/contracts/interfaces/IDefifaGovernor.sol +++ b/contracts/interfaces/IDefifaGovernor.sol @@ -17,6 +17,8 @@ interface IDefifaGovernor { function attestToScorecard(uint256 _scorecardId) external; + function attestToScorecardWithReasonAndParams(uint256 _scorecardId, bytes memory params) external; + function ratifyScorecard(DefifaTierRedemptionWeight[] calldata _tierWeights) external returns (uint256);