Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(nft): fix s2 badges remigration #18578

Merged
merged 26 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6178142
tbz updated blacklist
bearni95 Oct 10, 2024
439b237
Merge branch 'main' of ssh://github.com/taikoxyz/taiko-mono
bearni95 Oct 11, 2024
f50eeb6
Merge branch 'main' of ssh://github.com/taikoxyz/taiko-mono
bearni95 Oct 16, 2024
cb0e4a8
Merge branch 'main' of ssh://github.com/taikoxyz/taiko-mono
bearni95 Oct 17, 2024
999f49e
Merge branch 'main' of ssh://github.com/taikoxyz/taiko-mono
bearni95 Dec 2, 2024
94c69a7
Merge branch 'main' of ssh://github.com/taikoxyz/taiko-mono
bearni95 Dec 3, 2024
1d85a0c
upgradable owner
KorbinianK Dec 5, 2024
5a6f431
Merge branch 'main' of ssh://github.com/taikoxyz/taiko-mono
bearni95 Dec 6, 2024
15343f9
adjust test
KorbinianK Dec 9, 2024
4fecb20
add initialize to deploy script
KorbinianK Dec 9, 2024
b60a2b5
deployment
KorbinianK Dec 9, 2024
e86cccc
Merge branch 'main' of ssh://github.com/taikoxyz/taiko-mono
bearni95 Dec 9, 2024
654fa7b
Merge branch 'main' into event-register-upgradeable
KorbinianK Dec 10, 2024
b9e2675
the commit
bearni95 Dec 11, 2024
c430ab3
recruitment script
bearni95 Dec 11, 2024
b08d0f9
fmt, lint
bearni95 Dec 11, 2024
6cf3954
Merge remote-tracking branch 'origin/event-register-upgradeable' into…
bearni95 Dec 11, 2024
4215325
subgraph changes
bearni95 Dec 11, 2024
49e9812
hekla deployment
bearni95 Dec 12, 2024
46da91c
Merge branch 'main' into s2-badges-remigrate-fix
KorbinianK Dec 13, 2024
511aed3
Merge branch 'main' into s2-badges-remigrate-fix
KorbinianK Dec 13, 2024
3de9e1e
added check to not allow starting recruitments too close to end cycle…
bearni95 Dec 13, 2024
5b0a77c
Merge branch 'main' into s2-badges-remigrate-fix
bearni95 Dec 16, 2024
16783c3
Merge branch 'main' into s2-badges-remigrate-fix
bearni95 Dec 16, 2024
dc770a7
mainnet deployment
bearni95 Dec 16, 2024
f49c39d
Merge branch 'main' into s2-badges-remigrate-fix
bearni95 Dec 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "./BadgeRecruitment.sol";

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

/// @notice Errors
error RECRUITMENT_ALREADY_COMPLETED();

/// @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)
{
bearni95 marked this conversation as resolved.
Show resolved Hide resolved
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();
}

/// @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 _recruitmentIdx The recruitment index
/// @param _s1TokenId The s1 token ID
/// @dev Must be called from the s1 badges contract
function resetRecruitment(
address _user,
uint256 _recruitmentIdx,
uint256 _s1TokenId
)
public
virtual
onlyRole(S1_BADGES_ROLE)
{
Recruitment memory recruitment_ = recruitments[_user][_recruitmentIdx];
if (recruitment_.s1TokenId != _s1TokenId) {
revert RECRUITMENT_NOT_STARTED();
}

if (recruitment_.s2TokenId != 0) {
revert RECRUITMENT_ALREADY_COMPLETED();
}

// reset
uint256 s1BadgeId_ = recruitment_.s1BadgeId;

//delete
delete recruitments[_user][_recruitmentIdx];
recruitmentCycleUniqueMints[recruitmentCycleId][_user][s1BadgeId_][RecruitmentType.Undefined]
= false;
recruitmentCycleUniqueMints[recruitmentCycleId][_user][s1BadgeId_][RecruitmentType.Claim] =
false;
recruitmentCycleUniqueMints[recruitmentCycleId][_user][s1BadgeId_][RecruitmentType.Migration]
= false;

emit RecruitmentReset(_user, _s1TokenId, s1BadgeId_);
}
}
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,71 @@
// 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();
/// @notice Updated version function
/// @return Version string

