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.
package/.prettierrc ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "overrides": [
3
+ {
4
+ "files": "*.sol",
5
+ "options": {
6
+ "printWidth": 80,
7
+ "tabWidth": 2,
8
+ "useTabs": false,
9
+ "singleQuote": false,
10
+ "bracketSpacing": false,
11
+ "explicitTypes": "always"
12
+ }
13
+ }
14
+ ]
15
+ }
package/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # Sample Hardhat Project
2
+
3
+ This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, and a Hardhat Ignition module that deploys that contract.
4
+
5
+ Try running some of the following tasks:
6
+
7
+ ```shell
8
+ npx hardhat help
9
+ npx hardhat test
10
+ REPORT_GAS=true npx hardhat test
11
+ npx hardhat node
12
+ npx hardhat ignition deploy ./ignition/modules/Lock.ts
13
+ ```
14
+ # gn-contract
@@ -0,0 +1,4 @@
1
+ export const getter = {
2
+ usdt: { address: "0x15D734dD9C92Ae6c298197890312B3A349Aa0Ae6" },
3
+ nftGenesis: { address: "0xd90EBefb468d78dd9d092389269484CC5f563304" },
4
+ };
@@ -0,0 +1,22 @@
1
+ export const rootAdressList = [
2
+ "0xbbf56FB6878F4f6665507495B059901a5124FDdE",
3
+ "0xa9968A081e9119ECb17e65b5B00504A770E7554D",
4
+ "0x4Ab1539b21B7d9aBB5a535467deD7bf155A30223",
5
+ "0xaF8014763e6c8919767125D235730b459FDbA364",
6
+ "0xfC6b100A7B23E2cB7952D8f5Ece1A36727532c4a",
7
+ "0xde668F1cd8C4F38127C4B43a9A711e6615a2A080",
8
+ "0xd9682cf0870cFaDc307baEDFD8A0d1F92Db1e187",
9
+ "0x0387376b07D3Ae19E56bfB4992208360c4F604f0",
10
+ "0xA6BcA768eDCEC76565918E93d257e981c14064c6",
11
+ "0xD554c09Ea646001A72B59f154D831258878e3ee9",
12
+ "0xc0A2C50E560eA064aA9d863A8A1005D553b23a67",
13
+ "0x9c963c63e5f8669fa07e85a8711e36C0D49544a2",
14
+ "0xB8f8C74C740fD806cA267EE2B8bB733AC36642E7",
15
+ "0x9ADeB9088d0D091f7C5dbf0bc9864ccd0aD9A2d4",
16
+ "0x65CA460b1398d1d335edA4186fa2213fBfe6B815",
17
+ ];
18
+
19
+ export const feeReceiverAddress = "0xFdA829C6E8825437365E666cBE3A07311c7B4337";
20
+ export const feeReceiverAddress2 = "0x456af512778C41cDf342b0778C49A3578C0A6C7E";
21
+ export const reserveAddress = "0xa1BA34674C0920d3113f2DDBDe6b7e586403c88B";
22
+ export const genesisPayment = "0x883EbD6056653712EFebd2787489fCdd9e63AfC4";
@@ -0,0 +1,32 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.17;
3
+
4
+ import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5
+ import "@openzeppelin/contracts/access/Ownable.sol";
6
+ import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
7
+
8
+ contract CROWD is ERC20, ERC20Burnable, Ownable {
9
+ address public minterContract;
10
+
11
+ // this is not real name, please check the contract first before deploying !
12
+ constructor() ERC20("Crowd Strike", "CROWD") {
13
+ _mint(msg.sender, 1_000_000_000 * 10 ** 18);
14
+ }
15
+
16
+ function decimals() public pure override returns (uint8) {
17
+ return 18;
18
+ }
19
+
20
+ function setMinterContract(address _minterContract) public onlyOwner {
21
+ require(
22
+ _minterContract != address(minterContract),
23
+ "minter contract already set"
24
+ );
25
+ minterContract = _minterContract;
26
+ }
27
+
28
+ function mintForFarm(uint amount, address target) external {
29
+ require(msg.sender == minterContract, "Unauthorized minter");
30
+ _mint(target, amount);
31
+ }
32
+ }
@@ -0,0 +1,32 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.17;
3
+
4
+ import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5
+ import "@openzeppelin/contracts/access/Ownable.sol";
6
+ import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
7
+
8
+ contract CUSDT is ERC20, ERC20Burnable, Ownable {
9
+ address public minterContract;
10
+
11
+ // this is not real name, please check the contract first before deploying !
12
+ constructor() ERC20("Crowd United State Dollar", "CUSDT") {
13
+ _mint(msg.sender, 1_000_000_000 * 10 ** 18);
14
+ }
15
+
16
+ function decimals() public pure override returns (uint8) {
17
+ return 18;
18
+ }
19
+
20
+ function setMinterContract(address _minterContract) public onlyOwner {
21
+ require(
22
+ _minterContract != address(minterContract),
23
+ "minter contract already set"
24
+ );
25
+ minterContract = _minterContract;
26
+ }
27
+
28
+ function mintForFarm(uint amount, address target) external {
29
+ require(msg.sender == minterContract, "Unauthorized minter");
30
+ _mint(target, amount);
31
+ }
32
+ }
@@ -0,0 +1,499 @@
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/proxy/utils/Initializable.sol";
8
+ import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";
9
+ import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol";
10
+ import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
11
+ import "./CROWD.sol";
12
+ import "./Network.sol";
13
+ import "./lib/ValhallaPool.sol";
14
+ import "./lib/NFTHelpers.sol";
15
+ import "./NFTGenesis.sol";
16
+
17
+ contract NFT is
18
+ ValhallaPool,
19
+ Initializable,
20
+ OwnableUpgradeable,
21
+ ERC721Upgradeable,
22
+ ERC721EnumerableUpgradeable,
23
+ UUPSUpgradeable
24
+ {
25
+ using CountersUpgradeable for CountersUpgradeable.Counter;
26
+ using StringsUpgradeable for uint256;
27
+ using NFTHelpers for *;
28
+
29
+ uint256 private randNonce;
30
+
31
+ mapping(uint => OwnedToken) public ownedTokenMap;
32
+ mapping(uint => Card) public cardMap;
33
+ mapping(address => uint) public totalValueMap;
34
+ mapping(address => uint) public rewardMap;
35
+ mapping(address => uint) public referralRewardMap;
36
+ mapping(address => uint) public farmMatchingRewardMap;
37
+ mapping(address => uint) public rankRewardClaimedAtMap;
38
+ CROWD public gnetERC20;
39
+ Network public valhalla;
40
+
41
+ CountersUpgradeable.Counter private _tokenIdCounter;
42
+ CountersUpgradeable.Counter private _cardIdCounter;
43
+
44
+ NFTGenesis public nftGenesis;
45
+
46
+ // events
47
+ event Buy(address indexed _from, uint indexed _tokenId);
48
+ event Farm(uint indexed _tokenId, uint _value);
49
+ event ClaimReward(address indexed _from, uint value);
50
+ event ClaimRankReward(address indexed _from, uint value);
51
+ event DirectReferralReward(
52
+ address indexed referrer,
53
+ address indexed buyer,
54
+ uint value
55
+ );
56
+
57
+ /// @custom:oz-upgrades-unsafe-allow constructor
58
+ constructor() {
59
+ _disableInitializers();
60
+ }
61
+
62
+ function initialize(CROWD _gnetERC20, Network _valhalla) public initializer {
63
+ // this is not a real name, please check this contract before deploy
64
+ __Ownable_init();
65
+ __ERC721_init("CrowdStrikeNFT", "CROWDNFT");
66
+ __ERC721Enumerable_init();
67
+ __UUPSUpgradeable_init();
68
+
69
+ gnetERC20 = _gnetERC20;
70
+ valhalla = _valhalla;
71
+
72
+ /**
73
+ * initiate 6 card on deployment
74
+ */
75
+ uint[6] memory initialCardPriceList = [
76
+ uint(5000),
77
+ uint(25000),
78
+ uint(100000),
79
+ uint(500000),
80
+ uint(2500000),
81
+ uint(10000000)
82
+ ];
83
+ for (uint i = 0; i < initialCardPriceList.length; i++) {
84
+ uint _cardId = _cardIdCounter.current();
85
+ Card storage _card = cardMap[_cardId];
86
+ _card.price = initialCardPriceList[_cardId] * 10 ** gnetERC20.decimals();
87
+ _card.halfingPercentage = 100;
88
+ _card.isMintable = true;
89
+ _cardIdCounter.increment();
90
+ }
91
+ }
92
+
93
+ function _authorizeUpgrade(
94
+ address newImplementation
95
+ ) internal override onlyOwner {}
96
+
97
+ // The following functions are overrides required by Solidity.
98
+
99
+ function _beforeTokenTransfer(
100
+ address from,
101
+ address to,
102
+ uint256 tokenId,
103
+ uint256 batchSize
104
+ ) internal override(ERC721Upgradeable, ERC721EnumerableUpgradeable) {
105
+ super._beforeTokenTransfer(from, to, tokenId, batchSize);
106
+ }
107
+
108
+ function supportsInterface(
109
+ bytes4 interfaceId
110
+ )
111
+ public
112
+ view
113
+ override(ERC721Upgradeable, ERC721EnumerableUpgradeable)
114
+ returns (bool)
115
+ {
116
+ return super.supportsInterface(interfaceId);
117
+ }
118
+
119
+ function _random(uint256 modulus) private returns (uint256) {
120
+ randNonce++;
121
+ return
122
+ uint256(
123
+ keccak256(abi.encodePacked(block.timestamp, msg.sender, randNonce))
124
+ ) % modulus;
125
+ }
126
+
127
+ function tokenURI(
128
+ uint256 tokenId
129
+ ) public view override returns (string memory) {
130
+ _requireMinted(tokenId);
131
+
132
+ string memory baseURI = _baseURI();
133
+ OwnedToken memory ownedToken = ownedTokenMap[tokenId];
134
+ uint cardId = ownedToken.cardId;
135
+ return
136
+ bytes(baseURI).length > 0
137
+ ? string(abi.encodePacked(baseURI, cardId.toString()))
138
+ : "";
139
+ }
140
+
141
+ function _baseURI() internal pure override returns (string memory) {
142
+ return "https://crowdstrike.club/api/image/";
143
+ }
144
+
145
+ /**
146
+ * calculate the probability of farm percentage
147
+ */
148
+ function _getRandomFarmPercentage() private returns (uint256) {
149
+ uint256 rand = _random(1000);
150
+ return NFTHelpers.getRandomFarmPercentage(rand);
151
+ }
152
+
153
+ /**
154
+ * calculate reward per seconds base on its own percentage
155
+ */
156
+ function getFarmValue(uint tokenId) public view returns (uint256) {
157
+ OwnedToken storage _tokenMetadata = ownedTokenMap[tokenId];
158
+ Card memory card = cardMap[_tokenMetadata.cardId];
159
+ return
160
+ NFTHelpers.calculateFarmValue(
161
+ _tokenMetadata.mintedAt,
162
+ _tokenMetadata.lastFarmedAt,
163
+ _tokenMetadata.percentage,
164
+ _tokenMetadata.mintingPrice,
165
+ card.halfingPercentage
166
+ );
167
+ }
168
+
169
+ function buy(uint cardId) public notInBlacklist {
170
+ bool is_registered;
171
+ Rank rank;
172
+ address directReferrer;
173
+ (is_registered, , rank, directReferrer, , , , ) = valhalla.accountMap(
174
+ msg.sender
175
+ );
176
+ address feeReceiver = valhalla.feeReceiverAddress();
177
+ address feeReceiver2 = valhalla.feeReceiverAddress2();
178
+ bool isRankRewardClaimable = valhalla.isRankRewardClaimable();
179
+ Card storage _card = cardMap[cardId];
180
+
181
+ require(isRankRewardClaimable == false, "Market closed");
182
+ require(is_registered, "Registration required");
183
+ require(_card.price > 0, "Invalid card");
184
+ require(_card.isMintable, "Card is not mintable");
185
+
186
+ uint32[7] memory maxBuy = [
187
+ 100_000,
188
+ 200_000,
189
+ 1000_000,
190
+ 5_000_000,
191
+ 20_000_000,
192
+ 100_000_000,
193
+ 500_000_000
194
+ ];
195
+
196
+ for (uint i = 0; i < 7; i++) {
197
+ if (uint(rank) == i) {
198
+ require(
199
+ _card.price + totalValueMap[msg.sender] <=
200
+ maxBuy[i] * 10 ** gnetERC20.decimals(),
201
+ "Max Buy Error"
202
+ );
203
+ }
204
+ }
205
+
206
+ uint distributeGenesis = (_card.price * 5) / 100;
207
+ gnetERC20.transferFrom(
208
+ msg.sender,
209
+ address(this),
210
+ _card.price - distributeGenesis
211
+ );
212
+
213
+ _storeGlobalPool((_card.price * 17) / 100);
214
+ genesisPoolResolver(distributeGenesis);
215
+ uint tax = (_card.price * 20) / 100;
216
+ uint halfTax = tax / 2;
217
+ // rewardMap[feeReceiver] += halfTax;
218
+ // rewardMap[feeReceiver2] += halfTax;
219
+ gnetERC20.transfer(feeReceiver, halfTax);
220
+ gnetERC20.transfer(feeReceiver2, halfTax);
221
+ gnetERC20.burn((_card.price * 50) / 100);
222
+
223
+ if (directReferrer != address(0)) {
224
+ uint referralReward = (_card.price * 8) / 100;
225
+ rewardMap[directReferrer] += referralReward;
226
+ referralRewardMap[directReferrer] += referralReward;
227
+ emit DirectReferralReward(directReferrer, msg.sender, referralReward);
228
+ }
229
+
230
+ uint256 tokenId = _tokenIdCounter.current();
231
+ OwnedToken storage _purchasedToken = ownedTokenMap[tokenId];
232
+ _purchasedToken.cardId = cardId;
233
+ _purchasedToken.mintingPrice = _card.price;
234
+ _purchasedToken.mintedAt = block.timestamp;
235
+ _purchasedToken.lastFarmedAt = block.timestamp;
236
+ _purchasedToken.percentage = _getRandomFarmPercentage();
237
+
238
+ _tokenIdCounter.increment();
239
+ _safeMint(msg.sender, tokenId);
240
+ emit Buy(msg.sender, tokenId);
241
+ }
242
+
243
+ function withdrawAllGenesisPool() public onlyOwner {
244
+ PoolType storage genesisPool = poolMap[GENESIS_POOL_KEY];
245
+ gnetERC20.transfer(msg.sender, genesisPool.claimable);
246
+ genesisPool.claimable = 0;
247
+ genesisPool.valueLeft = 0;
248
+ }
249
+
250
+ function _getReferrerFarmMatchingPercentage(
251
+ uint level,
252
+ address referrer
253
+ ) private view returns (uint) {
254
+ Rank rank;
255
+ (, , rank, , , , , ) = valhalla.accountMap(referrer);
256
+
257
+ return
258
+ NFTHelpers.getReferrerMatchingPercentage(
259
+ level,
260
+ uint8(rank),
261
+ totalValueMap[referrer],
262
+ gnetERC20.decimals()
263
+ );
264
+ }
265
+
266
+ function setNFTGenesis(NFTGenesis _nftGenesis) public onlyOwner {
267
+ nftGenesis = _nftGenesis;
268
+ }
269
+
270
+ function genesisPoolResolver(uint _genesisValue) private {
271
+ uint storedGenesisValue = 0;
272
+ uint amountNftTypes = nftGenesis.amountNftTypes();
273
+ address receiver = nftGenesis.receiverAddress();
274
+
275
+ for (uint256 i = 0; i < amountNftTypes; i++) {
276
+ (, uint genesisPercentage, uint totalMinted, uint maxMinted) = nftGenesis
277
+ .cardMap(i);
278
+ uint valueDistributed = ((_genesisValue * genesisPercentage) /
279
+ 100 /
280
+ maxMinted) * totalMinted;
281
+ storedGenesisValue += valueDistributed;
282
+ if (valueDistributed == 0) continue;
283
+ nftGenesis.distributeGenesisRewards(i, valueDistributed);
284
+ }
285
+
286
+ gnetERC20.transferFrom(msg.sender, address(nftGenesis), storedGenesisValue);
287
+ gnetERC20.transferFrom(
288
+ msg.sender,
289
+ receiver,
290
+ _genesisValue - storedGenesisValue
291
+ );
292
+ }
293
+
294
+ function farm(uint tokenId) public notInBlacklist {
295
+ require(ownerOf(tokenId) == msg.sender, "caller is not owner");
296
+ require(ownedTokenMap[tokenId].isBlackListed == false, "token blacklisted");
297
+ uint reward = getFarmValue(tokenId);
298
+ require(reward > 0, "No reward to farm");
299
+ uint tax = (reward * 10) / 100;
300
+ uint halTax = tax / 2;
301
+ gnetERC20.mintForFarm(halTax, valhalla.feeReceiverAddress());
302
+ gnetERC20.mintForFarm(halTax, valhalla.feeReceiverAddress2());
303
+ gnetERC20.mintForFarm(reward - tax, msg.sender);
304
+
305
+ Rank rank;
306
+ address referrer;
307
+ (, , rank, referrer, , , , ) = valhalla.accountMap(msg.sender);
308
+ for (uint i = 1; i <= 100; i++) {
309
+ if (referrer == address(0)) break;
310
+ uint matchingPercentage = _getReferrerFarmMatchingPercentage(i, referrer);
311
+ if (matchingPercentage > 0) {
312
+ uint uplineReward = (reward * matchingPercentage) / 100;
313
+ gnetERC20.mintForFarm(uplineReward, address(this));
314
+ rewardMap[referrer] += uplineReward;
315
+ farmMatchingRewardMap[referrer] += uplineReward;
316
+ }
317
+ (, , rank, referrer, , , , ) = valhalla.accountMap(referrer);
318
+ }
319
+ ownedTokenMap[tokenId].lastFarmedAt = block.timestamp;
320
+ emit Farm(tokenId, reward);
321
+ }
322
+
323
+ function startClaimingRankReward() external {
324
+ require(msg.sender == address(valhalla), "Only valhalla can call");
325
+ PoolType storage globalPool = poolMap[GLOBAL_POOL_KEY];
326
+ globalPool.valueLeft = globalPool.claimable;
327
+ }
328
+
329
+ function stopClaimingRankReward() external {
330
+ require(msg.sender == address(valhalla), "Only valhalla can call");
331
+ PoolType storage globalPool = poolMap[GLOBAL_POOL_KEY];
332
+ globalPool.claimable = globalPool.valueLeft;
333
+ globalPool.valueLeft = 0;
334
+ }
335
+
336
+ function getMyRankReward(address _accountAddress) public view returns (uint) {
337
+ Rank rank;
338
+ (, , rank, , , , , ) = valhalla.accountMap(_accountAddress);
339
+ PoolType storage globalPool = poolMap[GLOBAL_POOL_KEY];
340
+ bool isRankRewardClaimable = valhalla.isRankRewardClaimable();
341
+ if (globalPool.valueLeft == 0) return 0;
342
+ uint rankRewardClaimableAt = valhalla.rankRewardClaimableAt();
343
+ if (isRankRewardClaimable == false) return 0;
344
+ if (rankRewardClaimedAtMap[_accountAddress] >= rankRewardClaimableAt)
345
+ return 0;
346
+ if (rank == Rank.NoRank) return 0;
347
+ uint commonRankDistribution = 0;
348
+ uint rareRankDistribution = 0;
349
+ uint superRareRankDistribution = 0;
350
+ uint epicRankDistribution = 0;
351
+ uint legendRankDistribution = 0;
352
+ uint superLegendRankDistribution = 0;
353
+ (
354
+ commonRankDistribution,
355
+ rareRankDistribution,
356
+ superRareRankDistribution,
357
+ epicRankDistribution,
358
+ legendRankDistribution,
359
+ superLegendRankDistribution
360
+ ) = valhalla.rankDistribution();
361
+ uint distribution = 0;
362
+ uint base = 0;
363
+ if (rank == Rank.Common) {
364
+ distribution = commonRankDistribution;
365
+ base = (globalPool.claimable * 3) / 100;
366
+ }
367
+ if (rank == Rank.Rare) {
368
+ distribution = rareRankDistribution;
369
+ base = (globalPool.claimable * 7) / 100;
370
+ }
371
+ if (rank == Rank.SuperRare) {
372
+ distribution = superRareRankDistribution;
373
+ base = (globalPool.claimable * 12) / 100;
374
+ }
375
+ if (rank == Rank.Epic) {
376
+ distribution = epicRankDistribution;
377
+ base = (globalPool.claimable * 18) / 100;
378
+ }
379
+ if (rank == Rank.Legend) {
380
+ distribution = legendRankDistribution;
381
+ base = (globalPool.claimable * 26) / 100;
382
+ }
383
+ if (rank == Rank.SuperLegend) {
384
+ distribution = superLegendRankDistribution;
385
+ base = (globalPool.claimable * 34) / 100;
386
+ }
387
+
388
+ return base / distribution;
389
+ }
390
+
391
+ function claimRankReward() public notInBlacklist {
392
+ Rank rank;
393
+ (, , rank, , , , , ) = valhalla.accountMap(msg.sender);
394
+ PoolType storage globalPool = poolMap[GLOBAL_POOL_KEY];
395
+ uint myReward = getMyRankReward(msg.sender);
396
+ uint nftValue = totalValueMap[msg.sender];
397
+
398
+ uint32[7] memory eligValue = [
399
+ 0,
400
+ 50_000,
401
+ 200_000,
402
+ 1_000_000,
403
+ 5_000_000,
404
+ 25_000_000,
405
+ 100_000_000
406
+ ];
407
+
408
+ require(myReward > 0, "No Reward can be claimed");
409
+
410
+ for (uint i = 0; i < 7; i++) {
411
+ if (uint(rank) == i && rank != Rank.NoRank) {
412
+ require(
413
+ nftValue >= eligValue[i] * 10 ** gnetERC20.decimals(),
414
+ "Not Eligible"
415
+ );
416
+ }
417
+ }
418
+
419
+ uint tax = (myReward * 10) / 100;
420
+ uint halfTax = tax / 2;
421
+ gnetERC20.transfer(valhalla.feeReceiverAddress(), halfTax);
422
+ gnetERC20.transfer(valhalla.feeReceiverAddress2(), halfTax);
423
+ gnetERC20.transfer(msg.sender, myReward - tax);
424
+ rankRewardClaimedAtMap[msg.sender] = block.timestamp;
425
+ globalPool.valueLeft -= myReward;
426
+ emit ClaimRankReward(msg.sender, myReward);
427
+ }
428
+
429
+ function claimReward() public notInBlacklist {
430
+ uint _reward = rewardMap[msg.sender];
431
+ address feeReceiver = valhalla.feeReceiverAddress();
432
+ address feeReceiver2 = valhalla.feeReceiverAddress2();
433
+ require(_reward > 0, "No reward to be claimed");
434
+ // apply 10% tax
435
+ uint tax = (_reward * 10) / 100;
436
+ uint halfTax = tax / 2;
437
+ gnetERC20.transfer(feeReceiver, halfTax);
438
+ gnetERC20.transfer(feeReceiver2, halfTax);
439
+ gnetERC20.transfer(msg.sender, _reward - tax);
440
+ rewardMap[msg.sender] = 0;
441
+ referralRewardMap[msg.sender] = 0; // TAMBAH INI
442
+ farmMatchingRewardMap[msg.sender] = 0;
443
+
444
+ emit ClaimReward(msg.sender, _reward - tax);
445
+ }
446
+
447
+ function blacklistToken(uint tokenId) public onlyAdmin {
448
+ OwnedToken storage token = ownedTokenMap[tokenId];
449
+ token.isBlackListed = true;
450
+ }
451
+
452
+ function _afterTokenTransfer(
453
+ address from,
454
+ address to,
455
+ uint256 tokenId,
456
+ uint256 batchSize
457
+ ) internal virtual override {
458
+ super._afterTokenTransfer(from, to, tokenId, batchSize);
459
+ uint256 price = ownedTokenMap[tokenId].mintingPrice;
460
+ if (from == address(0)) {
461
+ totalValueMap[to] += price;
462
+ } else if (to == address(0)) {
463
+ totalValueMap[from] -= price;
464
+ } else {
465
+ totalValueMap[from] -= price;
466
+ totalValueMap[to] += price;
467
+ }
468
+ }
469
+
470
+ modifier onlyAdmin() {
471
+ require(
472
+ valhalla.hasRole(valhalla.DEFAULT_ADMIN_ROLE(), msg.sender),
473
+ "Only Admin can perform action"
474
+ );
475
+ _;
476
+ }
477
+
478
+ modifier onlyStaff() {
479
+ require(
480
+ valhalla.hasRole(valhalla.DEFAULT_ADMIN_ROLE(), msg.sender) ||
481
+ valhalla.hasRole(valhalla.STAFF_ROLE(), msg.sender),
482
+ "Only Admin can perform action"
483
+ );
484
+ _;
485
+ }
486
+
487
+ modifier notInBlacklist() {
488
+ require(
489
+ valhalla.blacklistedAddressMap(msg.sender) != true,
490
+ "Address blacklisted"
491
+ );
492
+ _;
493
+ }
494
+
495
+ modifier onlyGenesis() {
496
+ require(msg.sender == address(nftGenesis), "Transaction Prohibited");
497
+ _;
498
+ }
499
+ }