gn-contract 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,254 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.17;
3
+
4
+ import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
5
+ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
6
+ import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";
7
+ import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";
8
+ import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
9
+ import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
10
+ import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol";
11
+ import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";
12
+
13
+ import "./USDT.sol";
14
+ import "./lib/NFTGetter.sol";
15
+ import "./NFT.sol";
16
+ import "./Network.sol";
17
+
18
+ contract NFTFounder is
19
+ Initializable,
20
+ ERC721Upgradeable,
21
+ OwnableUpgradeable,
22
+ ERC721EnumerableUpgradeable,
23
+ ERC721URIStorageUpgradeable,
24
+ UUPSUpgradeable
25
+ {
26
+ using CountersUpgradeable for CountersUpgradeable.Counter;
27
+
28
+ CountersUpgradeable.Counter private _tokenIdCounter;
29
+ CountersUpgradeable.Counter private _cardIdCounter;
30
+ USDT public usdtERC20;
31
+ Network public valhalla;
32
+
33
+ CardFounder public cardFounder;
34
+ mapping(address => CardsRewardFounder) public nftFounder;
35
+ uint public nftFounderPoolMarker;
36
+ address public receiverAddress;
37
+ address public receiverAddress2;
38
+ uint256 public nftFounderPool;
39
+
40
+ // events
41
+ event BuyNFTs(address indexed _from, uint[] _tokenIds);
42
+ event ClaimReward(address indexed _from, uint value);
43
+ event DistributeRewards(address indexed from, uint value);
44
+
45
+ /// @custom:oz-upgrades-unsafe-allow constructor
46
+ constructor() {
47
+ _disableInitializers();
48
+ }
49
+
50
+ function initialize(
51
+ USDT _usdtERC20,
52
+ Network _valhalla,
53
+ address _receiver
54
+ ) public initializer {
55
+ __ERC721_init("NFTFounder", "NFTF");
56
+ __ERC721Enumerable_init();
57
+ __Ownable_init();
58
+ __UUPSUpgradeable_init();
59
+ valhalla = _valhalla;
60
+ receiverAddress = _receiver;
61
+ usdtERC20 = _usdtERC20;
62
+
63
+ cardFounder.totalMinted = 0;
64
+ _cardIdCounter.increment();
65
+ }
66
+
67
+ modifier onlyValhalla() {
68
+ require(msg.sender == address(valhalla), "Only Admin can perform action");
69
+ _;
70
+ }
71
+
72
+ function setFounderProps(uint _price, uint _maxMinted) public {
73
+ cardFounder.price = _price * 10 ** usdtERC20.decimals();
74
+ cardFounder.maxMinted = _maxMinted;
75
+ }
76
+
77
+ function myNftRewards(address _address) public view returns (uint) {
78
+ CardsRewardFounder memory nftCards = nftFounder[_address];
79
+ uint poolMarker = nftFounderPoolMarker;
80
+
81
+ if (!(poolMarker > nftCards.currentRewards)) return 0;
82
+ return (poolMarker - nftCards.currentRewards) * nftCards.ownedNfts;
83
+ }
84
+
85
+ function buyNFTs(uint amount) public {
86
+ bool isRegistered;
87
+ address referrer;
88
+ (isRegistered, , , referrer, , , , ) = valhalla.accountMap(msg.sender);
89
+
90
+ uint8[3] memory distributedValue = [5, 3, 2];
91
+
92
+ require(isRegistered, "Not registered yet");
93
+
94
+ uint[] memory tokenIds = new uint[](amount);
95
+ // usdtERC20.transferFrom(msg.sender, receiverAddress, cardFounder.price * amount);
96
+
97
+ require(
98
+ cardFounder.maxMinted >= cardFounder.totalMinted + amount,
99
+ "Max minted reached"
100
+ );
101
+
102
+ for (uint i = 0; i < 3; i++) {
103
+ if (referrer == address(0)) {
104
+ usdtERC20.transferFrom(
105
+ msg.sender,
106
+ receiverAddress,
107
+ (distributedValue[i] * cardFounder.price * amount) / 100
108
+ );
109
+ } else {
110
+ usdtERC20.transferFrom(
111
+ msg.sender,
112
+ referrer,
113
+ (distributedValue[i] * cardFounder.price * amount) / 100
114
+ );
115
+ (, , , referrer, , , , ) = valhalla.accountMap(referrer);
116
+ }
117
+ }
118
+
119
+ usdtERC20.transferFrom(
120
+ msg.sender,
121
+ receiverAddress,
122
+ ((36 * cardFounder.price) / 100) * amount
123
+ );
124
+ usdtERC20.transferFrom(
125
+ msg.sender,
126
+ receiverAddress2,
127
+ ((54 * cardFounder.price) / 100) * amount
128
+ );
129
+
130
+ for (uint i = 0; i < amount; i++) {
131
+ uint256 tokenId = _tokenIdCounter.current();
132
+ tokenIds[i] = tokenId;
133
+ _tokenIdCounter.increment();
134
+ _safeMint(msg.sender, tokenId);
135
+ }
136
+
137
+ uint rewards = myNftRewards(msg.sender);
138
+ if (rewards > 0) claimRewards();
139
+
140
+ CardsRewardFounder storage nftCards = nftFounder[msg.sender];
141
+ nftCards.ownedNfts += amount;
142
+ cardFounder.totalMinted += amount;
143
+ nftCards.currentRewards = nftFounderPoolMarker;
144
+
145
+ emit BuyNFTs(msg.sender, tokenIds);
146
+ }
147
+
148
+ function claimRewards() public {
149
+ uint rewards = myNftRewards(msg.sender);
150
+ require(rewards > 0, "No rewards yet");
151
+
152
+ CardsRewardFounder storage nftCards = nftFounder[msg.sender];
153
+ nftCards.currentRewards = nftFounderPoolMarker;
154
+ nftFounderPool -= rewards;
155
+
156
+ usdtERC20.transfer(msg.sender, rewards);
157
+ emit ClaimReward(msg.sender, rewards);
158
+ }
159
+
160
+ function setReceiverAddress2(address _receiver) public onlyOwner {
161
+ receiverAddress2 = _receiver;
162
+ }
163
+
164
+ function distributeFounderRewards(uint value) external onlyValhalla {
165
+ // Always add value to pool so it's tracked
166
+ nftFounderPool += value;
167
+
168
+ // Only distribute per-NFT rewards if NFTs have been minted
169
+ // This prevents division by zero and accumulates rewards for future distribution
170
+ if (cardFounder.totalMinted == 0) return;
171
+
172
+ nftFounderPoolMarker += value / cardFounder.totalMinted;
173
+ }
174
+
175
+ function safeMint(address to) public onlyOwner {
176
+ uint256 tokenId = _tokenIdCounter.current();
177
+ _tokenIdCounter.increment();
178
+ _safeMint(to, tokenId);
179
+ }
180
+
181
+ function _authorizeUpgrade(
182
+ address newImplementation
183
+ ) internal override onlyOwner {}
184
+
185
+ // The following functions are overrides required by Solidity.
186
+
187
+ function _beforeTokenTransfer(
188
+ address from,
189
+ address to,
190
+ uint256 tokenId,
191
+ uint256 batchSize
192
+ ) internal override(ERC721Upgradeable, ERC721EnumerableUpgradeable) {
193
+ super._beforeTokenTransfer(from, to, tokenId, batchSize);
194
+ }
195
+
196
+ function _burn(
197
+ uint256 tokenId
198
+ ) internal override(ERC721Upgradeable, ERC721URIStorageUpgradeable) {
199
+ super._burn(tokenId);
200
+ }
201
+
202
+ function tokenURI(
203
+ uint256 tokenId
204
+ )
205
+ public
206
+ view
207
+ override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
208
+ returns (string memory)
209
+ {
210
+ return super.tokenURI(tokenId);
211
+ }
212
+
213
+ function supportsInterface(
214
+ bytes4 interfaceId
215
+ )
216
+ public
217
+ view
218
+ override(
219
+ ERC721EnumerableUpgradeable,
220
+ ERC721URIStorageUpgradeable,
221
+ ERC721Upgradeable
222
+ )
223
+ returns (bool)
224
+ {
225
+ return super.supportsInterface(interfaceId);
226
+ }
227
+
228
+ function _baseURI() internal pure override returns (string memory) {
229
+ return "https://crowdstrike.club/api/image/founder/";
230
+ }
231
+
232
+ function transferFrom(
233
+ address from,
234
+ address to,
235
+ uint256 tokenId
236
+ ) public override(ERC721Upgradeable, IERC721Upgradeable) {
237
+ super.transferFrom(from, to, tokenId);
238
+
239
+ CardsRewardFounder storage cardSender = nftFounder[from];
240
+
241
+ uint rewards = myNftRewards(from);
242
+ if (rewards > 0) {
243
+ cardSender.currentRewards = nftFounderPoolMarker;
244
+ nftFounderPool -= rewards;
245
+ usdtERC20.transfer(msg.sender, rewards);
246
+ }
247
+
248
+ require(cardSender.ownedNfts > 0, "no card left");
249
+ cardSender.ownedNfts -= 1;
250
+ CardsRewardFounder storage cardReceiver = nftFounder[to];
251
+ cardReceiver.ownedNfts += 1;
252
+ cardReceiver.currentRewards = nftFounderPoolMarker;
253
+ }
254
+ }
@@ -0,0 +1,337 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.17;
3
+
4
+ import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
5
+ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
6
+ import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";
7
+ import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";
8
+ import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
9
+ import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
10
+ import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
11
+ import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol";
12
+ import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";
13
+ import "./lib/NFTGetter.sol";
14
+ import "./NFT.sol";
15
+ import "./CROWD.sol";
16
+ import "./CUSDT.sol";
17
+ import "./Network.sol";
18
+
19
+ contract NFTGenesis is
20
+ Initializable,
21
+ ERC721Upgradeable,
22
+ OwnableUpgradeable,
23
+ ERC721EnumerableUpgradeable,
24
+ ERC721URIStorageUpgradeable,
25
+ UUPSUpgradeable,
26
+ ReentrancyGuardUpgradeable
27
+ {
28
+ using CountersUpgradeable for CountersUpgradeable.Counter;
29
+ using StringsUpgradeable for uint256;
30
+
31
+ CountersUpgradeable.Counter private _tokenIdCounter;
32
+ CountersUpgradeable.Counter private _cardIdCounter;
33
+ CROWD public gnetERC20;
34
+ CUSDT public usdtERC20;
35
+ Network public valhalla;
36
+ NFT valhallaNFT;
37
+
38
+ // define token id
39
+ mapping(uint => uint) public tokenIdToCardId;
40
+ mapping(uint => CardGenesis) public cardMap;
41
+ // address -> nftType -> flagRewards
42
+ mapping(address => mapping(uint => CardsRewardGenesis)) public nftGenesis;
43
+ // nftType -> poolMarker
44
+ mapping(uint => uint) public nftGenesisPoolMarker;
45
+ mapping(address => uint) public genesisReferralRewardMap;
46
+ address public receiverAddress;
47
+ uint256 public nftGenesisPool;
48
+
49
+ // events
50
+ event BuyMultipleNFT(address indexed _from, uint[] _tokenIds);
51
+ event ClaimReward(address indexed _from, uint value);
52
+ event DistributeRewards(address indexed from, uint value);
53
+ event GenesisReferralReward(
54
+ address indexed referrer,
55
+ address indexed buyer,
56
+ uint value
57
+ );
58
+ event GenesisClaimReferralReward(address indexed referrer, uint value);
59
+ event NFTTypeAdded(
60
+ uint indexed cardId,
61
+ uint price,
62
+ uint percentage,
63
+ uint maxMinted
64
+ );
65
+ event GenesisPoolDistributed(
66
+ uint indexed typePool,
67
+ uint value,
68
+ uint newMarker
69
+ );
70
+
71
+ /// @custom:oz-upgrades-unsafe-allow constructor
72
+ constructor() {
73
+ _disableInitializers();
74
+ }
75
+
76
+ function initialize(
77
+ CROWD _gnetERC20,
78
+ CUSDT _usdtERC20,
79
+ NFT _valhallaNFT,
80
+ Network _valhalla,
81
+ address _receiver
82
+ ) public initializer {
83
+ require(address(_gnetERC20) != address(0), "Invalid GNET address");
84
+ require(address(_usdtERC20) != address(0), "Invalid USDT address");
85
+ require(address(_valhallaNFT) != address(0), "Invalid NFT address");
86
+ require(address(_valhalla) != address(0), "Invalid Network address");
87
+ require(_receiver != address(0), "Invalid receiver address");
88
+
89
+ __ERC721_init("NFTGenesis", "NFTG");
90
+ __ERC721Enumerable_init();
91
+ __ERC721URIStorage_init();
92
+ __Ownable_init();
93
+ __UUPSUpgradeable_init();
94
+ __ReentrancyGuard_init();
95
+ gnetERC20 = _gnetERC20;
96
+ valhallaNFT = _valhallaNFT;
97
+ receiverAddress = _receiver;
98
+ usdtERC20 = _usdtERC20;
99
+ valhalla = _valhalla;
100
+ }
101
+
102
+ modifier onlyValhallaNFT() {
103
+ require(
104
+ msg.sender == address(valhallaNFT),
105
+ "Only Admin can perform action"
106
+ );
107
+ _;
108
+ }
109
+
110
+ function amountNftTypes() public view returns (uint) {
111
+ return _cardIdCounter.current();
112
+ }
113
+
114
+ function percentageByNftType(uint nftType) public view returns (uint) {
115
+ return cardMap[nftType].genesisPercentage;
116
+ }
117
+
118
+ function addNft(
119
+ uint _price,
120
+ uint _percentage,
121
+ uint _maxMinted
122
+ ) public onlyOwner {
123
+ require(_price > 0, "Price must be greater than 0");
124
+ require(_percentage > 0 && _percentage <= 100, "Invalid percentage");
125
+ require(_maxMinted > 0, "Max minted must be greater than 0");
126
+
127
+ uint _cardId = _cardIdCounter.current();
128
+ CardGenesis storage _card = cardMap[_cardId];
129
+ _card.price = _price * 10 ** usdtERC20.decimals();
130
+ _card.genesisPercentage = _percentage;
131
+ _card.totalMinted = 0;
132
+ _card.maxMinted = _maxMinted;
133
+ _cardIdCounter.increment();
134
+
135
+ emit NFTTypeAdded(_cardId, _card.price, _percentage, _maxMinted);
136
+ }
137
+
138
+ function myNftRewards(
139
+ uint cardId,
140
+ address _address
141
+ ) public view returns (uint) {
142
+ CardsRewardGenesis memory nftCards = nftGenesis[_address][cardId];
143
+ uint poolMarker = nftGenesisPoolMarker[cardId];
144
+
145
+ if (!(poolMarker > nftCards.currentRewards)) return 0;
146
+ return (poolMarker - nftCards.currentRewards) * nftCards.ownedNfts;
147
+ }
148
+
149
+ function buyMultipleNFT(uint cardId, uint amount) public nonReentrant {
150
+ // 1. CHECKS - All validations first
151
+ CardGenesis storage _card = cardMap[cardId];
152
+ require(_card.maxMinted > _card.totalMinted + amount, "Max minted reached");
153
+
154
+ bool isRegistered;
155
+ address referrer;
156
+ (isRegistered, , , referrer, , , , ) = valhalla.accountMap(msg.sender);
157
+ require(isRegistered, "Registration required");
158
+
159
+ uint totalPrice = _card.price * amount;
160
+ uint commission = (totalPrice * 10) / 100;
161
+ uint toReceiver = totalPrice - commission;
162
+
163
+ // Calculate rewards before state change
164
+ uint rewards = myNftRewards(cardId, msg.sender);
165
+
166
+ // 2. EFFECTS - Update state BEFORE external calls
167
+ CardsRewardGenesis storage nftCards = nftGenesis[msg.sender][cardId];
168
+ nftCards.ownedNfts += amount;
169
+ _card.totalMinted += amount;
170
+ nftCards.currentRewards = nftGenesisPoolMarker[cardId];
171
+
172
+ // Prepare token IDs for minting
173
+ uint[] memory tokenIds = new uint[](amount);
174
+ for (uint i = 0; i < amount; i++) {
175
+ uint256 tokenId = _tokenIdCounter.current();
176
+ tokenIds[i] = tokenId;
177
+ tokenIdToCardId[tokenId] = cardId;
178
+ _tokenIdCounter.increment();
179
+ }
180
+
181
+ // 3. INTERACTIONS - External calls last
182
+ usdtERC20.transferFrom(msg.sender, address(this), totalPrice);
183
+ usdtERC20.transfer(receiverAddress, toReceiver);
184
+
185
+ if (referrer != address(0)) {
186
+ genesisReferralRewardMap[referrer] += commission;
187
+ emit GenesisReferralReward(referrer, msg.sender, commission);
188
+ } else {
189
+ usdtERC20.transfer(receiverAddress, commission);
190
+ }
191
+
192
+ // Mint NFTs
193
+ for (uint i = 0; i < amount; i++) {
194
+ _safeMint(msg.sender, tokenIds[i]);
195
+ _setTokenURI(tokenIds[i], cardId.toString());
196
+ }
197
+
198
+ // Claim rewards if available
199
+ if (rewards > 0) _distributeReward(msg.sender, rewards);
200
+
201
+ emit BuyMultipleNFT(msg.sender, tokenIds);
202
+ }
203
+
204
+ function claimRewards(uint cardId) public nonReentrant {
205
+ uint rewards = myNftRewards(cardId, msg.sender);
206
+ require(rewards > 0, "No rewards yet");
207
+
208
+ CardsRewardGenesis storage nftCards = nftGenesis[msg.sender][cardId];
209
+ nftCards.currentRewards = nftGenesisPoolMarker[cardId];
210
+
211
+ _distributeReward(msg.sender, rewards);
212
+ }
213
+
214
+ function _distributeReward(address to, uint amount) private {
215
+ require(nftGenesisPool >= amount, "Insufficient pool balance");
216
+ nftGenesisPool -= amount;
217
+ gnetERC20.transfer(to, amount);
218
+ emit ClaimReward(to, amount);
219
+ }
220
+
221
+ function claimReferralReward() public nonReentrant {
222
+ uint reward = genesisReferralRewardMap[msg.sender];
223
+ require(reward > 0, "No referral reward to claim");
224
+
225
+ genesisReferralRewardMap[msg.sender] = 0;
226
+ usdtERC20.transfer(msg.sender, reward);
227
+
228
+ emit GenesisClaimReferralReward(msg.sender, reward);
229
+ }
230
+
231
+ function distributeGenesisRewards(
232
+ uint typePool,
233
+ uint value
234
+ ) external onlyValhallaNFT {
235
+ uint totalMinted = cardMap[typePool].totalMinted;
236
+ require(totalMinted > 0, "No NFTs minted for this type");
237
+
238
+ uint perNftReward = value / totalMinted;
239
+ nftGenesisPoolMarker[typePool] += perNftReward;
240
+ nftGenesisPool += value;
241
+
242
+ emit GenesisPoolDistributed(
243
+ typePool,
244
+ value,
245
+ nftGenesisPoolMarker[typePool]
246
+ );
247
+ }
248
+
249
+ function _baseURI() internal pure override returns (string memory) {
250
+ return "https://globalnetwork.finance/api/image/genesis/";
251
+ }
252
+
253
+ function safeMint(address to) public onlyOwner {
254
+ uint256 tokenId = _tokenIdCounter.current();
255
+ _tokenIdCounter.increment();
256
+ _safeMint(to, tokenId);
257
+ }
258
+
259
+ function _authorizeUpgrade(
260
+ address newImplementation
261
+ ) internal override onlyOwner {}
262
+
263
+ // The following functions are overrides required by Solidity.
264
+
265
+ function _beforeTokenTransfer(
266
+ address from,
267
+ address to,
268
+ uint256 tokenId,
269
+ uint256 batchSize
270
+ ) internal override(ERC721Upgradeable, ERC721EnumerableUpgradeable) {
271
+ super._beforeTokenTransfer(from, to, tokenId, batchSize);
272
+ }
273
+
274
+ function _burn(
275
+ uint256 tokenId
276
+ ) internal override(ERC721Upgradeable, ERC721URIStorageUpgradeable) {
277
+ super._burn(tokenId);
278
+ }
279
+
280
+ function tokenURI(
281
+ uint256 tokenId
282
+ )
283
+ public
284
+ view
285
+ override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
286
+ returns (string memory)
287
+ {
288
+ return super.tokenURI(tokenId);
289
+ }
290
+
291
+ function transferFrom(
292
+ address from,
293
+ address to,
294
+ uint256 tokenId
295
+ ) public override(ERC721Upgradeable, IERC721Upgradeable) nonReentrant {
296
+ // Get card info and calculate rewards before any state changes
297
+ uint cardId = tokenIdToCardId[tokenId];
298
+ CardsRewardGenesis storage cardSender = nftGenesis[from][cardId];
299
+ uint rewards = myNftRewards(cardId, from);
300
+
301
+ // Update state for sender
302
+ if (rewards > 0) {
303
+ cardSender.currentRewards = nftGenesisPoolMarker[cardId];
304
+ nftGenesisPool -= rewards;
305
+ }
306
+
307
+ require(cardSender.ownedNfts > 0, "no card left");
308
+ cardSender.ownedNfts -= 1;
309
+
310
+ // Update state for receiver
311
+ CardsRewardGenesis storage cardReceiver = nftGenesis[to][cardId];
312
+ cardReceiver.ownedNfts += 1;
313
+ cardReceiver.currentRewards = nftGenesisPoolMarker[cardId];
314
+
315
+ // External calls last
316
+ if (rewards > 0) {
317
+ gnetERC20.transfer(from, rewards); // Send to 'from', not msg.sender
318
+ }
319
+
320
+ super.transferFrom(from, to, tokenId);
321
+ }
322
+
323
+ function supportsInterface(
324
+ bytes4 interfaceId
325
+ )
326
+ public
327
+ view
328
+ override(
329
+ ERC721EnumerableUpgradeable,
330
+ ERC721URIStorageUpgradeable,
331
+ ERC721Upgradeable
332
+ )
333
+ returns (bool)
334
+ {
335
+ return super.supportsInterface(interfaceId);
336
+ }
337
+ }