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/.openzeppelin/bsc-testnet.json +1847 -0
- package/.prettierrc +15 -0
- package/README.md +14 -0
- package/constants/getter.ts +4 -0
- package/constants/rootAddress.ts +22 -0
- package/contracts/CROWD.sol +32 -0
- package/contracts/CUSDT.sol +32 -0
- package/contracts/NFT.sol +499 -0
- package/contracts/NFTFounder.sol +254 -0
- package/contracts/NFTGenesis.sol +337 -0
- package/contracts/Network.sol +503 -0
- package/contracts/Swap.sol +86 -0
- package/contracts/USDT.sol +32 -0
- package/contracts/lib/AccessControl.sol +35 -0
- package/contracts/lib/NFTGetter.sol +60 -0
- package/contracts/lib/NFTHelpers.sol +111 -0
- package/contracts/lib/ValhallaBlackList.sol +18 -0
- package/contracts/lib/ValhallaPool.sol +44 -0
- package/hardhat.config.ts +44 -0
- package/package.json +50 -0
- package/scripts/DeployNetwork.ts +123 -0
- package/scripts/DeploySwap.ts +57 -0
- package/scripts/DeployUSDT.ts +16 -0
- package/test/Swap.test.ts +182 -0
- package/test/lib/initializer.ts +193 -0
- package/test/nft_genesis.test.ts +399 -0
- package/test/nft_purchase.test.ts +210 -0
- package/test/rank_distribution.test.ts +142 -0
- package/test/registration.test.ts +267 -0
- package/test/registration_reward.test.ts +114 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
//SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.17;
|
|
3
|
+
|
|
4
|
+
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
|
5
|
+
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
6
|
+
import "./CROWD.sol";
|
|
7
|
+
import "./NFTFounder.sol";
|
|
8
|
+
import "./lib/NFTGetter.sol";
|
|
9
|
+
import "./lib/ValhallaPool.sol";
|
|
10
|
+
import "./lib/AccessControl.sol";
|
|
11
|
+
import "./lib/ValhallaBlackList.sol";
|
|
12
|
+
|
|
13
|
+
enum Rank {
|
|
14
|
+
NoRank,
|
|
15
|
+
Common,
|
|
16
|
+
Rare,
|
|
17
|
+
SuperRare,
|
|
18
|
+
Epic,
|
|
19
|
+
Legend,
|
|
20
|
+
SuperLegend
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
struct Account {
|
|
24
|
+
bool isRegistered;
|
|
25
|
+
bool isImported;
|
|
26
|
+
Rank rank;
|
|
27
|
+
address referrer;
|
|
28
|
+
uint downlineCount;
|
|
29
|
+
uint directDownlineCount;
|
|
30
|
+
uint rankUpdatedAt;
|
|
31
|
+
uint rankRewardClaimedAt;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
struct RankDistribution {
|
|
35
|
+
uint common;
|
|
36
|
+
uint rare;
|
|
37
|
+
uint superRare;
|
|
38
|
+
uint epic;
|
|
39
|
+
uint legend;
|
|
40
|
+
uint superLegend;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
contract Network is
|
|
44
|
+
ValhallaPool,
|
|
45
|
+
ValhallaBlackList,
|
|
46
|
+
Initializable,
|
|
47
|
+
AccessControl,
|
|
48
|
+
UUPSUpgradeable
|
|
49
|
+
{
|
|
50
|
+
mapping(address => Account) public accountMap;
|
|
51
|
+
mapping(address => uint) public rewardMap;
|
|
52
|
+
mapping(address => uint) public directCommonRankMap;
|
|
53
|
+
mapping(address => uint) public directRareRankMap;
|
|
54
|
+
mapping(address => uint) public directSuperRareRankMap;
|
|
55
|
+
mapping(address => uint) public directEpicRankMap;
|
|
56
|
+
mapping(address => uint) public directLegendRankMap;
|
|
57
|
+
mapping(address => uint) public directSuperLegendRankMap;
|
|
58
|
+
address public feeReceiverAddress;
|
|
59
|
+
address public feeReceiverAddress2;
|
|
60
|
+
address public reserveAddress;
|
|
61
|
+
bool public isRankRewardClaimable;
|
|
62
|
+
uint public rankRewardClaimableAt;
|
|
63
|
+
uint public deployedAtBlock;
|
|
64
|
+
|
|
65
|
+
// ipoPoolDistrbution + referrerPooDistribution = registrationFee
|
|
66
|
+
uint private ipoPoolDistribution;
|
|
67
|
+
uint private referrerPoolDistribution;
|
|
68
|
+
|
|
69
|
+
RankDistribution public rankDistribution;
|
|
70
|
+
NFTGetter public nftGetter;
|
|
71
|
+
CROWD public gnetERC20;
|
|
72
|
+
ERC20 public usdtERC20;
|
|
73
|
+
NFTFounder public nftFounder;
|
|
74
|
+
|
|
75
|
+
// events
|
|
76
|
+
event Registration(address indexed _from, address indexed referrer);
|
|
77
|
+
event ClaimReward(address indexed _from, uint value);
|
|
78
|
+
event ClaimRankReward(address indexed _from, uint value);
|
|
79
|
+
event Blacklisted(address indexed _target);
|
|
80
|
+
event RankUpgraded(address indexed _from, Rank rank);
|
|
81
|
+
event RankRewardOpened(uint indexed _timestamp);
|
|
82
|
+
event RankRewardClosed(uint indexed _timestamp);
|
|
83
|
+
|
|
84
|
+
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
85
|
+
constructor() {
|
|
86
|
+
_disableInitializers();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function initialize(
|
|
90
|
+
address _admin,
|
|
91
|
+
address[] memory root_address,
|
|
92
|
+
address _feeReceiverAddress,
|
|
93
|
+
address _feeReceiverAddress2,
|
|
94
|
+
address _reserveAddress,
|
|
95
|
+
uint _ipoPoolDistribution,
|
|
96
|
+
uint _referrerPoolDistribution
|
|
97
|
+
) public initializer {
|
|
98
|
+
__AccessControl_init();
|
|
99
|
+
__UUPSUpgradeable_init();
|
|
100
|
+
|
|
101
|
+
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
|
|
102
|
+
_grantRole(UPGRADER_ROLE, msg.sender);
|
|
103
|
+
_grantRole(DEFAULT_ADMIN_ROLE, _admin);
|
|
104
|
+
|
|
105
|
+
deployedAtBlock = block.number;
|
|
106
|
+
ipoPoolDistribution = _ipoPoolDistribution;
|
|
107
|
+
referrerPoolDistribution = _referrerPoolDistribution;
|
|
108
|
+
feeReceiverAddress = _feeReceiverAddress;
|
|
109
|
+
feeReceiverAddress2 = _feeReceiverAddress2;
|
|
110
|
+
reserveAddress = _reserveAddress;
|
|
111
|
+
|
|
112
|
+
accountMap[_feeReceiverAddress2].isRegistered = true;
|
|
113
|
+
accountMap[_feeReceiverAddress2].referrer = address(0);
|
|
114
|
+
|
|
115
|
+
accountMap[_feeReceiverAddress].isRegistered = true;
|
|
116
|
+
accountMap[_feeReceiverAddress].referrer = address(0);
|
|
117
|
+
emit Registration(_feeReceiverAddress, address(0));
|
|
118
|
+
|
|
119
|
+
accountMap[_reserveAddress].isRegistered = true;
|
|
120
|
+
accountMap[_reserveAddress].referrer = address(0);
|
|
121
|
+
emit Registration(_feeReceiverAddress, address(0));
|
|
122
|
+
|
|
123
|
+
address _parent;
|
|
124
|
+
for (uint i = 0; i < root_address.length; i++) {
|
|
125
|
+
address _current = root_address[i];
|
|
126
|
+
accountMap[_current].isRegistered = true;
|
|
127
|
+
accountMap[_current].downlineCount = root_address.length - i - 1;
|
|
128
|
+
accountMap[_current].directDownlineCount = 1;
|
|
129
|
+
accountMap[_current].rank = Rank.NoRank;
|
|
130
|
+
accountMap[_current].referrer = _parent;
|
|
131
|
+
emit Registration(_current, _parent);
|
|
132
|
+
_parent = _current;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function _authorizeUpgrade(
|
|
137
|
+
address newImplementation
|
|
138
|
+
) internal override onlyUpgrader {}
|
|
139
|
+
|
|
140
|
+
function _addDownlineAndAdjustRank(address _address) private {
|
|
141
|
+
Account storage _account = accountMap[_address];
|
|
142
|
+
_account.downlineCount += 1;
|
|
143
|
+
// if its already in max rank dont do anything
|
|
144
|
+
// for the sake of gas optimization
|
|
145
|
+
if (_account.rank == Rank.SuperLegend) return;
|
|
146
|
+
|
|
147
|
+
if (_account.downlineCount >= 64000 && _account.rank == Rank.Legend) {
|
|
148
|
+
uint totalEligibleDirectRank = directLegendRankMap[_address] +
|
|
149
|
+
directSuperLegendRankMap[_address];
|
|
150
|
+
|
|
151
|
+
if (totalEligibleDirectRank >= 2) {
|
|
152
|
+
_account.rank = Rank.SuperLegend;
|
|
153
|
+
rankDistribution.legend -= 1;
|
|
154
|
+
rankDistribution.superLegend += 1;
|
|
155
|
+
directLegendRankMap[_account.referrer] -= 1;
|
|
156
|
+
directSuperLegendRankMap[_account.referrer] += 1;
|
|
157
|
+
}
|
|
158
|
+
} else if (_account.downlineCount >= 16000 && _account.rank == Rank.Epic) {
|
|
159
|
+
uint totalEligibleDirectRank = directEpicRankMap[_address] +
|
|
160
|
+
directLegendRankMap[_address] +
|
|
161
|
+
directSuperLegendRankMap[_address];
|
|
162
|
+
|
|
163
|
+
if (totalEligibleDirectRank >= 2) {
|
|
164
|
+
_account.rank = Rank.Legend;
|
|
165
|
+
rankDistribution.epic -= 1;
|
|
166
|
+
rankDistribution.legend += 1;
|
|
167
|
+
directEpicRankMap[_account.referrer] -= 1;
|
|
168
|
+
directLegendRankMap[_account.referrer] += 1;
|
|
169
|
+
}
|
|
170
|
+
} else if (
|
|
171
|
+
_account.downlineCount >= 6400 && _account.rank == Rank.SuperRare
|
|
172
|
+
) {
|
|
173
|
+
uint totalEligibleDirectRank = directSuperRareRankMap[_address] +
|
|
174
|
+
directEpicRankMap[_address] +
|
|
175
|
+
directLegendRankMap[_address] +
|
|
176
|
+
directSuperLegendRankMap[_address];
|
|
177
|
+
|
|
178
|
+
if (totalEligibleDirectRank >= 2) {
|
|
179
|
+
_account.rank = Rank.Epic;
|
|
180
|
+
rankDistribution.superRare -= 1;
|
|
181
|
+
rankDistribution.epic += 1;
|
|
182
|
+
directSuperRareRankMap[_account.referrer] -= 1;
|
|
183
|
+
directEpicRankMap[_account.referrer] += 1;
|
|
184
|
+
}
|
|
185
|
+
} else if (_account.downlineCount >= 1600 && _account.rank == Rank.Rare) {
|
|
186
|
+
uint totalEligibleDirectRank = directRareRankMap[_address] +
|
|
187
|
+
directSuperRareRankMap[_address] +
|
|
188
|
+
directEpicRankMap[_address] +
|
|
189
|
+
directLegendRankMap[_address] +
|
|
190
|
+
directSuperLegendRankMap[_address];
|
|
191
|
+
if (totalEligibleDirectRank >= 2) {
|
|
192
|
+
_account.rank = Rank.SuperRare;
|
|
193
|
+
rankDistribution.rare -= 1;
|
|
194
|
+
rankDistribution.superRare += 1;
|
|
195
|
+
directRareRankMap[_account.referrer] -= 1;
|
|
196
|
+
directSuperRareRankMap[_account.referrer] += 1;
|
|
197
|
+
}
|
|
198
|
+
} else if (_account.downlineCount >= 400 && _account.rank == Rank.Common) {
|
|
199
|
+
uint totalEligibleDirectRank = directCommonRankMap[_address] +
|
|
200
|
+
directRareRankMap[_address] +
|
|
201
|
+
directSuperRareRankMap[_address] +
|
|
202
|
+
directEpicRankMap[_address] +
|
|
203
|
+
directLegendRankMap[_address] +
|
|
204
|
+
directSuperLegendRankMap[_address];
|
|
205
|
+
if (totalEligibleDirectRank >= 2) {
|
|
206
|
+
_account.rank = Rank.Rare;
|
|
207
|
+
rankDistribution.common -= 1;
|
|
208
|
+
rankDistribution.rare += 1;
|
|
209
|
+
directCommonRankMap[_account.referrer] -= 1;
|
|
210
|
+
directRareRankMap[_account.referrer] += 1;
|
|
211
|
+
}
|
|
212
|
+
} else if (_account.downlineCount >= 100 && _account.rank == Rank.NoRank) {
|
|
213
|
+
_account.rank = Rank.Common;
|
|
214
|
+
rankDistribution.common += 1;
|
|
215
|
+
directCommonRankMap[_account.referrer] += 1;
|
|
216
|
+
} else {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
emit RankUpgraded(_address, _account.rank);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function _distributeRegistrationFeeToNthReferrer(
|
|
224
|
+
uint value
|
|
225
|
+
) private returns (uint) {
|
|
226
|
+
uint _reference = value;
|
|
227
|
+
uint _valueLeft = value;
|
|
228
|
+
|
|
229
|
+
Account storage currentAccount = accountMap[msg.sender];
|
|
230
|
+
|
|
231
|
+
// rules of how registration fee going to be distributed
|
|
232
|
+
// into up to 15 upline in percentage
|
|
233
|
+
// root 1 - 2 = 10%, 3 = 6%, 4 = 5%, etc.
|
|
234
|
+
uint8[15] memory uplineRegistrationFeeDistributionPercentage = [
|
|
235
|
+
30,
|
|
236
|
+
8,
|
|
237
|
+
3,
|
|
238
|
+
2,
|
|
239
|
+
2,
|
|
240
|
+
1,
|
|
241
|
+
1,
|
|
242
|
+
1,
|
|
243
|
+
1,
|
|
244
|
+
1,
|
|
245
|
+
1,
|
|
246
|
+
1,
|
|
247
|
+
1,
|
|
248
|
+
1,
|
|
249
|
+
1
|
|
250
|
+
];
|
|
251
|
+
for (
|
|
252
|
+
uint i = 0;
|
|
253
|
+
i < uplineRegistrationFeeDistributionPercentage.length;
|
|
254
|
+
i++
|
|
255
|
+
) {
|
|
256
|
+
address _parentAddress = currentAccount.referrer;
|
|
257
|
+
|
|
258
|
+
// exit loop once it encounter zero address
|
|
259
|
+
// because it's expected to be no other upline can be processed
|
|
260
|
+
if (_parentAddress == address(0)) break;
|
|
261
|
+
|
|
262
|
+
// ignore blacklisted upline
|
|
263
|
+
if (blacklistedAddressMap[_parentAddress] == false) {
|
|
264
|
+
_addDownlineAndAdjustRank(_parentAddress);
|
|
265
|
+
uint _percentage = uplineRegistrationFeeDistributionPercentage[i];
|
|
266
|
+
uint _distribution_value = (_reference * _percentage) / 100;
|
|
267
|
+
rewardMap[_parentAddress] += _distribution_value;
|
|
268
|
+
_valueLeft -= _distribution_value;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
currentAccount = accountMap[_parentAddress];
|
|
272
|
+
}
|
|
273
|
+
return _valueLeft;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function wdUSDT(uint amount) public onlyAdmin {
|
|
277
|
+
require(
|
|
278
|
+
amount <= usdtERC20.balanceOf(address(this)),
|
|
279
|
+
"Insufficient CUSD balance"
|
|
280
|
+
);
|
|
281
|
+
usdtERC20.transfer(msg.sender, amount);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function setNFTFounderAddress(NFTFounder _nftFounder) public onlyAdmin {
|
|
285
|
+
nftFounder = _nftFounder;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function setNftAddress(NFTGetter _nftGetter) public onlyAdmin {
|
|
289
|
+
nftGetter = _nftGetter;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function setCRWDAddress(CROWD _gnetERC20) public onlyAdmin {
|
|
293
|
+
gnetERC20 = _gnetERC20;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function setCUSDAddress(ERC20 _usdtERC20) public onlyAdmin {
|
|
297
|
+
usdtERC20 = _usdtERC20;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function getRegistrationFee() public view returns (uint) {
|
|
301
|
+
return ipoPoolDistribution + referrerPoolDistribution;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function register(address referrer) public notInBlacklist {
|
|
305
|
+
uint registrationFee = getRegistrationFee();
|
|
306
|
+
Account storage account = accountMap[msg.sender];
|
|
307
|
+
uint balance = usdtERC20.balanceOf(msg.sender);
|
|
308
|
+
require(address(usdtERC20) != address(0), "admin didn't set token ERC");
|
|
309
|
+
require(balance >= registrationFee, "Unmatch Registration Fee");
|
|
310
|
+
require(account.isRegistered == false, "Address already registered");
|
|
311
|
+
require(referrer != address(0), "Invalid referrer");
|
|
312
|
+
require(accountMap[referrer].isRegistered, "Referrer should be registered");
|
|
313
|
+
require(blacklistedAddressMap[referrer] == false, "Referrer blacklisted");
|
|
314
|
+
require(!isRankRewardClaimable, "Registration closed");
|
|
315
|
+
|
|
316
|
+
account.referrer = referrer;
|
|
317
|
+
account.isRegistered = true;
|
|
318
|
+
account.rank = Rank.NoRank;
|
|
319
|
+
account.directDownlineCount = 0;
|
|
320
|
+
accountMap[referrer].directDownlineCount += 1;
|
|
321
|
+
|
|
322
|
+
_storeIpoPool(ipoPoolDistribution);
|
|
323
|
+
uint valueLeft = _distributeRegistrationFeeToNthReferrer(
|
|
324
|
+
referrerPoolDistribution
|
|
325
|
+
);
|
|
326
|
+
uint globalPoolDistribution = (referrerPoolDistribution * 17) / 100;
|
|
327
|
+
_storeGlobalPool(globalPoolDistribution);
|
|
328
|
+
valueLeft -= globalPoolDistribution;
|
|
329
|
+
uint reserveDistribution = (referrerPoolDistribution * 3) / 100;
|
|
330
|
+
// need approval
|
|
331
|
+
usdtERC20.transferFrom(msg.sender, address(this), registrationFee);
|
|
332
|
+
|
|
333
|
+
usdtERC20.transfer(address(nftFounder), reserveDistribution);
|
|
334
|
+
nftFounder.distributeFounderRewards(reserveDistribution);
|
|
335
|
+
|
|
336
|
+
valueLeft -= reserveDistribution;
|
|
337
|
+
|
|
338
|
+
usdtERC20.transfer(feeReceiverAddress, valueLeft / 2);
|
|
339
|
+
usdtERC20.transfer(feeReceiverAddress2, valueLeft / 2);
|
|
340
|
+
emit Registration(msg.sender, referrer);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function importAccount(address _address, address _referrer) public onlyAdmin {
|
|
344
|
+
Account storage account = accountMap[_address];
|
|
345
|
+
require(account.isRegistered == false, "Address already registered");
|
|
346
|
+
require(_referrer != address(0), "Invalid referrer");
|
|
347
|
+
require(
|
|
348
|
+
accountMap[_referrer].isRegistered,
|
|
349
|
+
"Referrer should be registered"
|
|
350
|
+
);
|
|
351
|
+
require(blacklistedAddressMap[_referrer] == false, "Referrer blacklisted");
|
|
352
|
+
require(!isRankRewardClaimable, "Registration closed");
|
|
353
|
+
|
|
354
|
+
account.referrer = _referrer;
|
|
355
|
+
account.isRegistered = true;
|
|
356
|
+
account.rank = Rank.NoRank;
|
|
357
|
+
account.directDownlineCount = 0;
|
|
358
|
+
account.isImported = true;
|
|
359
|
+
accountMap[_referrer].directDownlineCount += 1;
|
|
360
|
+
|
|
361
|
+
address _currentParent = _referrer;
|
|
362
|
+
for (uint i = 0; i < 15; i++) {
|
|
363
|
+
_addDownlineAndAdjustRank(_currentParent);
|
|
364
|
+
_currentParent = accountMap[_currentParent].referrer;
|
|
365
|
+
}
|
|
366
|
+
emit Registration(_address, _referrer);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function claimReward() public notInBlacklist {
|
|
370
|
+
uint _reward = rewardMap[msg.sender];
|
|
371
|
+
require(_reward > 0, "No reward to be claimed");
|
|
372
|
+
// apply 10% tax
|
|
373
|
+
uint tax = (_reward * 10) / 100;
|
|
374
|
+
// claim reward
|
|
375
|
+
|
|
376
|
+
uint halfTax = tax / 2;
|
|
377
|
+
usdtERC20.transfer(feeReceiverAddress, halfTax);
|
|
378
|
+
usdtERC20.transfer(feeReceiverAddress2, halfTax);
|
|
379
|
+
usdtERC20.transfer(msg.sender, _reward - tax);
|
|
380
|
+
rewardMap[msg.sender] = 0;
|
|
381
|
+
emit ClaimReward(msg.sender, _reward - tax);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function getMyRankReward(address _address) public view returns (uint) {
|
|
385
|
+
Account memory account = accountMap[_address];
|
|
386
|
+
PoolType storage globalPool = poolMap[GLOBAL_POOL_KEY];
|
|
387
|
+
if (globalPool.valueLeft == 0) return 0;
|
|
388
|
+
if (isRankRewardClaimable == false) return 0;
|
|
389
|
+
if (account.rankRewardClaimedAt >= rankRewardClaimableAt) return 0;
|
|
390
|
+
if (account.rank == Rank.NoRank) return 0;
|
|
391
|
+
uint distribution = 0;
|
|
392
|
+
uint base = 0;
|
|
393
|
+
if (account.rank == Rank.Common) {
|
|
394
|
+
distribution = rankDistribution.common;
|
|
395
|
+
base = (globalPool.valueLeft * 3) / 100;
|
|
396
|
+
}
|
|
397
|
+
if (account.rank == Rank.Rare) {
|
|
398
|
+
distribution = rankDistribution.rare;
|
|
399
|
+
base = (globalPool.valueLeft * 7) / 100;
|
|
400
|
+
}
|
|
401
|
+
if (account.rank == Rank.SuperRare) {
|
|
402
|
+
distribution = rankDistribution.superRare;
|
|
403
|
+
base = (globalPool.valueLeft * 12) / 100;
|
|
404
|
+
}
|
|
405
|
+
if (account.rank == Rank.Epic) {
|
|
406
|
+
distribution = rankDistribution.epic;
|
|
407
|
+
base = (globalPool.valueLeft * 18) / 100;
|
|
408
|
+
}
|
|
409
|
+
if (account.rank == Rank.Legend) {
|
|
410
|
+
distribution = rankDistribution.legend;
|
|
411
|
+
base = (globalPool.valueLeft * 26) / 100;
|
|
412
|
+
}
|
|
413
|
+
if (account.rank == Rank.SuperLegend) {
|
|
414
|
+
distribution = rankDistribution.superLegend;
|
|
415
|
+
base = (globalPool.valueLeft * 34) / 100;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return base / distribution;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function claimRankReward() public notInBlacklist {
|
|
422
|
+
uint myReward = getMyRankReward(msg.sender);
|
|
423
|
+
uint nftValue = nftGetter.totalValueMap(msg.sender);
|
|
424
|
+
Account storage account = accountMap[msg.sender];
|
|
425
|
+
|
|
426
|
+
require(myReward > 0, "No Reward can be claimed");
|
|
427
|
+
if (account.rank == Rank.Common) {
|
|
428
|
+
require(nftValue >= 50_000 * 10 ** gnetERC20.decimals(), "Not Eligible");
|
|
429
|
+
}
|
|
430
|
+
if (account.rank == Rank.Rare) {
|
|
431
|
+
require(nftValue >= 200_000 * 10 ** gnetERC20.decimals(), "Not Eligible");
|
|
432
|
+
}
|
|
433
|
+
if (account.rank == Rank.SuperRare) {
|
|
434
|
+
require(
|
|
435
|
+
nftValue >= 1000_000 * 10 ** gnetERC20.decimals(),
|
|
436
|
+
"Not Eligible"
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
if (account.rank == Rank.Epic) {
|
|
440
|
+
require(
|
|
441
|
+
nftValue >= 5_000_000 * 10 ** gnetERC20.decimals(),
|
|
442
|
+
"Not Eligible"
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
if (account.rank == Rank.Legend) {
|
|
446
|
+
require(
|
|
447
|
+
nftValue >= 25_000_000 * 10 ** gnetERC20.decimals(),
|
|
448
|
+
"Not Eligible"
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
if (account.rank == Rank.SuperLegend) {
|
|
452
|
+
require(
|
|
453
|
+
nftValue >= 100_000_000 * 10 ** gnetERC20.decimals(),
|
|
454
|
+
"Not Eligible"
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
uint tax = (myReward * 10) / 100;
|
|
459
|
+
uint halfTax = tax / 2;
|
|
460
|
+
// claim rank reward
|
|
461
|
+
usdtERC20.transfer(feeReceiverAddress, halfTax);
|
|
462
|
+
usdtERC20.transfer(feeReceiverAddress2, halfTax);
|
|
463
|
+
usdtERC20.transfer(msg.sender, myReward - tax);
|
|
464
|
+
account.rankRewardClaimedAt = block.timestamp;
|
|
465
|
+
PoolType storage globalPool = poolMap[GLOBAL_POOL_KEY];
|
|
466
|
+
globalPool.valueLeft -= myReward;
|
|
467
|
+
emit ClaimRankReward(msg.sender, myReward);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function startClaimingRankReward() public onlyStaff {
|
|
471
|
+
require(isRankRewardClaimable == false, "Already started");
|
|
472
|
+
isRankRewardClaimable = true;
|
|
473
|
+
rankRewardClaimableAt = block.timestamp;
|
|
474
|
+
|
|
475
|
+
PoolType storage globalPool = poolMap[GLOBAL_POOL_KEY];
|
|
476
|
+
globalPool.valueLeft = globalPool.claimable;
|
|
477
|
+
globalPool.claimable = globalPool.claimable - globalPool.valueLeft;
|
|
478
|
+
nftGetter.startClaimingRankReward();
|
|
479
|
+
emit RankRewardOpened(block.timestamp);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function stopClaimingRankReward() public onlyStaff {
|
|
483
|
+
require(isRankRewardClaimable, "Rank reward not started");
|
|
484
|
+
isRankRewardClaimable = false;
|
|
485
|
+
PoolType storage globalPool = poolMap[GLOBAL_POOL_KEY];
|
|
486
|
+
globalPool.claimable += globalPool.valueLeft;
|
|
487
|
+
globalPool.valueLeft = 0;
|
|
488
|
+
nftGetter.stopClaimingRankReward();
|
|
489
|
+
emit RankRewardClosed(block.timestamp);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function blackListAddress(address addr) public onlyAdmin {
|
|
493
|
+
require(addr != msg.sender, "You cannot blacklist yourself");
|
|
494
|
+
require(addr != address(0), "You cannot blacklist address zero");
|
|
495
|
+
addToBlacklistMap(addr);
|
|
496
|
+
emit Blacklisted(addr);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function changeFeeRegister(uint _ipoPol, uint _referalPol) public onlyAdmin {
|
|
500
|
+
ipoPoolDistribution = _ipoPol;
|
|
501
|
+
referrerPoolDistribution = _referalPol;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.9;
|
|
3
|
+
|
|
4
|
+
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
|
5
|
+
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
|
6
|
+
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
7
|
+
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
|
8
|
+
|
|
9
|
+
contract Swap is Initializable, OwnableUpgradeable, UUPSUpgradeable {
|
|
10
|
+
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
11
|
+
constructor() {
|
|
12
|
+
_disableInitializers();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
event SwapToken(
|
|
16
|
+
ERC20 _from,
|
|
17
|
+
ERC20 _to,
|
|
18
|
+
uint _quantity,
|
|
19
|
+
address _user,
|
|
20
|
+
uint _timeStamp
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
ERC20 public usdt;
|
|
24
|
+
ERC20 public cusdt;
|
|
25
|
+
ERC20 public crowd;
|
|
26
|
+
address public feeReceiver;
|
|
27
|
+
address public feeMarketing;
|
|
28
|
+
|
|
29
|
+
function initialize(
|
|
30
|
+
ERC20 _usdt,
|
|
31
|
+
ERC20 _cusdt,
|
|
32
|
+
ERC20 _crowd,
|
|
33
|
+
address _feeReceiver,
|
|
34
|
+
address _feeMarketing
|
|
35
|
+
) public initializer {
|
|
36
|
+
__Ownable_init();
|
|
37
|
+
__UUPSUpgradeable_init();
|
|
38
|
+
usdt = _usdt;
|
|
39
|
+
cusdt = _cusdt;
|
|
40
|
+
crowd = _crowd;
|
|
41
|
+
feeReceiver = _feeReceiver;
|
|
42
|
+
feeMarketing = _feeMarketing;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function swapToCUSDT(uint _amount) public {
|
|
46
|
+
// USDT has 18 decimals. CUSDT has 18 decimals.
|
|
47
|
+
// 1:1 ratio.
|
|
48
|
+
uint cusdtAmount = _amount;
|
|
49
|
+
require(cusdt.balanceOf(address(this)) >= cusdtAmount, "Insufficient Pool");
|
|
50
|
+
|
|
51
|
+
usdt.transferFrom(msg.sender, address(this), _amount);
|
|
52
|
+
cusdt.transfer(msg.sender, cusdtAmount);
|
|
53
|
+
emit SwapToken(usdt, cusdt, _amount, msg.sender, block.timestamp);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function swapToCROWD(uint _amount) public {
|
|
57
|
+
// 1 CROWD = 0.002 USDT -> 1 USDT = 500 CROWD.
|
|
58
|
+
// USDT (18 dec) -> CROWD (18 dec).
|
|
59
|
+
// Multiplier = 500.
|
|
60
|
+
uint crowdAmount = _amount * 500;
|
|
61
|
+
require(crowd.balanceOf(address(this)) >= crowdAmount, "Insufficient Pool");
|
|
62
|
+
|
|
63
|
+
usdt.transferFrom(msg.sender, address(this), _amount);
|
|
64
|
+
crowd.transfer(msg.sender, crowdAmount);
|
|
65
|
+
emit SwapToken(usdt, crowd, _amount, msg.sender, block.timestamp);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function withdrawCUSDT(uint _amount) public onlyOwner {
|
|
69
|
+
require(cusdt.balanceOf(address(this)) >= _amount, "Insufficient Pool");
|
|
70
|
+
cusdt.transfer(msg.sender, _amount);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function withdrawCROWD(uint _amount) public onlyOwner {
|
|
74
|
+
require(crowd.balanceOf(address(this)) >= _amount, "Insufficient Pool");
|
|
75
|
+
crowd.transfer(msg.sender, _amount);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function withdrawUSDT(uint _amount) public onlyOwner {
|
|
79
|
+
require(usdt.balanceOf(address(this)) >= _amount, "Insufficient Pool");
|
|
80
|
+
usdt.transfer(msg.sender, _amount);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function _authorizeUpgrade(
|
|
84
|
+
address newImplementation
|
|
85
|
+
) internal override onlyOwner {}
|
|
86
|
+
}
|
|
@@ -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 USDT 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("United State Dolar", "USDT") {
|
|
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,35 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.17;
|
|
3
|
+
|
|
4
|
+
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
|
|
5
|
+
|
|
6
|
+
abstract contract AccessControl is AccessControlUpgradeable {
|
|
7
|
+
// role definition
|
|
8
|
+
bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
|
|
9
|
+
bytes32 public constant STAFF_ROLE = keccak256("STAFF_ROLE");
|
|
10
|
+
|
|
11
|
+
modifier onlyAdmin() {
|
|
12
|
+
require(
|
|
13
|
+
hasRole(DEFAULT_ADMIN_ROLE, msg.sender),
|
|
14
|
+
"Only Admin can perform action"
|
|
15
|
+
);
|
|
16
|
+
_;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
modifier onlyUpgrader() {
|
|
20
|
+
require(
|
|
21
|
+
hasRole(UPGRADER_ROLE, msg.sender),
|
|
22
|
+
"Only UPGRADER can perform action"
|
|
23
|
+
);
|
|
24
|
+
_;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
modifier onlyStaff() {
|
|
28
|
+
require(
|
|
29
|
+
hasRole(DEFAULT_ADMIN_ROLE, msg.sender) ||
|
|
30
|
+
hasRole(STAFF_ROLE, msg.sender),
|
|
31
|
+
"Only Admin can perform action"
|
|
32
|
+
);
|
|
33
|
+
_;
|
|
34
|
+
}
|
|
35
|
+
}
|