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

feat(nfts): trailblazer-badges v2 upgrade #17848

Merged
merged 4 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
40 changes: 40 additions & 0 deletions packages/nfts/contracts/trailblazers-badges/TrailblazersBadges.sol
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,44 @@ contract TrailblazersBadges is ERC721EnumerableUpgradeable, ECDSAWhitelist {
balances[7] = 0 != getTokenId(_owner, BADGE_SHINTO);
return balances;
}

/// @notice v2

/// @notice Retrieve the base URI
function baseURI() public view returns (string memory) {
return _baseURIExtended;
}

/// @notice Upgraded badgeBalances using tokenOfOwnerByIndex
/// @param _owner The addresses to check
/// @return balances The badges atomic balances
function badgeBalancesV2(address _owner) public view returns (bool[] memory balances) {
uint256 balance = balanceOf(_owner);
uint256[] memory tokenIds = new uint256[](balance);
for (uint256 i = 0; i < balance; i++) {
tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
}
balances = new bool[](8);

for (uint256 i = 0; i < balance; i++) {
uint256 badgeId = badges[tokenIds[i]];
balances[badgeId] = true;
}

return balances;
}

/// @notice Return the total badge supply by badgeId
/// @return balances The amount of each badge id
function totalBadgeSupply() public view returns (uint256[] memory balances) {
uint256 totalSupply = totalSupply();
balances = new uint256[](8);

for (uint256 i = 1; i <= totalSupply; i++) {
uint256 badgeId = badges[i];
balances[badgeId]++;
}

return balances;
}
}
2 changes: 1 addition & 1 deletion packages/nfts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"eslint": "pnpm exec eslint --ignore-path .eslintignore --ext .js,.ts . --fix",
"fmt:sol": "forge fmt",
"lint:sol": "forge fmt && pnpm solhint 'contracts/**/*.sol'",
"test": "pnpm clean && pnpm compile && forge test --match-path 'test/*.t.sol' -vvv",
"test": "forge test --match-path 'test/*.t.sol' -vvv",
"node": "anvil",
"layout": "./deployments/gen-layouts.sh",
"taikoon:merkle": "node script/taikoon/js/generate-merkle-tree.js",
Expand Down
5 changes: 3 additions & 2 deletions packages/nfts/script/trailblazers-badges/sol/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ contract DeployScript is Script {

// Hardhat Testnet Values
address owner = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
address mintSigner = 0x3cda4F2EaC3fc2FdE78B3DFFe1A1A1Eff88c68c5;
string baseURI = "https://taikonfts.4everland.link/ipfs/bafybeierqzehlrqeqqeb6fwmil4dj3ij2p6exgoj4lysl53fsxwob6wbdy";
address mintSigner = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
string baseURI =
"https://taikonfts.4everland.link/ipfs/bafybeierqzehlrqeqqeb6fwmil4dj3ij2p6exgoj4lysl53fsxwob6wbdy";
IMinimalBlacklist blacklist = IMinimalBlacklist(0xe61E9034b5633977eC98E302b33e321e8140F105);

function setUp() public {
Expand Down
41 changes: 41 additions & 0 deletions packages/nfts/script/trailblazers-badges/sol/UpgradeV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import { UtilsScript } 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";

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

address tokenV1 = 0xa20a8856e00F5ad024a55A663F06DCc419FFc4d5;
TrailblazersBadges public token;

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

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

function run() public {
token = TrailblazersBadges(tokenV1);
vm.startBroadcast(deployerPrivateKey);

token.upgradeToAndCall(
address(new TrailblazersBadges()), abi.encodeCall(TrailblazersBadges.baseURI, ())
);

token = TrailblazersBadges(token);

console.log("Upgraded TrailblazersBadges to:", address(token));
}
}
88 changes: 88 additions & 0 deletions packages/nfts/test/trailblazers-badges/TrailblazersBadges.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -295,4 +295,92 @@ contract TrailblazersBadgesTest is Test {
vm.assertEq(token.getTokenId(minters[0], badgeId), 0);
vm.assertEq(token.getTokenId(minters[1], badgeId), 1);
}

function test_transfer_dataConsistency2() public {
// mint a token to minter 0
uint256 badgeId = token.BADGE_DRUMMERS();

// mint the badge

vm.startBroadcast(owner);
bytes32 _hash = token.getHash(minters[0], badgeId);

(uint8 v, bytes32 r, bytes32 s) = vm.sign(mintSignerPk, _hash);

bool canMint = token.canMint(abi.encodePacked(r, s, v), minters[0], badgeId);
assertTrue(canMint);

token.mint(abi.encodePacked(r, s, v), minters[0], badgeId);
vm.stopBroadcast();

// transfer to minters[1]
vm.startBroadcast(minters[0]);
token.safeTransferFrom(minters[0], minters[1], 1);

// ensure the badge balances are consistent
bool[] memory badges = token.badgeBalancesV2(minters[1]);

// ensure only badgeId = 5 (Drummers) is true
vm.assertFalse(badges[token.BADGE_RAVERS()]);
vm.assertFalse(badges[token.BADGE_ROBOTS()]);
vm.assertFalse(badges[token.BADGE_BOUNCERS()]);
vm.assertFalse(badges[token.BADGE_MASTERS()]);
vm.assertFalse(badges[token.BADGE_MONKS()]);
vm.assertTrue(badges[token.BADGE_DRUMMERS()]);
vm.assertFalse(badges[token.BADGE_ANDROIDS()]);
vm.assertFalse(badges[token.BADGE_SHINTO()]);

vm.stopBroadcast();

// ensure wallets[0] has no badges
badges = token.badgeBalancesV2(minters[0]);

vm.assertFalse(badges[token.BADGE_RAVERS()]);
vm.assertFalse(badges[token.BADGE_ROBOTS()]);
vm.assertFalse(badges[token.BADGE_BOUNCERS()]);
vm.assertFalse(badges[token.BADGE_MASTERS()]);
vm.assertFalse(badges[token.BADGE_MONKS()]);
vm.assertFalse(badges[token.BADGE_DRUMMERS()]);
vm.assertFalse(badges[token.BADGE_ANDROIDS()]);
vm.assertFalse(badges[token.BADGE_SHINTO()]);

// check the token IDs
vm.assertEq(token.getTokenId(minters[0], badgeId), 0);
vm.assertEq(token.getTokenId(minters[1], badgeId), 1);
}

function mintBadgeTo(uint256 badgeId, address minter) private {
vm.startBroadcast(owner);
bytes32 _hash = token.getHash(minter, badgeId);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(mintSignerPk, _hash);
bool canMint = token.canMint(abi.encodePacked(r, s, v), minter, badgeId);
assertTrue(canMint);

token.mint(abi.encodePacked(r, s, v), minter, badgeId);
vm.stopBroadcast();
}

function test_totalBadgeSupply() public {
mintBadgeTo(token.BADGE_RAVERS(), minters[0]);
mintBadgeTo(token.BADGE_ROBOTS(), minters[0]);
mintBadgeTo(token.BADGE_BOUNCERS(), minters[1]);
mintBadgeTo(token.BADGE_MASTERS(), minters[0]);
mintBadgeTo(token.BADGE_MONKS(), minters[0]);
mintBadgeTo(token.BADGE_DRUMMERS(), minters[0]);
mintBadgeTo(token.BADGE_DRUMMERS(), minters[1]);
mintBadgeTo(token.BADGE_DRUMMERS(), minters[2]);
mintBadgeTo(token.BADGE_ANDROIDS(), minters[0]);
mintBadgeTo(token.BADGE_SHINTO(), minters[0]);

uint256[] memory badges = token.totalBadgeSupply();

vm.assertEq(badges[token.BADGE_RAVERS()], 1);
vm.assertEq(badges[token.BADGE_ROBOTS()], 1);
vm.assertEq(badges[token.BADGE_BOUNCERS()], 1);
vm.assertEq(badges[token.BADGE_MASTERS()], 1);
vm.assertEq(badges[token.BADGE_MONKS()], 1);
vm.assertEq(badges[token.BADGE_DRUMMERS()], 3);
vm.assertEq(badges[token.BADGE_ANDROIDS()], 1);
vm.assertEq(badges[token.BADGE_SHINTO()], 1);
}
}