-
Notifications
You must be signed in to change notification settings - Fork 1
/
GenesisMinter.sol
177 lines (148 loc) · 6.59 KB
/
GenesisMinter.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.24;
// ** ** ** ** **** **
// /** /** /** // /**/ /**
// /** /** /** ** ****** ****** ****** ******
// /** /** /****** /** **//// **////**///**/ ///**/
// /** /** /**///** /**//***** /** /** /** /**
// /** /** /** /** /** /////**/** /** /** /**
// //******* /****** /** ****** //****** /** //**
// /////// ///// // ////// ////// // //
import {GenesisUpgradeable} from "src/abstracts/GenesisUpgradeable.sol";
import {IGenesisChampion} from "src/interfaces/IGenesisChampion.sol";
import {IGenesisChampionFactory} from "src/interfaces/IGenesisChampionFactory.sol";
import {IGenesisMinter} from "src/interfaces/IGenesisMinter.sol";
import {Errors} from "src/librairies/Errors.sol";
import {MintData} from "src/types/MintDataV2.sol";
import {SupplyConfig} from "src/types/SupplyConfig.sol";
/**
* @title GenesisMinter
*
* @notice GenesisMinter is a UUPS proxy implementing supply mechanisms and claim for GenesisChampion tokens
*/
contract GenesisMinter is IGenesisMinter, GenesisUpgradeable {
// =============================================================
// EVENTS
// =============================================================
/// @notice emitted after a successful `claim`
event Claim(address indexed collection, bytes32 indexed nonce, uint256 amount);
/// @notice emitted after changing the factory address
event GenesisFactoryUpdate(address oldFactory, address newFactory);
// =============================================================
// MODIFIERS
// =============================================================
modifier validRequestParams(MintData calldata request) {
// Cannot mint zero tokens
if (request.amount == 0) revert Errors.InvalidMintAmount();
// Collection address is address(0)
if (request.collection == address(0)) revert Errors.ZeroAddress();
// Collection was deployed by factory
uint256 index = factory.deployedVersions(request.collection);
if (index == 0) revert Errors.CollectionUnknown(request.collection);
_;
}
// =============================================================
// CONSTANTS
// =============================================================
/// @notice Minter role used for AccessControl
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
// =============================================================
// MAPPINGS
// =============================================================
/// @notice Supply associated to the initial claim for each collection
mapping(address collectionAddress => SupplyConfig collectionSupply) public supply;
// =============================================================
// VARIABLES
// =============================================================
/// @notice GenesisChampionFactory contract instance
IGenesisChampionFactory public factory;
/// @notice Storage gap for future upgrades
uint256[48] __gap;
// =============================================================
// UUPS
// =============================================================
function initialize(address factory_, address minter_)
external
initializer
{
// Initialize upgradeable contracts
__Ownable_init(_msgSender());
__AccessControl_init();
__UUPSUpgradeable_init();
// Grant DEFAULT_ADMIN_ROLE to owner()
_grantRole(DEFAULT_ADMIN_ROLE, _msgSender());
// Grant MINTER_ROLE to minter_
_grantRole(MINTER_ROLE, minter_);
// Instantiate the factory and crafter
require(factory_ != address(0));
factory = IGenesisChampionFactory(factory_);
}
// =============================================================
// PUBLIC
// =============================================================
/**
* @inheritdoc IGenesisMinter
*/
function claim(MintData calldata request)
external
validRequestParams(request)
onlyRole(MINTER_ROLE)
returns (uint256 firstId, uint256 lastId)
{
// Tokens are still available for mint
uint256 currentSupply;
if (request.holder) currentSupply = supply[request.collection].sHolder;
else currentSupply = supply[request.collection].sPublic;
if (currentSupply == 0) revert Errors.MaxSupplyReached();
// Get user allocation
uint256 allocation = request.amount;
if (allocation > currentSupply) allocation = currentSupply;
// Decrement the supply
request.holder
? supply[request.collection].sHolder -= allocation
: supply[request.collection].sPublic -= allocation;
// Mint the tokens
(firstId, lastId) = _mint(request.collection, request.to, allocation);
emit Claim(request.collection, request.nonce, allocation);
}
/**
* @inheritdoc IGenesisMinter
*/
function registerSupply(address collection, uint256 holderSupply, uint256 publicSupply) external onlyOwner {
if (supply[collection].init) revert Errors.SupplyUnregistered(collection);
supply[collection].sHolder = holderSupply;
supply[collection].sPublic = publicSupply;
supply[collection].init = true;
}
/**
* @inheritdoc IGenesisMinter
*/
function mint(address collection, address to, uint256 amount)
external
onlyRole(MINTER_ROLE)
returns (uint256 firstId, uint256 lastId)
{
return _mint(collection, to, amount);
}
/**
* @inheritdoc IGenesisMinter
*/
function updateFactory(address newFactory) external onlyOwner {
address currentFactory = address(factory);
factory = IGenesisChampionFactory(newFactory);
emit GenesisFactoryUpdate(currentFactory, newFactory);
}
/**
* @inheritdoc GenesisUpgradeable
*/
function version() external pure override returns (uint256) {
return 1;
}
// =============================================================
// INTERNAL
// =============================================================
function _mint(address collection, address to, uint256 amount) internal returns (uint256 firstId, uint256 lastId) {
IGenesisChampion champion = IGenesisChampion(collection);
(firstId, lastId) = champion.mint(to, amount);
}
}