Skip to content

Commit

Permalink
feat: add demo script
Browse files Browse the repository at this point in the history
  • Loading branch information
Doge-is-Dope committed Nov 16, 2024
1 parent 4e69aad commit 3987be1
Show file tree
Hide file tree
Showing 5 changed files with 273 additions and 7 deletions.
2 changes: 1 addition & 1 deletion script/BaseDeploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ contract BaseDeploy is Script {
}

function _calculateSalt(string memory input) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(input)) & ~bytes32(uint256(0xffff));
return keccak256(abi.encodePacked(input)) & ~bytes32(uint256(0xffff) - 4);
}
}
181 changes: 178 additions & 3 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,94 @@ contract Deploy is BaseDeploy {
Challenge challenge;
ChallengeManager challengeManager;
DripProfile profile;

address vault0;
address vault1;
// Profiles
mapping(address => Types.Profile) public profiles;

function run() public {
_deployContracts();

// DEMO ONLY
_initializeEpochs();
_createProfiles();

// Create claimable challenges
uint256[] memory timestamps1 = new uint256[](5);
timestamps1[0] = 1;
timestamps1[1] = 0;
timestamps1[2] = 0;
timestamps1[3] = 0;
timestamps1[4] = 1;
_createClaimableChallenge(1, 0, timestamps1, 100e18, deployerPrivateKey);
uint256[] memory timestamps2 = new uint256[](5);
timestamps2[0] = 1;
timestamps2[1] = 1;
timestamps2[2] = 1;
timestamps2[3] = 1;
timestamps2[4] = 1;
_createClaimableChallenge(2, 0, timestamps2, 100e18, ShanePrivateKey);

// Deployer calculates claimable
_calculateClaimable(vault0);

// Create active challenges
// 0/5
uint256[] memory ts1 = new uint256[](5);
ts1[0] = 0;
ts1[1] = 0;
ts1[2] = 0;
ts1[3] = 0;
ts1[4] = 0;
_createActiveChallenge(2, 1, "7 Days Quest", "Daily quests for one week", ts1, 101e18, ShanePrivateKey);

// 1/5
uint256[] memory ts2 = new uint256[](5);
ts2[0] = 0;
ts2[1] = 0;
ts2[2] = 1;
ts2[3] = 0;
ts2[4] = 0;
_createActiveChallenge(2, 1, "Challenge", "Demo challenge", ts2, 10e18, ShanePrivateKey);

// 2/5
uint256[] memory ts3 = new uint256[](5);
ts3[0] = 0;
ts3[1] = 0;
ts3[2] = 1;
ts3[3] = 0;
ts3[4] = 1;
_createActiveChallenge(2, 1, "Happy Challenge", "Practice makes perfect", ts3, 5e18, ShanePrivateKey);

// 3/5
uint256[] memory ts4 = new uint256[](5);
ts4[0] = 0;
ts4[1] = 1;
ts4[2] = 1;
ts4[3] = 1;
ts4[4] = 0;
_createActiveChallenge(2, 1, "Better myself", "I luv Challenge", ts4, 12e18, ShanePrivateKey);

// 5/5
uint256[] memory ts5 = new uint256[](5);
ts5[0] = 1;
ts5[1] = 1;
ts5[2] = 1;
ts5[3] = 1;
ts5[4] = 1;
_createActiveChallenge(2, 1, "New Begin", "Whole new me", ts4, 100e18, ShanePrivateKey);

// 4/5
uint256[] memory ts6 = new uint256[](5);
ts6[0] = 1;
ts6[1] = 1;
ts6[2] = 1;
ts6[3] = 1;
ts6[4] = 0;
_createActiveChallenge(2, 1, "Nailed it", "I'm a pro", ts6, 100e18, ShanePrivateKey);
}

function _deployContracts() private broadcast(deployerPrivateKey) {
function _deployContracts() private {
// Deploy Challenge
bytes memory challengeBytecode = abi.encodePacked(type(Challenge).creationCode);
challenge = Challenge(_create2Deploy("Drip.Challenge.ff", challengeBytecode));
Expand All @@ -50,8 +129,104 @@ contract Deploy is BaseDeploy {
console.log("DripProfile deployed to", address(profile));
}

function _create2Deploy(string memory fileName, bytes memory creationBytecode) private returns (address) {
function _create2Deploy(string memory fileName, bytes memory creationBytecode)
private
broadcast(deployerPrivateKey)
returns (address)
{
bytes32 salt = _calculateSalt(fileName);
return Create2.deploy(0, salt, creationBytecode);
}

function _initializeEpochs() private {
uint256 currentTimestamp = block.timestamp;
vault0 = _createEpoch(0, currentTimestamp - 5 days, "ETHGlobal Bangkok Demo");
vault1 = _createEpoch(1, currentTimestamp - 4 days, "TOEFL 7000 words");
console.log("Epochs initialized");
}

/// @notice DEMO only - Helper function to create an epoch
function _createEpoch(uint256 id, uint256 startTimestamp, string memory description)
private
broadcast(deployerPrivateKey)
returns (address)
{
DripVault vault = new DripVault(MOCK_TOKEN, address(challengeManager));
Types.Epoch memory epoch = Types.Epoch({
id: id,
startTimestamp: startTimestamp,
endTimestamp: startTimestamp + DURATION,
durationInDays: DURATION.convertSecondsToDays(),
vault: address(vault),
asset: MOCK_TOKEN,
description: description,
participantCount: 0,
totalDeposits: 0
});
challengeManager.setEpoch(id, epoch);
return address(vault);
}

/// @notice DEMO only - Helper function to create profiles
function _createProfiles() private {
uint32[] memory avatar1 = new uint32[](5);
avatar1[0] = uint32(0);
avatar1[1] = uint32(0);
avatar1[2] = uint32(0);
avatar1[3] = uint32(0);
avatar1[4] = uint32(0);
_createProfile("@clement", avatar1, vm.envUint("PRIVATE_KEY"));

uint32[] memory avatar2 = new uint32[](5);
avatar2[0] = uint32(1);
avatar2[1] = uint32(1);
avatar2[2] = uint32(1);
avatar2[3] = uint32(1);
avatar2[4] = uint32(1);
_createProfile("@shane", avatar2, vm.envUint("PRIVATE_KEY_SHA"));
}

function _createProfile(string memory handle, uint32[] memory avatar, uint256 pk) private broadcast(pk) {
address account = vm.addr(pk);
uint256 profileId = profile.createProfile(account, handle, avatar);
Types.Profile memory createdProfile = profile.getProfileById(profileId);
profiles[account] = createdProfile;
console.log(handle, "profile with ID:", profileId);

// Fund profile with mock token
ERC20Mock(MOCK_TOKEN).setBalance(account, 1_000_000e18);
ERC20Mock(MOCK_TOKEN).approve(address(challenge), type(uint256).max);
}

function _calculateClaimable(address vault) private broadcast(deployerPrivateKey) {
DripVault(vault).calculateOwnersClaimable();
}

function _createClaimableChallenge(
uint256 profileId,
uint256 epochId,
uint256[] memory timestamps,
uint256 amount,
uint256 pk
) private broadcast(pk) {
uint256 current = block.timestamp;
uint256 challengeId =
profile.createChallengeDemo(profileId, epochId, "Title", "desc", current - 388800, amount, 5);
profile.setDailyCompletionDemo(challengeId, timestamps);
}

function _createActiveChallenge(
uint256 profileId,
uint256 epochId,
string memory title,
string memory description,
uint256[] memory timestamps,
uint256 amount,
uint256 pk
) private broadcast(pk) {
uint256 current = block.timestamp;
uint256 challengeId =
profile.createChallengeDemo(profileId, epochId, title, description, current - 4 days, amount, 5);
profile.setDailyCompletionDemo(challengeId, timestamps);
}
}
54 changes: 54 additions & 0 deletions src/Challenge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {ERC20} from "../lib/solmate/src/tokens/ERC20.sol";
import {SafeTransferLib} from "../lib/solmate/src/utils/SafeTransferLib.sol";
import {ChallengeManager} from "./ChallengeManager.sol";
import {IChallengeManager} from "./interfaces/IChallengeManager.sol";
import {IChallenge} from "./interfaces/IChallenge.sol";
import {Types} from "./libraries/Types.sol";
Expand Down Expand Up @@ -118,4 +119,57 @@ contract Challenge is ERC721, IChallenge {

emit DailyCompletionSubmitted(tokenId, day);
}

/// @dev Only for demo
function createChallengeDemo(Types.CreateChallengeParams calldata params, uint256 epochId, uint256 startTime)
external
onlyProfile(params.owner)
returns (uint256 challengeId)
{
(Types.Epoch memory epoch,) = IChallengeManager(managerContract).getEpochInfo(epochId);

// Transfer epoch asset from user to challenge manager
ERC20(epoch.asset).safeTransferFrom(params.owner, managerContract, params.depositAmount);

// Calculate duration and end time
uint256 endTime = TimeLib.addDaysToTimestamp(startTime, params.durationInDays);

Types.Challenge storage challenge = _challenges[_tokenId];
challenge.id = _tokenId;
challenge.title = params.title;
challenge.description = params.description;
challenge.owner = params.owner;
challenge.startTime = startTime;
challenge.endTime = endTime;
challenge.depositAmount = params.depositAmount;
challenge.depositToken = address(0); // TODO: Get from epoch
challenge.durationInDays = params.durationInDays;
challenge.epochId = params.epochId;
challenge.dailyCompletionTimestamps = new uint256[](params.durationInDays);

// Mint and emit the challenge event
_safeMint(params.owner, _tokenId);
emit ChallengeCreated(_tokenId, params.owner);

// Add the challenge to the epoch
ChallengeManager(managerContract).addChallengeToEpochDemo(params.epochId, challenge);

// Return challenge ID and increment the token counter
challengeId = _tokenId;
++_tokenId;
}

function setDailyCompletionDemo(address owner, uint256 tokenId, uint256[] memory timestamps)
external
onlyProfile(owner)
{
Types.Challenge storage challenge = _challenges[tokenId];

challenge.dailyCompletionTimestamps = timestamps;

// Update vault
(Types.Epoch memory epoch,) = IChallengeManager(managerContract).getEpochInfo(challenge.epochId);
DripVault vault = DripVault(epoch.vault);
vault.submitDailyCompletion(owner, challenge.dailyCompletionTimestamps);
}
}
20 changes: 17 additions & 3 deletions src/ChallengeManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,29 @@ contract ChallengeManager is Ownable, IChallengeManager {
return _getChallengeManagerStorage().isWhitelistedToken[token];
}

/// @notice DEMO ONLY
/// @notice Sets the epoch.
function setEpoch(uint256 epochId, Types.Epoch memory epoch) external onlyOwner {
/// @dev DEMO ONLY
function setEpoch(uint256 epochId, Types.Epoch memory epoch) external {
Types.ChallengeManagerStorage storage $ = _getChallengeManagerStorage();
$.epochs[epochId] = epoch;
$.currentEpoch = epoch;
$.nextEpochId++;
}

/// @dev DEMO ONLY
function addChallengeToEpochDemo(uint256 epochId, Types.Challenge calldata userChallenge) external onlyChallenge {
Types.ChallengeManagerStorage storage $ = _getChallengeManagerStorage();
IERC20($.epochs[epochId].asset).approve($.epochs[epochId].vault, type(uint256).max);
IERC4626($.epochs[epochId].vault).deposit(userChallenge.depositAmount, userChallenge.owner);
DripVault($.epochs[epochId].vault).setOwnerChallengeDays(userChallenge.owner, userChallenge.durationInDays);

$.epochChallenges[epochId].push(userChallenge.id);
EnumerableSet.AddressSet storage participants = $.epochParticipants[epochId];
participants.add(userChallenge.owner);
// Update epoch info
$.epochs[epochId].totalDeposits = IERC4626($.epochs[epochId].vault).totalAssets();
$.epochs[epochId].participantCount = participants.length();
}

/**
* @notice Preview rewards in an epoch
*/
Expand Down
23 changes: 23 additions & 0 deletions src/DripProfile.sol
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,24 @@ contract DripProfile is ERC721, IDripProfile {
return challengeId;
}

/// @dev Only for demo
function createChallengeDemo(
uint256 profileId,
uint256 epochId,
string calldata name,
string calldata description,
uint256 startTime,
uint256 depositAmount,
uint16 durationInDays
) external onlyProfileOwner(profileId) returns (uint256) {
require(profileId != 0, ErrorsLib.PROFILE_NOT_EXISTS);
Types.CreateChallengeParams memory params =
Types.CreateChallengeParams(msg.sender, depositAmount, epochId, durationInDays, name, description);
uint256 challengeId = challenge.createChallengeDemo(params, epochId, startTime);
_profileIdToEpochIdToChallengeIds[profileId][epochId].push(challengeId);
return challengeId;
}

/**
* @dev Retrieves the challenges associated with a profile.
* @param profileId The ID of the profile to retrieve the challenges.
Expand Down Expand Up @@ -148,6 +166,11 @@ contract DripProfile is ERC721, IDripProfile {
challenge.submitDailyCompletion(msg.sender, challengeId, day);
}

/// @dev Only for demo
function setDailyCompletionDemo(uint256 challengeId, uint256[] memory timestamps) external {
challenge.setDailyCompletionDemo(msg.sender, challengeId, timestamps);
}

function _update(address to, uint256 tokenId, address auth) internal override returns (address) {
address from = super._update(to, tokenId, auth);
require(from == address(0), ErrorsLib.NOT_TRANSFERABLE);
Expand Down

0 comments on commit 3987be1

Please sign in to comment.