-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: init * chore: init of Imultiplier @secbajor * chore: implementing interfaces from #71 * chore: init permanftmul impl * chore: tmp commit * fix: reverting auto changes to yd * fix: changing to interface * fix: fixing imports * chore: init derived interfaces * fix: changing variable name" * fix: removing ref to external, impl in implemtations * chore: first multiplier * chore: Adding voting multiplier handling and integration to yd * fix: amending functionality to handle no multiplier for voter properly * chore: adding unit and fuzzy tests * chore: adding basic NFTMultiplier implementation, deploy script and config with tests Changes to be committed: * fix: updating wrong documentation * fix: reducing scope of pr * fix: order of operations clarification * chore: adding gas benchmark tests for mutipliers * rename: using PRECISION instead of hardcoded 1e18 for clarity" * chore: removing external calls by declaring public * chore: renaming outdating convention * chore: including prefix for function param and fixing up previous commit rename * chore: renaming constant to fit camel case convention * chore: refactoring constant to snake case * style: underscore for internal vars" * docs: updating authors * chore: removing voting multiplier gas snapshot testing * style: internal / function-scoped variables should have underscore * perf: optimizing init variable validation * Revert "perf: optimizing init variable validation" This reverts commit de0309d. * chore: introducing offchain indexing of multipliers to be bundled with voting function to prevent on-chain iteriations * fmt: removing underscore from natspec comment * fmt: moving func closer to similiar func and documenting func * fmt: removing line break * fmt: removing line break * fmt: removing line break * fmt: removing line break * fmt: removing line break * fmt: removing line break * chore: fixing checking of minimum voting power to include voting multipliers * chore: unclear why this is needed as it should have been merged from dev, reintroducing * chore: attempting to revert changes from upstream * chore: attempting to remove more unclear merge issues --------- Co-authored-by: Ron Turetzky <[email protected]>
- Loading branch information
1 parent
59eeba7
commit 4da5fa7
Showing
17 changed files
with
6,054 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.22; | ||
|
||
import {Script} from "forge-std/Script.sol"; | ||
import {NFTMultiplier} from "src/multipliers/NFTMultiplier.sol"; | ||
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; | ||
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; | ||
import {console} from "forge-std/console.sol"; | ||
|
||
contract DeployNFTMultiplier is Script { | ||
function run() external { | ||
uint256 deployerPrivateKey; | ||
address nftContractAddress; | ||
uint256 initialMultiplyingFactor; | ||
uint256 validUntilBlock; | ||
|
||
string memory configPath = "deploy_config.json"; | ||
string memory jsonData; | ||
// Try to read the JSON file, if it doesn't exist or can't be read, catch the error | ||
try vm.readFile(configPath) returns (string memory data) { | ||
jsonData = data; | ||
} catch { | ||
console.log("Config file not found or couldn't be read. Falling back to environment variables."); | ||
jsonData = ""; | ||
} | ||
|
||
if (bytes(jsonData).length > 0) { | ||
// Read from JSON if file exists | ||
deployerPrivateKey = vm.parseJsonUint(jsonData, ".deployerPrivateKey"); | ||
nftContractAddress = vm.parseJsonAddress(jsonData, ".nftContractAddress"); | ||
initialMultiplyingFactor = vm.parseJsonUint(jsonData, ".initialMultiplyingFactor"); | ||
validUntilBlock = vm.parseJsonUint(jsonData, ".validUntilBlock"); | ||
} else { | ||
// Fall back to environment variables | ||
deployerPrivateKey = vm.envUint("PRIVATE_KEY"); | ||
nftContractAddress = vm.envAddress("NFT_CONTRACT_ADDRESS"); | ||
initialMultiplyingFactor = vm.envUint("INITIAL_MULTIPLYING_FACTOR"); | ||
validUntilBlock = vm.envUint("VALID_UNTIL_BLOCK"); | ||
} | ||
|
||
// Check if all required variables are set | ||
require(deployerPrivateKey != 0, "Deployer private key not set"); | ||
require(nftContractAddress != address(0), "NFT contract address not set"); | ||
require(initialMultiplyingFactor != 0, "Initial multiplying factor not set"); | ||
require(validUntilBlock != 0, "Valid until block not set"); | ||
|
||
vm.startBroadcast(deployerPrivateKey); | ||
|
||
NFTMultiplier implementation = new NFTMultiplier(); | ||
|
||
bytes memory initData = abi.encodeWithSelector( | ||
NFTMultiplier.initialize.selector, IERC721(nftContractAddress), initialMultiplyingFactor, validUntilBlock | ||
); | ||
|
||
TransparentUpgradeableProxy proxy = | ||
new TransparentUpgradeableProxy(address(implementation), vm.addr(deployerPrivateKey), initData); | ||
|
||
NFTMultiplier nftMultiplier = NFTMultiplier(address(proxy)); | ||
|
||
vm.stopBroadcast(); | ||
|
||
console.log("NFTMultiplier deployed at:", address(nftMultiplier)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"deployerPrivateKey": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", | ||
"nftContractAddress": "0x1234567890123456789012345678901234567890", | ||
"initialMultiplyingFactor": 100, | ||
"validUntilBlock": 1000000 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.22; | ||
|
||
import {IVotingMultipliers, IMultiplier} from "src/interfaces/IVotingMultipliers.sol"; | ||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; | ||
|
||
/// @title VotingMultipliers | ||
/// @notice A contract for managing voting multipliers | ||
/// @dev Implements IVotingMultipliers interface | ||
contract VotingMultipliers is OwnableUpgradeable, IVotingMultipliers { | ||
/// @notice Array of allowlisted multiplier contracts | ||
IMultiplier[] public allowlistedMultipliers; | ||
|
||
/// @notice Adds a multiplier to the allowlist | ||
/// @param _multiplier The multiplier contract to be added | ||
function addMultiplier(IMultiplier _multiplier) external onlyOwner { | ||
// Check if the multiplier is already allowlisted | ||
for (uint256 i = 0; i < allowlistedMultipliers.length; i++) { | ||
if (allowlistedMultipliers[i] == _multiplier) { | ||
revert MultiplierAlreadyAllowlisted(); | ||
} | ||
} | ||
allowlistedMultipliers.push(_multiplier); | ||
emit MultiplierAdded(_multiplier); | ||
} | ||
|
||
/// @notice Removes a multiplier from the allowlist | ||
/// @param _multiplier The multiplier contract to be removed | ||
function removeMultiplier(IMultiplier _multiplier) external onlyOwner { | ||
bool isallowlisted = false; | ||
for (uint256 i = 0; i < allowlistedMultipliers.length; i++) { | ||
if (allowlistedMultipliers[i] == _multiplier) { | ||
allowlistedMultipliers[i] = allowlistedMultipliers[allowlistedMultipliers.length - 1]; | ||
allowlistedMultipliers.pop(); | ||
isallowlisted = true; | ||
emit MultiplierRemoved(_multiplier); | ||
break; | ||
} | ||
} | ||
if (!isallowlisted) { | ||
revert MultiplierNotAllowlisted(); | ||
} | ||
} | ||
|
||
/// @notice Gets the indexes of valid multipliers for a user | ||
/// @param _user The address of the user | ||
/// @return uint256[] Array of valid multiplier indexes | ||
function getValidMultiplierIndexes(address _user) public view returns (uint256[] memory) { | ||
uint256[] memory validIndexes = new uint256[](allowlistedMultipliers.length); | ||
uint256 count = 0; | ||
|
||
for (uint256 i = 0; i < allowlistedMultipliers.length; i++) { | ||
if ( | ||
block.number <= allowlistedMultipliers[i].validUntil(_user) | ||
&& allowlistedMultipliers[i].getMultiplyingFactor(_user) > 0 | ||
) { | ||
validIndexes[count] = i; | ||
count++; | ||
} | ||
} | ||
|
||
// Create correctly sized array | ||
uint256[] memory result = new uint256[](count); | ||
for (uint256 i = 0; i < count; i++) { | ||
result[i] = validIndexes[i]; | ||
} | ||
return result; | ||
} | ||
|
||
/// @notice Calculates the total multiplier for a given user using specific multiplier indexes | ||
/// @param _user The address of the user | ||
/// @param _multiplierIndexes Array of multiplier indexes to use | ||
/// @return The total multiplier value for the user | ||
function getTotalMultipliers(address _user, uint256[] calldata _multiplierIndexes) public view returns (uint256) { | ||
uint256 _totalMultiplier = 0; | ||
|
||
for (uint256 i = 0; i < _multiplierIndexes.length; i++) { | ||
uint256 index = _multiplierIndexes[i]; | ||
if (index >= allowlistedMultipliers.length) { | ||
revert InvalidMultiplierIndex(); | ||
} | ||
|
||
IMultiplier multiplier = allowlistedMultipliers[index]; | ||
if (block.number <= multiplier.validUntil(_user)) { | ||
_totalMultiplier += multiplier.getMultiplyingFactor(_user); | ||
} | ||
} | ||
return _totalMultiplier; | ||
} | ||
|
||
/// @notice Calculates the total multiplier for a given user | ||
/// @param _user The address of the _user | ||
/// @return The total multiplier value for the _user | ||
/// @dev This function is intended for frontend and testing purposes | ||
function getTotalMultipliers(address _user) public view returns (uint256) { | ||
uint256 _totalMultiplier = 0; | ||
for (uint256 i = 0; i < allowlistedMultipliers.length; i++) { | ||
IMultiplier multiplier = allowlistedMultipliers[i]; | ||
if (block.number <= multiplier.validUntil(_user)) { | ||
_totalMultiplier += multiplier.getMultiplyingFactor(_user); | ||
} | ||
} | ||
return _totalMultiplier; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
pragma solidity ^0.8.22; | ||
|
||
import {IMultiplier} from "./multipliers/IMultiplier.sol"; | ||
|
||
/// @title IVotingMultipliers | ||
/// @notice Interface for the VotingMultipliers contract | ||
/// @dev This interface defines the structure and functions for managing voting multipliers | ||
interface IVotingMultipliers { | ||
/// @notice Thrown when attempting to add a multiplier that is already allowlisted | ||
error MultiplierAlreadyAllowlisted(); | ||
/// @notice Thrown when attempting to remove a multiplier that is not allowlisted | ||
error MultiplierNotAllowlisted(); | ||
/// @notice Thrown when an invalid multiplier index is provided | ||
error InvalidMultiplierIndex(); | ||
/// @notice Emitted when a new multiplier is added to the allowlist | ||
/// @param multiplier The address of the added multiplier | ||
event MultiplierAdded(IMultiplier indexed multiplier); | ||
/// @notice Emitted when a multiplier is removed from the allowlist | ||
/// @param multiplier The address of the removed multiplier | ||
event MultiplierRemoved(IMultiplier indexed multiplier); | ||
/// @notice Returns the multiplier at the specified index in the allowlist | ||
/// @param index The index of the multiplier in the allowlist | ||
/// @return The multiplier contract at the specified index | ||
function allowlistedMultipliers(uint256 index) external view returns (IMultiplier); | ||
/// @notice Calculates the total multiplier for a given _user | ||
/// @param __user The address of the _user | ||
/// @return The total multiplier value for the _user | ||
function getTotalMultipliers(address __user) external view returns (uint256); | ||
/// @notice Adds a multiplier to the allowlist | ||
/// @param _multiplier The multiplier contract to be added | ||
function addMultiplier(IMultiplier _multiplier) external; | ||
/// @notice Removes a multiplier from the allowlist | ||
/// @param _multiplier The multiplier contract to be removed | ||
function removeMultiplier(IMultiplier _multiplier) external; | ||
} |
12 changes: 12 additions & 0 deletions
12
src/interfaces/multipliers/ICrossChainProveableMultiplier.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.22; | ||
|
||
import {IProveableMultiplier} from "src/interfaces/multipliers/IProveableMultiplier.sol"; | ||
|
||
/// @title Cross-Chain Proveable Multiplier Interface | ||
/// @notice Interface for contracts that provide a cross-chain proveable multiplying factor | ||
interface ICrossChainProveableMultiplier is IProveableMultiplier { | ||
/// @notice Get the address of the bridge contract | ||
/// @return The address of the contract used for cross-chain communication | ||
function bridge() external view returns (address); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.22; | ||
|
||
import {INFTMultiplier} from "src/interfaces/multipliers/INFTMultiplier.sol"; | ||
/// @title Dynamic NFT Multiplier Interface | ||
/// @notice Interface for contracts that provide a dynamic multiplying factor for _users based on NFT ownership | ||
/// @dev Extends the INFTMultiplier interface with dynamic multiplier functionality | ||
interface IDynamicNFTMultiplier is INFTMultiplier { | ||
/// @notice Get the multiplying factor for a _user | ||
/// @param _user The address of the _user | ||
/// @return The multiplying factor for the _user | ||
function _userToFactor(address _user) external view returns (uint256); | ||
|
||
/// @notice Get the validity period for a _user's factor | ||
/// @param _user The address of the _user | ||
/// @return The timestamp until which the _user's factor is valid | ||
function _userToValidity(address _user) external view returns (uint256); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
interface IMultiplier { | ||
/// @notice Returns the voting multiplier for `_user`. | ||
function getMultiplyingFactor(address _user) external view returns (uint256); | ||
|
||
/// @notice Returns the validity period of the multiplier for `_user`. | ||
function validUntil(address _user) external view returns (uint256); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.22; | ||
|
||
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; | ||
import {IMultiplier} from "src/interfaces/multipliers/IMultiplier.sol"; | ||
|
||
/// @title NFT Multiplier Interface | ||
/// @notice Interface for contracts that provide multiplying factors based on NFT ownership | ||
/// @dev Extends the IMultiplier interface with NFT-specific functionality | ||
interface INFTMultiplier is IMultiplier { | ||
/// @notice Get the address of the NFT contract | ||
/// @return The address of the NFT contract used for checking ownership | ||
function NFT_ADDRESS() external view returns (IERC721); | ||
|
||
/// @notice Check if a _user owns an NFT | ||
/// @param _user The address of the _user to check | ||
/// @return True if the _user owns at least one NFT, false otherwise | ||
function hasNFT(address _user) external view returns (bool); | ||
} |
12 changes: 12 additions & 0 deletions
12
src/interfaces/multipliers/IOffChainProveableMultiplier.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.22; | ||
|
||
import {IProveableMultiplier} from "src/interfaces/multipliers/IProveableMultiplier.sol"; | ||
|
||
/// @title Off-Chain Proveable Multiplier Interface | ||
/// @notice Interface for contracts that provide an off-chain proveable multiplying factor | ||
interface IOffChainProveableMultiplier is IProveableMultiplier { | ||
/// @notice Get the address of the pull oracle | ||
/// @return The address of the oracle used for off-chain data verification | ||
function oracle() external view returns (address); | ||
} |
11 changes: 11 additions & 0 deletions
11
src/interfaces/multipliers/IOnChainProveableMultiplier.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.22; | ||
|
||
import {IProveableMultiplier} from "src/interfaces/multipliers/IProveableMultiplier.sol"; | ||
/// @title On-Chain Proveable Multiplier Interface | ||
/// @notice Interface for contracts that provide an on-chain proveable multiplying factor | ||
interface IOnChainProveableMultiplier is IProveableMultiplier { | ||
/// @notice Get the address of the activity contract | ||
/// @return The address of the contract used for verifying on-chain activities | ||
function activityContract() external view returns (address); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.22; | ||
|
||
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; | ||
import {IDynamicNFTMultiplier} from "src/interfaces/multipliers/IDynamicNFTMultiplier.sol"; | ||
/// @title Proveable Multiplier Interface | ||
/// @notice Interface for contracts that provide a proveable multiplying factor based on _user activities | ||
interface IProveableMultiplier is IERC721, IDynamicNFTMultiplier { | ||
/// @notice Submit activities to potentially earn or upgrade an NFT | ||
/// @param data Encoded data representing the activities | ||
function submitActivities(bytes calldata data) external; | ||
} |
Oops, something went wrong.