-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(nft): fix s2 badges remigration (#18578)
Co-authored-by: Korbinian <[email protected]> Co-authored-by: Korbinian <[email protected]>
- Loading branch information
1 parent
ec5f599
commit abcec66
Showing
9 changed files
with
728 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
141 changes: 141 additions & 0 deletions
141
packages/nfts/contracts/trailblazers-season-2/BadgeRecruitmentV2.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
66 changes: 66 additions & 0 deletions
66
packages/nfts/contracts/trailblazers-season-2/TrailblazersS1BadgesV5.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.