Skip to content

Commit

Permalink
fix(nft): fix s2 badges remigration (#18578)
Browse files Browse the repository at this point in the history
Co-authored-by: Korbinian <[email protected]>
Co-authored-by: Korbinian <[email protected]>
  • Loading branch information
3 people authored Dec 16, 2024
1 parent ec5f599 commit abcec66
Show file tree
Hide file tree
Showing 9 changed files with 728 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ contract BadgeRecruitment is
TrailblazersBadgesS2 public s2Badges;
/// @notice Wallet authorized to sign as a source of randomness
address public randomSigner;
/// @notice Recruitment-enabled badge IDs per cycle
//mapping(uint256 cycle => mapping(uint256 s1BadgeId => bool enabled)) public enabledBadgeIds;
// uint256[] public currentCycleEnabledRecruitmentIds;
/// @notice Current recruitment cycle
uint256 public recruitmentCycleId;

Expand Down
141 changes: 141 additions & 0 deletions packages/nfts/contracts/trailblazers-season-2/BadgeRecruitmentV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "./BadgeRecruitment.sol";

contract BadgeRecruitmentV2 is BadgeRecruitment {
/// @notice Events
event RecruitmentReset(
uint256 indexed cycleId, address indexed user, uint256 indexed s1TokenId, uint256 s1BadgeId
);

/// @notice Errors
error RECRUITMENT_ALREADY_COMPLETED();
error RECRUITMENT_NOT_FOUND();
error NOT_ENOUGH_TIME_LEFT();

modifier recruitmentHasTimeLeft(address _user) {
uint256 endCycleTime = recruitmentCycles[recruitmentCycleId].endTime;
uint256 potentialRecruitmentEndTime = block.timestamp + this.getConfig().cooldownRecruitment;

if (potentialRecruitmentEndTime > endCycleTime) {
revert NOT_ENOUGH_TIME_LEFT();
}
_;
}

/// @notice Updated version function
function version() external pure virtual returns (string memory) {
return "V2";
}

/// @notice Start a recruitment for a badge
/// @param _s1BadgeId The badge ID (s1)
/// @dev Not all badges are eligible for recruitment at the same time
/// @dev Defines a cooldown for the recruitment to be complete
/// @dev the cooldown is lesser the higher the Pass Tier
/// @dev Must be called from the s1 badges contract
function startRecruitment(
address _user,
uint256 _s1BadgeId,
uint256 _s1TokenId
)
external
virtual
onlyRole(S1_BADGES_ROLE)
recruitmentOpen(_s1BadgeId)
isNotMigrating(_user)
hasntMigratedInCycle(_s1BadgeId, _user, RecruitmentType.Migration)
recruitmentHasTimeLeft(_user)
{
if (s1Badges.ownerOf(_s1TokenId) != _user) {
revert TOKEN_NOT_OWNED();
}
_startRecruitment(_user, _s1BadgeId, _s1TokenId, RecruitmentType.Migration);
}

/// @notice Disable all current recruitments
/// @dev Bypasses the default date checks
function forceDisableAllRecruitments() external virtual onlyRole(DEFAULT_ADMIN_ROLE) {
forceDisableRecruitments();

emit RecruitmentCycleToggled(
recruitmentCycleId,
recruitmentCycles[recruitmentCycleId].startTime,
recruitmentCycles[recruitmentCycleId].endTime,
recruitmentCycles[recruitmentCycleId].s1BadgeIds,
false
);
}

/// @notice Get the active recruitment for a user
/// @param _user The user address
/// @return The active recruitment
function getActiveRecruitmentsFor(address _user) public view returns (Recruitment[] memory) {
if (recruitments[_user].length == 0) {
revert RECRUITMENT_NOT_STARTED();
}
return recruitments[_user];
}

/// @notice Reset a recruitment that hasn't been completed
/// @param _user The user address
/// @param _s1TokenId The s1 token ID
/// @param _s1BadgeId The s1 badge ID
/// @param _recruitmentCycle The recruitment index
/// @dev Must be called from the s1 badges contract
function resetRecruitment(
address _user,
uint256 _s1TokenId,
uint256 _s1BadgeId,
uint256 _recruitmentCycle
)
public
virtual
onlyRole(S1_BADGES_ROLE)
{
if (
!recruitmentCycleUniqueMints[_recruitmentCycle][_user][_s1BadgeId][RecruitmentType
.Migration]
&& !recruitmentCycleUniqueMints[_recruitmentCycle][_user][_s1BadgeId][RecruitmentType.Claim]
&& !recruitmentCycleUniqueMints[_recruitmentCycle][_user][_s1BadgeId][RecruitmentType
.Undefined]
) {
revert RECRUITMENT_NOT_FOUND();
}

bool found = false;

for (uint256 i = 0; i < recruitments[_user].length; i++) {
if (
recruitments[_user][i].recruitmentCycle == _recruitmentCycle
&& recruitments[_user][i].s1TokenId == _s1TokenId
&& recruitments[_user][i].s2TokenId == 0
) {
delete recruitments[_user][i];
found = true;
break;
}
}

if (!found) {
revert RECRUITMENT_NOT_FOUND();
}

recruitmentCycleUniqueMints[_recruitmentCycle][_user][_s1BadgeId][RecruitmentType.Undefined]
= false;
recruitmentCycleUniqueMints[_recruitmentCycle][_user][_s1BadgeId][RecruitmentType.Claim] =
false;
recruitmentCycleUniqueMints[_recruitmentCycle][_user][_s1BadgeId][RecruitmentType.Migration]
= false;

emit RecruitmentReset(_recruitmentCycle, _user, _s1TokenId, _s1BadgeId);
}

/// @notice Set the s2 badges contract
/// @param _s2Badges The s2 badges contract address
/// @dev Must be called from the admin account
function setS2BadgesContract(address _s2Badges) external virtual onlyRole(DEFAULT_ADMIN_ROLE) {
s2Badges = TrailblazersBadgesS2(_s2Badges);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ contract TrailblazersBadgesV4 is TrailblazersBadgesV3 {

/// @notice Start recruitment for a badge
/// @param _badgeId Badge id
function startRecruitment(uint256 _badgeId) public {
function startRecruitment(uint256 _badgeId) public virtual {
if (recruitmentLockDuration == 0) {
revert RECRUITMENT_LOCK_DURATION_NOT_SET();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "./TrailblazersS1BadgesV4.sol";
import "./BadgeRecruitment.sol";
import "./BadgeRecruitmentV2.sol";

contract TrailblazersBadgesV5 is TrailblazersBadgesV4 {
/// @notice Errors
error RECRUITMENT_ALREADY_COMPLETED();
error NOT_OWNER();
error NOT_IMPLEMENTED();
error RECRUITMENT_NOT_FOUND();
/// @notice Updated version function
/// @return Version string

function version() external pure virtual override returns (string memory) {
return "V5";
}
/// @notice Recruitment contract

BadgeRecruitmentV2 public recruitmentContractV2;
/// @notice Setter for recruitment contract

function setRecruitmentContractV2(address _recruitmentContractV2) public onlyOwner {
recruitmentContractV2 = BadgeRecruitmentV2(_recruitmentContractV2);
}

/// @notice Start recruitment for a badge
/// @param _badgeId Badge ID
/// @param _tokenId Token ID
function startRecruitment(uint256 _badgeId, uint256 _tokenId) public {
if (recruitmentLockDuration == 0) {
revert RECRUITMENT_LOCK_DURATION_NOT_SET();
}
if (ownerOf(_tokenId) != _msgSender()) {
revert NOT_OWNER();
}

if (unlockTimestamps[_tokenId] > block.timestamp) {
revert BADGE_LOCKED();
}

unlockTimestamps[_tokenId] = block.timestamp + recruitmentLockDuration;
recruitmentContractV2.startRecruitment(_msgSender(), _badgeId, _tokenId);
}

/// @notice Deprecated of legacy function
function startRecruitment(uint256 /*_badgeId*/ ) public virtual override {
revert NOT_IMPLEMENTED();
}

/// @notice Reset an ongoing migration
/// @param _tokenId Token ID
/// @param _badgeId Badge ID
/// @param _cycleId Cycle ID
/// @dev Only the owner of the token can reset the migration
function resetMigration(uint256 _tokenId, uint256 _badgeId, uint256 _cycleId) public virtual {
if (ownerOf(_tokenId) != _msgSender()) {
revert NOT_OWNER();
}

recruitmentContractV2.resetRecruitment(_msgSender(), _tokenId, _badgeId, _cycleId);
unlockTimestamps[_tokenId] = 0;
}
}
6 changes: 3 additions & 3 deletions packages/nfts/deployments/trailblazers-season-2/hekla.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"BadgeRecruitment": "0xBd368C65Cb354eBAd6c1429b551bD0197f19C2B8",
"BadgeRecruitment": "0xcb00B57e8F5fCFffE87bb65f3047b6e4e5A73cA9",
"Owner": "0x4100a9B680B1Be1F10Cb8b5a57fE59eA77A8184e",
"TrailblazersBadges": "0x9E14C357E964BeE012bA82Ce9d6513dAec6ea961",
"TrailblazersBadgesS2": "0xc84B76a5836Cb0CeF094808af445F7E98504ED5B"
"TrailblazersBadges": "0x3a7d7c963EF905FCdb6CefAA21b52497fae3EFC4",
"TrailblazersBadgesS2": "0xDE43b7b9A485d76bc8D48a69DdE6b89540b27DdD"
}
6 changes: 4 additions & 2 deletions packages/nfts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@
"pfp:deploy:hekla": "forge clean && pnpm compile && forge script script/profile/Deploy.s.sol --rpc-url https://rpc.hekla.taiko.xyz --broadcast --gas-estimate-multiplier 200",
"pfp:deploy:mainnet": "forge clean && pnpm compile && forge script script/profile/Deploy.s.sol --rpc-url https://rpc.mainnet.taiko.xyz --broadcast --gas-estimate-multiplier 200",
"tbz:airdrop:hekla": "forge clean && pnpm compile && forge script script/trailblazers-airdrop/Deploy.s.sol --rpc-url https://rpc.hekla.taiko.xyz --broadcast --gas-estimate-multiplier 200",
"tbz:airdrop:mainnet": "forge clean && pnpm compile && forge script script/trailblazers-airdrop/Deploy.s.sol --rpc-url https://rpc.mainnet.taiko.xyz --broadcast --gas-estimate-multiplier 100",
"tbz:airdrop:mainnet": "forge clean && pnpm compile && forge script script/trailblazers-airdrop/Deploy.s.sol --rpc-url https://rpc.mainnet.taiko.xyz --verify --broadcast --gas-estimate-multiplier 100",
"tbz:upgradeV3:hekla": "forge clean && pnpm compile && forge script script/trailblazers-badges/sol/UpgradeV3.s.sol --rpc-url https://rpc.hekla.taiko.xyz --broadcast --gas-estimate-multiplier 200",
"tbz:upgradeV3:mainnet": "forge clean && pnpm compile && forge script script/trailblazers-badges/sol/UpgradeV3.s.sol --rpc-url https://rpc.mainnet.taiko.xyz --broadcast --gas-estimate-multiplier 100",
"tbz:upgradeV4:mainnet": "forge clean && pnpm compile && forge script script/trailblazers-badges/UpgradeV4.s.sol --rpc-url https://rpc.mainnet.taiko.xyz --broadcast --gas-estimate-multiplier 100",
"tbz-s2:upgradeV2:mainnet": "forge clean && pnpm compile && forge script script/trailblazers-season-2/UpgradeV2.s.sol --rpc-url https://rpc.mainnet.taiko.xyz --broadcast --gas-estimate-multiplier 100"
"tbz-s2:upgradeV2:mainnet": "forge clean && pnpm compile && forge script script/trailblazers-season-2/UpgradeV2.s.sol --rpc-url https://rpc.mainnet.taiko.xyz --broadcast --gas-estimate-multiplier 100",
"tbz-s2:upgradeRecruitmentV2:hekla": "forge clean && pnpm compile && forge script script/trailblazers-season-2/RecruitmentUpgradeV2.s.sol --rpc-url https://rpc.hekla.taiko.xyz --broadcast --gas-estimate-multiplier 200",
"tbz-s2:upgradeRecruitmentV2:mainnet": "forge clean && pnpm compile && forge script script/trailblazers-season-2/RecruitmentUpgradeV2.s.sol --rpc-url https://rpc.mainnet.taiko.xyz --broadcast --gas-estimate-multiplier 100"
},
"devDependencies": {
"@types/node": "^20.11.30",
Expand Down
Loading

0 comments on commit abcec66

Please sign in to comment.