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): fba refactor #18557

Draft
wants to merge 43 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
14e5501
scaffolding for s2 tbz contracts
bearni95 Aug 27, 2024
1b722cd
simplified and unified contracts
bearni95 Aug 28, 2024
d926dae
added clarification method on BadgeMigration
bearni95 Aug 28, 2024
0c74f75
partial tests and proper, full implementation
bearni95 Sep 2, 2024
70ac2c0
flow for start, tamper and end migrations
bearni95 Sep 2, 2024
fafcffa
enabling of badgeIds and revert case tests
bearni95 Sep 2, 2024
fc5a771
feature-complete tests
bearni95 Sep 2, 2024
55379a7
natspec docs for s2 badges contract
bearni95 Sep 2, 2024
82d4fa0
hekla deployment script and typo fix
bearni95 Sep 2, 2024
b6a1e2b
minor cleanup
bearni95 Sep 2, 2024
8bc8fbf
hekla testing
bearni95 Sep 3, 2024
d898be4
frontend changes
bearni95 Sep 4, 2024
f64468c
ideal 8-participant structure, tests
bearni95 Sep 5, 2024
de82834
latest hekla deployment
bearni95 Sep 5, 2024
3db7acf
Merge branch 'tbz-s2-setup' into nfts-tbz-s2-champion-game-draft
bearni95 Sep 5, 2024
af66ab9
pnpm scripts cleanup
bearni95 Sep 5, 2024
4ad9fbe
game implementation with leagues
bearni95 Sep 5, 2024
64fcd42
contract simplification: pending event-driven tests
bearni95 Sep 5, 2024
506492f
runcommand added
bearni95 Sep 6, 2024
8979d9d
badge champions update
bearni95 Sep 7, 2024
dce2579
Merge branch 'main' into nfts-tbz-s2-champion-game-draft
bearni95 Sep 11, 2024
46cdf8b
forge fmt & update contract layout table
bearni95 Sep 11, 2024
284112f
s2 deployments hekla updates
bearni95 Sep 11, 2024
6920914
Merge branch 'nfts-tbz-s2-champion-game-draft' of ssh://github.com/ta…
bearni95 Sep 11, 2024
c53cb86
swapping branches
bearni95 Sep 12, 2024
934104e
s2 badges rework
bearni95 Sep 18, 2024
b6211bf
added pfps mainnet deployment
bearni95 Sep 18, 2024
161dbc0
Merge branch 'main' into nfts-tbz-s2-champion-game-draft
bearni95 Sep 19, 2024
e6a0f9a
updated hash method
bearni95 Oct 1, 2024
0d66eb2
badge champions comment corrections
bearni95 Oct 1, 2024
03301d2
badge champions comment corrections
bearni95 Oct 1, 2024
0dec153
initial commit
bearni95 Oct 2, 2024
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
5a6f431
Merge branch 'main' of ssh://github.com/taikoxyz/taiko-mono
bearni95 Dec 6, 2024
1d9cfda
Merge branch 'main' into nfts-tbz-s1-champion-game-contracts
bearni95 Dec 6, 2024
46c37fc
cleanup
bearni95 Dec 6, 2024
38e2b68
further cleanup
bearni95 Dec 6, 2024
a085cd4
renamed test for consistency
bearni95 Dec 6, 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
242 changes: 242 additions & 0 deletions packages/nfts/contracts/trailblazers-season-2/FactionBattleArena.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import { AccessControlUpgradeable } from
"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import { PausableUpgradeable } from
"@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
// import { IMinimalBlacklist } from "@taiko/blacklist/IMinimalBlacklist.sol";
import { UUPSUpgradeable } from
"@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { Ownable2StepUpgradeable } from
"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import "./TrailblazersS1BadgesV4.sol";
import "./TrailblazersBadgesS2.sol";

