Platform: Code4rena
Start Date: 31/10/2023
Pot Size: $60,500 USDC
Total HM: 9
Participants: 65
Period: 10 days
Judge: gzeon
Total Solo HM: 2
Id: 301
League: ETH
Rank: 47/65
Findings: 1
Award: $60.01
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: catellatech
Also found by: 0xSmartContract, 0xbrett8571, Bauchibred, K42, Myd, SAAJ, ZanyBonzy, clara, foxb868, hunter_w3b, kaveyjoe, pavankv
60.0107 USDC - $60.01
The Party Protocol enables decentralized group coordination and governance for forming parties, making proposals, distributing assets, and more. The core component is the Party contract which handles membership as ERC721 tokens, voting power, proposals, and asset custody.
Contract | Purpose | Libraries used |
---|---|---|
contracts/crowdfund/InitialETHCrowdfund.sol | This contract is a crowdfund for creating a new ETH party | |
contracts/crowdfund/ETHCrowdfundBase.sol | The base contract for InitialETHCrowdfund | |
contracts/party/PartyGovernance.sol | This contract is inherited by the Party contract--the core contract in the protocol. This contract has the governance logic for parties | |
contracts/party/PartyGovernanceNFT.sol | This contract is inherited by the Party contract--the core contract in the protocol. This contract has the token logic for parties | solmate/ERC721, openzeppelin/contracts/interfaces/IERC2981.sol |
contracts/proposals/ProposalExecutionEngine.sol | This contract is delegate called from parties for execution logic involved with proposal. Parties also have a fallback that does a static delegate call to the ProposalExecutionEngine | |
contracts/proposals/ProposalStorage.sol | Shared storage storage bucket that is accessed in multiple contracts | |
contracts/proposals/SetGovernanceParameterProposal.sol | A new proposal type that allows setting governance parameters for the party | |
contracts/proposals/SetSignatureValidatorProposal.sol | A new proposal type that allows setting a signature validator for a given signature hash or simply validating the hash | |
contracts/signature-validators/OffChainSignatureValidator.sol | Validator contract that reconstructs a message and ensures it's a plaintext message. It then returns valid if the signer has sufficient voting power or membership in the party | |
contracts/utils/Implementation.sol | A contract that provides helper functions for implementation contracts used from a proxy |
In the "Libraries used" column I left some empty where there are no libraries mentioned.
Key Contracts
PartyGovernance
- Implements group membership, voting power, proposals, and governance logic. Inherits token logic from PartyGovernanceNFT
.
PartyGovernanceNFT
- Implements ERC721 token functionality for Party membership NFTs. Inherits governance logic from PartyGovernance
.
ProposalExecutionEngine
- Contains logic for executing proposals like listing NFTs on platforms. Party
delegatecalls into this.
ProposalStorage
- Shared storage accessed by Party
and ProposalExecutionEngine
.
InitialETHCrowdfund
- Used to crowdfund and initialize a new Party.
Mechanisms
Proposals
Stage | Description |
---|---|
Voting | - Proposal created via propose() <br>- Members vote via accept() <br>- Hosts can veto |
Passed | - Proposal passes vote threshold <br>- Execution delay starts |
Ready | - Execution delay over <br>- Proposal can now be executed |
InProgress | - execute() called <br>- Further executions potentially needed |
Completed | - Proposal fully executed |
Proposals progress through predefined stages enforced by the Party
contract. This prevents premature execution and enables multi-transaction proposals.
The ProposalExecutionEngine
contains the logic for each proposal type like listing NFTs or making arbitrary calls. Party
delegatecalls into it to execute proposals.
The changelog lists new features, enhancements, and fixes added to the Party Protocol smart contracts.
Adding ERC1271 Support
Motivation: Allow Parties to integrate with web3 apps requiring signatures from their on-chain address. Also enable signing messages via proposals.
Implementation: ProposalExecutionEngine
now implements ERC1271. executeProposal
validates signatures. OffChainSignatureValidator
added to validate signatures with voting power checks.
Scenarios:
Members propose and pass a transaction requiring an ERC1271 signature from the Party address. The signature is provided in the proposal call data.
A web3 app requires members sign a message proving membership in a specific Party. The app verifies the signature validity via ERC1271.
Modifying Governance Settings
Motivation: Allow governance parameters like voting duration to be changed by the Party after initialization.
Implementation: SetGovernanceParameterProposal
added. Calls can modify governance values stored in ProposalStorage
.
Scenarios:
Party members propose reducing the voting period for quicker governance.
A Party proposes increasing the proposal acceptance threshold to require broader consensus.
Skipping Veto Period
Motivation: Speed up execution if all Hosts have already accepted the proposal.
Implementation: Additional logic checks if all Hosts accepted before veto period ends. If so, status immediately changes to Ready.
Scenarios:
Voting Power - Each Party membership NFT has voting power. Members delegate voting power to vote on proposals.
<img src="https://i.ibb.co/6XYf7Kk/Voting-Power.png" width="500" />Party
contract tracks voting power snapshotsTracking voting power snapshots provides flexibility compared to a static system. However, complexity is increased. Voting power accounting logic should be thoroughly reviewed.
Distributions - Mechanism for Party to distribute assets to members proportionally to voting power.
<img src="https://i.ibb.co/Q9WsX4p/Distributions.png" width="500" />Requiring a proposal for distributions provides oversight at the cost of speed. Distribution calculations should be thoroughly reviewed.
Rage Quit - Members can burn their NFT and withdraw a proportional share of assets.
Architecture
The Party contract acts as the main governance interface and coordinates all logic. It inherits:
This separation of concerns provides flexibility.
Proposal execution logic lives in the ProposalExecutionEngine
. The Party contract delegatecalls
into this contract to execute proposals. This enables upgrading the execution logic independently from the Party itself.
ProposalStorage
provides shared storage accessed by both Party and ProposalExecutionEngine
. This avoids duplication.
The IGlobals
contract provides configurable addresses for components like the ProposalExecutionEngine
. While relying on a central source of truth introduces some centralization risks, it enables easy upgrades to the ecosystem. The immutability of IGlobals mitigates some risks.
Party
acts as the governance interface and coordinates all logic.
Party
inherits token logic from PartyGovernanceNFT
and governance logic from PartyGovernance
.
ProposalExecutionEngine
contains modular proposal logic that Party
delegatecalls into.
ProposalStorage
enables sharing storage between Party
and ProposalExecutionEngine
.
IGlobals
provides global configuration. Addresses are trusted.
Gatekeepers like AllowListGateKeeper
manage access.
Implementation
pattern used for upgradability via proxies.
Key Mechanisms
Proposals
Members create proposals like executing arbitrary calls or changing parameters. Proposals progress through stages enforced by the Party contract:
This lifecycle prevents premature execution and enables multi-step proposals.
Voting Power
Each Party membership NFT confers voting power to its holder. Members can delegate their voting power to others to vote on their behalf. This enables flexible and fluid governance.
The Party contract tracks snapshots of voting power over time to determine voting power at the time of proposals.
Distributions
The Party can distribute assets like ETH or ERC20 tokens to members proportional to their voting power. This incentivizes participation and alignment.
Distributions can be configured to either require a proposal or be executable by any member with voting power. The latter increases flexibility but reduces oversight.
Rage Quit
Members can burn their NFT and withdraw a proportional share of assets based on voting power. This provides an escape hatch if members become dissatisfied with the Party's governance. The ability to rage quit can be configured on/off.
Proposals
Member calls propose()
with details of proposal
Proposal enters Voting
stage
accept()
If proposal passes vote threshold, enters Passed
stage
executionDelay
countdown startsAfter executionDelay
passes, proposal enters Ready
stage
execute()
On first call to execute()
:
InProgress
stageParty
delegatecalls ProposalEngine
to run execution logicInProgress
prevents other proposals from executingIf multi-step proposal:
ProposalEngine
returns non-empty nextProgressData
execute()
calls required with nextProgressData
When ProposalEngine
returns empty nextProgressData
:
Completed
stageVoting Power
Each Party membership NFT confers intrinsic voting power
Members can delegate voting power via delegateVotingPower()
Party
contract tracks snapshots of voting power
On proposal, voting power at time of proposal determined from snapshots
Voting power can be re-delegated at any time
Distributions
Member calls distribute()
on Party
Party transfers assets to TokenDistributor
TokenDistributor
mints member tokens proportional to voting power
Optional: Require distribution proposal to pass before executing
Rage Quit
Member calls rageQuit()
Member burns NFT
Party
transfers proportional share of assets to member based on voting power
Configurable whether rage quit enabled
The overall architecture promotes separation of concerns and upgradeability while keeping the Party contract as the coordinator.
Relying on IGlobals
for configuration introduces some centralization risks. For example, a compromized IGlobals
could point critical addresses like the ProposalEngine
to a malicious contract. Additional trust assumptions are placed on the initial setters of IGlobals
.
The usage of delegatecall
to the ProposalEngine
warrants extra care to ensure state mutations are valid. Potential reentrancy issues should be evaluated thoroughly.
No major systemic issues identified with the core mechanisms like voting and distributions. However, detailed analysis of the voting power accounting and rage quit calculations is recommended.
Beyond the core protocol, integrations with external contracts like NFT platforms carry additional risks and trust assumptions. I'd recommend thoroughly reviewing the related proposal types is recommended.
11 hours
#0 - c4-pre-sort
2023-11-13T10:42:15Z
ydspa marked the issue as sufficient quality report
#1 - c4-judge
2023-11-20T18:37:16Z
gzeon-c4 marked the issue as grade-b