Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Voting Multipliers #100

Open
wants to merge 35 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
47bdbff
chore: init
Sep 23, 2024
0aa29f4
chore: init of Imultiplier @secbajor
RonTuretzky Sep 28, 2024
2534725
chore: implementing interfaces from #71
RonTuretzky Sep 28, 2024
bc9abf8
chore: init permanftmul impl
RonTuretzky Sep 28, 2024
12fa7ea
chore: tmp commit
RonTuretzky Sep 28, 2024
faf437f
fix: reverting auto changes to yd
RonTuretzky Sep 28, 2024
8c89ed0
fix: changing to interface
RonTuretzky Sep 28, 2024
8dd45db
fix: fixing imports
RonTuretzky Sep 28, 2024
e0d2527
chore: init derived interfaces
RonTuretzky Sep 28, 2024
3906049
fix: changing variable name"
RonTuretzky Sep 28, 2024
3f06af0
fix: removing ref to external, impl in implemtations
RonTuretzky Sep 28, 2024
0cc8661
chore: first multiplier
RonTuretzky Sep 28, 2024
6f95cc5
chore: Adding voting multiplier handling and integration to yd
RonTuretzky Sep 28, 2024
1c6c8c0
fix: amending functionality to handle no multiplier for voter properly
RonTuretzky Sep 28, 2024
fffe13b
chore: adding unit and fuzzy tests
RonTuretzky Sep 28, 2024
fc1221b
chore: adding basic NFTMultiplier implementation, deploy script and c…
RonTuretzky Sep 28, 2024
daeb1ce
fix: updating wrong documentation
RonTuretzky Sep 28, 2024
cf53a4f
fix: reducing scope of pr
RonTuretzky Sep 28, 2024
dce84d8
Merge branch 'dev' into feat/voting_multiplier
RonTuretzky Oct 24, 2024
3d92685
merge: merging dev
RonTuretzky Oct 24, 2024
bf324f1
fix: order of operations clarification
RonTuretzky Oct 26, 2024
5b9b7b3
chore: adding gas benchmark tests for mutipliers
RonTuretzky Oct 29, 2024
12bfd60
rename: using PRECISION instead of hardcoded 1e18 for clarity"
RonTuretzky Dec 1, 2024
50787c1
chore: removing external calls by declaring public
RonTuretzky Dec 1, 2024
47333b3
chore: renaming outdating convention
RonTuretzky Dec 1, 2024
967d6cc
chore: including prefix for function param and fixing up previous com…
RonTuretzky Dec 1, 2024
706cd8e
chore: renaming constant to fit camel case convention
RonTuretzky Dec 1, 2024
2d04f5c
chore: refactoring constant to snake case
RonTuretzky Dec 1, 2024
6e78550
style: underscore for internal vars"
RonTuretzky Dec 1, 2024
ec07fb1
docs: updating authors
RonTuretzky Dec 1, 2024
f867e06
chore: removing voting multiplier gas snapshot testing
RonTuretzky Dec 1, 2024
80b7345
style: internal / function-scoped variables should have underscore
RonTuretzky Dec 1, 2024
de0309d
perf: optimizing init variable validation
RonTuretzky Dec 1, 2024
1c5f5cd
Revert "perf: optimizing init variable validation"
RonTuretzky Dec 1, 2024
0d4836e
chore: introducing offchain indexing of multipliers to be bundled wit…
RonTuretzky Dec 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions script/deploy/DeployNFTMultiplier.s.sol
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));
}
}
6 changes: 6 additions & 0 deletions script/deploy/config/deployNFTMul.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"deployerPrivateKey": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"nftContractAddress": "0x1234567890123456789012345678901234567890",
"initialMultiplyingFactor": 100,
"validUntilBlock": 1000000
}
104 changes: 104 additions & 0 deletions src/VotingMultipliers.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// 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 {
bagelface marked this conversation as resolved.
Show resolved Hide resolved
/// @notice Array of allowlisted multiplier contracts
IMultiplier[] public allowlistedMultipliers;

/// @notice Calculates the total multiplier for a given _user
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop the underscore form _user when referring to it in the comments to be consistent with other comments.

/// @param _user The address of the _user
/// @return The total multiplier value for the _user
function getTotalMultipliers(address _user) public view returns (uint256) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming we keeping this as a quality of life function so we can avoid the double query getValidMultiplierIndexes(address) -> getTotalMultipliers(address, uint256[])? If so, I think this should be moved to be closer to getTotalMultipliers(address, uint256[]) so the overload is obvious. Maybe word adding a note in the natspec comments with a @dev tag

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;
}

/// @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;
}
}
32 changes: 25 additions & 7 deletions src/YieldDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,20 @@ import {ERC20VotesUpgradeable} from
import {Bread} from "bread-token/src/Bread.sol";

import {IYieldDistributor} from "src/interfaces/IYieldDistributor.sol";
import {VotingMultipliers} from "src/VotingMultipliers.sol";