contract FactionBattleArena is
PausableUpgradeable,
UUPSUpgradeable,
Ownable2StepUpgradeable,
AccessControlUpgradeable
{
struct Champion {
address owner;
address badgeContract;
uint256 tokenId;
uint256 leagueId;
uint256 color; // 0 = neutral, 1 = pink, 2 = purple
uint256 power;
}

struct League {
uint64 openTime; // registration starts
uint64 closeTime; // registration ends
uint64 startTime; // league starts (requires admin action)
uint256 seed;
}

mapping(uint256 leagueId => League league) public leagues;
uint256 public currentLeagueId = 0;

TrailblazersBadges public season1Badges;
TrailblazersBadgesS2 public season2Badges;

uint256[8] public powerLevels = [
4, // Ravers
58, // Robots
40, // Bouncers
43, // Masters
99, // Monks
51, // Androids
42, // Drummers
77 // Shinto
];

event LeagueCreated(
uint256 indexed leagueId, uint256 openTime, uint256 startTime, uint256 endTime
);
event LeagueStarted(uint256 leagueId, uint256 seed);

event ChampionRegistered(
uint256 indexed leagueId,
address indexed owner,
address badgesContract,
uint256 tokenId,
uint256 power,
uint256 badgeId
);

error ELEMENT_NOT_FOUND();
error TOURNAMENT_NOT_STARTED();
error TOURNAMENT_NOT_OPEN();
error TOURNAMENT_NOT_CLOSED();
error TOURNAMENT_NOT_ENDED();
error CHAMPION_NOT_OWNED();
error INVALID_PARTICIPANT_COUNT();
error INVALID_ROUND();
error INVALID_CHAMPION_CONTRACT();
error INVALID_MATCH();

modifier leagueOpen(uint256 _leagueId) {
League memory league = leagues[_leagueId];
if (block.timestamp < league.openTime || block.timestamp > league.closeTime) {
revert TOURNAMENT_NOT_OPEN();
}

_;
}

modifier ownedToken(address _badgeContract, uint256 _badgeId) {
// TODO: erc1155 ownership checkup for s2 badges
uint256 tokenId = season1Badges.getTokenId(_msgSender(), _badgeId);

if (
season1Badges.ownerOf(tokenId) != _msgSender()
&& season1Badges.getApproved(tokenId) != address(this)
&& season1Badges.isApprovedForAll(_msgSender(), address(this))
) {
revert CHAMPION_NOT_OWNED();
}

_;
}

function initialize(address _season1Badges, address _season2Badges) external initializer {
__Context_init();
_grantRole(DEFAULT_ADMIN_ROLE, _msgSender());
_transferOwnership(_msgSender());
season1Badges = TrailblazersBadges(_season1Badges);
season2Badges = TrailblazersBadgesS2(_season2Badges);
}

function getCurrentLeague() public view returns (League memory league) {
return getLeague(currentLeagueId);
}

function getLeague(uint256 _leagueId) public view returns (League memory league) {
return leagues[_leagueId];
}

function createLeague(
uint64 _openTime,
uint64 _closeTime,
uint64 _startTime
)
public
onlyOwner
{
League memory league =
League({ openTime: _openTime, closeTime: _closeTime, startTime: _startTime, seed: 0 });
currentLeagueId += 1;

leagues[currentLeagueId] = league;

emit LeagueCreated(currentLeagueId, _openTime, _closeTime, _startTime);
}

function calculatePower(uint256 _badgeId) public pure returns (uint256) {
return ((1 + _badgeId) * 125) / 10;
//return powerLevels[_badgeId % powerLevels.length];
}

function _registerChampionFor(
address _player,
address _badgeContract,
uint256 _badgeId
)
internal
{
if (_badgeContract != address(season1Badges) && _badgeContract != address(season2Badges)) {
revert INVALID_CHAMPION_CONTRACT();
}

uint256 tokenId = season1Badges.getTokenId(_player, _badgeId);
uint256 power = calculatePower(_badgeId);

emit ChampionRegistered(currentLeagueId, _player, _badgeContract, tokenId, power, _badgeId);
}

function registerChampionFor(
address _player,
address _badgeContract,
uint256 _badgeId
)
public
onlyOwner
{
_registerChampionFor(_player, _badgeContract, _badgeId);
}

function registerChampion(
address _badgeContract,
uint256 _badgeId
)
public
leagueOpen(currentLeagueId)
ownedToken(_badgeContract, _badgeId)
{
_registerChampionFor(_msgSender(), _badgeContract, _badgeId);
}

function startLeague(uint256 seed) public onlyOwner {
League storage league = leagues[currentLeagueId];
league.seed = seed;
emit LeagueStarted(currentLeagueId, seed);
}

function calculateAdvantage(
uint256 _colorLeft,
uint256 _colorRight
)
public
pure
returns (bool leftAdvantage, bool rightAdvantage)
{
// neutral >> pink >> purple
// 0 >> 1 >> 2
if (_colorLeft == 0 && _colorRight == 1) {
return (true, false);
} else if (_colorLeft == 0 && _colorRight == 2) {
return (true, false);
} else if (_colorLeft == 1 && _colorRight == 0) {
return (false, true);
} else if (_colorLeft == 1 && _colorRight == 2) {
return (true, false);
} else if (_colorLeft == 2 && _colorRight == 0) {
return (false, true);
} else if (_colorLeft == 2 && _colorRight == 1) {
return (false, true);
} else {
return (false, false);
}
}

function getChampionId(
uint256 _leagueId,
address _owner,
address _badgeContract,
uint256 _tokenId
)
public
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(_owner, _badgeContract, _tokenId, _leagueId));
}

