diff --git a/.gitignore b/.gitignore index fa497d9..2801739 100644 --- a/.gitignore +++ b/.gitignore @@ -7,9 +7,6 @@ out/ /broadcast/*/31337/ /broadcast/**/dry-run/ -# Docs -docs/ - # Dotenv file .env .gas-report diff --git a/docs/Badge-Tutorial.md b/docs/Badge-Tutorial.md new file mode 100644 index 0000000..e62414e --- /dev/null +++ b/docs/Badge-Tutorial.md @@ -0,0 +1,267 @@ +# Badge Contract Tutorial + +The Badge contract implements an NFT-based achievement system that rewards users for their platform participation with badges that provide tangible benefits and governance weight multipliers. + +## Core Features + +1. Achievement Badges (NFTs) +2. Tiered Progression System +3. Platform Benefits +4. Governance Weight Multipliers + +## Badge Types and Tiers + +### Badge Types + +1. **Early Supporter** + - Awarded to first 100 users to back a project + - 5% platform discount + - 10x governance weight + +2. **Power Backer** + - For users who back multiple projects + - 10% platform discount + - 5x governance weight + - Progression based on number of backed projects + +3. **Liquidity Provider** + - For significant liquidity contributors + - 15% platform discount + - 7.5x governance weight + +4. **Governance Active** + - For active governance participants + - 7.5% platform discount + - 20x governance weight + - Progression based on governance participation + +### Badge Tiers + +Each badge can progress through four tiers: +1. **Bronze** (Starting tier) +2. **Silver** (25% governance bonus) +3. **Gold** (50% governance bonus) +4. **Platinum** (100% governance bonus) + +## Badge Management + +### Awarding Badges + +Platform administrators can award badges to users: + +```solidity +// Award a badge to a user +function awardBadge( + address recipient, + BadgeType badgeType, + string memory uri +) external onlyOwner +``` + +Example usage: +```solidity +// Award Early Supporter badge +badge.awardBadge( + userAddress, + Badge.BadgeType.EARLY_SUPPORTER, + "ipfs://Qm..." // Metadata URI +); +``` + +### Recording Actions + +Track user actions for badge progression: + +```solidity +// Record a qualifying action +function recordAction( + address user, + BadgeType badgeType +) external onlyOwner +``` + +Example usage: +```solidity +// Record a project backing for Power Backer progression +badge.recordAction( + userAddress, + Badge.BadgeType.POWER_BACKER +); +``` + +### Revoking Badges + +Administrators can revoke badges if necessary: + +```solidity +function revokeBadge(uint256 tokenId) external onlyOwner +``` + +## Tier Requirements + +### Power Backer Requirements +- Bronze: 5 backed projects +- Silver: 10 backed projects +- Gold: 20 backed projects +- Platinum: 50 backed projects + +### Governance Active Requirements +- Bronze: 3 governance participations +- Silver: 10 governance participations +- Gold: 25 governance participations +- Platinum: 100 governance participations + +## Benefits System + +### Platform Discounts + +Users can accumulate benefits from multiple badges: + +```solidity +// Get total benefits for a user +function getTotalBenefits(address user) external view returns (uint256) +``` + +**Important Notes**: +- Benefits are in basis points (100 = 1%) +- Maximum total benefit capped at 25% +- Benefits stack from different badge types + +### Governance Weights + +Badges provide governance weight multipliers: + +```solidity +// Get total governance weight for a user +function getGovernanceWeight(address user) external view returns (uint256) +``` + +**Weight Calculation**: +- Base weight: 1x (100 basis points) +- Tier bonuses apply to badge weights: + - Silver: +25% bonus + - Gold: +50% bonus + - Platinum: +100% bonus + +## Integration Example + +Here's a complete example of integrating the badge system: + +```solidity +contract PlatformCore { + Badge public badge; + + function backProject(uint256 projectId) external { + // Apply badge benefits to transaction + uint256 discount = badge.getTotalBenefits(msg.sender); + uint256 cost = calculateCostWithDiscount(basePrice, discount); + + // Process backing... + + // Record action for Power Backer badge + badge.recordAction(msg.sender, Badge.BadgeType.POWER_BACKER); + } + + function vote(uint256 proposalId) external { + // Apply governance weight + uint256 weight = badge.getGovernanceWeight(msg.sender); + uint256 votingPower = calculateVotingPower(baseVotes, weight); + + // Process vote... + + // Record action for Governance Active badge + badge.recordAction(msg.sender, Badge.BadgeType.GOVERNANCE_ACTIVE); + } +} +``` + +## Events + +Monitor badge activities through these events: + +```solidity +event BadgeAwarded(address indexed recipient, BadgeType badgeType, BadgeTier tier, uint256 tokenId); +event BadgeRevoked(address indexed holder, uint256 tokenId); +event BadgeProgressed(address indexed holder, uint256 tokenId, BadgeTier newTier); +event BenefitUpdated(BadgeType badgeType, uint256 newBenefit); +event GovernanceWeightUpdated(BadgeType indexed badgeType, uint256 newWeight); +``` + +## Best Practices + +1. **Badge Awarding** + - Verify eligibility before awarding badges + - Use meaningful metadata URIs + - Monitor BadgeAwarded events + +2. **Action Recording** + - Record actions immediately after qualifying events + - Verify action authenticity + - Monitor BadgeProgressed events + +3. **Benefits Management** + - Keep benefits reasonable (under 25% total) + - Consider economic impact of discounts + - Monitor BenefitUpdated events + +4. **Governance Integration** + - Apply weights correctly in voting systems + - Consider cumulative effect of tier bonuses + - Monitor GovernanceWeightUpdated events + +## Testing Example + +Here's how to test the badge system: + +```solidity +contract BadgeTest is Test { + Badge public badge; + address user = address(0x1); + + function setUp() public { + badge = new Badge(); + } + + function testBadgeProgression() public { + // Award Power Backer badge + badge.awardBadge( + user, + Badge.BadgeType.POWER_BACKER, + "ipfs://test" + ); + + // Record actions to reach Silver + for(uint i = 0; i < 10; i++) { + badge.recordAction(user, Badge.BadgeType.POWER_BACKER); + } + + // Get badge token ID + uint256 tokenId = badge.getUserBadgeTokenId(user, Badge.BadgeType.POWER_BACKER); + + // Verify tier progression + assertEq(uint256(badge.badgeTiers(tokenId)), uint256(Badge.BadgeTier.SILVER)); + } +} +``` + +## Security Considerations + +1. **Access Control** + - Only owner can award/revoke badges + - Only owner can record actions + - Only owner can update benefits/weights + +2. **Benefit Limits** + - Total benefits capped at 25% + - Individual benefits capped at 100% + - Governance weights reasonably scaled + +3. **NFT Security** + - Implements ERC721 standard + - Uses OpenZeppelin's secure implementations + - Proper token URI management + +4. **Progression System** + - Automatic tier progression + - Non-reversible progression + - Clear tier requirements diff --git a/docs/BadgeMarketplace-Tutorial.md b/docs/BadgeMarketplace-Tutorial.md new file mode 100644 index 0000000..2746e72 --- /dev/null +++ b/docs/BadgeMarketplace-Tutorial.md @@ -0,0 +1,234 @@ +# BadgeMarketplace Contract Tutorial + +The BadgeMarketplace contract enables users to trade their achievement badges and supports time-limited badge features. It provides a secure way to list, purchase, and manage badge transfers on the platform. + +## Core Features + +1. Badge Listing Management +2. Secure Purchase System +3. Time-Limited Badge Support +4. Active Listings Query + +## Marketplace Operations + +### Listing a Badge + +To list a badge for sale, users must own the badge and approve the marketplace: + +```solidity +// First approve the marketplace +badge.approve(marketplaceAddress, tokenId); + +// Then list the badge +marketplace.listBadge( + tokenId, // Badge token ID + price, // Price in wei + expiry // 0 for permanent, timestamp for time-limited +); +``` + +**Important Notes**: +- Only badge owners can list +- Marketplace must be approved for transfer +- Expiry of 0 means permanent badge +- Price is in wei (1 ether = 1e18 wei) + +### Purchasing a Badge + +Users can purchase listed badges by sending the required payment: + +```solidity +// Purchase a badge +marketplace.purchaseBadge{value: price}(tokenId); +``` + +**Purchase Process**: +1. Validates listing exists and payment sufficient +2. Checks badge hasn't expired (for time-limited badges) +3. Transfers badge ownership +4. Sends payment to seller +5. Refunds excess payment if any + +### Unlisting a Badge + +Sellers can remove their badges from the marketplace: + +```solidity +marketplace.unlistBadge(tokenId); +``` + +## Time-Limited Badges + +The marketplace supports time-limited badges that expire after a certain timestamp: + +```solidity +// Check if a badge has expired +bool expired = marketplace.isBadgeExpired(tokenId); +``` + +**Time-Limited Features**: +- Set expiry when listing +- Cannot purchase expired badges +- Expiry status publicly queryable +- Permanent badges use expiry = 0 + +## Viewing Listings + +Get all active (non-expired) listings: + +```solidity +( + uint256[] memory tokenIds, + uint256[] memory prices, + address[] memory sellers, + uint256[] memory expiries +) = marketplace.getActiveListings(); +``` + +## Integration Example + +Here's a complete example of integrating the marketplace: + +```solidity +contract MarketplaceUI { + BadgeMarketplace public marketplace; + Badge public badge; + + function listMyBadge( + uint256 tokenId, + uint256 price, + uint256 expiry + ) external { + // First approve marketplace + badge.approve(address(marketplace), tokenId); + + // Then list badge + marketplace.listBadge(tokenId, price, expiry); + } + + function buyBadge(uint256 tokenId) external payable { + // Get listing details + (address seller, uint256 price, uint256 expiry) = marketplace.listings(tokenId); + + // Verify badge isn't expired + require(!marketplace.isBadgeExpired(tokenId), "Badge expired"); + + // Purchase badge + marketplace.purchaseBadge{value: price}(tokenId); + } + + function displayActiveListings() external view returns ( + uint256[] memory tokens, + uint256[] memory prices, + address[] memory sellers, + uint256[] memory expiries + ) { + return marketplace.getActiveListings(); + } +} +``` + +## Events + +Monitor marketplace activity through these events: + +```solidity +event BadgeListed(uint256 indexed tokenId, address indexed seller, uint256 price, uint256 expiry); +event BadgeSold(uint256 indexed tokenId, address indexed seller, address indexed buyer, uint256 price); +event BadgeUnlisted(uint256 indexed tokenId); +event BadgeExpired(uint256 indexed tokenId); +``` + +## Best Practices + +1. **Listing Management** + - Verify badge ownership before listing + - Set reasonable prices + - Consider time-limited use cases + - Monitor BadgeListed events + +2. **Purchase Handling** + - Check badge validity before purchase + - Verify price and expiry + - Handle failed transactions + - Monitor BadgeSold events + +3. **Time-Limited Badges** + - Set appropriate expiry times + - Check expiry before interactions + - Monitor BadgeExpired events + - Consider timezone implications + +4. **Market Monitoring** + - Track active listings + - Monitor price trends + - Watch for unusual activity + - Use events for updates + +## Testing Example + +Here's how to test the marketplace functionality: + +```solidity +contract MarketplaceTest is Test { + BadgeMarketplace public marketplace; + Badge public badge; + address seller = address(0x1); + address buyer = address(0x2); + + function setUp() public { + badge = new Badge(); + marketplace = new BadgeMarketplace(address(badge)); + + // Mint a badge to seller + badge.awardBadge( + seller, + Badge.BadgeType.POWER_BACKER, + "ipfs://test" + ); + } + + function testBadgeSale() public { + vm.startPrank(seller); + + // Approve and list badge + uint256 tokenId = 1; + uint256 price = 1 ether; + badge.approve(address(marketplace), tokenId); + marketplace.listBadge(tokenId, price, 0); + + vm.stopPrank(); + + // Purchase badge + vm.startPrank(buyer); + vm.deal(buyer, 1 ether); + + marketplace.purchaseBadge{value: price}(tokenId); + + // Verify ownership transferred + assertEq(badge.ownerOf(tokenId), buyer); + } +} +``` + +## Security Considerations + +1. **Reentrancy Protection** + - Uses OpenZeppelin's ReentrancyGuard + - Clears listing before transfer + - Handles payments last + +2. **Access Control** + - Only owners can list/unlist + - Requires marketplace approval + - Ownership verified on listing + +3. **Payment Handling** + - Secure payment transfers + - Excess payment refunding + - Failed transfer handling + +4. **Time Management** + - Secure expiry checking + - Block timestamp usage + - Expired badge protection diff --git a/docs/CommitteeGovernance-Tutorial.md b/docs/CommitteeGovernance-Tutorial.md new file mode 100644 index 0000000..1f409a5 --- /dev/null +++ b/docs/CommitteeGovernance-Tutorial.md @@ -0,0 +1,219 @@ +# Committee Governance Tutorial + +This tutorial explains how to use the CommitteeGovernance contract, which manages specialized committees with their own voting domains in the Backr platform. + +## Overview + +The CommitteeGovernance system allows for: +- Creation of specialized committees +- Management of committee membership +- Control of committee voting powers +- Function-level permissions for proposals + +## Core Concepts + +### Committees +Each committee has: +- Name and description +- Voting power multiplier (in basis points) +- Active status +- Member list +- Allowed functions list + +### Roles +- `DEFAULT_ADMIN_ROLE`: Overall contract administration +- `COMMITTEE_ADMIN_ROLE`: Committee management permissions + +## Creating and Managing Committees + +### Creating a Committee + +```solidity +function createCommittee( + "Technical Review", // name + "Reviews technical implementations", // description + 500 // votingPowerMultiplier (5x) +) +``` + +**Important Notes**: +- Only addresses with `COMMITTEE_ADMIN_ROLE` can create committees +- Voting power multiplier is in basis points (100 = 1x, 1000 = 10x) +- Maximum multiplier is 10000 (100x) + +### Managing Committee Members + +Adding members: +```solidity +// Add a member to committee ID 0 +committeeGovernance.addMember(0, memberAddress); +``` + +Removing members: +```solidity +// Remove a member from committee ID 0 +committeeGovernance.removeMember(0, memberAddress); +``` + +**Requirements**: +- Only `COMMITTEE_ADMIN_ROLE` can add/remove members +- Committee must exist +- Cannot add existing members +- Cannot remove non-members + +### Managing Function Permissions + +Allow functions for committee proposals: +```solidity +// Allow a function for committee ID 0 +bytes4 functionSelector = bytes4(keccak256("functionName(paramTypes)")); +committeeGovernance.allowFunction(0, functionSelector); +``` + +## Querying Committee Information + +### Check Committee Membership + +```solidity +// Check if an address is a committee member +bool isMember = committeeGovernance.isMember( + 0, // committeeId + memberAddress // address to check +); +``` + +### Get Voting Power Multiplier + +```solidity +// Get member's voting power multiplier +uint256 multiplier = committeeGovernance.getVotingPowerMultiplier( + 0, // committeeId + memberAddress // member address +); +``` + +### Check Function Permissions + +```solidity +// Check if a function can be proposed by a committee +bool isAllowed = committeeGovernance.isFunctionAllowed( + 0, // committeeId + bytes4(keccak256("functionName(paramTypes)")) // functionSelector +); +``` + +## Events to Monitor + +The contract emits several important events: + +1. `CommitteeCreated(uint256 committeeId, string name)` + - Triggered when a new committee is created + - Includes committee ID and name + +2. `MemberAdded(uint256 committeeId, address member)` + - Triggered when a member is added to a committee + - Includes committee ID and member address + +3. `MemberRemoved(uint256 committeeId, address member)` + - Triggered when a member is removed from a committee + - Includes committee ID and member address + +4. `FunctionAllowed(uint256 committeeId, bytes4 functionSelector)` + - Triggered when a function is allowed for a committee + - Includes committee ID and function selector + +## Best Practices + +1. **Committee Creation** + - Use descriptive names and clear descriptions + - Set appropriate voting power multipliers + - Document committee purposes and responsibilities + +2. **Member Management** + - Regularly review committee membership + - Maintain appropriate committee sizes + - Document member selection criteria + +3. **Function Permissions** + - Carefully review functions before allowing + - Document allowed functions for each committee + - Regularly audit function permissions + +4. **Voting Power** + - Set multipliers based on committee importance + - Consider impact on overall governance + - Document multiplier rationale + +## Testing Example + +Here's a complete example of setting up and managing a committee: + +```solidity +// 1. Create a technical committee +committeeGovernance.createCommittee( + "Technical Committee", + "Reviews and approves technical implementations", + 500 // 5x voting power +); + +// 2. Add committee members +address[] memory technicalExperts = [ + address(0x123...), + address(0x456...), + address(0x789...) +]; + +for (uint i = 0; i < technicalExperts.length; i++) { + committeeGovernance.addMember(0, technicalExperts[i]); +} + +// 3. Allow specific functions +bytes4[] memory allowedFunctions = [ + bytes4(keccak256("upgradeContract(address)")), + bytes4(keccak256("setTechnicalParameters(uint256)")) +]; + +for (uint i = 0; i < allowedFunctions.length; i++) { + committeeGovernance.allowFunction(0, allowedFunctions[i]); +} + +// 4. Verify setup +bool isMember = committeeGovernance.isMember(0, technicalExperts[0]); +uint256 multiplier = committeeGovernance.getVotingPowerMultiplier(0, technicalExperts[0]); +bool canPropose = committeeGovernance.isFunctionAllowed(0, allowedFunctions[0]); +``` + +## Security Considerations + +1. **Role Management** + - Carefully manage admin role assignments + - Regularly audit role holders + - Use multi-sig for admin actions + +2. **Voting Power** + - Consider impact of multipliers on governance + - Monitor for potential voting power concentration + - Regular review of multiplier settings + +3. **Function Permissions** + - Audit allowed functions regularly + - Consider function dependencies + - Document permission changes + +4. **Committee Structure** + - Maintain appropriate committee sizes + - Regular review of committee effectiveness + - Document committee changes + +## Integration with Governance + +The CommitteeGovernance contract works in conjunction with the main Governance contract: + +1. Committee members get voting power multipliers for their domain +2. Proposals for allowed functions can be made by committee members +3. Committee structure provides specialized governance domains + +Remember to: +- Coordinate committee actions with main governance +- Consider overall governance impact +- Document committee-governance interactions diff --git a/docs/DisputeResolution-Tutorial.md b/docs/DisputeResolution-Tutorial.md new file mode 100644 index 0000000..f39dc92 --- /dev/null +++ b/docs/DisputeResolution-Tutorial.md @@ -0,0 +1,320 @@ +# DisputeResolution Contract Tutorial + +The DisputeResolution contract provides a structured system for handling project-related disputes on the platform. It enables users to initiate disputes, mediators to review and resolve them, and maintains a transparent record of dispute history. + +## Core Features + +1. Dispute Management +2. Mediator System +3. Project-specific Tracking +4. Status Progression + +## Dispute Categories + +The system supports five types of disputes: + +1. **Funding** + - Payment-related issues + - Fund distribution conflicts + - Budget disagreements + +2. **MilestoneCompletion** + - Milestone achievement disputes + - Completion criteria conflicts + - Timeline disagreements + +3. **Collaboration** + - Team communication issues + - Contribution disputes + - Responsibility conflicts + +4. **Deliverables** + - Quality of deliverables + - Scope disagreements + - Technical specification conflicts + +5. **Other** + - General disputes + - Miscellaneous issues + +## Dispute Status Flow + +Disputes progress through the following statuses: + +1. **Initiated** + - Initial dispute filing + - Awaiting review + +2. **UnderReview** + - Being examined by mediators + - Evidence collection phase + +3. **Mediation** + - Active mediation process + - Parties working towards resolution + +4. **Resolved** + - Resolution reached + - Solution implemented + +5. **Closed** + - Dispute formally closed + - No further action needed + +## Core Functions + +### Initiating a Dispute + +Users can create new disputes: + +```solidity +function initiateDispute( + address project, + address respondent, + DisputeCategory category, + string memory description +) public returns (uint256) +``` + +Example usage: +```solidity +uint256 disputeId = disputeResolution.initiateDispute( + projectAddress, + respondentAddress, + DisputeResolution.DisputeCategory.Funding, + "Delayed milestone payment for Phase 1" +); +``` + +### Managing Dispute Status + +Approved mediators can update dispute status: + +```solidity +function updateDisputeStatus( + uint256 disputeId, + DisputeStatus newStatus +) public onlyApprovedMediator +``` + +Example usage: +```solidity +// Move dispute to mediation +disputeResolution.updateDisputeStatus( + disputeId, + DisputeResolution.DisputeStatus.Mediation +); +``` + +### Resolving Disputes + +Mediators can mark disputes as resolved: + +```solidity +function resolveDispute( + uint256 disputeId, + string memory resolution +) public onlyApprovedMediator +``` + +Example usage: +```solidity +disputeResolution.resolveDispute( + disputeId, + "Parties agreed to revised milestone schedule with adjusted payments" +); +``` + +## Mediator Management + +### Adding Mediators + +```solidity +function addMediator(address mediator) public +``` + +Example usage: +```solidity +disputeResolution.addMediator(mediatorAddress); +``` + +## Querying Disputes + +### Get Project Disputes + +Retrieve all disputes for a specific project: + +```solidity +function getProjectDisputes( + address project +) public view returns (uint256[] memory) +``` + +Example usage: +```solidity +uint256[] memory disputes = disputeResolution.getProjectDisputes(projectAddress); +``` + +## Integration Example + +Here's a complete example of integrating the dispute resolution system: + +```solidity +contract ProjectManagement { + DisputeResolution public disputeResolution; + + function handleProjectDispute( + address project, + address respondent, + string memory description + ) external { + // Initiate funding dispute + uint256 disputeId = disputeResolution.initiateDispute( + project, + respondent, + DisputeResolution.DisputeCategory.Funding, + description + ); + + // Get project's active disputes + uint256[] memory projectDisputes = disputeResolution.getProjectDisputes(project); + + // Get dispute details + ( + uint256 id, + address projectAddr, + address initiator, + address disputeRespondent, + DisputeResolution.DisputeCategory category, + string memory desc, + DisputeResolution.DisputeStatus status, + uint256 createdAt, + uint256 resolvedAt, + address mediator, + string memory resolution + ) = disputeResolution.disputes(disputeId); + } +} +``` + +## Events + +Monitor dispute activities through these events: + +```solidity +event DisputeInitiated( + uint256 indexed disputeId, + address indexed project, + address initiator, + DisputeCategory category +); + +event DisputeStatusChanged( + uint256 indexed disputeId, + DisputeStatus newStatus +); + +event DisputeResolved( + uint256 indexed disputeId, + string resolution +); +``` + +## Best Practices + +1. **Dispute Initiation** + - Provide detailed descriptions + - Include relevant evidence + - Choose appropriate category + - Monitor DisputeInitiated events + +2. **Mediation Process** + - Follow status progression + - Document all communications + - Maintain impartiality + - Track DisputeStatusChanged events + +3. **Resolution Handling** + - Document resolution clearly + - Ensure all parties agree + - Monitor DisputeResolved events + - Verify implementation + +4. **Project Management** + - Track active disputes + - Monitor resolution timelines + - Maintain dispute history + - Review common dispute patterns + +## Testing Example + +Here's how to test the dispute resolution system: + +```solidity +contract DisputeResolutionTest is Test { + DisputeResolution public disputes; + address project = address(0x1); + address initiator = address(0x2); + address respondent = address(0x3); + address mediator = address(0x4); + + function setUp() public { + disputes = new DisputeResolution(); + disputes.addMediator(mediator); + } + + function testDisputeFlow() public { + // Initiate dispute + vm.prank(initiator); + uint256 disputeId = disputes.initiateDispute( + project, + respondent, + DisputeResolution.DisputeCategory.Funding, + "Payment dispute" + ); + + // Update status + vm.prank(mediator); + disputes.updateDisputeStatus( + disputeId, + DisputeResolution.DisputeStatus.Mediation + ); + + // Resolve dispute + vm.prank(mediator); + disputes.resolveDispute( + disputeId, + "Payment schedule adjusted" + ); + + // Verify resolution + (,,,,,,DisputeResolution.DisputeStatus status,,,, string memory resolution) = + disputes.disputes(disputeId); + + assertEq(uint256(status), uint256(DisputeResolution.DisputeStatus.Resolved)); + assertEq(resolution, "Payment schedule adjusted"); + } +} +``` + +## Security Considerations + +1. **Access Control** + - Only approved mediators can update status + - Only approved mediators can resolve disputes + - Proper mediator management + +2. **Data Integrity** + - Immutable dispute history + - Transparent status tracking + - Clear resolution documentation + +3. **Process Management** + - Logical status progression + - Proper event emission + - Accurate timestamp recording + +4. **Project Tracking** + - Accurate dispute mapping + - Project-specific history + - Active dispute monitoring diff --git a/docs/GaslessVoting-Tutorial.md b/docs/GaslessVoting-Tutorial.md new file mode 100644 index 0000000..4b1414f --- /dev/null +++ b/docs/GaslessVoting-Tutorial.md @@ -0,0 +1,304 @@ +# Gasless Voting Tutorial + +This tutorial explains how to use the GaslessVoting contract, which implements meta-transactions to enable gas-free voting in the Backr governance system. + +## Overview + +GaslessVoting enables users to vote on governance proposals without paying gas fees by using meta-transactions. This is achieved through EIP-712 signed messages that can be submitted to the blockchain by anyone on behalf of the voter. + +## Core Concepts + +### Vote Permits +A vote permit contains: +- Voter address +- Proposal ID +- Support (true/false) +- Nonce (for replay protection) +- Deadline (timestamp) + +### EIP-712 Typing +The contract uses EIP-712 for structured data signing with the following domain: +- Name: "Backr Governance" +- Version: "1" + +## Creating and Signing Vote Permits + +### 1. Creating a Vote Permit + +```javascript +// Using ethers.js +const permit = { + voter: voterAddress, + proposalId: proposalId, + support: true, // true for support, false against + nonce: await governance.getNonce(voterAddress), + deadline: Math.floor(Date.now() / 1000) + 3600 // 1 hour from now +}; +``` + +### 2. Signing the Permit + +```javascript +// Using ethers.js +const domain = { + name: 'Backr Governance', + version: '1', + chainId: await signer.getChainId(), + verifyingContract: governanceAddress +}; + +const types = { + VotePermit: [ + { name: 'voter', type: 'address' }, + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'bool' }, + { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint256' } + ] +}; + +const signature = await signer._signTypedData(domain, types, permit); +``` + +## Submitting Vote Permits + +### On-Chain Verification + +The contract verifies: +1. Signature validity +2. Deadline not expired +3. Correct nonce +4. Signer matches voter + +```solidity +// Submit vote with permit +governance.castVoteWithPermit(permit, signature); +``` + +### Checking Nonces + +```solidity +// Get current nonce for an address +uint256 nonce = governance.getNonce(voterAddress); +``` + +## Complete Implementation Example + +Here's a full example using ethers.js: + +```javascript +async function submitGaslessVote( + signer, + governanceContract, + proposalId, + support +) { + // 1. Get current nonce + const nonce = await governanceContract.getNonce(await signer.getAddress()); + + // 2. Create permit + const deadline = Math.floor(Date.now() / 1000) + 3600; // 1 hour + const permit = { + voter: await signer.getAddress(), + proposalId: proposalId, + support: support, + nonce: nonce, + deadline: deadline + }; + + // 3. Prepare EIP-712 signature + const domain = { + name: 'Backr Governance', + version: '1', + chainId: await signer.getChainId(), + verifyingContract: governanceContract.address + }; + + const types = { + VotePermit: [ + { name: 'voter', type: 'address' }, + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'bool' }, + { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint256' } + ] + }; + + // 4. Sign the permit + const signature = await signer._signTypedData(domain, types, permit); + + // 5. Submit the vote + // This can be done by anyone, not necessarily the signer + return governanceContract.castVoteWithPermit(permit, signature); +} +``` + +## Frontend Integration Example + +```javascript +// React component example +function GaslessVoteButton({ proposalId, support }) { + const { signer } = useEthers(); + const governanceContract = useGovernanceContract(); + + async function handleVote() { + try { + const tx = await submitGaslessVote( + signer, + governanceContract, + proposalId, + support + ); + await tx.wait(); + console.log('Vote submitted successfully'); + } catch (error) { + console.error('Error submitting vote:', error); + } + } + + return ( + + ); +} +``` + +## Relay Server Implementation + +To fully enable gasless voting, you'll need a relay server to submit transactions: + +```javascript +// Relay server example (Node.js) +const ethers = require('ethers'); +const express = require('express'); + +const app = express(); +const provider = new ethers.providers.JsonRpcProvider(RPC_URL); +const relayerWallet = new ethers.Wallet(PRIVATE_KEY, provider); +const governanceContract = new ethers.Contract( + GOVERNANCE_ADDRESS, + GOVERNANCE_ABI, + relayerWallet +); + +app.post('/relay-vote', async (req, res) => { + try { + const { permit, signature } = req.body; + + // Verify permit before submitting + const signer = await governanceContract.verifyVotePermit( + permit, + signature + ); + + if (signer.toLowerCase() !== permit.voter.toLowerCase()) { + throw new Error('Invalid signature'); + } + + // Submit the vote + const tx = await governanceContract.castVoteWithPermit( + permit, + signature + ); + await tx.wait(); + + res.json({ txHash: tx.hash }); + } catch (error) { + res.status(400).json({ error: error.message }); + } +}); +``` + +## Security Considerations + +1. **Signature Verification** + - Always verify signatures server-side + - Check deadline hasn't expired + - Verify nonce matches expected value + +2. **Nonce Management** + - Track nonces carefully + - Handle nonce conflicts + - Consider nonce recovery mechanisms + +3. **Relay Server** + - Implement rate limiting + - Verify all parameters + - Monitor gas prices + - Handle transaction failures + +4. **Frontend** + - Validate all inputs + - Handle signature rejections + - Show clear transaction status + - Implement proper error handling + +## Best Practices + +1. **Permit Creation** + - Use reasonable deadlines + - Verify nonce before signing + - Include clear metadata + +2. **Signature Handling** + - Store signatures securely + - Clear signatures after use + - Handle signature errors gracefully + +3. **Transaction Submission** + - Implement proper retries + - Monitor transaction status + - Handle reversion cases + - Provide clear user feedback + +4. **Error Handling** + - Implement proper error messages + - Handle network issues + - Provide recovery mechanisms + - Log errors for debugging + +## Testing + +Example test cases using Hardhat: + +```javascript +describe("GaslessVoting", function() { + it("Should accept valid vote permit", async function() { + const [voter] = await ethers.getSigners(); + const proposalId = 1; + const support = true; + + // Create and sign permit + const permit = { + voter: voter.address, + proposalId: proposalId, + support: support, + nonce: await governance.getNonce(voter.address), + deadline: Math.floor(Date.now() / 1000) + 3600 + }; + + const signature = await createPermitSignature( + voter, + governance, + permit + ); + + // Submit vote + await expect( + governance.castVoteWithPermit(permit, signature) + ).to.not.be.reverted; + }); + + it("Should reject expired permit", async function() { + // Test implementation + }); + + it("Should reject invalid signature", async function() { + // Test implementation + }); + + it("Should reject reused nonce", async function() { + // Test implementation + }); +}); diff --git a/docs/Governance-Tutorial.md b/docs/Governance-Tutorial.md new file mode 100644 index 0000000..cdba911 --- /dev/null +++ b/docs/Governance-Tutorial.md @@ -0,0 +1,271 @@ +# Governance Contract Tutorial + +This tutorial explains how to interact with the Governance contract, which manages the platform's DAO structure, including proposal creation, voting, delegation, and execution. + +## Core Concepts + +### Proposals +Each proposal contains: +- Description of the proposed action +- Target contract address +- Function call data to execute +- Voting period and results +- Execution status + +### Key Parameters +- `VOTING_PERIOD`: 7 days +- `EXECUTION_DELAY`: 2 days +- `PROPOSAL_THRESHOLD`: 100 tokens required to create proposals + +## Creating and Managing Proposals + +### Creating a Proposal + +```solidity +// Example: Create a proposal to call setParam(uint256) on a target contract +bytes memory callData = abi.encodeWithSignature("setParam(uint256)", 123); + +governance.createProposal( + "Update platform parameter to 123", // description + targetContractAddress, // target + callData // function call data +); +``` + +**Requirements**: +- Must hold at least 100 platform tokens +- Target address must be valid +- Provide valid function call data + +### Canceling a Proposal + +```solidity +governance.cancelProposal(proposalId); +``` + +**Notes**: +- Only the proposer or contract owner can cancel +- Must be canceled before voting period ends +- Cannot cancel already executed proposals + +## Voting System + +### Standard Voting + +```solidity +// Vote in favor of a proposal +governance.castVote(proposalId, true); // true for support, false against +``` + +### Gasless Voting +Using meta-transactions for gas-free voting: + +```solidity +// Create vote permit +VotePermit memory permit = VotePermit({ + voter: voterAddress, + proposalId: id, + support: true, + nonce: nonce, + deadline: deadline +}); + +// Sign permit off-chain +bytes memory signature = signPermit(permit); + +// Submit vote with permit +governance.castVoteWithPermit(permit, signature); +``` + +### Checking Proposal Status + +```solidity +( + uint256 forVotes, + uint256 againstVotes, + uint256 startTime, + uint256 endTime, + bool executed +) = governance.getProposal(proposalId); +``` + +## Delegation System + +### Delegating Voting Power + +```solidity +// Delegate voting power to another address +governance.delegate(delegateeAddress); +``` + +**Important Notes**: +- Cannot delegate to zero address or self +- Automatically updates voting power for active proposals +- Previous delegations are removed when delegating to a new address + +### Checking Voting Power + +```solidity +// Get total voting power of an address +uint256 power = governance.getVotingPower(address); +``` + +Voting power includes: +- Own token balance (if not delegated) +- Total amount delegated by others + +## Proposal Execution + +### Executing Passed Proposals + +```solidity +governance.executeProposal(proposalId); +``` + +**Requirements**: +1. Voting period must be over +2. Proposal must have more support than opposition +3. Must wait for execution delay (2 days) after voting ends +4. Proposal must not be already executed + +## Events to Monitor + +1. Proposal Lifecycle Events: + ```solidity + event ProposalCreated( + uint256 indexed proposalId, + address indexed proposer, + string description, + uint256 startTime, + uint256 endTime + ); + event ProposalExecuted(uint256 indexed proposalId); + event ProposalCancelled(uint256 indexed proposalId); + ``` + +2. Voting Events: + ```solidity + event VoteCast( + address indexed voter, + uint256 indexed proposalId, + bool support, + uint256 weight + ); + ``` + +3. Delegation Events: + ```solidity + event DelegateChanged( + address indexed delegator, + address indexed fromDelegate, + address indexed toDelegate + ); + ``` + +## Best Practices + +1. **Proposal Creation** + - Write clear, detailed descriptions + - Test call data before submission + - Consider impact on platform + - Ensure sufficient token balance + +2. **Voting** + - Review proposal details thoroughly + - Consider using gasless voting for better UX + - Check voting power before casting + - Monitor voting progress + +3. **Delegation** + - Choose delegates carefully + - Monitor delegate voting patterns + - Regularly review delegation status + - Consider impact on active proposals + +4. **Execution** + - Wait for execution delay + - Verify proposal passed + - Monitor execution success + - Have fallback plans for failed execution + +## Complete Example + +Here's a full example of the governance process: + +```solidity +// 1. Create a proposal +bytes memory callData = abi.encodeWithSignature( + "updateParameter(uint256)", + newValue +); + +governance.createProposal( + "Update platform parameter", + targetContract, + callData +); + +// 2. Delegate voting power (optional) +governance.delegate(trustedDelegate); + +// 3. Cast votes +governance.castVote(proposalId, true); + +// Or use gasless voting +VotePermit memory permit = VotePermit({ + voter: msg.sender, + proposalId: proposalId, + support: true, + nonce: nonce, + deadline: block.timestamp + 1 hours +}); +bytes memory signature = signPermit(permit); +governance.castVoteWithPermit(permit, signature); + +// 4. Monitor proposal status +( + uint256 forVotes, + uint256 againstVotes, + uint256 startTime, + uint256 endTime, + bool executed +) = governance.getProposal(proposalId); + +// 5. Execute proposal after voting period + delay +governance.executeProposal(proposalId); +``` + +## Security Considerations + +1. **Proposal Creation** + - Verify target contract address + - Test call data thoroughly + - Consider impact on platform security + +2. **Voting Power** + - Monitor delegation changes + - Track voting power snapshots + - Watch for voting manipulation + +3. **Execution** + - Ensure proper execution delay + - Verify proposal details before execution + - Monitor for failed executions + +4. **Meta-transactions** + - Verify signature validity + - Check permit deadlines + - Monitor nonce management + +## Integration with Committee Governance + +The Governance contract works alongside CommitteeGovernance: + +1. Committees get specialized voting domains +2. Committee voting power affects proposal outcomes +3. Function-level permissions control what can be proposed + +Remember to: +- Consider committee structure in proposals +- Account for voting power multipliers +- Coordinate with committee actions diff --git a/docs/LiquidityIncentives-Tutorial.md b/docs/LiquidityIncentives-Tutorial.md new file mode 100644 index 0000000..50cfeb6 --- /dev/null +++ b/docs/LiquidityIncentives-Tutorial.md @@ -0,0 +1,306 @@ +# Liquidity Incentives Tutorial + +This tutorial explains how to interact with the LiquidityIncentives contract, which manages liquidity provider tiers, yield farming, and flash loans on the Backr platform. + +## Core Concepts + +### Tier System +- Three tiers with increasing benefits +- Based on liquidity provided +- Affects reward multipliers and flash loan fees + +### Yield Farming +- Multiple staking pools +- Time-based rewards +- Customizable reward rates + +### Flash Loans +- Tier-based access +- Variable fees based on tier +- Instant borrowing and repayment + +## Tier System + +### Tier Levels and Benefits + +```solidity +// Tier 1 +- Minimum Liquidity: 0.001 tokens +- Reward Multiplier: 1x +- Flash Loan Fee: 0.3% + +// Tier 2 +- Minimum Liquidity: 0.01 tokens +- Reward Multiplier: 1.5x +- Flash Loan Fee: 0.25% + +// Tier 3 +- Minimum Liquidity: 0.1 tokens +- Reward Multiplier: 2x +- Flash Loan Fee: 0.2% +``` + +### Checking Tier Status + +```solidity +// Get user's current tier +uint256 tier = liquidityIncentives.userTiers(userAddress); + +// Get tier details +(uint256 minLiquidity, uint256 rewardMultiplier, uint256 flashLoanFee, bool enabled) = + liquidityIncentives.tiers(tierLevel); +``` + +## Yield Farming + +### Creating a Pool + +```solidity +// Only owner can create pools +liquidityIncentives.createPool( + 1, // poolId + 100000000 // rewardRate (tokens per second) +); +``` + +### Staking Tokens + +```solidity +// First approve tokens +token.approve(liquidityIncentives, amount); + +// Stake tokens in pool +liquidityIncentives.stake(poolId, amount); +``` + +### Managing Stakes + +```solidity +// Unstake tokens +liquidityIncentives.unstake(poolId, amount); + +// Claim rewards +liquidityIncentives.claimRewards(poolId); + +// Check pending rewards +uint256 pending = liquidityIncentives.calculatePendingRewards(poolId, userAddress); +``` + +## Flash Loans + +### Taking a Flash Loan + +```solidity +// Implement flash loan receiver interface +contract MyContract is IFlashLoanReceiver { + function executeOperation( + uint256 amount, + uint256 fee, + bytes calldata data + ) external override { + // Use borrowed funds here + + // Ensure repayment + token.transfer(msg.sender, amount + fee); + } +} + +// Request flash loan +liquidityIncentives.flashLoan( + amount, + abi.encode(/* your parameters */) +); +``` + +### Flash Loan Requirements +1. Must have active tier +2. Sufficient contract balance +3. Complete repayment in same transaction +4. Pay tier-based fee + +## Events to Monitor + +1. Tier Events: + ```solidity + event TierUpdated( + uint256 tierId, + uint256 minLiquidity, + uint256 rewardMultiplier, + uint256 flashLoanFee + ); + event UserTierChanged( + address indexed user, + uint256 oldTier, + uint256 newTier + ); + ``` + +2. Yield Farming Events: + ```solidity + event PoolCreated(uint256 poolId, uint256 rewardRate); + event Staked(address indexed user, uint256 poolId, uint256 amount); + event Unstaked(address indexed user, uint256 poolId, uint256 amount); + event RewardsClaimed(address indexed user, uint256 poolId, uint256 amount); + ``` + +3. Flash Loan Events: + ```solidity + event FlashLoanTaken( + address indexed borrower, + uint256 amount, + uint256 fee + ); + event FlashLoanRepaid( + address indexed borrower, + uint256 amount, + uint256 fee + ); + ``` + +## Best Practices + +1. **Tier Management** + - Monitor liquidity levels + - Track tier changes + - Understand benefits + - Plan for upgrades + +2. **Yield Farming** + - Calculate optimal staking + - Monitor reward rates + - Time claims efficiently + - Consider gas costs + +3. **Flash Loans** + - Verify tier status + - Calculate fees accurately + - Ensure repayment + - Handle failures gracefully + +## Complete Examples + +### Yield Farming Strategy + +```solidity +// Complete yield farming flow +contract YieldFarmingStrategy { + LiquidityIncentives public incentives; + PlatformToken public token; + + constructor(address _incentives, address _token) { + incentives = LiquidityIncentives(_incentives); + token = PlatformToken(_token); + } + + function startFarming(uint256 poolId, uint256 amount) external { + // 1. Approve tokens + token.approve(address(incentives), amount); + + // 2. Stake in pool + incentives.stake(poolId, amount); + + // 3. Monitor rewards + uint256 pending = incentives.calculatePendingRewards( + poolId, + address(this) + ); + + // 4. Claim when profitable + if (pending > getGasCost()) { + incentives.claimRewards(poolId); + } + } +} +``` + +### Flash Loan Implementation + +```solidity +contract FlashLoanExample is IFlashLoanReceiver { + LiquidityIncentives public incentives; + PlatformToken public token; + + constructor(address _incentives, address _token) { + incentives = LiquidityIncentives(_incentives); + token = PlatformToken(_token); + } + + function executeFlashLoan(uint256 amount) external { + // 1. Request flash loan + incentives.flashLoan( + amount, + abi.encode("Example") + ); + } + + function executeOperation( + uint256 amount, + uint256 fee, + bytes calldata data + ) external override { + // 2. Use funds + // ... your arbitrage or other logic here ... + + // 3. Repay loan + uint256 repayAmount = amount + fee; + require( + token.transfer(msg.sender, repayAmount), + "Repayment failed" + ); + } +} +``` + +## Error Handling + +Common errors you might encounter: + +```solidity +InvalidTier() // Invalid tier parameters +InvalidPool() // Pool doesn't exist +PoolNotActive() // Pool is not accepting stakes +InsufficientBalance() // Not enough tokens +FlashLoanActive() // Another loan in progress +UnauthorizedFlashLoan() // Not eligible for flash loans +FlashLoanRepaymentFailed() // Repayment unsuccessful +``` + +## Security Considerations + +1. **Tier System** + - Verify tier updates + - Monitor threshold changes + - Track user eligibility + +2. **Yield Farming** + - Check reward calculations + - Monitor pool balances + - Verify staking amounts + - Track reward distribution + +3. **Flash Loans** + - Validate borrower eligibility + - Ensure proper repayment + - Monitor loan usage + - Track fee collection + +4. **General Security** + - Monitor contract state + - Watch for paused status + - Track owner actions + - Verify calculations + +## Integration with LiquidityPool + +The LiquidityIncentives contract works closely with the LiquidityPool: + +1. Automatic tier updates based on liquidity +2. Reward multipliers affect earnings +3. Flash loan access tied to liquidity +4. Pool state affects incentives + +Remember to: +- Monitor both contracts +- Understand interactions +- Track state changes +- Coordinate operations diff --git a/docs/LiquidityPool-Tutorial.md b/docs/LiquidityPool-Tutorial.md new file mode 100644 index 0000000..3e599a5 --- /dev/null +++ b/docs/LiquidityPool-Tutorial.md @@ -0,0 +1,275 @@ +# Liquidity Pool Tutorial + +This tutorial explains how to interact with the LiquidityPool contract, which implements an Automated Market Maker (AMM) for ETH/BACKR token trading on the Backr platform. + +## Core Concepts + +### Pool Mechanics +- Constant product AMM (x * y = k) +- 0.3% trading fee +- Minimum liquidity requirement +- Slippage protection +- Liquidity provider incentives + +### Key Parameters +- `FEE_DENOMINATOR`: 1000 (0.3% fee) +- `FEE_NUMERATOR`: 3 +- `MINIMUM_LIQUIDITY`: Set at deployment +- `maxSlippage`: Configurable maximum slippage (in basis points) + +## Providing Liquidity + +### Adding Initial Liquidity + +```solidity +// First approve tokens +token.approve(liquidityPool, tokenAmount); + +// Add liquidity +liquidityPool.addLiquidity{value: ethAmount}(tokenAmount); +``` + +**Important Notes**: +- First liquidity provider sets the initial price +- Must provide balanced amounts +- Minimum liquidity requirement must be met + +### Adding Subsequent Liquidity + +```solidity +// Calculate optimal token amount based on current ratio +uint256 ethReserve = liquidityPool.ethReserve(); +uint256 tokenReserve = liquidityPool.tokenReserve(); +uint256 optimalTokenAmount = (ethAmount * tokenReserve) / ethReserve; + +// Approve and add liquidity +token.approve(liquidityPool, optimalTokenAmount); +liquidityPool.addLiquidity{value: ethAmount}(optimalTokenAmount); +``` + +### Removing Liquidity + +```solidity +// Remove liquidity and receive both tokens and ETH +liquidityPool.removeLiquidity(liquidityAmount); +``` + +## Trading + +### Swapping ETH for Tokens + +```solidity +// Calculate minimum tokens to receive +uint256 minTokens = calculateMinTokens(ethAmount); + +// Perform swap +liquidityPool.swapETHForTokens{value: ethAmount}(minTokens); +``` + +### Swapping Tokens for ETH + +```solidity +// Calculate minimum ETH to receive +uint256 minETH = calculateMinETH(tokenAmount); + +// Approve tokens and swap +token.approve(liquidityPool, tokenAmount); +liquidityPool.swapTokensForETH(tokenAmount, minETH); +``` + +### Calculating Output Amounts + +```solidity +// Get expected output amount +uint256 outputAmount = liquidityPool.getOutputAmount( + inputAmount, + inputReserve, + outputReserve +); +``` + +## Price Calculations + +### Getting Exchange Rate + +```solidity +// Get current exchange rate (tokens per ETH) +uint256 rate = liquidityPool.getExchangeRate(); +``` + +### Calculating Price Impact + +```javascript +// Example price impact calculation +function calculatePriceImpact(uint256 inputAmount, uint256 inputReserve, uint256 outputReserve) { + const k = inputReserve * outputReserve; + const newInputReserve = inputReserve + inputAmount; + const newOutputReserve = k / newInputReserve; + const outputAmount = outputReserve - newOutputReserve; + + const spotPrice = outputReserve / inputReserve; + const executionPrice = outputAmount / inputAmount; + const priceImpact = (spotPrice - executionPrice) / spotPrice * 100; + + return priceImpact; +} +``` + +## Events to Monitor + +1. Liquidity Events: + ```solidity + event LiquidityAdded( + address indexed provider, + uint256 ethAmount, + uint256 tokenAmount, + uint256 liquidity + ); + event LiquidityRemoved( + address indexed provider, + uint256 ethAmount, + uint256 tokenAmount, + uint256 liquidity + ); + ``` + +2. Trading Events: + ```solidity + event TokensPurchased( + address indexed buyer, + uint256 ethIn, + uint256 tokensOut + ); + event TokensSold( + address indexed seller, + uint256 tokensIn, + uint256 ethOut + ); + ``` + +3. Pool State Events: + ```solidity + event PoolStateChanged( + uint256 newEthReserve, + uint256 newTokenReserve + ); + event MaxSlippageUpdated(uint256 newMaxSlippage); + ``` + +## Best Practices + +1. **Adding Liquidity** + - Calculate optimal amounts + - Consider price impact + - Monitor pool share + - Check minimum liquidity + +2. **Trading** + - Set reasonable slippage limits + - Calculate price impact + - Monitor gas prices + - Check output amounts + +3. **Removing Liquidity** + - Consider timing + - Monitor pool share + - Check expected returns + - Account for fees + +4. **Price Monitoring** + - Track exchange rate + - Monitor reserves + - Watch for arbitrage + - Consider external prices + +## Complete Examples + +### Liquidity Provider Flow + +```solidity +// 1. Calculate optimal token amount +uint256 ethAmount = 1 ether; +uint256 ethReserve = liquidityPool.ethReserve(); +uint256 tokenReserve = liquidityPool.tokenReserve(); +uint256 tokenAmount = (ethAmount * tokenReserve) / ethReserve; + +// 2. Approve tokens +token.approve(address(liquidityPool), tokenAmount); + +// 3. Add liquidity +liquidityPool.addLiquidity{value: ethAmount}(tokenAmount); + +// 4. Monitor position +uint256 myLiquidity = liquidityPool.liquidityBalance(address(this)); +uint256 totalLiquidity = liquidityPool.totalLiquidity(); +uint256 poolShare = (myLiquidity * 100) / totalLiquidity; + +// 5. Remove liquidity when ready +liquidityPool.removeLiquidity(myLiquidity); +``` + +### Trading Flow + +```solidity +// 1. ETH to Token Swap +uint256 ethIn = 1 ether; +uint256 minTokens = calculateMinTokensOut(ethIn); +liquidityPool.swapETHForTokens{value: ethIn}(minTokens); + +// 2. Token to ETH Swap +uint256 tokensIn = 1000 * 10**18; +uint256 minETH = calculateMinETHOut(tokensIn); +token.approve(address(liquidityPool), tokensIn); +liquidityPool.swapTokensForETH(tokensIn, minETH); +``` + +## Error Handling + +Common errors you might encounter: + +```solidity +InsufficientLiquidity() // Pool lacks liquidity +InsufficientInputAmount() // Input amount too low +InsufficientOutputAmount() // Output amount too low +InvalidK() // Constant product invariant violated +TransferFailed() // Token transfer failed +UnbalancedLiquidityRatios() // Liquidity ratios don't match +InsufficientTokenAmount() // Not enough tokens provided +SlippageExceeded() // Price moved beyond slippage +EmergencyWithdrawalFailed() // Emergency withdrawal failed +``` + +## Security Considerations + +1. **Slippage Protection** + - Set appropriate slippage limits + - Monitor price movements + - Use maxSlippage parameter + +2. **Liquidity Management** + - Monitor pool share + - Watch for impermanent loss + - Consider pool concentration + +3. **Trading Safety** + - Verify output amounts + - Check price impact + - Monitor for front-running + +4. **Emergency Features** + - Understand pause mechanism + - Monitor owner actions + - Watch for emergency withdrawals + +## Integration with Incentives + +The LiquidityPool works with LiquidityIncentives contract: + +1. Tier updates on liquidity changes +2. Rewards based on liquidity provided +3. Incentive tracking for providers + +Remember to: +- Monitor tier status +- Track rewards +- Understand incentive mechanics diff --git a/docs/PlatformToken-Tutorial.md b/docs/PlatformToken-Tutorial.md new file mode 100644 index 0000000..76983e9 --- /dev/null +++ b/docs/PlatformToken-Tutorial.md @@ -0,0 +1,273 @@ +# PlatformToken Contract Tutorial + +The PlatformToken contract implements the platform's native ERC20 token (BACKR) with built-in staking and reward mechanisms to incentivize long-term platform participation. + +## Core Features + +1. ERC20 Token Implementation +2. Token Staking System +3. Automatic Reward Generation +4. Owner-controlled Token Minting + +## Token Economics + +### Initial Supply +- 1 million BACKR tokens (1,000,000 * 10^18) +- Minted to contract deployer +- Additional minting controlled by owner + +### Staking Parameters +- Minimum Stake Duration: 7 days +- Annual Reward Rate: 5% +- No maximum staking limit +- Rewards calculated based on time and amount staked + +## Token Management + +### Minting New Tokens + +Only the contract owner can mint additional tokens: + +```solidity +function mint(address to, uint256 amount) external onlyOwner +``` + +Example usage: +```solidity +// Mint 1000 tokens to an address +platformToken.mint( + recipientAddress, + 1000 * 10**18 // Amount with 18 decimals +); +``` + +### Basic Token Operations + +Standard ERC20 operations are available: + +```solidity +// Transfer tokens +function transfer(address to, uint256 amount) external returns (bool) + +// Approve spending +function approve(address spender, uint256 amount) external returns (bool) + +// Transfer from approved amount +function transferFrom(address from, address to, uint256 amount) external returns (bool) +``` + +## Staking System + +### Staking Tokens + +Users can stake their tokens for rewards: + +```solidity +function stake(uint256 amount) external +``` + +Example usage: +```solidity +// Stake 100 tokens +platformToken.stake(100 * 10**18); +``` + +**Requirements**: +- Amount must be greater than 0 +- User must have sufficient balance +- Tokens are transferred to contract during stake + +### Unstaking Tokens + +Users can unstake their tokens and claim rewards: + +```solidity +function unstake() external +``` + +**Important Notes**: +- Must have staked tokens +- Must meet minimum stake duration (7 days) +- Receives original stake plus rewards +- Staking position is cleared after unstaking + +### Viewing Stake Information + +Get current staking details for an address: + +```solidity +function getStakeInfo(address account) external view returns ( + uint256 amount, + uint256 since, + uint256 reward +) +``` + +Example usage: +```solidity +// Get stake info +(uint256 amount, uint256 since, uint256 reward) = platformToken.getStakeInfo(userAddress); +``` + +## Reward Calculation + +### Formula + +Rewards are calculated using the following formula: +``` +reward = (staked_amount * rate * time) / (365 days * 100) +``` + +Where: +- staked_amount: Amount of tokens staked +- rate: 5 (5% annual rate) +- time: Duration since stake (in seconds) + +### Calculating Rewards + +View current reward for an address: + +```solidity +function calculateReward(address account) public view returns (uint256) +``` + +Example usage: +```solidity +// Get current reward amount +uint256 reward = platformToken.calculateReward(userAddress); +``` + +## Integration Example + +Here's a complete example of integrating the token and staking system: + +```solidity +contract PlatformCore { + PlatformToken public token; + + function stakePlatformTokens(uint256 amount) external { + // First approve token transfer + require(token.approve(address(token), amount), "Approve failed"); + + // Stake tokens + try token.stake(amount) { + // Staking successful + emit TokensStaked(msg.sender, amount); + } catch Error(string memory reason) { + // Handle staking failure + revert(string(abi.encodePacked("Stake failed: ", reason))); + } + } + + function unstakePlatformTokens() external { + // Unstake and get rewards + try token.unstake() { + // Get updated balance + uint256 newBalance = token.balanceOf(msg.sender); + emit TokensUnstaked(msg.sender, newBalance); + } catch Error(string memory reason) { + revert(string(abi.encodePacked("Unstake failed: ", reason))); + } + } +} +``` + +## Events + +Monitor token and staking activities: + +```solidity +event Transfer(address indexed from, address indexed to, uint256 value); +event Approval(address indexed owner, address indexed spender, uint256 value); +event Staked(address indexed user, uint256 amount); +event Unstaked(address indexed user, uint256 amount, uint256 reward); +``` + +## Best Practices + +1. **Token Management** + - Always use SafeMath operations (built into Solidity 0.8+) + - Check balances before operations + - Use proper decimal handling (18 decimals) + +2. **Staking** + - Verify minimum stake duration + - Consider gas costs for large numbers + - Monitor staking events + +3. **Rewards** + - Regular monitoring of reward calculations + - Consider economic implications of reward rate + - Track total rewards distributed + +4. **Security** + - Implement access controls for admin functions + - Regular audits of token distribution + - Monitor for unusual activity + +## Testing Example + +Here's how to test the token and staking system: + +```solidity +contract PlatformTokenTest is Test { + PlatformToken public token; + address user = address(0x1); + + function setUp() public { + token = new PlatformToken(); + token.transfer(user, 1000 * 10**18); // Give user some tokens + } + + function testStaking() public { + vm.startPrank(user); + + // Stake tokens + uint256 stakeAmount = 100 * 10**18; + token.stake(stakeAmount); + + // Check stake info + (uint256 amount, uint256 since, ) = token.getStakeInfo(user); + assertEq(amount, stakeAmount); + assertEq(since, block.timestamp); + + // Fast forward 7 days + vm.warp(block.timestamp + 7 days); + + // Calculate expected reward + uint256 expectedReward = (stakeAmount * 5 * 7 days) / (365 days * 100); + uint256 actualReward = token.calculateReward(user); + assertEq(actualReward, expectedReward); + + // Unstake and verify reward + uint256 balanceBefore = token.balanceOf(user); + token.unstake(); + uint256 balanceAfter = token.balanceOf(user); + assertEq(balanceAfter, balanceBefore + stakeAmount + expectedReward); + + vm.stopPrank(); + } +} +``` + +## Security Considerations + +1. **Access Control** + - Minting restricted to owner + - Staking/unstaking open to all users + - No admin control over user stakes + +2. **Economic Security** + - Fixed reward rate + - Minimum stake duration + - No maximum supply cap (controlled by owner) + +3. **Smart Contract Security** + - OpenZeppelin base contracts + - Reentrancy protection (CEI pattern) + - Integer overflow protection (Solidity 0.8+) + +4. **Operational Security** + - Event emission for tracking + - View functions for transparency + - Clear error messages diff --git a/docs/Project-Tutorial.md b/docs/Project-Tutorial.md new file mode 100644 index 0000000..98beda7 --- /dev/null +++ b/docs/Project-Tutorial.md @@ -0,0 +1,208 @@ +# Project Contract Tutorial + +This tutorial explains how to interact with the Project contract, which is a core component of the Backr platform for managing project creation, funding, and milestone tracking. + +## Prerequisites + +- A registered user profile on the Backr platform +- Some ETH for funding projects and gas fees +- Basic understanding of blockchain transactions + +## Core Concepts + +### Projects +A project consists of: +- Title and description +- A series of milestones +- Funding goals +- Voting requirements for milestone completion + +### Milestones +Each milestone includes: +- Description +- Required funding amount +- Required number of votes for completion +- Vote tracking + +## Creating a Project + +To create a new project, you'll need to prepare: +1. Project title and description +2. List of milestone descriptions +3. Funding requirements for each milestone +4. Required votes for each milestone + +```solidity +// Example: Creating a project with 2 milestones +string[] milestoneDescriptions = ["Initial prototype", "Final product"]; +uint256[] milestoneFunding = [1 ether, 2 ether]; +uint256[] milestoneVotes = [3, 5]; // Votes required for each milestone + +project.createProject( + "My Project", + "A description of my project", + milestoneDescriptions, + milestoneFunding, + milestoneVotes +); +``` + +**Note**: You can only create one project per 24 hours due to rate limiting. + +## Contributing Funds + +You can contribute funds to any active project: + +```solidity +// Example: Contributing 1 ETH to project ID 1 +project.contributeToProject{value: 1 ether}(1); +``` + +**Important Security Notes**: +- Contributions over 10 ETH require multi-signature approval +- The circuit breaker must be off to contribute +- The contract must not be paused + +## Milestone Voting + +Stakeholders can vote on milestone completion: + +```solidity +// Example: Voting for milestone 0 of project 1 +project.voteMilestone(1, 0); +``` + +**Key Points**: +- Each address can only vote once per milestone +- When sufficient votes are received, the milestone is marked complete +- Funds are automatically released to the project creator upon completion + +## Viewing Project Information + +### Getting Milestone Details + +```solidity +// Example: Getting details for milestone 0 of project 1 +( + string memory description, + uint256 fundingRequired, + uint256 votesRequired, + uint256 votesReceived, + bool isCompleted +) = project.getMilestone(1, 0); +``` + +### Checking Vote Status + +```solidity +// Example: Checking if an address has voted +bool hasVoted = project.hasVotedForMilestone(1, 0, voterAddress); +``` + +## Emergency Features + +The contract includes emergency features accessible only to administrators: + +- Emergency withdrawal of funds when paused +- Circuit breaker protection +- Rate limiting on critical operations + +## Events to Monitor + +The contract emits several events you can monitor: + +1. `ProjectCreated(uint256 projectId, address creator, string title)` +2. `MilestoneAdded(uint256 projectId, uint256 milestoneId, string description)` +3. `FundsContributed(uint256 projectId, address contributor, uint256 amount)` +4. `MilestoneCompleted(uint256 projectId, uint256 milestoneId)` +5. `FundsReleased(uint256 projectId, uint256 milestoneId, uint256 amount)` + +## Best Practices + +1. **Project Creation** + - Ensure milestone descriptions are clear and specific + - Set reasonable funding requirements + - Choose appropriate voting thresholds + +2. **Contributing** + - Verify project details before contributing + - Be aware of large funding thresholds + - Check project status and milestone progress + +3. **Milestone Voting** + - Review milestone deliverables before voting + - Verify milestone completion criteria + - Check current vote counts + +## Error Handling + +Common errors you might encounter: + +- `UserNotRegistered`: Ensure you have a registered profile +- `InvalidProjectParameters`: Check all project parameters are valid +- `ProjectNotFound`: Verify the project ID exists +- `InsufficientFunds`: Ensure adequate funds for contribution +- `MilestoneNotFound`: Verify milestone ID exists +- `AlreadyVoted`: Each address can only vote once +- `MilestoneAlreadyCompleted`: Cannot vote on completed milestones +- `InsufficientVotes`: Milestone needs more votes for completion + +## Testing Example + +Here's a complete example of creating and interacting with a project: + +```solidity +// 1. Create a project +string[] memory descriptions = new string[](2); +descriptions[0] = "Build MVP"; +descriptions[1] = "Launch Product"; + +uint256[] memory funding = new uint256[](2); +funding[0] = 1 ether; +funding[1] = 2 ether; + +uint256[] memory votes = new uint256[](2); +votes[0] = 3; +votes[1] = 5; + +project.createProject( + "My DApp", + "A decentralized application", + descriptions, + funding, + votes +); + +// 2. Contribute funds +project.contributeToProject{value: 1.5 ether}(0); + +// 3. Vote on milestone +project.voteMilestone(0, 0); + +// 4. Check milestone status +( + string memory desc, + uint256 fundingReq, + uint256 votesReq, + uint256 votesRec, + bool completed +) = project.getMilestone(0, 0); +``` + +## Security Considerations + +1. **Rate Limiting** + - Project creation: 1 per 24 hours + - Milestone completions: 10 per day + +2. **Multi-Signature Requirements** + - Large funding operations (≥10 ETH) require approval + - Emergency operations require proper roles + +3. **Circuit Breaker** + - Protects against potential vulnerabilities + - Affects funding and voting operations + +4. **Access Control** + - Emergency functions restricted to admin roles + - Proper role management is crucial diff --git a/docs/ProjectCategories-Tutorial.md b/docs/ProjectCategories-Tutorial.md new file mode 100644 index 0000000..27769fb --- /dev/null +++ b/docs/ProjectCategories-Tutorial.md @@ -0,0 +1,248 @@ +# ProjectCategories Contract Tutorial + +The ProjectCategories contract provides a structured system for organizing and discovering projects through categories and domains. It enables efficient project classification and discovery on the platform. + +## Core Features + +1. Project Domain Classification +2. Custom Category Management +3. Project Categorization +4. Category Querying + +## Project Domains + +The system supports seven primary project domains: + +1. **Technology** + - Software Development + - Hardware Projects + - Blockchain Initiatives + +2. **SocialImpact** + - Community Projects + - Social Justice + - Humanitarian Efforts + +3. **CreativeArts** + - Visual Arts + - Music + - Digital Media + +4. **Education** + - Learning Platforms + - Educational Content + - Research Projects + +5. **Environment** + - Sustainability + - Conservation + - Green Technology + +6. **Healthcare** + - Medical Research + - Health Technology + - Wellness Initiatives + +7. **Other** + - Miscellaneous Projects + - Cross-domain Initiatives + +## Category Management + +### Creating Categories + +Create new project categories within domains: + +```solidity +function createCategory( + string memory name, + ProjectDomain domain, + string memory description +) public returns (uint256) +``` + +Example usage: +```solidity +uint256 categoryId = projectCategories.createCategory( + "DeFi Protocols", + ProjectCategories.ProjectDomain.Technology, + "Decentralized finance protocols and applications" +); +``` + +### Categorizing Projects + +Assign categories to projects: + +```solidity +function categorizeProject( + address project, + uint256[] memory categoryIds +) public +``` + +Example usage: +```solidity +uint256[] memory categories = new uint256[](2); +categories[0] = defiCategoryId; +categories[1] = blockchainCategoryId; + +projectCategories.categorizeProject(projectAddress, categories); +``` + +### Querying Categories + +Retrieve project categories: + +```solidity +function getProjectCategories( + address project +) public view returns (uint256[] memory) +``` + +Example usage: +```solidity +uint256[] memory projectCats = projectCategories.getProjectCategories(projectAddress); +``` + +## Integration Example + +Here's a complete example of integrating the project categories system: + +```solidity +contract ProjectManagement { + ProjectCategories public categories; + + function setupProjectCategories() external { + // Create categories + uint256 defiId = categories.createCategory( + "DeFi", + ProjectCategories.ProjectDomain.Technology, + "Decentralized Finance Projects" + ); + + uint256 nftId = categories.createCategory( + "NFT", + ProjectCategories.ProjectDomain.CreativeArts, + "Non-Fungible Token Projects" + ); + + // Categorize a project + uint256[] memory projectCats = new uint256[](2); + projectCats[0] = defiId; + projectCats[1] = nftId; + + categories.categorizeProject(address(this), projectCats); + + // Query project categories + uint256[] memory assignedCats = categories.getProjectCategories(address(this)); + } +} +``` + +## Events + +Monitor category activities through these events: + +```solidity +event CategoryCreated( + uint256 indexed categoryId, + string name, + ProjectDomain domain +); + +event ProjectCategorized( + address indexed project, + uint256[] categoryIds +); +``` + +## Best Practices + +1. **Category Creation** + - Use descriptive names + - Provide detailed descriptions + - Choose appropriate domains + - Monitor CategoryCreated events + +2. **Project Categorization** + - Select relevant categories + - Limit number of categories per project + - Keep categories updated + - Monitor ProjectCategorized events + +3. **Domain Management** + - Use specific domains when possible + - Reserve "Other" for unique cases + - Consider domain relevance + +4. **Category Maintenance** + - Review category usage + - Monitor category effectiveness + - Update descriptions as needed + - Consider category consolidation + +## Testing Example + +Here's how to test the project categories system: + +```solidity +contract ProjectCategoriesTest is Test { + ProjectCategories public categories; + address project = address(0x1); + + function setUp() public { + categories = new ProjectCategories(); + } + + function testCategoryManagement() public { + // Create categories + uint256 techId = categories.createCategory( + "Blockchain", + ProjectCategories.ProjectDomain.Technology, + "Blockchain projects" + ); + + uint256 socialId = categories.createCategory( + "Community", + ProjectCategories.ProjectDomain.SocialImpact, + "Community projects" + ); + + // Assign categories to project + uint256[] memory cats = new uint256[](2); + cats[0] = techId; + cats[1] = socialId; + + categories.categorizeProject(project, cats); + + // Verify assignments + uint256[] memory projectCats = categories.getProjectCategories(project); + assertEq(projectCats.length, 2); + assertEq(projectCats[0], techId); + assertEq(projectCats[1], socialId); + } +} +``` + +## Security Considerations + +1. **Data Validation** + - Verify category existence + - Check category active status + - Validate project addresses + +2. **Access Control** + - Consider who can create categories + - Control project categorization + - Manage category updates + +3. **Data Integrity** + - Maintain consistent categorization + - Prevent duplicate categories + - Handle category deactivation + +4. **System Scalability** + - Manage category growth + - Optimize category queries + - Consider gas costs diff --git a/docs/ProjectPortfolio-Tutorial.md b/docs/ProjectPortfolio-Tutorial.md new file mode 100644 index 0000000..3266ed7 --- /dev/null +++ b/docs/ProjectPortfolio-Tutorial.md @@ -0,0 +1,321 @@ +# ProjectPortfolio Contract Tutorial + +The ProjectPortfolio contract enables users to create and manage professional portfolios showcasing their project work. It provides features for organizing projects, highlighting achievements, and controlling portfolio visibility. + +## Core Features + +1. Portfolio Management +2. Project Showcasing +3. Privacy Controls +4. Featured Items System + +## Portfolio Structure + +### Portfolio Items + +Each portfolio item contains: +- Project ID +- Title +- Description +- Tags +- Media URL +- Featured status +- Timestamp + +### Portfolio Metadata + +Portfolio-level information includes: +- Title +- Description +- Highlighted Skills +- Privacy Setting + +## Core Functions + +### Adding Portfolio Items + +Add projects to your portfolio: + +```solidity +function addPortfolioItem( + uint256 projectId, + string calldata description, + string[] calldata tags, + string calldata mediaUrl, + bool featured +) external +``` + +Example usage: +```solidity +string[] memory tags = new string[](2); +tags[0] = "DeFi"; +tags[1] = "Smart Contracts"; + +portfolio.addPortfolioItem( + projectId, + "Led development of decentralized exchange", + tags, + "ipfs://Qm...", + true // featured +); +``` + +### Updating Portfolio Metadata + +Customize your portfolio presentation: + +```solidity +function updatePortfolioMetadata( + string calldata title, + string calldata description, + string[] calldata highlightedSkills, + bool isPublic +) external +``` + +Example usage: +```solidity +string[] memory skills = new string[](3); +skills[0] = "Solidity"; +skills[1] = "Smart Contract Security"; +skills[2] = "DeFi Protocol Design"; + +portfolio.updatePortfolioMetadata( + "Blockchain Developer Portfolio", + "Specialized in DeFi and Security", + skills, + true // public visibility +); +``` + +### Managing Portfolio Items + +Update or remove portfolio items: + +```solidity +// Update an item +function updatePortfolioItem( + uint256 projectId, + string calldata description, + string[] calldata tags, + string calldata mediaUrl, + bool featured +) external + +// Remove an item +function removePortfolioItem(uint256 projectId) external +``` + +Example usage: +```solidity +// Update item +string[] memory newTags = new string[](1); +newTags[0] = "Updated Project"; + +portfolio.updatePortfolioItem( + projectId, + "Updated description", + newTags, + "ipfs://new-media", + true +); + +// Remove item +portfolio.removePortfolioItem(projectId); +``` + +## Querying Portfolios + +### Get All Portfolio Items + +Retrieve all items in a portfolio: + +```solidity +function getPortfolioItems(address user) + external + view + returns (PortfolioItem[] memory) +``` + +### Get Featured Items + +Retrieve only featured portfolio items: + +```solidity +function getFeaturedItems(address user) + external + view + returns (PortfolioItem[] memory) +``` + +### Get Portfolio Metadata + +Retrieve portfolio-level information: + +```solidity +function getPortfolioMetadata(address user) + external + view + returns ( + string memory title, + string memory description, + string[] memory highlightedSkills, + bool isPublic + ) +``` + +## Integration Example + +Here's a complete example of portfolio management: + +```solidity +contract PortfolioManager { + ProjectPortfolio public portfolio; + + function setupPortfolio() external { + // Update portfolio metadata + string[] memory skills = new string[](2); + skills[0] = "Smart Contracts"; + skills[1] = "DeFi"; + + portfolio.updatePortfolioMetadata( + "DeFi Developer Portfolio", + "Specialized in DeFi protocols", + skills, + true // public + ); + + // Add portfolio item + string[] memory tags = new string[](1); + tags[0] = "DeFi"; + + portfolio.addPortfolioItem( + 1, // projectId + "Automated Market Maker Protocol", + tags, + "ipfs://Qm...", + true // featured + ); + + // Get portfolio data + PortfolioItem[] memory items = portfolio.getPortfolioItems(address(this)); + PortfolioItem[] memory featured = portfolio.getFeaturedItems(address(this)); + } +} +``` + +## Events + +Monitor portfolio activities through these events: + +```solidity +event PortfolioItemAdded(address indexed user, uint256 indexed projectId); +event PortfolioItemRemoved(address indexed user, uint256 indexed projectId); +event PortfolioMetadataUpdated(address indexed user); +event PortfolioItemUpdated(address indexed user, uint256 indexed projectId); +``` + +## Best Practices + +1. **Portfolio Setup** + - Create clear, professional descriptions + - Use relevant tags + - Include quality media content + - Highlight key achievements + +2. **Content Management** + - Keep descriptions concise + - Update regularly + - Maintain relevant tags + - Curate featured items + +3. **Privacy Management** + - Consider visibility settings + - Review public content + - Update privacy as needed + - Protect sensitive information + +4. **Media Management** + - Use stable media links + - Optimize media content + - Backup media files + - Update broken links + +## Testing Example + +Here's how to test the portfolio system: + +```solidity +contract ProjectPortfolioTest is Test { + ProjectPortfolio public portfolio; + address user = address(0x1); + + function setUp() public { + portfolio = new ProjectPortfolio( + payable(address(0x2)), // project contract + address(0x3) // user profile contract + ); + } + + function testPortfolioManagement() public { + vm.startPrank(user); + + // Set up portfolio metadata + string[] memory skills = new string[](1); + skills[0] = "Solidity"; + + portfolio.updatePortfolioMetadata( + "Test Portfolio", + "Test Description", + skills, + true + ); + + // Add portfolio item + string[] memory tags = new string[](1); + tags[0] = "Test"; + + portfolio.addPortfolioItem( + 1, // projectId + "Test Project", + tags, + "test://media", + true + ); + + // Verify portfolio + PortfolioItem[] memory items = portfolio.getPortfolioItems(user); + assertEq(items.length, 1); + assertEq(items[0].projectId, 1); + + vm.stopPrank(); + } +} +``` + +## Security Considerations + +1. **Access Control** + - Verify user registration + - Enforce privacy settings + - Protect portfolio updates + - Validate ownership + +2. **Data Validation** + - Verify project existence + - Validate media URLs + - Check tag validity + - Ensure unique entries + +3. **Privacy Protection** + - Respect visibility settings + - Protect private data + - Validate viewers + - Handle permissions + +4. **Error Handling** + - Handle missing items + - Manage duplicates + - Process removals safely + - Validate updates diff --git a/docs/ProjectTemplates-Tutorial.md b/docs/ProjectTemplates-Tutorial.md new file mode 100644 index 0000000..1dfe15a --- /dev/null +++ b/docs/ProjectTemplates-Tutorial.md @@ -0,0 +1,285 @@ +# ProjectTemplates Contract Tutorial + +The ProjectTemplates contract provides a system for creating and managing project templates, enabling standardized project initialization and consistent project structures across the platform. + +## Core Features + +1. Template Management +2. Project Type Classification +3. Required Fields Definition +4. Category Integration + +## Template Types + +The system supports six template types: + +1. **TechInnovation** + - Software Development + - Hardware Projects + - Technical Solutions + +2. **SocialImpact** + - Community Projects + - Social Enterprises + - Humanitarian Initiatives + +3. **CreativeArts** + - Digital Art + - Music + - Media Projects + +4. **ResearchAndDevelopment** + - Scientific Research + - Product Development + - Innovation Studies + +5. **CommunityInitiative** + - Local Projects + - Community Programs + - Grassroots Movements + +6. **Other** + - Custom Projects + - Cross-domain Initiatives + - Unique Ventures + +## Template Structure + +Each template contains: +- Unique ID +- Name +- Template Type +- Description +- Required Fields +- Recommended Categories +- Active Status +- Creator Address + +## Core Functions + +### Creating Templates + +Create new project templates: + +```solidity +function createTemplate( + string memory name, + TemplateType templateType, + string memory description, + string[] memory requiredFields, + uint256[] memory recommendedCategories +) public returns (uint256) +``` + +Example usage: +```solidity +string[] memory fields = new string[](3); +fields[0] = "projectGoals"; +fields[1] = "technicalSpecs"; +fields[2] = "timeline"; + +uint256[] memory categories = new uint256[](2); +categories[0] = 1; // e.g., "DeFi" category +categories[1] = 2; // e.g., "Smart Contracts" category + +uint256 templateId = projectTemplates.createTemplate( + "DeFi Protocol Template", + ProjectTemplates.TemplateType.TechInnovation, + "Template for creating new DeFi protocols", + fields, + categories +); +``` + +### Using Templates + +Use existing templates for new projects: + +```solidity +function useTemplate(uint256 templateId) + public + view + returns (Template memory) +``` + +Example usage: +```solidity +Template memory template = projectTemplates.useTemplate(templateId); + +// Access template details +string memory name = template.name; +string[] memory requiredFields = template.requiredFields; +uint256[] memory categories = template.recommendedCategories; +``` + +### Querying Templates + +Find templates by type: + +```solidity +function getTemplatesByType(TemplateType templateType) + public + view + returns (uint256[] memory) +``` + +Example usage: +```solidity +uint256[] memory techTemplates = projectTemplates.getTemplatesByType( + ProjectTemplates.TemplateType.TechInnovation +); +``` + +## Integration Example + +Here's a complete example of template management: + +```solidity +contract ProjectManager { + ProjectTemplates public templates; + + function setupTemplates() external { + // Create required fields + string[] memory fields = new string[](4); + fields[0] = "title"; + fields[1] = "description"; + fields[2] = "timeline"; + fields[3] = "budget"; + + // Set recommended categories + uint256[] memory categories = new uint256[](2); + categories[0] = 1; // Tech category + categories[1] = 2; // Innovation category + + // Create template + uint256 templateId = templates.createTemplate( + "Standard Tech Project", + ProjectTemplates.TemplateType.TechInnovation, + "Template for technology projects", + fields, + categories + ); + + // Use template + Template memory template = templates.useTemplate(templateId); + + // Get all tech templates + uint256[] memory techTemplates = templates.getTemplatesByType( + ProjectTemplates.TemplateType.TechInnovation + ); + } +} +``` + +## Events + +Monitor template activities through these events: + +```solidity +event TemplateCreated( + uint256 indexed templateId, + string name, + TemplateType templateType +); + +event TemplateUsed( + address indexed project, + uint256 templateId +); +``` + +## Best Practices + +1. **Template Creation** + - Use clear, descriptive names + - Include essential required fields + - Choose appropriate categories + - Provide detailed descriptions + +2. **Required Fields** + - Include all necessary information + - Use consistent field names + - Consider project type needs + - Balance completeness with usability + +3. **Category Integration** + - Validate category existence + - Choose relevant categories + - Consider cross-category needs + - Update as categories change + +4. **Template Management** + - Monitor template usage + - Update outdated templates + - Remove unused templates + - Maintain template quality + +## Testing Example + +Here's how to test the template system: + +```solidity +contract ProjectTemplatesTest is Test { + ProjectTemplates public templates; + ProjectCategories public categories; + + function setUp() public { + categories = new ProjectCategories(); + templates = new ProjectTemplates(address(categories)); + } + + function testTemplateCreation() public { + // Create required fields + string[] memory fields = new string[](2); + fields[0] = "name"; + fields[1] = "description"; + + // Create categories + uint256[] memory cats = new uint256[](1); + cats[0] = 1; + + // Create template + uint256 templateId = templates.createTemplate( + "Test Template", + ProjectTemplates.TemplateType.TechInnovation, + "Test Description", + fields, + cats + ); + + // Use template + Template memory template = templates.useTemplate(templateId); + + // Verify template + assertEq(template.name, "Test Template"); + assertEq(template.requiredFields.length, 2); + assertEq(template.recommendedCategories.length, 1); + } +} +``` + +## Security Considerations + +1. **Data Validation** + - Validate category existence + - Check required fields + - Verify template activity + - Validate input lengths + +2. **Access Control** + - Consider creator permissions + - Manage template updates + - Control template usage + - Monitor template creation + +3. **Template Integrity** + - Maintain consistent structure + - Validate field requirements + - Ensure category validity + - Check template status + +4. **System Scalability** + - Manage template growth + - Optimize queries + - Handle template updates + - Consider gas costs diff --git a/docs/ProposalTemplates-Tutorial.md b/docs/ProposalTemplates-Tutorial.md new file mode 100644 index 0000000..a3d74a5 --- /dev/null +++ b/docs/ProposalTemplates-Tutorial.md @@ -0,0 +1,320 @@ +# ProposalTemplates Contract Tutorial + +The ProposalTemplates contract provides a system for creating and managing standardized governance proposal templates, making it easier for users to create well-structured proposals while ensuring consistency and security. + +## Core Features + +1. Template Management System +2. Role-based Access Control +3. Dynamic Parameter Handling +4. Proposal Call Encoding + +## Template Structure + +### Template Components +- Name +- Description +- Target Contract Address +- Function Selector +- Parameter Names +- Parameter Types +- Active Status + +### Access Control +- DEFAULT_ADMIN_ROLE: Contract administration +- TEMPLATE_ADMIN_ROLE: Template management + +## Template Management + +### Creating Templates + +Administrators can create new proposal templates: + +```solidity +function createTemplate( + string memory name, + string memory description, + address targetContract, + bytes4 functionSelector, + string[] memory parameterNames, + string[] memory parameterTypes +) external onlyRole(TEMPLATE_ADMIN_ROLE) +``` + +Example usage: +```solidity +// Create a template for updating platform fees +string[] memory paramNames = new string[](1); +paramNames[0] = "newFeePercentage"; + +string[] memory paramTypes = new string[](1); +paramTypes[0] = "uint256"; + +proposalTemplates.createTemplate( + "Update Platform Fee", + "Proposal to update the platform fee percentage", + platformAddress, + bytes4(keccak256("setFeePercentage(uint256)")), + paramNames, + paramTypes +); +``` + +### Deactivating Templates + +Administrators can deactivate obsolete templates: + +```solidity +function deactivateTemplate(uint256 templateId) external onlyRole(TEMPLATE_ADMIN_ROLE) +``` + +Example usage: +```solidity +// Deactivate an obsolete template +proposalTemplates.deactivateTemplate(templateId); +``` + +### Retrieving Template Information + +View template details: + +```solidity +function getTemplate(uint256 templateId) external view returns ( + string memory name, + string memory description, + address targetContract, + bytes4 functionSelector, + string[] memory parameterNames, + string[] memory parameterTypes, + bool active +) +``` + +Example usage: +```solidity +// Get template details +( + string memory name, + string memory description, + address target, + bytes4 selector, + string[] memory paramNames, + string[] memory paramTypes, + bool active +) = proposalTemplates.getTemplate(templateId); +``` + +## Proposal Generation + +### Generating Descriptions + +Create human-readable proposal descriptions: + +```solidity +function generateDescription( + uint256 templateId, + string[] memory parameters +) public view returns (string memory) +``` + +Example usage: +```solidity +// Generate proposal description +string[] memory params = new string[](1); +params[0] = "2.5"; + +string memory description = proposalTemplates.generateDescription( + templateId, + params +); +``` + +### Encoding Proposal Calls + +Generate encoded function calls for proposals: + +```solidity +function encodeProposalCall( + uint256 templateId, + bytes memory parameters +) public view returns (address, bytes memory) +``` + +Example usage: +```solidity +// Encode proposal call +bytes memory params = abi.encode(250); // 2.5% encoded as basis points +(address target, bytes memory data) = proposalTemplates.encodeProposalCall( + templateId, + params +); +``` + +## Integration Example + +Here's a complete example of integrating proposal templates with a governance system: + +```solidity +contract GovernanceSystem { + ProposalTemplates public templates; + + function createProposal( + uint256 templateId, + string[] memory humanReadableParams, + bytes memory encodedParams + ) external { + // Generate proposal description + string memory description = templates.generateDescription( + templateId, + humanReadableParams + ); + + // Get encoded call data + (address target, bytes memory data) = templates.encodeProposalCall( + templateId, + encodedParams + ); + + // Create proposal + uint256 proposalId = _createProposal( + description, + target, + data + ); + + emit ProposalCreated(proposalId, msg.sender, templateId); + } + + function _createProposal( + string memory description, + address target, + bytes memory data + ) internal returns (uint256) { + // Implementation specific to governance system + // ... + } +} +``` + +## Events + +Monitor template management activities: + +```solidity +event TemplateCreated(uint256 indexed templateId, string name); +event TemplateUpdated(uint256 indexed templateId); +event TemplateDeactivated(uint256 indexed templateId); +``` + +## Best Practices + +1. **Template Creation** + - Use clear, descriptive names + - Provide detailed descriptions + - Verify parameter counts match + - Document parameter types clearly + +2. **Parameter Management** + - Use consistent parameter naming + - Validate parameter types + - Consider parameter constraints + - Document expected formats + +3. **Template Maintenance** + - Regular template reviews + - Deactivate obsolete templates + - Update documentation + - Monitor usage patterns + +4. **Integration** + - Validate encoded calls + - Handle template updates + - Monitor events + - Implement proper error handling + +## Testing Example + +Here's how to test the proposal templates system: + +```solidity +contract ProposalTemplatesTest is Test { + ProposalTemplates public templates; + address admin = address(0x1); + + function setUp() public { + templates = new ProposalTemplates(); + vm.startPrank(admin); + + // Setup template admin role + templates.grantRole(templates.TEMPLATE_ADMIN_ROLE(), admin); + } + + function testCreateTemplate() public { + string[] memory paramNames = new string[](1); + paramNames[0] = "newFee"; + + string[] memory paramTypes = new string[](1); + paramTypes[0] = "uint256"; + + templates.createTemplate( + "Update Fee", + "Update platform fee", + address(0x2), + bytes4(keccak256("setFee(uint256)")), + paramNames, + paramTypes + ); + + // Verify template + ( + string memory name, + , + address target, + bytes4 selector, + string[] memory names, + string[] memory types, + bool active + ) = templates.getTemplate(0); + + assertEq(name, "Update Fee"); + assertEq(target, address(0x2)); + assertEq(selector, bytes4(keccak256("setFee(uint256)"))); + assertEq(names[0], "newFee"); + assertEq(types[0], "uint256"); + assertTrue(active); + } + + function testGenerateDescription() public { + // Create template first + // ... (setup as above) + + string[] memory params = new string[](1); + params[0] = "100"; + + string memory description = templates.generateDescription(0, params); + assertTrue(bytes(description).length > 0); + } +} +``` + +## Security Considerations + +1. **Access Control** + - Role-based permissions + - Admin role management + - Template activation control + +2. **Input Validation** + - Parameter count validation + - Parameter type checking + - Target contract verification + +3. **Template Security** + - Function selector validation + - Target contract verification + - Parameter encoding safety + +4. **Integration Security** + - Proper error handling + - Event monitoring + - State consistency checks diff --git a/docs/QuadraticFunding-Tutorial.md b/docs/QuadraticFunding-Tutorial.md new file mode 100644 index 0000000..e4372ed --- /dev/null +++ b/docs/QuadraticFunding-Tutorial.md @@ -0,0 +1,295 @@ +# Quadratic Funding Tutorial + +This tutorial explains how to use the QuadraticFunding contract, which implements a quadratic funding mechanism for distributing matching funds to projects on the Backr platform. + +## Core Concepts + +### Funding Rounds +Each funding round has: +- Start and end time +- Matching pool +- Contribution limits (min/max) +- Project contributions tracking +- Participant eligibility + +### Quadratic Funding +The matching amount for each project is calculated based on the square root of contributions, giving more weight to multiple small contributions over fewer large ones. + +## Managing Funding Rounds + +### Creating a New Round + +```solidity +// Round configuration +RoundConfig memory config = RoundConfig({ + startTime: block.timestamp + 1 days, + endTime: block.timestamp + 15 days, + minContribution: 0.1 ether, + maxContribution: 10 ether +}); + +// Create round with initial matching pool +quadraticFunding.createRound{value: 100 ether}(config); +``` + +**Requirements**: +- Only admins can create rounds +- Must include initial matching pool funds +- Valid time period (end > start) +- Valid contribution limits (max > min) + +### Contributing to Matching Pool + +```solidity +// Add more funds to matching pool +quadraticFunding.contributeToMatchingPool{value: 50 ether}(roundId); +``` + +### Managing Participant Eligibility + +```solidity +// Verify participant eligibility +quadraticFunding.verifyParticipant(participantAddress, true); +``` + +## Contributing to Projects + +### Making Contributions + +```solidity +// Contribute to a project +quadraticFunding.contribute{value: 1 ether}(projectId); +``` + +**Requirements**: +- Active round +- Eligible participant +- Contribution within min/max limits +- Round not cancelled + +### Checking Contribution Status + +```solidity +// Get total contributions for a project +uint256 total = quadraticFunding.getProjectContributions(roundId, projectId); + +// Get individual contribution +uint256 amount = quadraticFunding.getContribution( + roundId, + projectId, + contributorAddress +); +``` + +## Round Management + +### Checking Round Status + +```solidity +// Check if round is active +bool active = quadraticFunding.isRoundActive(); +``` + +### Cancelling a Round + +```solidity +// Only admins can cancel rounds +quadraticFunding.cancelRound(); +``` + +### Finalizing a Round + +```solidity +// Calculate and distribute matching funds +quadraticFunding.finalizeRound(); +``` + +**Important Notes**: +- Round must be ended +- Cannot be already finalized +- Must have contributions +- Not cancelled + +## Analytics + +### Viewing Round Analytics + +```solidity +// Get round statistics +RoundAnalytics memory analytics = quadraticFunding.getRoundAnalytics(roundId); + +// Analytics include: +// - Unique contributors +// - Total projects +// - Average contribution +// - Median contribution +``` + +## Events to Monitor + +1. Round Lifecycle Events: + ```solidity + event RoundStarted(uint256 indexed roundId, uint256 matchingPool); + event RoundFinalized(uint256 indexed roundId, uint256 totalMatching); + event RoundCancelledEvent(uint256 indexed roundId); + event RoundConfigured( + uint256 indexed roundId, + uint256 startTime, + uint256 endTime, + uint256 minContribution, + uint256 maxContribution + ); + ``` + +2. Contribution Events: + ```solidity + event ContributionAdded( + uint256 indexed roundId, + uint256 indexed projectId, + address indexed contributor, + uint256 amount + ); + event MatchingPoolContribution( + uint256 indexed roundId, + address indexed contributor, + uint256 amount + ); + event MatchingFundsDistributed( + uint256 indexed roundId, + uint256 indexed projectId, + uint256 amount + ); + ``` + +3. Participant Management: + ```solidity + event ParticipantVerified( + address indexed participant, + bool eligible + ); + ``` + +## Understanding Matching Calculations + +The matching amount for each project is calculated using the quadratic funding formula: + +1. Calculate square root of each project's total contributions +2. Sum all square roots +3. Distribute matching pool proportionally based on square root ratios + +Example: +``` +Project A: 100 ETH from 1 contributor +Project B: 100 ETH from 100 contributors + +Square root calculation: +A = √100 = 10 +B = √(1² × 100) = √100 = 10 + +Despite same total, they receive equal matching because B had more contributors +``` + +## Best Practices + +1. **Round Creation** + - Set appropriate duration (default 14 days) + - Consider contribution limits carefully + - Ensure sufficient matching pool + +2. **Participant Management** + - Verify participants before round starts + - Document verification criteria + - Monitor eligibility status + +3. **Contribution Handling** + - Monitor contribution patterns + - Track matching pool size + - Consider gas costs + +4. **Round Finalization** + - Wait for round completion + - Verify all contributions processed + - Monitor matching distribution + +## Complete Example + +Here's a full example of managing a funding round: + +```solidity +// 1. Create new round +RoundConfig memory config = RoundConfig({ + startTime: block.timestamp + 1 days, + endTime: block.timestamp + 15 days, + minContribution: 0.1 ether, + maxContribution: 10 ether +}); + +quadraticFunding.createRound{value: 100 ether}(config); + +// 2. Verify participants +address[] memory participants = getEligibleParticipants(); +for (uint i = 0; i < participants.length; i++) { + quadraticFunding.verifyParticipant(participants[i], true); +} + +// 3. Accept contributions during round +// (from participant perspective) +quadraticFunding.contribute{value: 1 ether}(projectId); + +// 4. Monitor round progress +RoundAnalytics memory analytics = quadraticFunding.getRoundAnalytics( + currentRound +); + +// 5. Finalize round after end +if (block.timestamp > config.endTime) { + quadraticFunding.finalizeRound(); +} + +// 6. Check matching results +uint256 matching = quadraticFunding.getMatchingAmount( + currentRound, + projectId +); +``` + +## Security Considerations + +1. **Round Management** + - Verify round parameters + - Monitor matching pool + - Handle cancellations properly + +2. **Contribution Validation** + - Check eligibility + - Verify contribution limits + - Monitor for manipulation + +3. **Matching Distribution** + - Verify calculations + - Monitor fund transfers + - Handle edge cases + +4. **Analytics** + - Track unusual patterns + - Monitor for gaming attempts + - Validate statistics + +## Error Handling + +Common errors you might encounter: + +```solidity +RoundNotActive() // Round hasn't started or has ended +RoundAlreadyActive() // Cannot start new round while one is active +InsufficientContribution() // Contribution below minimum +RoundNotEnded() // Cannot finalize active round +RoundAlreadyFinalized() // Round already completed +NoContributions() // No contributions to process +MatchingPoolEmpty() // No matching funds available +RoundCancelledError() // Round was cancelled +UnauthorizedAdmin() // Not an admin +ContributionTooLow() // Below minimum contribution +ContributionTooHigh() // Above maximum contribution +ParticipantNotEligible() // Contributor not verified +InvalidRoundConfig() // Invalid round parameters diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..771c549 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,45 @@ +# Documentation Index + +This directory contains comprehensive documentation for all platform features and components. Each document provides detailed tutorials and implementation guides. + +## Core Platform Features + +- [User Profile Tutorial](./UserProfile-Tutorial.md) - User account management and profile features +- [Badge Tutorial](./Badge-Tutorial.md) - Platform badge system implementation +- [Badge Marketplace Tutorial](./BadgeMarketplace-Tutorial.md) - Trading and managing badges +- [Platform Token Tutorial](./PlatformToken-Tutorial.md) - Native token implementation and usage + +## Project Management + +- [Project Tutorial](./Project-Tutorial.md) - Core project functionality +- [Project Categories Tutorial](./ProjectCategories-Tutorial.md) - Project categorization system +- [Project Portfolio Tutorial](./ProjectPortfolio-Tutorial.md) - Portfolio management features +- [Project Templates Tutorial](./ProjectTemplates-Tutorial.md) - Project template system +- [Team Management Tutorial](./TeamManagement-Tutorial.md) - Team collaboration features +- [Proposal Templates Tutorial](./ProposalTemplates-Tutorial.md) - Project proposal system + +## Governance & Voting + +- [Governance Tutorial](./Governance-Tutorial.md) - Platform governance mechanisms +- [Committee Governance Tutorial](./CommitteeGovernance-Tutorial.md) - Committee-based governance +- [Gasless Voting Tutorial](./GaslessVoting-Tutorial.md) - Gas-efficient voting implementation +- [Dispute Resolution Tutorial](./DisputeResolution-Tutorial.md) - Conflict resolution system + +## Financial Features + +- [Quadratic Funding Tutorial](./QuadraticFunding-Tutorial.md) - Quadratic funding implementation +- [Liquidity Pool Tutorial](./LiquidityPool-Tutorial.md) - Platform liquidity management +- [Liquidity Incentives Tutorial](./LiquidityIncentives-Tutorial.md) - Incentive mechanisms + +## Security & Settings + +- [Security Controls Tutorial](./SecurityControls-Tutorial.md) - Platform security features +- [Security Controls Settings](./SecurityControls-Settings.md) - Security configuration guide + +## Contributing + +When adding new documentation: +1. Follow the existing naming convention: `FeatureName-Tutorial.md` +2. Update this index to include the new documentation +3. Group the documentation in the appropriate category +4. Provide a brief description of the feature/component diff --git a/docs/SecurityControls-Settings.md b/docs/SecurityControls-Settings.md new file mode 100644 index 0000000..df9aea0 --- /dev/null +++ b/docs/SecurityControls-Settings.md @@ -0,0 +1,80 @@ +# Security Controls Settings Documentation + +## Rate Limiting Settings + +Rate limiting can be configured per operation using `configureRateLimit(bytes32 operation, uint256 limit, uint256 window)`: + +- `operation`: Unique identifier for the operation (bytes32 hash) +- `limit`: Maximum number of calls allowed within the time window +- `window`: Time window in seconds +- `currentCount`: Tracks current number of calls (auto-managed) +- `windowStart`: Timestamp when current window started (auto-managed) + +Example: +```solidity +_configureRateLimit(WITHDRAWAL, 10, 1 days); // 10 withdrawals per day +``` + +## Multi-Signature Settings + +Multi-sig requirements configured via `configureMultiSig(bytes32 operation, uint256 requiredApprovals, address[] memory approvers)`: + +- `operation`: Unique identifier for the operation requiring multi-sig +- `requiredApprovals`: Number of approvals needed to execute +- `approvers`: Array of addresses authorized to approve +- Transaction tracking (auto-managed): + - `approvals`: Maps transaction hashes to approver addresses + - `executed`: Tracks which transactions have been executed + - `approvalCount`: Number of approvals received per transaction + +Example: +```solidity +address[] memory approvers = new address[](3); +approvers[0] = address(0x1); +approvers[1] = address(0x2); +approvers[2] = address(0x3); +_configureMultiSig(LARGE_WITHDRAWAL, 2, approvers); // Requires 2 of 3 approvers +``` + +## Emergency Control Settings + +Emergency settings managed through EmergencyConfig struct: + +- `circuitBreakerEnabled`: Boolean flag for emergency state + - Set to true via `triggerEmergency(string reason)` + - Set to false via `resolveEmergency()` +- `lastEmergencyAction`: Timestamp of last emergency action (auto-managed) +- `cooldownPeriod`: Minimum time between emergency actions + - Default: 24 hours + - Configurable via `setEmergencyCooldownPeriod(uint256 cooldownPeriod)` + +## Access Control Roles + +Built-in roles (managed via OpenZeppelin AccessControl): + +- `DEFAULT_ADMIN_ROLE`: Can configure rate limits and multi-sig settings +- `EMERGENCY_ROLE`: Can trigger and resolve emergency states +- `OPERATOR_ROLE`: Basic operational permissions + +## Modifiers Available + +Security modifiers that can be applied to functions: + +- `rateLimitGuard(bytes32 operation)`: Enforces rate limiting +- `requiresApproval(bytes32 operation, bytes32 txHash)`: Requires multi-sig approval +- `whenCircuitBreakerOff()`: Blocks execution during emergency +- `nonReentrant`: Prevents reentrancy attacks (inherited from ReentrancyGuard) +- `whenNotPaused`: Blocks execution when contract is paused (inherited from Pausable) + +## Events Emitted + +Events for monitoring and tracking: + +- `RateLimitConfigured(bytes32 indexed operation, uint256 limit, uint256 window)` +- `RateLimitExceeded(bytes32 indexed operation, address indexed caller)` +- `MultiSigConfigured(bytes32 indexed operation, uint256 requiredApprovals)` +- `MultiSigApproval(bytes32 indexed operation, bytes32 indexed txHash, address indexed approver)` +- `MultiSigExecuted(bytes32 indexed operation, bytes32 indexed txHash)` +- `EmergencyActionTriggered(address indexed triggeredBy, string reason)` +- `EmergencyCooldownUpdated(uint256 newCooldownPeriod)` +- `CircuitBreakerStatusChanged(bool enabled)` diff --git a/docs/SecurityControls-Tutorial.md b/docs/SecurityControls-Tutorial.md new file mode 100644 index 0000000..3079f4f --- /dev/null +++ b/docs/SecurityControls-Tutorial.md @@ -0,0 +1,256 @@ +# SecurityControls Contract Tutorial + +The SecurityControls contract is a comprehensive security management system for Solidity smart contracts that implements three core security features: +1. Rate Limiting +2. Multi-signature Requirements +3. Emergency Controls + +> **Note**: For a complete list of all available settings and configurations, see [SecurityControls-Settings.md](SecurityControls-Settings.md) + +## Overview + +The contract inherits from three OpenZeppelin contracts: +- `AccessControl`: For role-based access control +- `Pausable`: For emergency pause functionality +- `ReentrancyGuard`: For protection against reentrancy attacks + +## Key Features + +### 1. Rate Limiting + +Rate limiting prevents excessive calls to specific operations within a time window. This is useful for protecting against spam attacks or resource exhaustion. + +```solidity +// Configure rate limiting for an operation +function configureRateLimit( + bytes32 operation, + uint256 limit, + uint256 window +) external onlyRole(DEFAULT_ADMIN_ROLE) + +// Usage example: +contract MyContract is SecurityControls { + bytes32 public constant WITHDRAW_OPERATION = keccak256("WITHDRAW"); + + function setUp() { + // Allow 5 withdrawals per day + configureRateLimit(WITHDRAW_OPERATION, 5, 1 days); + } + + function withdraw() external rateLimitGuard(WITHDRAW_OPERATION) { + // Withdrawal logic here + } +} +``` + +### 2. Multi-signature Requirements + +Multi-sig functionality requires multiple approvers to sign off on sensitive operations before they can be executed. + +```solidity +// Configure multi-sig requirements +function configureMultiSig( + bytes32 operation, + uint256 requiredApprovals, + address[] memory approvers +) public onlyRole(DEFAULT_ADMIN_ROLE) + +// Usage example: +contract MyContract is SecurityControls { + bytes32 public constant LARGE_TRANSFER = keccak256("LARGE_TRANSFER"); + bytes32 public transferTxHash; + + function setUp() { + address[] memory approvers = new address[](3); + approvers[0] = address(0x1); // Replace with actual addresses + approvers[1] = address(0x2); + approvers[2] = address(0x3); + + // Require 2 out of 3 approvals + configureMultiSig(LARGE_TRANSFER, 2, approvers); + } + + function initiateTransfer() external requiresApproval(LARGE_TRANSFER, transferTxHash) { + // Transfer logic here + } +} +``` + +### 3. Emergency Controls + +Emergency controls provide circuit breaker functionality and cool-down periods for crisis management. + +```solidity +// Trigger emergency mode +function triggerEmergency(string calldata reason) external onlyRole(EMERGENCY_ROLE) + +// Resolve emergency +function resolveEmergency() external onlyRole(EMERGENCY_ROLE) + +// Usage example: +contract MyContract is SecurityControls { + function criticalOperation() external whenCircuitBreakerOff { + // Critical operation logic here + } +} +``` + +## Role-Based Access Control + +The contract defines three main roles: +1. `DEFAULT_ADMIN_ROLE`: Can configure rate limits and multi-sig requirements +2. `EMERGENCY_ROLE`: Can trigger and resolve emergency situations +3. `OPERATOR_ROLE`: For day-to-day operations + +```solidity +// Granting roles +contract MyContract is SecurityControls { + function setUp() { + _grantRole(EMERGENCY_ROLE, emergencyAdmin); + _grantRole(OPERATOR_ROLE, operator); + } +} +``` + +## Best Practices + +1. **Rate Limiting** + - Set appropriate limits based on expected legitimate usage + - Consider different time windows for different operations + - Monitor rate limit hits to detect potential attacks + +2. **Multi-signature** + - Choose an appropriate number of required approvals + - Maintain a diverse set of approvers + - Consider the operational impact of required approvals + +3. **Emergency Controls** + - Limit emergency role access to trusted entities + - Have clear procedures for emergency situations + - Test emergency procedures regularly + - Set appropriate cooldown periods + +## Events + +The contract emits various events for monitoring and auditing: + +```solidity +event RateLimitConfigured(bytes32 indexed operation, uint256 limit, uint256 window); +event RateLimitExceeded(bytes32 indexed operation, address indexed caller); +event MultiSigConfigured(bytes32 indexed operation, uint256 requiredApprovals); +event MultiSigApproval(bytes32 indexed operation, bytes32 indexed txHash, address indexed approver); +event MultiSigExecuted(bytes32 indexed operation, bytes32 indexed txHash); +event EmergencyActionTriggered(address indexed triggeredBy, string reason); +event EmergencyCooldownUpdated(uint256 newCooldownPeriod); +event CircuitBreakerStatusChanged(bool enabled); +``` + +## Testing + +Here's an example of how to test the security controls: + +```solidity +contract SecurityControlsTest is Test { + SecurityControls public securityControls; + + function setUp() public { + securityControls = new SecurityControls(); + } + + function testRateLimit() public { + // Configure rate limit + securityControls.configureRateLimit( + keccak256("TEST_OP"), + 2, // 2 calls allowed + 1 hours // per hour + ); + + // First two calls should succeed + rateLimitedOperation(); + rateLimitedOperation(); + + // Third call should fail + vm.expectRevert("Rate limit exceeded"); + rateLimitedOperation(); + + // After time window, should work again + vm.warp(block.timestamp + 1 hours + 1); + rateLimitedOperation(); + } +} +``` + +## Integration Example + +Here's a complete example of integrating SecurityControls into a contract: + +```solidity +contract SecureVault is SecurityControls { + bytes32 public constant WITHDRAWAL = keccak256("WITHDRAWAL"); + bytes32 public constant LARGE_WITHDRAWAL = keccak256("LARGE_WITHDRAWAL"); + + uint256 public constant LARGE_AMOUNT = 100 ether; + + constructor() { + // Configure rate limiting + _configureRateLimit(WITHDRAWAL, 10, 1 days); // 10 withdrawals per day + + // Configure multi-sig for large withdrawals + address[] memory approvers = new address[](3); + approvers[0] = address(0x1); // Replace with actual addresses + approvers[1] = address(0x2); + approvers[2] = address(0x3); + _configureMultiSig(LARGE_WITHDRAWAL, 2, approvers); + } + + function withdraw(uint256 amount) external + rateLimitGuard(WITHDRAWAL) + whenCircuitBreakerOff + { + require(amount < LARGE_AMOUNT, "Use largeWithdraw for large amounts"); + // Withdrawal logic + } + + function largeWithdraw(uint256 amount, bytes32 txHash) external + requiresApproval(LARGE_WITHDRAWAL, txHash) + whenCircuitBreakerOff + { + require(amount >= LARGE_AMOUNT, "Use regular withdraw for small amounts"); + // Large withdrawal logic + } +} +``` + +## Security Considerations + +1. **Rate Limiting** + - Ensure rate limits are set appropriately for your use case + - Consider the impact of rate limits on legitimate users + - Monitor rate limit events to detect potential attacks + +2. **Multi-signature** + - Choose approvers carefully and maintain their list + - Consider the operational impact of required approvals + - Implement proper transaction hash generation and verification + +3. **Emergency Controls** + - Have clear procedures for emergency situations + - Test emergency procedures regularly + - Monitor emergency events + - Consider the impact of pausing on dependent contracts + +4. **Access Control** + - Carefully manage role assignments + - Regularly audit role holders + - Consider implementing role rotation procedures + +## Conclusion + +The SecurityControls contract provides a robust security framework for your smart contracts. By properly implementing rate limiting, multi-signature requirements, and emergency controls, you can significantly enhance the security of your smart contract system. + +Remember to: +- Thoroughly test all security features +- Monitor security events +- Maintain proper access control +- Have clear procedures for emergency situations +- Regularly review and update security parameters diff --git a/docs/TeamManagement-Tutorial.md b/docs/TeamManagement-Tutorial.md new file mode 100644 index 0000000..4eb9896 --- /dev/null +++ b/docs/TeamManagement-Tutorial.md @@ -0,0 +1,288 @@ +# TeamManagement Contract Tutorial + +The TeamManagement contract provides a comprehensive system for managing project teams, roles, and delegations. It enables structured team organization and flexible delegation of responsibilities. + +## Core Features + +1. Team Member Management +2. Role-based Access +3. Delegation System +4. Team Queries + +## Team Roles + +The system supports four hierarchical roles: + +1. **Owner** + - Highest level of access + - Full project control + - Team management rights + +2. **Admin** + - Administrative privileges + - Team management + - Project configuration + +3. **Member** + - Standard team access + - Project participation + - Basic permissions + +4. **Viewer** + - Read-only access + - Limited interaction + - Project observation + +## Team Structure + +### Team Members + +Each team member has: +- Ethereum Address +- Name +- Email +- Role +- Active Status + +### Delegations + +Delegation records include: +- Delegator Address +- Delegatee Address +- Validity Period +- Active Status + +## Core Functions + +### Managing Team Members + +Add new team members: + +```solidity +function addTeamMember( + address project, + address member, + string memory name, + string memory email, + TeamRole role +) public +``` + +Example usage: +```solidity +teamManagement.addTeamMember( + projectAddress, + memberAddress, + "John Doe", + "john@example.com", + TeamManagement.TeamRole.Member +); +``` + +### Managing Delegations + +Create and manage delegations: + +```solidity +// Create delegation +function createDelegation( + address delegatee, + uint256 validUntil +) public + +// Revoke delegation +function revokeDelegation() public +``` + +Example usage: +```solidity +// Create a 30-day delegation +uint256 validUntil = block.timestamp + 30 days; +teamManagement.createDelegation(delegateeAddress, validUntil); + +// Later, revoke the delegation +teamManagement.revokeDelegation(); +``` + +### Querying Team Information + +Get team and delegation information: + +```solidity +// Get team members +function getProjectTeamMembers(address project) + public + view + returns (TeamMember[] memory) + +// Check delegation status +function isDelegationActive(address delegator) + public + view + returns (bool) + +// Get current delegatee +function getDelegatee(address delegator) + public + view + returns (address) +``` + +## Integration Example + +Here's a complete example of team management: + +```solidity +contract ProjectCoordinator { + TeamManagement public teamManagement; + + function setupProjectTeam(address project) external { + // Add project owner + teamManagement.addTeamMember( + project, + msg.sender, + "Project Lead", + "lead@project.com", + TeamManagement.TeamRole.Owner + ); + + // Add team member + teamManagement.addTeamMember( + project, + address(0x123), + "Team Member", + "member@project.com", + TeamManagement.TeamRole.Member + ); + + // Create delegation + uint256 validUntil = block.timestamp + 30 days; + teamManagement.createDelegation(address(0x123), validUntil); + + // Query team + TeamMember[] memory team = teamManagement.getProjectTeamMembers(project); + + // Check delegation + bool isActive = teamManagement.isDelegationActive(msg.sender); + address delegatee = teamManagement.getDelegatee(msg.sender); + } +} +``` + +## Events + +Monitor team activities through these events: + +```solidity +event TeamMemberAdded( + address indexed project, + address indexed member, + TeamRole role +); + +event DelegationCreated( + address indexed delegator, + address indexed delegatee, + uint256 validUntil +); + +event DelegationRevoked( + address indexed delegator, + address indexed delegatee +); +``` + +## Best Practices + +1. **Team Structure** + - Define clear roles + - Maintain role hierarchy + - Document responsibilities + - Update roles as needed + +2. **Member Management** + - Verify member identities + - Keep information current + - Monitor active status + - Regular team audits + +3. **Delegation System** + - Set appropriate durations + - Monitor active delegations + - Regular delegation reviews + - Clear delegation paths + +4. **Access Control** + - Implement role checks + - Validate permissions + - Monitor role changes + - Audit access patterns + +## Testing Example + +Here's how to test the team management system: + +```solidity +contract TeamManagementTest is Test { + TeamManagement public teamMgmt; + address project = address(0x1); + address member = address(0x2); + address delegatee = address(0x3); + + function setUp() public { + teamMgmt = new TeamManagement(); + } + + function testTeamManagement() public { + // Add team member + teamMgmt.addTeamMember( + project, + member, + "Test Member", + "test@example.com", + TeamManagement.TeamRole.Member + ); + + // Create delegation + vm.startPrank(member); + uint256 validUntil = block.timestamp + 1 days; + teamMgmt.createDelegation(delegatee, validUntil); + + // Verify delegation + assertTrue(teamMgmt.isDelegationActive(member)); + assertEq(teamMgmt.getDelegatee(member), delegatee); + + // Revoke delegation + teamMgmt.revokeDelegation(); + assertFalse(teamMgmt.isDelegationActive(member)); + + vm.stopPrank(); + } +} +``` + +## Security Considerations + +1. **Role Management** + - Validate role assignments + - Protect role changes + - Maintain role hierarchy + - Audit role access + +2. **Delegation Security** + - Verify delegation periods + - Protect delegation changes + - Monitor active delegations + - Handle expired delegations + +3. **Member Data** + - Protect member information + - Validate email formats + - Secure member updates + - Handle member removal + +4. **Access Validation** + - Check permissions + - Validate operations + - Monitor activities + - Handle edge cases diff --git a/docs/UserProfile-Tutorial.md b/docs/UserProfile-Tutorial.md new file mode 100644 index 0000000..76b335f --- /dev/null +++ b/docs/UserProfile-Tutorial.md @@ -0,0 +1,278 @@ +# UserProfile Contract Tutorial + +This tutorial explains how to interact with the UserProfile contract, which manages user profiles, reputation, social connections, and endorsements on the Backr platform. + +## Core Features + +1. Profile Management +2. Verification System +3. Social Graph (Following/Followers) +4. Endorsement System +5. Profile Recovery + +## Profile Management + +### Creating a Profile + +To participate in the Backr platform, users must first create a profile: + +```solidity +userProfile.createProfile( + "alice_dev", // username + "Blockchain Developer", // bio + "ipfs://Qm..." // metadata IPFS hash +); +``` + +**Important Notes**: +- Usernames must be unique +- Profiles cannot be created while the contract is paused +- Each address can only have one profile + +### Updating a Profile + +Profiles can be updated with a 24-hour cooldown period: + +```solidity +userProfile.updateProfile( + "alice_web3", // new username + "Senior Web3 Dev", // new bio + "ipfs://Qm..." // new metadata IPFS hash +); +``` + +**Restrictions**: +- Must wait 24 hours between updates +- New username must be unique +- Cannot update while contract is paused + +### Checking Profile Status + +```solidity +// Check if an address has a profile +bool hasProfile = userProfile.hasProfile(address); + +// Get profile details +Profile memory profile = userProfile.getProfile(address); + +// Look up profile by username +Profile memory profile = userProfile.getProfileByUsername("alice_dev"); +``` + +## Verification System + +The platform supports multiple types of verification: + +### Basic Verification +Only accessible by addresses with VERIFIER_ROLE: + +```solidity +userProfile.verifyProfile(userAddress); +``` + +### Enhanced Verification +Supports different verification types with proof: + +```solidity +userProfile.verifyProfileEnhanced( + userAddress, + "KYC", // verification type + "ipfs://Qm..." // verification proof +); +``` + +### Checking Verification Status + +```solidity +VerificationData memory data = userProfile.getVerificationDetails(userAddress); +``` + +## Social Graph Features + +### Following Users + +```solidity +// Follow a user +userProfile.followUser(addressToFollow); + +// Unfollow a user +userProfile.unfollowUser(addressToUnfollow); +``` + +### Viewing Social Connections + +```solidity +// Get following list +address[] memory following = userProfile.getFollowing(userAddress); + +// Get followers list +address[] memory followers = userProfile.getFollowers(userAddress); + +// Check if following +bool isFollowing = userProfile.checkFollowing(follower, followed); + +// Get counts +uint256 followersCount = userProfile.followersCount(userAddress); +uint256 followingCount = userProfile.followingCount(userAddress); +``` + +## Endorsement System + +### Adding Endorsements + +```solidity +userProfile.addEndorsement( + userAddress, + "Solidity", // skill + "Excellent developer" // description +); +``` + +**Rules**: +- Cannot endorse yourself +- Cannot endorse the same skill twice +- User must have a profile + +### Managing Endorsements + +```solidity +// Remove an endorsement +userProfile.removeEndorsement(userAddress, "Solidity"); + +// View endorsements +Endorsement[] memory endorsements = userProfile.getEndorsements(userAddress); + +// Get skill endorsement count +uint256 count = userProfile.getSkillEndorsementCount(userAddress, "Solidity"); + +// Check if endorsed +bool hasEndorsed = userProfile.hasEndorsedSkill(endorser, endorsed, "Solidity"); +``` + +## Profile Recovery + +The platform includes a secure recovery system for lost access: + +### Setting Up Recovery + +```solidity +// Set recovery address +userProfile.setRecoveryAddress(recoveryAddress); +``` + +### Recovery Process + +1. Initiate Recovery: +```solidity +userProfile.initiateRecovery(oldAddress); +``` + +2. Execute Recovery (after 3-day delay): +```solidity +userProfile.executeRecovery(oldAddress); +``` + +**Important Notes**: +- Must wait 3 days between initiation and execution +- Only the recovery address can initiate and execute +- All profile data is transferred to the new address + +## Events to Monitor + +The contract emits various events for tracking changes: + +1. Profile Management: + - `ProfileCreated(address user, string username)` + - `ProfileUpdated(address user)` + - `MetadataUpdated(address user, string metadata)` + +2. Verification: + - `ProfileVerified(address user)` + - `ProfileVerificationUpdated(address user, string verificationType, bool verified)` + +3. Social: + - `FollowUser(address follower, address followed)` + - `UnfollowUser(address follower, address unfollowed)` + +4. Endorsements: + - `EndorsementAdded(address endorser, address endorsed, string skill)` + - `EndorsementRemoved(address endorser, address endorsed, string skill)` + +5. Recovery: + - `RecoveryAddressSet(address user, address recoveryAddress)` + - `RecoveryRequested(address user, uint256 requestTime)` + - `RecoveryExecuted(address oldAddress, address newAddress)` + +## Error Handling + +Common errors you might encounter: + +```solidity +ProfileAlreadyExists() // Address already has a profile +ProfileDoesNotExist() // Profile not found +InvalidUsername() // Empty username +UsernameTaken() // Username already in use +UpdateTooSoon() // Cooldown period not met +NotVerified() // Profile not verified +InvalidRecoveryAddress() // Invalid recovery address +RecoveryDelayNotMet() // 3-day delay not met +NoRecoveryRequested() // Recovery not initiated +Unauthorized() // Not authorized for action +InvalidReputationScore() // Score exceeds maximum +``` + +## Best Practices + +1. **Profile Creation** + - Choose a unique, meaningful username + - Provide comprehensive bio information + - Store detailed metadata in IPFS + +2. **Profile Updates** + - Plan updates around cooldown period + - Maintain consistent username scheme + - Keep metadata current + +3. **Social Interactions** + - Verify profiles before following + - Build meaningful connections + - Regularly update social graph + +4. **Endorsements** + - Provide detailed endorsement descriptions + - Endorse specific, verifiable skills + - Maintain professional endorsement practices + +5. **Security** + - Set up recovery address immediately + - Store recovery information securely + - Regularly verify profile settings + +## Testing Example + +Here's a complete example of setting up and using a profile: + +```solidity +// 1. Create profile +userProfile.createProfile( + "dev_alice", + "Blockchain Developer specializing in DeFi", + "ipfs://Qm..." +); + +// 2. Set recovery address +userProfile.setRecoveryAddress(recoveryWallet); + +// 3. Follow other users +userProfile.followUser(otherDev); + +// 4. Add endorsements +userProfile.addEndorsement( + otherDev, + "Smart Contracts", + "Excellent Solidity developer, worked together on DeFi project" +); + +// 5. Check profile status +Profile memory myProfile = userProfile.getProfile(address(this)); +VerificationData memory verificationStatus = userProfile.getVerificationDetails(address(this)); diff --git a/script/DeployMVP.s.sol b/script/DeployMVP.s.sol index a0c63af..df41cbc 100644 --- a/script/DeployMVP.s.sol +++ b/script/DeployMVP.s.sol @@ -73,24 +73,16 @@ contract DeployMVP is Script { // Setup rate limits for key operations bytes32 projectCreationOp = keccak256("PROJECT_CREATION"); bytes32 qfContributionOp = keccak256("QF_CONTRIBUTION"); - - securityControls.configureRateLimit( - projectCreationOp, - PROJECT_CREATION_LIMIT, - RATE_LIMIT_WINDOW - ); - securityControls.configureRateLimit( - qfContributionOp, - QF_CONTRIBUTION_LIMIT, - RATE_LIMIT_WINDOW - ); + + securityControls.configureRateLimit(projectCreationOp, PROJECT_CREATION_LIMIT, RATE_LIMIT_WINDOW); + securityControls.configureRateLimit(qfContributionOp, QF_CONTRIBUTION_LIMIT, RATE_LIMIT_WINDOW); // Setup multi-sig configuration for emergency actions address[] memory emergencyApprovers = new address[](3); emergencyApprovers[0] = deployer; emergencyApprovers[1] = address(governance); emergencyApprovers[2] = address(project); - + securityControls.configureMultiSig( keccak256("EMERGENCY_ACTION"), 2, // Require 2 out of 3 approvals @@ -101,7 +93,7 @@ contract DeployMVP is Script { securityControls.grantRole(securityControls.OPERATOR_ROLE(), address(project)); securityControls.grantRole(securityControls.OPERATOR_ROLE(), address(qf)); securityControls.grantRole(securityControls.EMERGENCY_ROLE(), address(governance)); - + console2.log("Setup security controls and permissions"); // 5. Initial funding and setup @@ -124,11 +116,11 @@ contract DeployMVP is Script { }); qf.createRound{value: INITIAL_QF_POOL}(config); qf.verifyParticipant(deployer, true); - console2.log("Created initial funding round with", INITIAL_QF_POOL/1e18, "ETH"); + console2.log("Created initial funding round with", INITIAL_QF_POOL / 1e18, "ETH"); // 5.3 Fund governance treasury token.transfer(address(governance), INITIAL_GOVERNANCE_TOKENS); - console2.log("Funded governance treasury with", INITIAL_GOVERNANCE_TOKENS/1e18, "tokens"); + console2.log("Funded governance treasury with", INITIAL_GOVERNANCE_TOKENS / 1e18, "tokens"); // 5.4 Create sample project string[] memory descriptions = new string[](1); @@ -139,11 +131,7 @@ contract DeployMVP is Script { votes[0] = 10; project.createProject( - "Sample Project", - "A demonstration project for the Backr protocol", - descriptions, - funding, - votes + "Sample Project", "A demonstration project for the Backr protocol", descriptions, funding, votes ); console2.log("Created sample project"); diff --git a/test/DeployMVP.t.sol b/test/DeployMVP.t.sol index 1d29daa..f201452 100644 --- a/test/DeployMVP.t.sol +++ b/test/DeployMVP.t.sol @@ -46,7 +46,9 @@ contract DeployMVPTest is Test { assertTrue(userProfile.hasProfile(DEPLOYER), "Deployer profile not created"); UserProfile.Profile memory profile = userProfile.getProfile(DEPLOYER); assertTrue(profile.isVerified, "Deployer profile not verified"); - assertTrue(userProfile.hasRole(userProfile.REPUTATION_MANAGER_ROLE(), DEPLOYER), "Missing reputation manager role"); + assertTrue( + userProfile.hasRole(userProfile.REPUTATION_MANAGER_ROLE(), DEPLOYER), "Missing reputation manager role" + ); assertTrue(userProfile.hasRole(userProfile.VERIFIER_ROLE(), DEPLOYER), "Missing verifier role"); assertEq(profile.reputationScore, 100, "Incorrect reputation score"); @@ -54,10 +56,10 @@ contract DeployMVPTest is Test { // Check rate limits bytes32 projectCreationOp = keccak256("PROJECT_CREATION"); bytes32 qfContributionOp = keccak256("QF_CONTRIBUTION"); - + (uint256 projectLimit, uint256 projectWindow,,) = securityControls.rateLimits(projectCreationOp); (uint256 qfLimit, uint256 qfWindow,,) = securityControls.rateLimits(qfContributionOp); - + assertEq(projectLimit, deployer.PROJECT_CREATION_LIMIT(), "Incorrect project creation limit"); assertEq(qfLimit, deployer.QF_CONTRIBUTION_LIMIT(), "Incorrect QF contribution limit"); assertEq(projectWindow, deployer.RATE_LIMIT_WINDOW(), "Incorrect project window"); @@ -68,10 +70,7 @@ contract DeployMVPTest is Test { securityControls.hasRole(securityControls.OPERATOR_ROLE(), address(project)), "Project missing operator role" ); - assertTrue( - securityControls.hasRole(securityControls.OPERATOR_ROLE(), address(qf)), - "QF missing operator role" - ); + assertTrue(securityControls.hasRole(securityControls.OPERATOR_ROLE(), address(qf)), "QF missing operator role"); assertTrue( securityControls.hasRole(securityControls.EMERGENCY_ROLE(), address(governance)), "Governance missing emergency role" @@ -96,10 +95,12 @@ contract DeployMVPTest is Test { address creator, string memory title, string memory description, - ,,, // Skip unused variables + , + , + , // Skip unused variables bool isActive, ) = project.projects(0); - + assertTrue(isActive, "Sample project not active"); assertEq(creator, DEPLOYER, "Incorrect project creator"); assertEq(title, "Sample Project", "Incorrect project title"); @@ -116,13 +117,13 @@ contract DeployMVPTest is Test { function testEmergencyControls() public { vm.setEnv("PRIVATE_KEY", "1"); deployer.run(); - + SecurityControls securityControls = deployer.securityControls(); - + // Get multi-sig config for emergency actions bytes32 emergencyAction = keccak256("EMERGENCY_ACTION"); (uint256 requiredApprovals, address[] memory approvers) = securityControls.getMultiSigConfig(emergencyAction); - + // Verify multi-sig configuration assertEq(requiredApprovals, 2, "Incorrect required approvals"); assertEq(approvers.length, 3, "Incorrect number of approvers"); diff --git a/test/examples/SecurityControlsExample.t.sol b/test/examples/SecurityControlsExample.t.sol index ee982ee..ea8f393 100644 --- a/test/examples/SecurityControlsExample.t.sol +++ b/test/examples/SecurityControlsExample.t.sol @@ -11,14 +11,14 @@ import "../../src/SecurityControls.sol"; contract SecureVault is SecurityControls { bytes32 public constant WITHDRAWAL = keccak256("WITHDRAWAL"); bytes32 public constant LARGE_WITHDRAWAL = keccak256("LARGE_WITHDRAWAL"); - + uint256 public constant LARGE_AMOUNT = 100 ether; mapping(address => uint256) public balances; - + constructor() { // Configure rate limiting for regular withdrawals - _configureRateLimit(WITHDRAWAL, 10, 1 days); // 10 withdrawals per day - + _configureRateLimit(WITHDRAWAL, 10, 1 days); // 10 withdrawals per day + // Configure multi-sig for large withdrawals address[] memory approvers = new address[](3); approvers[0] = address(0x1); @@ -26,30 +26,28 @@ contract SecureVault is SecurityControls { approvers[2] = address(0x3); _configureMultiSig(LARGE_WITHDRAWAL, 2, approvers); } - + function deposit() external payable { balances[msg.sender] += msg.value; } - - function withdraw(uint256 amount) external - rateLimitGuard(WITHDRAWAL) - whenCircuitBreakerOff - { + + function withdraw(uint256 amount) external rateLimitGuard(WITHDRAWAL) whenCircuitBreakerOff { require(amount < LARGE_AMOUNT, "Use largeWithdraw for large amounts"); require(balances[msg.sender] >= amount, "Insufficient balance"); - + balances[msg.sender] -= amount; (bool success,) = msg.sender.call{value: amount}(""); require(success, "Transfer failed"); } - - function largeWithdraw(uint256 amount, bytes32 txHash) external + + function largeWithdraw(uint256 amount, bytes32 txHash) + external requiresApproval(LARGE_WITHDRAWAL, txHash) - whenCircuitBreakerOff + whenCircuitBreakerOff { require(amount >= LARGE_AMOUNT, "Use regular withdraw for small amounts"); require(balances[msg.sender] >= amount, "Insufficient balance"); - + balances[msg.sender] -= amount; (bool success,) = msg.sender.call{value: amount}(""); require(success, "Transfer failed"); @@ -66,149 +64,149 @@ contract SecureVaultTest is Test { address public user1; address public user2; address[] public approvers; - + function setUp() public { admin = makeAddr("admin"); user1 = makeAddr("user1"); user2 = makeAddr("user2"); - + // Setup approvers approvers = new address[](3); approvers[0] = makeAddr("approver1"); approvers[1] = makeAddr("approver2"); approvers[2] = makeAddr("approver3"); - + // Deploy vault vm.startPrank(admin); vault = new SecureVault(); - + // Fund the vault vm.deal(address(vault), 1000 ether); - + // Setup roles vault.grantRole(vault.EMERGENCY_ROLE(), admin); vault.grantRole(vault.OPERATOR_ROLE(), admin); vm.stopPrank(); - + // Setup test users with balances vm.deal(user1, 200 ether); vm.deal(user2, 200 ether); - + vm.prank(user1); vault.deposit{value: 150 ether}(); - + vm.prank(user2); vault.deposit{value: 150 ether}(); } - + function test_RegularWithdrawal() public { vm.startPrank(user1); - + // Should be able to withdraw small amounts uint256 initialBalance = user1.balance; vault.withdraw(1 ether); assertEq(user1.balance, initialBalance + 1 ether); - + // Should be able to make multiple withdrawals within limit - for(uint i = 0; i < 8; i++) { + for (uint256 i = 0; i < 8; i++) { vault.withdraw(1 ether); } - + // Should fail on exceeding rate limit vm.expectRevert("Rate limit exceeded"); vault.withdraw(1 ether); - + vm.stopPrank(); } - + function test_LargeWithdrawalFlow() public { bytes32 txHash = keccak256("large_withdrawal_1"); - + // First approval vm.prank(approvers[0]); vault.approveOperation(vault.LARGE_WITHDRAWAL(), txHash); - + // Second approval vm.prank(approvers[1]); vault.approveOperation(vault.LARGE_WITHDRAWAL(), txHash); - + // Now user can execute large withdrawal vm.prank(user1); uint256 initialBalance = user1.balance; vault.largeWithdraw(100 ether, txHash); assertEq(user1.balance, initialBalance + 100 ether); } - + function test_EmergencyControls() public { // Trigger emergency vm.prank(admin); vault.triggerEmergency("Potential exploit detected"); - + // Withdrawals should be blocked vm.expectRevert("Pausable: paused"); vm.prank(user1); vault.withdraw(1 ether); - + // Resolve emergency vm.prank(admin); vault.resolveEmergency(); - + // Withdrawals should work again vm.prank(user1); vault.withdraw(1 ether); } - + function test_RateLimitReset() public { vm.startPrank(user1); - + // Make max withdrawals - for(uint i = 0; i < 10; i++) { + for (uint256 i = 0; i < 10; i++) { vault.withdraw(1 ether); } - + // Should fail vm.expectRevert("Rate limit exceeded"); vault.withdraw(1 ether); - + // Advance time by 1 day vm.warp(block.timestamp + 1 days + 1); - + // Should work again vault.withdraw(1 ether); - + vm.stopPrank(); } - + function test_UnauthorizedEmergencyControl() public { // User without EMERGENCY_ROLE should not be able to trigger emergency vm.prank(user1); vm.expectRevert(); vault.triggerEmergency("Unauthorized attempt"); } - + function test_InvalidMultiSigApproval() public { bytes32 txHash = keccak256("invalid_tx"); - + // Non-approver should not be able to approve vm.prank(user1); vm.expectRevert("Not an approver"); vault.approveOperation(vault.LARGE_WITHDRAWAL(), txHash); } - + function test_CircuitBreakerBlock() public { // Trigger emergency vm.prank(admin); vault.triggerEmergency("Test emergency"); - + // Large withdrawals should be blocked bytes32 txHash = keccak256("blocked_tx"); - + // Get approvals vm.prank(approvers[0]); vault.approveOperation(vault.LARGE_WITHDRAWAL(), txHash); vm.prank(approvers[1]); vault.approveOperation(vault.LARGE_WITHDRAWAL(), txHash); - + // Should still be blocked due to circuit breaker vm.expectRevert("Pausable: paused"); vm.prank(user1);