/**
* @title Breadchain Yield Distributor
* @notice Distribute $BREAD yield to eligible member projects based on a voted distribution
* @author Breadchain Collective
* @custom:coauthor @RonTuretzky
* @custom:coauthor postcapitalistcrypto.eth
* @custom:coauthor bagelface.eth
* @custom:coauthor prosalads.eth
* @custom:coauthor kassandra.eth
* @custom:coauthor theblockchainsocialist.eth
* @custom:coauthor github.com/daopunk
*/
contract YieldDistributor is IYieldDistributor, OwnableUpgradeable {
contract YieldDistributor is IYieldDistributor, OwnableUpgradeable, VotingMultipliers {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH I'm a little dubious of the upgrade safety here. It would probably be best to implement VotingMultipliers to use ERC7201 storage layouts (like they do with OwnableUpgradeable) to avoid storage layout collisions. It seems complicated but it's actually a pretty trivial one time calculation and some boilerplate code for accessing storage variables.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking we should just deploy a new proxy for this version, and use the setter on the bread contract, as this would also help us resolve #96

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a foreseeable problem deploying as a new proxy, thus changing the address? if there is not, i would prefer we deploy fresh, therefore do not need to worry about upgrade-safety, and not over-complicated things. but again, this is assuming there is no major problem with changing the address.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploying a new contract is definitely the move in this instance but I mean in future instances where we maybe want to make some changes to the VotingMultipliers.sol contract. Namespacing the storage layouts ensure YieldDistributor and VotingMultipliers are using their own storage locations that won't clash, so if we want to add a variable to one or the other, we can do so safely. I can make a quick branch so show what it would look like.

Copy link
Contributor

@bagelface bagelface Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think there is a strong case to be made for VotingMultipliers to be its own contract.

/// @notice The address of the $BREAD token contract
Bread public BREAD;
RonTuretzky marked this conversation as resolved.
Show resolved Hide resolved
/// @notice The precision to use for calculations
Expand Down Expand Up @@ -110,17 +112,20 @@ contract YieldDistributor is IYieldDistributor, OwnableUpgradeable {
* @return uint256 The voting power of the user
*/
function getCurrentVotingPower(address _account) public view returns (uint256) {
return this.getVotingPowerForPeriod(BREAD, previousCycleStartingBlock, lastClaimedBlockNumber, _account)
+ this.getVotingPowerForPeriod(BUTTERED_BREAD, previousCycleStartingBlock, lastClaimedBlockNumber, _account);
uint256 lastCycleStart = lastClaimedBlockNumber - cycleLength;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realizing this will be invalid if cycleLength is changed. We need a "lastCycleLength" variable. Maybe it'd be good to create a Cycle struct?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should open a separate issue for this ... also mark it as bug so we don't upgrade changes without considering this...

uint256 breadVotingPower = getVotingPowerForPeriod(BREAD, lastCycleStart, lastClaimedBlockNumber, _account);
uint256 butteredBreadVotingPower =
getVotingPowerForPeriod(BUTTERED_BREAD, lastCycleStart, lastClaimedBlockNumber, _account);
return breadVotingPower + butteredBreadVotingPower;
}

/// @notice Get the current accumulated voting power for a user
/// @dev This is the voting power that has been accumulated since the last yield distribution
/// @param _account Address of the user to get the current accumulated voting power for
/// @return uint256 The current accumulated voting power for the user
function getCurrentAccumulatedVotingPower(address _account) public view returns (uint256) {
return this.getVotingPowerForPeriod(BUTTERED_BREAD, lastClaimedBlockNumber, block.number, _account)
+ this.getVotingPowerForPeriod(BREAD, lastClaimedBlockNumber, block.number, _account);
return getVotingPowerForPeriod(BUTTERED_BREAD, lastClaimedBlockNumber, block.number, _account)
+ getVotingPowerForPeriod(BREAD, lastClaimedBlockNumber, block.number, _account);
}

/**
Expand All @@ -135,7 +140,7 @@ contract YieldDistributor is IYieldDistributor, OwnableUpgradeable {
uint256 _start,
uint256 _end,
address _account
) external view returns (uint256) {
) public view returns (uint256) {
if (_start >= _end) revert StartMustBeBeforeEnd();
if (_end > block.number) revert EndAfterCurrentBlock();

Expand Down Expand Up @@ -227,6 +232,19 @@ contract YieldDistributor is IYieldDistributor, OwnableUpgradeable {
_castVote(msg.sender, _points, _currentVotingPower);
}

/**
* @notice Cast votes for the distribution of $BREAD yield with multipliers
* @param _points List of points as integers for each project
* @param _multiplierIndices List of indices of multipliers to use for each project
*/
function castVoteWithMultipliers(uint256[] calldata _points, uint256[] calldata _multiplierIndices) public {
uint256 _currentVotingPower = getCurrentVotingPower(msg.sender);
if (_currentVotingPower < minRequiredVotingPower) revert BelowMinRequiredVotingPower();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure we want to check this requirement before multipliers are applied??

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trueeeee

uint256 multiplier = getTotalMultipliers(msg.sender, _multiplierIndices);
_currentVotingPower = multiplier == 0 ? _currentVotingPower : (_currentVotingPower * multiplier) / PRECISION;
_castVote(msg.sender, _points, _currentVotingPower);
}

/**
* @notice Internal function for casting votes for a specified user
* @param _account Address of user to cast votes for
Expand Down
37 changes: 37 additions & 0 deletions src/interfaces/IVotingMultipliers.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove line break

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove line break

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;
}
13 changes: 13 additions & 0 deletions src/interfaces/multipliers/ICrossChainProveableMultiplier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// 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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove line break

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);
}
19 changes: 19 additions & 0 deletions src/interfaces/multipliers/IDynamicNFTMultiplier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove line break

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);
}
10 changes: 10 additions & 0 deletions src/interfaces/multipliers/IMultiplier.sol
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);
}
19 changes: 19 additions & 0 deletions src/interfaces/multipliers/INFTMultiplier.sol
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 src/interfaces/multipliers/IOffChainProveableMultiplier.sol
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);
}
12 changes: 12 additions & 0 deletions src/interfaces/multipliers/IOnChainProveableMultiplier.sol
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 On-Chain Proveable Multiplier Interface
/// @notice Interface for contracts that provide an on-chain proveable multiplying factor

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove line break

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);
}
13 changes: 13 additions & 0 deletions src/interfaces/multipliers/IProveableMultiplier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// 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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove line break

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;
}
Loading