From f0937607c2c4d32a02d37540b24c1642ff85c903 Mon Sep 17 00:00:00 2001 From: Tempe Techie <95053628+tempe-techie@users.noreply.github.com> Date: Thu, 28 Dec 2023 17:34:25 +0100 Subject: [PATCH] custom activity points contract for fairchat --- contracts/custom/ActivityPointsFairchat.sol | 139 ++++++++++++++++++ .../custom/activityPointsFairchat.deploy.js | 36 +++++ scripts/stats/1_stats.deploy.js | 2 +- scripts/stats/2_statsMiddleware.deploy.js | 6 +- 4 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 contracts/custom/ActivityPointsFairchat.sol create mode 100644 scripts/custom/activityPointsFairchat.deploy.js diff --git a/contracts/custom/ActivityPointsFairchat.sol b/contracts/custom/ActivityPointsFairchat.sol new file mode 100644 index 0000000..b0976b5 --- /dev/null +++ b/contracts/custom/ActivityPointsFairchat.sol @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity 0.8.17; + +import { OwnableWithManagers } from "../access/OwnableWithManagers.sol"; + +interface IPunkTLD { + function balanceOf(address) external view returns (uint256); + function idCounter() external view returns (uint256); +} + +interface IStats { + function getWeiSpent(address user_) external view returns (uint256); + function weiSpentTotal() external view returns (uint256); +} + +/** +@title Collect all wei spending stats from different contracts and return them as one +@author Tempe Techie +*/ +contract ActivityPointsFairchat is OwnableWithManagers { + address public statsAddress; // stats for NFT launchpad, Friend Keys, Swap etc. + address public mintedPostsStatsAddress; + address public immutable tldAddress; + + uint256 public bonusWeiTotal; // total bonus wei (without multiplier) + uint256 public multiplier; // multiplier for points (e.g. 1 means 1 wei spent = 1 point) + uint256 public weiPerDomain = 1690000000000000000; + + mapping (address => uint256) public bonusWei; // bonus wei (without multiplier) + + // EVENTS + event BonusPointsAdded(address indexed manager_, address indexed user_, uint256 bp_); + event BonusPointsRemoved(address indexed manager_, address indexed user_, uint256 bp_); + + constructor( + address _statsAddress, + address _mintedPostsStatsAddress, + address _tldAddress, + uint256 _multiplier + ) { + statsAddress = _statsAddress; + mintedPostsStatsAddress = _mintedPostsStatsAddress; + tldAddress = _tldAddress; + multiplier = _multiplier; + } + + // READ + + function getPoints(address user_) external view returns (uint256) { + return (bonusWei[user_] + getTotalWeiSpent(user_)) * multiplier; + } + + function getTotalPointsAllUsers() external view returns (uint256) { + return (bonusWeiTotal + getTotalWeiSpentAllUsers()) * multiplier; + } + + function getTotalWeiSpent(address _user) public view returns (uint256) { + uint256 totalWeiSpent; + + if (statsAddress != address(0)) { + totalWeiSpent += IStats(statsAddress).getWeiSpent(_user); + } + + if (mintedPostsStatsAddress != address(0)) { + totalWeiSpent += IStats(mintedPostsStatsAddress).getWeiSpent(_user); + } + + // check how many domains the user owns + uint256 domainsOwned = IPunkTLD(tldAddress).balanceOf(_user); + totalWeiSpent += domainsOwned * weiPerDomain; + + return totalWeiSpent; + } + + function getTotalWeiSpentAllUsers() public view returns (uint256) { + uint256 totalWeiSpent; + + if (statsAddress != address(0)) { + totalWeiSpent += IStats(statsAddress).weiSpentTotal(); + } + + if (mintedPostsStatsAddress != address(0)) { + totalWeiSpent += IStats(mintedPostsStatsAddress).weiSpentTotal(); + } + + // check how many domains exist (idCounter-1) + uint256 domainsSupply = IPunkTLD(tldAddress).idCounter() - 1; + totalWeiSpent += domainsSupply * weiPerDomain; + + return totalWeiSpent; + } + + // OWNER + + /// @notice These points already include the multiplier + function addBonusPoints(address _user, uint256 _bp) external onlyManagerOrOwner { + bonusWei[_user] += _bp / multiplier; + bonusWeiTotal += _bp / multiplier; + emit BonusPointsAdded(msg.sender, _user, _bp); + } + + /// @notice These points already include the multiplier + function removeBonusPoints(address _user, uint256 _bp) external onlyManagerOrOwner { + require(bonusWei[_user] >= _bp / multiplier, "ActivityPoints: not enough bonus points"); + bonusWei[_user] -= _bp / multiplier; + bonusWeiTotal -= _bp / multiplier; + emit BonusPointsRemoved(msg.sender, _user, _bp); + } + + /// @notice Bonus wei does not include the multiplier + function addBonusWei(address _user, uint256 _wei) external onlyManagerOrOwner { + bonusWei[_user] += _wei; + bonusWeiTotal += _wei; + } + + /// @notice Bonus wei does not include the multiplier + function removeBonusWei(address _user, uint256 _wei) external onlyManagerOrOwner { + require(bonusWei[_user] >= _wei, "ActivityPoints: not enough bonus wei"); + bonusWei[_user] -= _wei; + bonusWeiTotal -= _wei; + } + + function setMintedPostsStatsAddress(address _mintedPostsStatsAddress) external onlyManagerOrOwner { + mintedPostsStatsAddress = _mintedPostsStatsAddress; + } + + function setMultiplier(uint256 _multiplier) external onlyManagerOrOwner { + multiplier = _multiplier; + } + + function setStatsAddress(address _statsAddress) external onlyManagerOrOwner { + statsAddress = _statsAddress; + } + + function setWeiPerDomain(uint256 _weiPerDomain) external onlyManagerOrOwner { + weiPerDomain = _weiPerDomain; + } + +} \ No newline at end of file diff --git a/scripts/custom/activityPointsFairchat.deploy.js b/scripts/custom/activityPointsFairchat.deploy.js new file mode 100644 index 0000000..374ec08 --- /dev/null +++ b/scripts/custom/activityPointsFairchat.deploy.js @@ -0,0 +1,36 @@ +// npx hardhat run scripts/custom/activityPointsFairchat.deploy.js --network zkfair + +const contractName = "ActivityPointsFairchat"; + +const statsAddress = "0x0BF6333Fc85159663A30Ac89FD02c5031B97c5ee"; // stats contract +const mintedPostsStatsAddress = "0x99Dbf11aCd46baFBCE82506FaeB4F13E6Ea1726A"; +const tldAddress = "0x4087fb91A1fBdef05761C02714335D232a2Bf3a1"; +const multiplier = 10; // 1 wei = 1000 points + +async function main() { + const [deployer] = await ethers.getSigners(); + + console.log("Deploying contracts with the account:", deployer.address); + console.log("Account balance:", (await deployer.getBalance()).toString()); + + // deploy contract + const contract = await ethers.getContractFactory(contractName); + const instance = await contract.deploy( + statsAddress, + mintedPostsStatsAddress, + tldAddress, + multiplier + ); + + console.log(contractName + " contract address:", instance.address); + + console.log("Wait a minute and then run this command to verify contracts on block explorer:"); + console.log("npx hardhat verify --network " + network.name + " " + instance.address + " " + statsAddress + " " + mintedPostsStatsAddress + " " + tldAddress + ' "' + multiplier + '"'); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); \ No newline at end of file diff --git a/scripts/stats/1_stats.deploy.js b/scripts/stats/1_stats.deploy.js index d1c815a..53f4679 100644 --- a/scripts/stats/1_stats.deploy.js +++ b/scripts/stats/1_stats.deploy.js @@ -1,5 +1,5 @@ // 1. Deploy LaunchpadStats contract. -// npx hardhat run scripts/stats/1_stats.deploy.js --network polygonMumbai +// npx hardhat run scripts/stats/1_stats.deploy.js --network zkfair const contractName = "Stats"; diff --git a/scripts/stats/2_statsMiddleware.deploy.js b/scripts/stats/2_statsMiddleware.deploy.js index de61b97..f080c81 100644 --- a/scripts/stats/2_statsMiddleware.deploy.js +++ b/scripts/stats/2_statsMiddleware.deploy.js @@ -1,9 +1,9 @@ // 2. Deploy StatsMiddleware contract. -// npx hardhat run scripts/stats/2_statsMiddleware.deploy.js --network polygonMumbai +// npx hardhat run scripts/stats/2_statsMiddleware.deploy.js --network zkfair -const contractName = "StatsMiddleware"; +const contractName = "StatsMiddleware"; // not run yet on ZKFair -const statsAddress = "0x6Cb1bA799566318Ba433DDF91462D6045Bb90Bc5"; +const statsAddress = "0x0BF6333Fc85159663A30Ac89FD02c5031B97c5ee"; async function main() { const [deployer] = await ethers.getSigners();