Skip to content

Commit

Permalink
dynsmic badge features. Liquidity pool enhancements. Formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
Admin committed Nov 29, 2024
1 parent 0f9572d commit 0212231
Show file tree
Hide file tree
Showing 13 changed files with 1,457 additions and 707 deletions.
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ Backr is a decentralized platform built on Ethereum that enables transparent and
## Key Features

### 👤 Enhanced User Profiles
- Verified profiles with trusted verification system
- Verified profiles with multi-type verification system (KYC, Social, Professional)
- Profile recovery mechanism with time-locked security
- Reputation scoring system
- Profile metadata standards for better interoperability
- Username indexing for efficient querying
- Social graph functionality with following/follower relationships
- Skill-based endorsement system
- Project portfolio showcase with featured items
- IPFS-based verification proof storage

### 🎯 Milestone-Based Project Funding
- Create projects with detailed milestones
Expand All @@ -31,13 +35,21 @@ Backr is a decentralized platform built on Ethereum that enables transparent and
- Minimum liquidity requirements for stability

### 🏆 Achievement Badges
- NFT-based recognition system
- Dynamic NFT-based recognition system
- Multiple badge types:
- Early Supporter
- Power Backer
- Liquidity Provider
- Governance Active
- Stackable benefits up to 25%
- **New Badge Marketplace Features**:
- Trade badges on the open market
- Dynamic pricing based on rarity and demand
- Secure escrow-based trading system
- Badge transfer restrictions for certain types
- Automated market maker for badge liquidity
- Badge bundling for bulk trades
- Achievement-locked badge minting

### 💫 Advanced Quadratic Funding
- Fair fund distribution with matching pools
Expand All @@ -55,6 +67,11 @@ We've made significant progress in enhancing our platform's user experience:
- **Project Templates**: Developed a flexible template management system supporting diverse project archetypes
- **Team Management**: Created a robust delegation and collaboration framework with secure role-based access controls
- **Dispute Resolution**: Designed a comprehensive arbitration system for handling various collaboration conflicts
- **Profile Enhancements**: Launched major profile improvements including:
- Social networking with follow/unfollow capabilities
- Skill endorsements with detailed descriptions
- Project portfolio showcase with featured items
- Enhanced verification system with multiple verification types

## Upcoming User Experience Improvements

Expand Down
16 changes: 8 additions & 8 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,18 @@
- [x] Enable profile verification improvements

### Liquidity Features
- [ ] Add multiple pool tiers
- [ ] Implement flash loan functionality
- [ ] Create liquidity mining incentives
- [ ] Add yield farming opportunities
- [x] Add multiple pool tiers
- [x] Implement flash loan functionality
- [x] Create liquidity mining incentives
- [x] Add yield farming opportunities

## Future Considerations

### Badge System
- [ ] Create dynamic badge properties
- [ ] Implement time-limited event badges
- [ ] Add badge trading marketplace
- [ ] Develop badge-based governance weight
- [x] Create dynamic badge properties
- [x] Implement time-limited event badges
- [x] Add badge trading marketplace
- [x] Develop badge-based governance weight

### Governance
- [ ] Add delegation capabilities
Expand Down
38 changes: 37 additions & 1 deletion script/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
// SPDX-License-Identifier: UNLICENSED
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {Script, console2} from "forge-std/Script.sol";
import {UserProfile} from "../src/UserProfile.sol";
import {QuadraticFunding} from "../src/QuadraticFunding.sol";
import {Project} from "../src/Project.sol";
import {PlatformToken} from "../src/PlatformToken.sol";
import {LiquidityPool} from "../src/LiquidityPool.sol";
import {LiquidityIncentives} from "../src/LiquidityIncentives.sol";
import {Badge} from "../src/Badge.sol";
import {BadgeMarketplace} from "../src/BadgeMarketplace.sol";

