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

feat: Otterspace badges voting strategy #242

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,9 @@
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/openzeppelin/openzeppelin-contracts-upgradeable
branch = v4.8.0
[submodule "lib/otterspace-contracts"]
path = lib/otterspace-contracts
url = https://github.com/otterspace-xyz/otterspace-contracts
[submodule "lib/ERC4973"]
path = lib/ERC4973
url = https://github.com/otterspace-xyz/ERC4973
1 change: 1 addition & 0 deletions lib/ERC4973
Submodule ERC4973 added at 1c8d61
1 change: 1 addition & 0 deletions lib/otterspace-contracts
Submodule otterspace-contracts added at aec3d4
2 changes: 2 additions & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ forge-gas-snapshot/=lib/forge-gas-snapshot/src
@prb/test/=lib/prb-test/src/
@zodiac/=lib/zodiac/contracts/
@gnosis.pm/safe-contracts=lib/safe-contracts
@otterspace/contracts/=lib/otterspace-contracts/src
ERC4973/=lib/ERC4973/src/
61 changes: 61 additions & 0 deletions src/voting-strategies/OtterspaceBadgesVotingStrategy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.18;

// import { Badges } from "@otterspace/contracts/Badges.sol";
import { IVotingStrategy } from "../interfaces/IVotingStrategy.sol";

interface IBadges {
function ownerOf(uint256 tokenId) external view returns (address);
}

/// @title Otterspace Badge Voting Strategy
/// @notice Allows Otterspace Badges to be used for voting power.
contract OtterspaceBadgesVotingStrategy is IVotingStrategy {
error InvalidBadge();

/// @notice The address of the Otterspace Badges Contract.
address public badgesRegistry;

/// @dev Data stored as parameters for each Badge.
struct Badge {
// spec of the badge.
string specUri;
// The voting power granted to badges of this spec.
uint96 vp;
}

constructor(address BadgesRegistry) {

Check warning on line 28 in src/voting-strategies/OtterspaceBadgesVotingStrategy.sol

View workflow job for this annotation

GitHub Actions / lint

Variable name must be in mixedCase
badgesRegistry = BadgesRegistry;
}

/// @notice Returns the voting power of an address.
/// @param voter The address to get the voting power of.
/// @param params Parameter array containing the encoded whitelist of addresses and their voting power.
/// The array should be an ABI encoded array of Member structs.
/// @param userParams Parameter array containing an array of indices of
Copy link
Member

Choose a reason for hiding this comment

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

Is this required? Can't we just query with balanceOf or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i thought we wanted different voting power for different badges? that would just give a single balance of all badges the address owns.

/// @return votingPower The voting power of the address if it exists in the whitelist, otherwise reverts.
function getVotingPower(
uint32 /* blockNumber */,
address voter,
bytes calldata params,
bytes calldata userParams
) external view override returns (uint256 votingPower) {
Badge[] memory badges = abi.decode(params, (Badge[]));
uint8[] memory userBadgeIndices = abi.decode(userParams, (uint8[]));

uint256 vp;
for (uint8 i = 0; i < userBadgeIndices.length; i++) {
uint256 tokenId = uint256(getBadgeIdHash(voter, badges[userBadgeIndices[i]].specUri));
if (IBadges(badgesRegistry).ownerOf(tokenId) != voter) revert InvalidBadge();
vp += badges[userBadgeIndices[i]].vp;
}

return vp;
}

/// @dev Generates the unique ID of a badge for a given address and spec.
function getBadgeIdHash(address _to, string memory _uri) internal pure returns (bytes32) {
return keccak256(abi.encode(_to, _uri));
}
}
Loading