function supportsInterface(bytes4 interfaceId)
public
view
override(AccessControlUpgradeable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}

function _authorizeUpgrade(address) internal virtual override onlyOwner { }
}
125 changes: 125 additions & 0 deletions packages/nfts/script/trailblazers-season-2/DeployFBA.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// 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 { TrailblazersBadgesS2 } from
"../../contracts/trailblazers-season-2/TrailblazersBadgesS2.sol";
import { FactionBattleArena } from "../../contracts/trailblazers-season-2/FactionBattleArena.sol";

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

// Taiko Mainnet Values
//address owner = 0xf8ff2AF0DC1D5BA4811f22aCb02936A1529fd2Be;
//bytes32 root = 0xa7e510d5aed347e65609cf6f0e0738cdd752ffdf5980749057c634489fd09fc3;
// string baseURI = "bafybeierqzehlrqeqqeb6fwmil4dj3ij2p6exgoj4lysl53fsxwob6wbdy";
// IMinimalBlacklist blacklist = IMinimalBlacklist(0xfA5EA6f9A13532cd64e805996a941F101CCaAc9a);

// Hekla Testnet Values
bytes32 root = 0xf1359c4c4ba41a72025f2534ea8ad23c6b941b55a715838ebdc71202a78c6c87;
string baseURI =
"https://taikonfts.4everland.link/ipfs/bafybeiebmvj6roz4iuoinackb5c6eeshvppctkydrckqrnxexdnzh6odq4";

IMinimalBlacklist blacklist = IMinimalBlacklist(0xe61E9034b5633977eC98E302b33e321e8140F105);
address mintSigner = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;

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

address s1Contract = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;

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

jsonLocation = utils.getContractJsonLocation();

string memory projectRoot = vm.projectRoot();
jsonLocation = string.concat(
projectRoot, "/deployments/trailblazers-badges/", utils.lowercaseNetworkKey(), ".json"
);

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

function run() public {
string memory jsonRoot = "root";
address owner = deployerAddress;
require(owner != address(0), "Owner must be specified");

address impl;
address proxy;
TrailblazersBadges s1Token;
TrailblazersBadgesS2 s2Token;
FactionBattleArena fba;

vm.startBroadcast(deployerPrivateKey);

if (block.chainid == 167_000) {
// mainnet, use existing contract
s1Token = TrailblazersBadges(s1Contract);
} else {
// hekla/localhost, deploy a s1 contract
impl = address(new TrailblazersBadges());
blacklist = new MockBlacklist();
proxy = address(
new ERC1967Proxy(
impl,
abi.encodeCall(
TrailblazersBadges.initialize, (owner, baseURI, mintSigner, blacklist)
)
)
);

s1Token = TrailblazersBadges(proxy);
}
/*
// deploy s2 contract
impl = address(new TrailblazersBadgesS2());
proxy = address(
new ERC1967Proxy(
impl,
abi.encodeCall(TrailblazersBadgesS2.initialize, (address(s1Token), mintSigner))
)
);
*/
s2Token = TrailblazersBadgesS2(proxy);

console.log("Token Base URI:", baseURI);
console.log("Deployed TrailblazersBadgesS2 to:", address(s2Token));

// Deploy Badge Champions
impl = address(new FactionBattleArena());
proxy = address(
new ERC1967Proxy(
impl,
abi.encodeCall(FactionBattleArena.initialize, (address(s1Token), address(s2Token)))
)
);

fba = FactionBattleArena(proxy);

// Register deployment

vm.serializeAddress(jsonRoot, "TrailblazersBadges", address(s1Token));
vm.serializeAddress(jsonRoot, "TrailblazersBadgesS2", address(s2Token));
vm.serializeAddress(jsonRoot, "FactionBattleArena", address(fba));
string memory finalJson = vm.serializeAddress(jsonRoot, "Owner", s2Token.owner());
vm.writeJson(finalJson, jsonLocation);

vm.stopBroadcast();
}
}
Loading