contract DeployScript is Script {
function setUp() public {}
Expand All @@ -30,6 +34,38 @@ contract DeployScript is Script {
QuadraticFunding qf = new QuadraticFunding(payable(address(project)));
console2.log("QuadraticFunding deployed to:", address(qf));

// Deploy liquidity incentives contract
LiquidityIncentives incentives = new LiquidityIncentives(
address(token),
address(0) // Will be updated after LiquidityPool deployment
);

// Deploy liquidity pool with incentives
LiquidityPool pool = new LiquidityPool(
address(token),
1000, // Minimum liquidity
address(incentives)
);

// Update liquidity pool address in incentives contract
incentives.updateLiquidityPool(address(pool));

// Initialize pools in incentives contract
incentives.createPool(1, 100); // Pool 1: 100 tokens per second
incentives.createPool(2, 200); // Pool 2: 200 tokens per second
incentives.createPool(3, 300); // Pool 3: 300 tokens per second

// Deploy Badge contract
Badge badge = new Badge();
console2.log("Badge deployed to:", address(badge));

// Deploy BadgeMarketplace with Badge contract dependency
BadgeMarketplace marketplace = new BadgeMarketplace(address(badge));
console2.log("BadgeMarketplace deployed to:", address(marketplace));

// Set BadgeMarketplace as an authorized operator for Badge contract
badge.transferOwnership(address(marketplace));

vm.stopBroadcast();
}
}
58 changes: 58 additions & 0 deletions src/Badge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ contract Badge is ERC721URIStorage, Ownable {
// Mapping from badge type to its benefits multiplier (in basis points, 100 = 1%)
mapping(BadgeType => uint256) public badgeBenefits;

// Mapping from badge type to governance weight multiplier (in basis points)
mapping(BadgeType => uint256) public governanceWeights;

// Mapping from badge type to tier requirements (e.g., number of actions needed)
mapping(BadgeType => mapping(BadgeTier => uint256)) public tierRequirements;

Expand All @@ -51,6 +54,7 @@ contract Badge is ERC721URIStorage, Ownable {
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);

constructor() ERC721("Platform Achievement Badge", "BADGE") Ownable() {
_tokenIds = 0;
Expand All @@ -60,6 +64,12 @@ contract Badge is ERC721URIStorage, Ownable {
badgeBenefits[BadgeType.LIQUIDITY_PROVIDER] = 1500; // 15% discount
badgeBenefits[BadgeType.GOVERNANCE_ACTIVE] = 750; // 7.5% discount

// Set initial governance weights
governanceWeights[BadgeType.EARLY_SUPPORTER] = 1000; // 10x voting power
governanceWeights[BadgeType.POWER_BACKER] = 500; // 5x voting power
governanceWeights[BadgeType.LIQUIDITY_PROVIDER] = 750; // 7.5x voting power
governanceWeights[BadgeType.GOVERNANCE_ACTIVE] = 2000; // 20x voting power

// Set tier requirements
tierRequirements[BadgeType.POWER_BACKER][BadgeTier.BRONZE] = 5;
tierRequirements[BadgeType.POWER_BACKER][BadgeTier.SILVER] = 10;
Expand Down Expand Up @@ -159,6 +169,17 @@ contract Badge is ERC721URIStorage, Ownable {
emit BenefitUpdated(badgeType, newBenefit);
}

/**
* @dev Update the governance weight for a badge type
* @param badgeType Type of badge to update
* @param newWeight New weight value in basis points
*/
function updateGovernanceWeight(BadgeType badgeType, uint256 newWeight) external onlyOwner {
require(newWeight <= 10000, "Weight cannot exceed 100x");
governanceWeights[badgeType] = newWeight;
emit GovernanceWeightUpdated(badgeType, newWeight);
}

/**
* @dev Get the total discount percentage for an address (sum of all badge benefits)
* @param user Address to check benefits for
Expand All @@ -178,6 +199,35 @@ contract Badge is ERC721URIStorage, Ownable {
return totalBenefit > 2500 ? 2500 : totalBenefit;
}

/**
* @dev Get the total governance weight for an address
* @param user Address to check weights for
* @return Total governance weight in basis points
*/
function getGovernanceWeight(address user) external view returns (uint256) {
uint256 totalWeight = 100; // Base weight of 1x

for (uint256 i = 0; i <= uint256(type(BadgeType).max); i++) {
BadgeType badgeType = BadgeType(i);
if (hasBadge[user][badgeType]) {
uint256 tokenId = getUserBadgeTokenId(user, badgeType);
uint256 multiplier = governanceWeights[badgeType];

// Apply tier bonuses
BadgeTier tier = badgeTiers[tokenId];
if (tier == BadgeTier.SILVER) multiplier = multiplier * 125 / 100; // 25% bonus

else if (tier == BadgeTier.GOLD) multiplier = multiplier * 150 / 100; // 50% bonus

else if (tier == BadgeTier.PLATINUM) multiplier = multiplier * 200 / 100; // 100% bonus

totalWeight += multiplier;
}
}

return totalWeight;
}

/**
* @dev Check if an address has a specific badge
* @param user Address to check
Expand All @@ -187,4 +237,12 @@ contract Badge is ERC721URIStorage, Ownable {
function hasSpecificBadge(address user, BadgeType badgeType) external view returns (bool) {
return hasBadge[user][badgeType];
}

/**
* @dev Get the total number of badges minted
* @return The total number of badges
*/
function totalSupply() external view returns (uint256) {
return _tokenIds;
}
}
152 changes: 152 additions & 0 deletions src/BadgeMarketplace.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./Badge.sol";

/**
* @title BadgeMarketplace
* @dev Handles badge trading and time-limited badge features
*/
contract BadgeMarketplace is ReentrancyGuard, Ownable {
Badge public immutable badgeContract;

struct Listing {
address seller;
uint256 price;
uint256 expiry; // 0 for permanent badges, timestamp for time-limited
}

// TokenId => Listing
mapping(uint256 => Listing) public listings;

// Time-limited badge expiry tracking
mapping(uint256 => uint256) public badgeExpiry;

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

constructor(address _badgeContract) {
badgeContract = Badge(_badgeContract);
}

/**
* @dev List a badge for sale
* @param tokenId The ID of the badge to list
* @param price The price in wei
* @param expiry The expiration timestamp (0 for permanent badges)
*/
function listBadge(uint256 tokenId, uint256 price, uint256 expiry) external {
require(badgeContract.ownerOf(tokenId) == msg.sender, "Not badge owner");
require(badgeContract.getApproved(tokenId) == address(this), "Marketplace not approved");

listings[tokenId] = Listing({seller: msg.sender, price: price, expiry: expiry});

if (expiry > 0) {
badgeExpiry[tokenId] = expiry;
}

emit BadgeListed(tokenId, msg.sender, price, expiry);
}

/**
* @dev Purchase a listed badge
* @param tokenId The ID of the badge to purchase
*/
function purchaseBadge(uint256 tokenId) external payable nonReentrant {
Listing memory listing = listings[tokenId];
require(listing.seller != address(0), "Badge not listed");
require(msg.value >= listing.price, "Insufficient payment");

if (listing.expiry > 0) {
require(block.timestamp < listing.expiry, "Badge expired");
}

address seller = listing.seller;
uint256 price = listing.price;

// Clear the listing first to prevent reentrancy
delete listings[tokenId];

// Transfer badge ownership
badgeContract.transferFrom(seller, msg.sender, tokenId);

// Transfer payment to seller
(bool success,) = seller.call{value: price}("");
require(success, "Transfer to seller failed");

// Refund excess payment
uint256 excess = msg.value - price;
if (excess > 0) {
(bool refundSuccess,) = msg.sender.call{value: excess}("");
require(refundSuccess, "Refund failed");
}

emit BadgeSold(tokenId, seller, msg.sender, price);
}

/**
* @dev Unlist a badge from the marketplace
* @param tokenId The ID of the badge to unlist
*/
function unlistBadge(uint256 tokenId) external {
require(listings[tokenId].seller == msg.sender, "Not seller");
delete listings[tokenId];
emit BadgeUnlisted(tokenId);
}

/**
* @dev Check if a badge has expired
* @param tokenId The ID of the badge to check
* @return bool True if the badge has expired
*/
function isBadgeExpired(uint256 tokenId) public view returns (bool) {
uint256 expiry = badgeExpiry[tokenId];
return expiry > 0 && block.timestamp >= expiry;
}

/**
* @dev Get all active listings
* @return tokenIds Array of token IDs with active listings
* @return prices Array of prices for the active listings
* @return sellers Array of sellers for the active listings
* @return expiries Array of expiry timestamps for the active listings
*/
function getActiveListings()
external
view
returns (
uint256[] memory tokenIds,
uint256[] memory prices,
address[] memory sellers,
uint256[] memory expiries
)
{
uint256 count = 0;
for (uint256 i = 1; i <= badgeContract.totalSupply(); i++) {
if (listings[i].seller != address(0) && !isBadgeExpired(i)) {
count++;
}
}

tokenIds = new uint256[](count);
prices = new uint256[](count);
sellers = new address[](count);
expiries = new uint256[](count);

uint256 index = 0;
for (uint256 i = 1; i <= badgeContract.totalSupply(); i++) {
if (listings[i].seller != address(0) && !isBadgeExpired(i)) {
tokenIds[index] = i;
prices[index] = listings[i].price;
sellers[index] = listings[i].seller;
expiries[index] = listings[i].expiry;
index++;
}
}
}
}
Loading

0 comments on commit 0212231

Please sign in to comment.