function version() external pure virtual override returns (string memory) {
return "V5";
}

BadgeRecruitmentV2 public recruitmentContractV2;

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

/// @notice Start recruitment for a badge
/// @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
function resetMigration(uint256 _tokenId) public virtual {
if (ownerOf(_tokenId) != _msgSender()) {
revert NOT_OWNER();
}

BadgeRecruitment.Recruitment[] memory recruitments_ =
recruitmentContractV2.getActiveRecruitmentsFor(_msgSender());

for (uint256 i = 0; i < recruitments_.length; i++) {
// check if the recruitment is ongoing
// AND if it isn't finished (s2TokenId == 0)
if (recruitments_[i].s1TokenId == _tokenId && recruitments_[i].s2TokenId == 0) {
unlockTimestamps[_tokenId] = 0;
recruitmentContractV2.resetRecruitment(_msgSender(), i, _tokenId);
return;
}
}

revert RECRUITMENT_ALREADY_COMPLETED();
}
}
3 changes: 2 additions & 1 deletion packages/nfts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"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"
},
"devDependencies": {
"@types/node": "^20.11.30",
Expand Down
151 changes: 151 additions & 0 deletions packages/nfts/script/trailblazers-season-2/RecruitmentUpgradeV2.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import { UtilsScript, MockBlacklist } from "./Utils.s.sol";
import { Script, console } from "forge-std/src/Script.sol";
import { Merkle } from "murky/Merkle.sol";
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { TrailblazersBadges } from "../../contracts/trailblazers-badges/TrailblazersBadges.sol";
import { IMinimalBlacklist } from "@taiko/blacklist/IMinimalBlacklist.sol";

import "../../contracts/trailblazers-season-2/TrailblazersBadgesS2.sol";

import "../../contracts/trailblazers-season-2/TrailblazersS1BadgesV5.sol";

contract UpgradeV2 is Script {
// setup
UtilsScript public utils;
string public jsonLocation;
uint256 public deployerPrivateKey;
address public deployerAddress;

// deployment vars
TrailblazersBadgesV5 public tokenV5;
BadgeRecruitmentV2 public badgeRecruitmentV2;

// mainnet config
address public s1TokenAddress = 0xa20a8856e00F5ad024a55A663F06DCc419FFc4d5;
address public badgeRecruitmentAddress = 0xa9Ceb04F3aF71fF123409d426A92BABb5124970C;

// hekla config
string baseURI =
"https://taikonfts.4everland.link/ipfs/bafybeiatuzeeeznd3hi5qiulslxcjd22ebu45t4fra2jvi3smhocr2c66a";

IMinimalBlacklist blacklist = IMinimalBlacklist(0xe61E9034b5633977eC98E302b33e321e8140F105);
address claimMintSigner = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
address recruitmentSigner = 0x3cda4F2EaC3fc2FdE78B3DFFe1A1A1Eff88c68c5;

uint256 public MAX_INFLUENCES = 5;
uint256 public COOLDOWN_RECRUITMENT = 10 minutes;
uint256 public COOLDOWN_INFLUENCE = 5 minutes;
uint256 public INFLUENCE_WEIGHT_PERCENT = 9;
uint256 public MAX_INFLUENCES_DIVIDER = 100;
uint256 public DEFAULT_CYCLE_DURATION = 7 days;
uint256 public s1EndDate = 1_734_350_400; // Dec 16th 2024, noon UTC
uint256 public S1_LOCK_DURATION = (s1EndDate - block.timestamp);

function setUp() public {
utils = new UtilsScript();
utils.setUp();

jsonLocation = utils.getContractJsonLocation();
deployerPrivateKey = utils.getPrivateKey();
deployerAddress = utils.getAddress();
}

function run() public {
vm.startBroadcast(deployerPrivateKey);

address impl;
address proxy;
TrailblazersBadgesV4 s1Token;
TrailblazersBadgesS2 s2Token;
BadgeRecruitment badgeRecruitment;

if (block.chainid == 167_000) {
// mainnet, use existing contract
s1Token = TrailblazersBadgesV4(s1TokenAddress);
badgeRecruitment = BadgeRecruitment(badgeRecruitmentAddress);
} else {
// non-mainnet, deploy contract chain
impl = address(new TrailblazersBadges());
blacklist = new MockBlacklist();
proxy = address(
new ERC1967Proxy(
impl,
abi.encodeCall(
TrailblazersBadges.initialize,
(deployerAddress, baseURI, claimMintSigner, blacklist)
)
)
);

TrailblazersBadges s1TokenV2 = TrailblazersBadges(proxy);

// upgrade s1 contract to v4
s1TokenV2.upgradeToAndCall(
address(new TrailblazersBadgesV4()),
abi.encodeCall(TrailblazersBadgesV4.version, ())
);

s1Token = TrailblazersBadgesV4(address(s1TokenV2));

// deploy recruitment contract
BadgeRecruitment.Config memory config = BadgeRecruitment.Config(
COOLDOWN_RECRUITMENT,
COOLDOWN_INFLUENCE,
INFLUENCE_WEIGHT_PERCENT,
MAX_INFLUENCES,
MAX_INFLUENCES_DIVIDER,
DEFAULT_CYCLE_DURATION
);
impl = address(new BadgeRecruitment());
proxy = address(
new ERC1967Proxy(
impl,
abi.encodeCall(
BadgeRecruitment.initialize,
(address(s1Token), address(s2Token), recruitmentSigner, config)
)
)
);

badgeRecruitment = BadgeRecruitment(proxy);
}

// upgrade token contract
s1Token.upgradeToAndCall(
address(new TrailblazersBadgesV5()), abi.encodeCall(TrailblazersBadgesV5.version, ())
);

tokenV5 = TrailblazersBadgesV5(address(s1Token));
console.log("Upgraded TrailblazersBadgesV4 to:", address(tokenV5));

// upgrade recruitment contract
badgeRecruitment.upgradeToAndCall(
address(new BadgeRecruitmentV2()), abi.encodeCall(BadgeRecruitmentV2.version, ())
);

badgeRecruitmentV2 = BadgeRecruitmentV2(address(badgeRecruitment));
console.log("Upgraded BadgeRecruitment to:", address(badgeRecruitmentV2));

// set upgraded recruitment contract
tokenV5.setRecruitmentContractV2(address(badgeRecruitmentV2));
console.log("Set recruitment contract to:", address(badgeRecruitmentV2));

/*
token.upgradeToAndCall(
address(new TrailblazersBadgesS2()), abi.encodeCall(TrailblazersBadgesS2.version, ())
);

token = TrailblazersBadgesS2(address(token));

console.log("Upgraded TrailblazersBadgesV3 to:", address(token));

// update uri
token.setUri(
"https://taikonfts.4everland.link/ipfs/bafybeief7o4u6f676e6uz4yt4cv34ai4mesd7motoq6y4xxaoyjfbna5de"
);
console.log("Updated token URI");*/
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { TrailblazersBadgesV4 } from
"../../contracts/trailblazers-season-2/TrailblazersS1BadgesV4.sol";
import { BadgeRecruitment } from "../../contracts/trailblazers-season-2/BadgeRecruitment.sol";

contract TrailblazersBadgesS2Test is Test {
contract BadgeRecruitmentTest is Test {
UtilsScript public utils;

TrailblazersBadgesV4 public s1BadgesV4;
Expand Down
Loading