├── .gitignore ├── .openzeppelin ├── unknown-50888.json └── unknown-51888.json ├── README.md ├── contracts ├── Auth.sol ├── LToken.sol ├── Punk.sol ├── XLToken.sol └── mock │ ├── MockERC1155.sol │ └── MockXLTokenV2.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── tasks ├── addwhitelist.ts ├── approveL.ts ├── approveXL.ts ├── balance.ts ├── claimxl.ts ├── deploy.ts ├── mintL.ts ├── mintnft.ts ├── release.ts ├── upgrade.ts └── version.ts ├── test ├── LToken.test.ts └── XLToken.test.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | # Hardhat files 5 | /cache 6 | /artifacts 7 | 8 | # TypeChain files 9 | /typechain 10 | /typechain-types 11 | 12 | # solidity-coverage files 13 | /coverage 14 | /coverage.json 15 | 16 | # Hardhat Ignition default folder for deployments against a local node 17 | ignition/deployments/chain-31337 18 | -------------------------------------------------------------------------------- /.openzeppelin/unknown-50888.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": "3.2", 3 | "proxies": [ 4 | { 5 | "address": "0xCBD46A2D6c99A7B8daa2C35DE2aEad37Aa36f506", 6 | "txHash": "0x2fbb189a73715697b78c5057359e8ce1ed53a300309e75e719f777f3f02c9925", 7 | "kind": "transparent" 8 | }, 9 | { 10 | "address": "0x9c5e37716861A7e03976fb996228c00D31Dd40Ea", 11 | "txHash": "0x2b93adef2facec2a10a22a5cfca2a1e16a0f31e5312f473eb2501415455aa517", 12 | "kind": "transparent" 13 | }, 14 | { 15 | "address": "0x5D6C04B0AA084c95b5F4f09fF3e9F9c5120Ef8FD", 16 | "txHash": "0xe55026f32f90013d9517ec0811298b381debc9a16462c02d06f6f00374b6de6a", 17 | "kind": "transparent" 18 | } 19 | ], 20 | "impls": { 21 | "fe84320a5bf9fd848f30926f4bc53a01f4654371a7edac70298bc38caf009318": { 22 | "address": "0x1DF0386369DbCD1a189dD36f79846b7c9cD62090", 23 | "txHash": "0x21c0203f81076d27380fddeca4d5f0bc0064cb11828eaba2ee7cc150c6665187", 24 | "layout": { 25 | "solcVersion": "0.8.20", 26 | "storage": [ 27 | { 28 | "label": "owner", 29 | "offset": 0, 30 | "slot": "0", 31 | "type": "t_address", 32 | "contract": "Auth", 33 | "src": "contracts/Auth.sol:14" 34 | }, 35 | { 36 | "label": "taskIncentiveAddress", 37 | "offset": 0, 38 | "slot": "1", 39 | "type": "t_address", 40 | "contract": "XLToken", 41 | "src": "contracts/XLToken.sol:21" 42 | }, 43 | { 44 | "label": "ecosystemFundAddress", 45 | "offset": 0, 46 | "slot": "2", 47 | "type": "t_address", 48 | "contract": "XLToken", 49 | "src": "contracts/XLToken.sol:22" 50 | }, 51 | { 52 | "label": "strategicFinanceAddress", 53 | "offset": 0, 54 | "slot": "3", 55 | "type": "t_address", 56 | "contract": "XLToken", 57 | "src": "contracts/XLToken.sol:23" 58 | }, 59 | { 60 | "label": "teamAddress", 61 | "offset": 0, 62 | "slot": "4", 63 | "type": "t_address", 64 | "contract": "XLToken", 65 | "src": "contracts/XLToken.sol:24" 66 | }, 67 | { 68 | "label": "marketingAddress", 69 | "offset": 0, 70 | "slot": "5", 71 | "type": "t_address", 72 | "contract": "XLToken", 73 | "src": "contracts/XLToken.sol:25" 74 | }, 75 | { 76 | "label": "ecosystemStartTime", 77 | "offset": 0, 78 | "slot": "6", 79 | "type": "t_uint256", 80 | "contract": "XLToken", 81 | "src": "contracts/XLToken.sol:38" 82 | }, 83 | { 84 | "label": "strategicFinanceStartTime", 85 | "offset": 0, 86 | "slot": "7", 87 | "type": "t_uint256", 88 | "contract": "XLToken", 89 | "src": "contracts/XLToken.sol:39" 90 | }, 91 | { 92 | "label": "teamStartTime", 93 | "offset": 0, 94 | "slot": "8", 95 | "type": "t_uint256", 96 | "contract": "XLToken", 97 | "src": "contracts/XLToken.sol:40" 98 | }, 99 | { 100 | "label": "ecosystemReleased", 101 | "offset": 0, 102 | "slot": "9", 103 | "type": "t_uint256", 104 | "contract": "XLToken", 105 | "src": "contracts/XLToken.sol:43" 106 | }, 107 | { 108 | "label": "strategicFinanceReleased", 109 | "offset": 0, 110 | "slot": "10", 111 | "type": "t_uint256", 112 | "contract": "XLToken", 113 | "src": "contracts/XLToken.sol:44" 114 | }, 115 | { 116 | "label": "teamReleased", 117 | "offset": 0, 118 | "slot": "11", 119 | "type": "t_uint256", 120 | "contract": "XLToken", 121 | "src": "contracts/XLToken.sol:45" 122 | }, 123 | { 124 | "label": "totalClaimed", 125 | "offset": 0, 126 | "slot": "12", 127 | "type": "t_uint256", 128 | "contract": "XLToken", 129 | "src": "contracts/XLToken.sol:48" 130 | } 131 | ], 132 | "types": { 133 | "t_address": { 134 | "label": "address", 135 | "numberOfBytes": "20" 136 | }, 137 | "t_bool": { 138 | "label": "bool", 139 | "numberOfBytes": "1" 140 | }, 141 | "t_bytes32": { 142 | "label": "bytes32", 143 | "numberOfBytes": "32" 144 | }, 145 | "t_mapping(t_address,t_bool)": { 146 | "label": "mapping(address => bool)", 147 | "numberOfBytes": "32" 148 | }, 149 | "t_mapping(t_address,t_mapping(t_address,t_uint256))": { 150 | "label": "mapping(address => mapping(address => uint256))", 151 | "numberOfBytes": "32" 152 | }, 153 | "t_mapping(t_address,t_uint256)": { 154 | "label": "mapping(address => uint256)", 155 | "numberOfBytes": "32" 156 | }, 157 | "t_mapping(t_bytes32,t_struct(RoleData)24_storage)": { 158 | "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", 159 | "numberOfBytes": "32" 160 | }, 161 | "t_string_storage": { 162 | "label": "string", 163 | "numberOfBytes": "32" 164 | }, 165 | "t_struct(AccessControlStorage)34_storage": { 166 | "label": "struct AccessControlUpgradeable.AccessControlStorage", 167 | "members": [ 168 | { 169 | "label": "_roles", 170 | "type": "t_mapping(t_bytes32,t_struct(RoleData)24_storage)", 171 | "offset": 0, 172 | "slot": "0" 173 | } 174 | ], 175 | "numberOfBytes": "32" 176 | }, 177 | "t_struct(ERC20Storage)243_storage": { 178 | "label": "struct ERC20Upgradeable.ERC20Storage", 179 | "members": [ 180 | { 181 | "label": "_balances", 182 | "type": "t_mapping(t_address,t_uint256)", 183 | "offset": 0, 184 | "slot": "0" 185 | }, 186 | { 187 | "label": "_allowances", 188 | "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", 189 | "offset": 0, 190 | "slot": "1" 191 | }, 192 | { 193 | "label": "_totalSupply", 194 | "type": "t_uint256", 195 | "offset": 0, 196 | "slot": "2" 197 | }, 198 | { 199 | "label": "_name", 200 | "type": "t_string_storage", 201 | "offset": 0, 202 | "slot": "3" 203 | }, 204 | { 205 | "label": "_symbol", 206 | "type": "t_string_storage", 207 | "offset": 0, 208 | "slot": "4" 209 | } 210 | ], 211 | "numberOfBytes": "160" 212 | }, 213 | "t_struct(InitializableStorage)158_storage": { 214 | "label": "struct Initializable.InitializableStorage", 215 | "members": [ 216 | { 217 | "label": "_initialized", 218 | "type": "t_uint64", 219 | "offset": 0, 220 | "slot": "0" 221 | }, 222 | { 223 | "label": "_initializing", 224 | "type": "t_bool", 225 | "offset": 8, 226 | "slot": "0" 227 | } 228 | ], 229 | "numberOfBytes": "32" 230 | }, 231 | "t_struct(RoleData)24_storage": { 232 | "label": "struct AccessControlUpgradeable.RoleData", 233 | "members": [ 234 | { 235 | "label": "hasRole", 236 | "type": "t_mapping(t_address,t_bool)", 237 | "offset": 0, 238 | "slot": "0" 239 | }, 240 | { 241 | "label": "adminRole", 242 | "type": "t_bytes32", 243 | "offset": 0, 244 | "slot": "1" 245 | } 246 | ], 247 | "numberOfBytes": "64" 248 | }, 249 | "t_uint256": { 250 | "label": "uint256", 251 | "numberOfBytes": "32" 252 | }, 253 | "t_uint64": { 254 | "label": "uint64", 255 | "numberOfBytes": "8" 256 | } 257 | }, 258 | "namespaces": { 259 | "erc7201:openzeppelin.storage.AccessControl": [ 260 | { 261 | "contract": "AccessControlUpgradeable", 262 | "label": "_roles", 263 | "type": "t_mapping(t_bytes32,t_struct(RoleData)24_storage)", 264 | "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61", 265 | "offset": 0, 266 | "slot": "0" 267 | } 268 | ], 269 | "erc7201:openzeppelin.storage.ERC20": [ 270 | { 271 | "contract": "ERC20Upgradeable", 272 | "label": "_balances", 273 | "type": "t_mapping(t_address,t_uint256)", 274 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:38", 275 | "offset": 0, 276 | "slot": "0" 277 | }, 278 | { 279 | "contract": "ERC20Upgradeable", 280 | "label": "_allowances", 281 | "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", 282 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:40", 283 | "offset": 0, 284 | "slot": "1" 285 | }, 286 | { 287 | "contract": "ERC20Upgradeable", 288 | "label": "_totalSupply", 289 | "type": "t_uint256", 290 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:42", 291 | "offset": 0, 292 | "slot": "2" 293 | }, 294 | { 295 | "contract": "ERC20Upgradeable", 296 | "label": "_name", 297 | "type": "t_string_storage", 298 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44", 299 | "offset": 0, 300 | "slot": "3" 301 | }, 302 | { 303 | "contract": "ERC20Upgradeable", 304 | "label": "_symbol", 305 | "type": "t_string_storage", 306 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:45", 307 | "offset": 0, 308 | "slot": "4" 309 | } 310 | ], 311 | "erc7201:openzeppelin.storage.Initializable": [ 312 | { 313 | "contract": "Initializable", 314 | "label": "_initialized", 315 | "type": "t_uint64", 316 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", 317 | "offset": 0, 318 | "slot": "0" 319 | }, 320 | { 321 | "contract": "Initializable", 322 | "label": "_initializing", 323 | "type": "t_bool", 324 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", 325 | "offset": 8, 326 | "slot": "0" 327 | } 328 | ] 329 | } 330 | } 331 | }, 332 | "63bcbf81e8a459ca9fa41a88180f625e31bf429882c5c080ccf278b8808dd2e6": { 333 | "address": "0x92F33Df758937393E5b3949e1a61C9aCeb734A84", 334 | "txHash": "0x369e238c66e4cbddbb405a3c1caa04a7648a5063bbbfc58e3204f87234a58e05", 335 | "layout": { 336 | "solcVersion": "0.8.20", 337 | "storage": [ 338 | { 339 | "label": "owner", 340 | "offset": 0, 341 | "slot": "0", 342 | "type": "t_address", 343 | "contract": "Auth", 344 | "src": "contracts/Auth.sol:14" 345 | } 346 | ], 347 | "types": { 348 | "t_address": { 349 | "label": "address", 350 | "numberOfBytes": "20" 351 | }, 352 | "t_bool": { 353 | "label": "bool", 354 | "numberOfBytes": "1" 355 | }, 356 | "t_bytes32": { 357 | "label": "bytes32", 358 | "numberOfBytes": "32" 359 | }, 360 | "t_mapping(t_address,t_bool)": { 361 | "label": "mapping(address => bool)", 362 | "numberOfBytes": "32" 363 | }, 364 | "t_mapping(t_address,t_mapping(t_address,t_uint256))": { 365 | "label": "mapping(address => mapping(address => uint256))", 366 | "numberOfBytes": "32" 367 | }, 368 | "t_mapping(t_address,t_uint256)": { 369 | "label": "mapping(address => uint256)", 370 | "numberOfBytes": "32" 371 | }, 372 | "t_mapping(t_bytes32,t_struct(RoleData)24_storage)": { 373 | "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", 374 | "numberOfBytes": "32" 375 | }, 376 | "t_string_storage": { 377 | "label": "string", 378 | "numberOfBytes": "32" 379 | }, 380 | "t_struct(AccessControlStorage)34_storage": { 381 | "label": "struct AccessControlUpgradeable.AccessControlStorage", 382 | "members": [ 383 | { 384 | "label": "_roles", 385 | "type": "t_mapping(t_bytes32,t_struct(RoleData)24_storage)", 386 | "offset": 0, 387 | "slot": "0" 388 | } 389 | ], 390 | "numberOfBytes": "32" 391 | }, 392 | "t_struct(ERC20Storage)243_storage": { 393 | "label": "struct ERC20Upgradeable.ERC20Storage", 394 | "members": [ 395 | { 396 | "label": "_balances", 397 | "type": "t_mapping(t_address,t_uint256)", 398 | "offset": 0, 399 | "slot": "0" 400 | }, 401 | { 402 | "label": "_allowances", 403 | "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", 404 | "offset": 0, 405 | "slot": "1" 406 | }, 407 | { 408 | "label": "_totalSupply", 409 | "type": "t_uint256", 410 | "offset": 0, 411 | "slot": "2" 412 | }, 413 | { 414 | "label": "_name", 415 | "type": "t_string_storage", 416 | "offset": 0, 417 | "slot": "3" 418 | }, 419 | { 420 | "label": "_symbol", 421 | "type": "t_string_storage", 422 | "offset": 0, 423 | "slot": "4" 424 | } 425 | ], 426 | "numberOfBytes": "160" 427 | }, 428 | "t_struct(InitializableStorage)158_storage": { 429 | "label": "struct Initializable.InitializableStorage", 430 | "members": [ 431 | { 432 | "label": "_initialized", 433 | "type": "t_uint64", 434 | "offset": 0, 435 | "slot": "0" 436 | }, 437 | { 438 | "label": "_initializing", 439 | "type": "t_bool", 440 | "offset": 8, 441 | "slot": "0" 442 | } 443 | ], 444 | "numberOfBytes": "32" 445 | }, 446 | "t_struct(RoleData)24_storage": { 447 | "label": "struct AccessControlUpgradeable.RoleData", 448 | "members": [ 449 | { 450 | "label": "hasRole", 451 | "type": "t_mapping(t_address,t_bool)", 452 | "offset": 0, 453 | "slot": "0" 454 | }, 455 | { 456 | "label": "adminRole", 457 | "type": "t_bytes32", 458 | "offset": 0, 459 | "slot": "1" 460 | } 461 | ], 462 | "numberOfBytes": "64" 463 | }, 464 | "t_uint256": { 465 | "label": "uint256", 466 | "numberOfBytes": "32" 467 | }, 468 | "t_uint64": { 469 | "label": "uint64", 470 | "numberOfBytes": "8" 471 | } 472 | }, 473 | "namespaces": { 474 | "erc7201:openzeppelin.storage.AccessControl": [ 475 | { 476 | "contract": "AccessControlUpgradeable", 477 | "label": "_roles", 478 | "type": "t_mapping(t_bytes32,t_struct(RoleData)24_storage)", 479 | "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61", 480 | "offset": 0, 481 | "slot": "0" 482 | } 483 | ], 484 | "erc7201:openzeppelin.storage.ERC20": [ 485 | { 486 | "contract": "ERC20Upgradeable", 487 | "label": "_balances", 488 | "type": "t_mapping(t_address,t_uint256)", 489 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:38", 490 | "offset": 0, 491 | "slot": "0" 492 | }, 493 | { 494 | "contract": "ERC20Upgradeable", 495 | "label": "_allowances", 496 | "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", 497 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:40", 498 | "offset": 0, 499 | "slot": "1" 500 | }, 501 | { 502 | "contract": "ERC20Upgradeable", 503 | "label": "_totalSupply", 504 | "type": "t_uint256", 505 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:42", 506 | "offset": 0, 507 | "slot": "2" 508 | }, 509 | { 510 | "contract": "ERC20Upgradeable", 511 | "label": "_name", 512 | "type": "t_string_storage", 513 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44", 514 | "offset": 0, 515 | "slot": "3" 516 | }, 517 | { 518 | "contract": "ERC20Upgradeable", 519 | "label": "_symbol", 520 | "type": "t_string_storage", 521 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:45", 522 | "offset": 0, 523 | "slot": "4" 524 | } 525 | ], 526 | "erc7201:openzeppelin.storage.Initializable": [ 527 | { 528 | "contract": "Initializable", 529 | "label": "_initialized", 530 | "type": "t_uint64", 531 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", 532 | "offset": 0, 533 | "slot": "0" 534 | }, 535 | { 536 | "contract": "Initializable", 537 | "label": "_initializing", 538 | "type": "t_bool", 539 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", 540 | "offset": 8, 541 | "slot": "0" 542 | } 543 | ] 544 | } 545 | } 546 | }, 547 | "de58389bf1783e3f04f35aceddb11c3ed88133bb9b6acc2dfa33b81f0c65242d": { 548 | "address": "0x8601C4af66E72d2fb89BcB57a4a8d1e4727a22ED", 549 | "txHash": "0xeab43544c3a38b65f0579bed7c2a229f271b4aa045f471221bf85b34519a2df7", 550 | "layout": { 551 | "solcVersion": "0.8.20", 552 | "storage": [ 553 | { 554 | "label": "owner", 555 | "offset": 0, 556 | "slot": "0", 557 | "type": "t_address", 558 | "contract": "Auth", 559 | "src": "contracts/Auth.sol:14" 560 | }, 561 | { 562 | "label": "taskIncentiveAddress", 563 | "offset": 0, 564 | "slot": "1", 565 | "type": "t_address", 566 | "contract": "XLToken", 567 | "src": "contracts/XLToken.sol:21" 568 | }, 569 | { 570 | "label": "ecosystemFundAddress", 571 | "offset": 0, 572 | "slot": "2", 573 | "type": "t_address", 574 | "contract": "XLToken", 575 | "src": "contracts/XLToken.sol:22" 576 | }, 577 | { 578 | "label": "strategicFinanceAddress", 579 | "offset": 0, 580 | "slot": "3", 581 | "type": "t_address", 582 | "contract": "XLToken", 583 | "src": "contracts/XLToken.sol:23" 584 | }, 585 | { 586 | "label": "teamAddress", 587 | "offset": 0, 588 | "slot": "4", 589 | "type": "t_address", 590 | "contract": "XLToken", 591 | "src": "contracts/XLToken.sol:24" 592 | }, 593 | { 594 | "label": "marketingAddress", 595 | "offset": 0, 596 | "slot": "5", 597 | "type": "t_address", 598 | "contract": "XLToken", 599 | "src": "contracts/XLToken.sol:25" 600 | }, 601 | { 602 | "label": "ecosystemStartTime", 603 | "offset": 0, 604 | "slot": "6", 605 | "type": "t_uint256", 606 | "contract": "XLToken", 607 | "src": "contracts/XLToken.sol:38" 608 | }, 609 | { 610 | "label": "strategicFinanceStartTime", 611 | "offset": 0, 612 | "slot": "7", 613 | "type": "t_uint256", 614 | "contract": "XLToken", 615 | "src": "contracts/XLToken.sol:39" 616 | }, 617 | { 618 | "label": "teamStartTime", 619 | "offset": 0, 620 | "slot": "8", 621 | "type": "t_uint256", 622 | "contract": "XLToken", 623 | "src": "contracts/XLToken.sol:40" 624 | }, 625 | { 626 | "label": "ecosystemReleased", 627 | "offset": 0, 628 | "slot": "9", 629 | "type": "t_uint256", 630 | "contract": "XLToken", 631 | "src": "contracts/XLToken.sol:43" 632 | }, 633 | { 634 | "label": "strategicFinanceReleased", 635 | "offset": 0, 636 | "slot": "10", 637 | "type": "t_uint256", 638 | "contract": "XLToken", 639 | "src": "contracts/XLToken.sol:44" 640 | }, 641 | { 642 | "label": "teamReleased", 643 | "offset": 0, 644 | "slot": "11", 645 | "type": "t_uint256", 646 | "contract": "XLToken", 647 | "src": "contracts/XLToken.sol:45" 648 | }, 649 | { 650 | "label": "totalClaimed", 651 | "offset": 0, 652 | "slot": "12", 653 | "type": "t_uint256", 654 | "contract": "XLToken", 655 | "src": "contracts/XLToken.sol:48" 656 | } 657 | ], 658 | "types": { 659 | "t_address": { 660 | "label": "address", 661 | "numberOfBytes": "20" 662 | }, 663 | "t_bool": { 664 | "label": "bool", 665 | "numberOfBytes": "1" 666 | }, 667 | "t_bytes32": { 668 | "label": "bytes32", 669 | "numberOfBytes": "32" 670 | }, 671 | "t_mapping(t_address,t_bool)": { 672 | "label": "mapping(address => bool)", 673 | "numberOfBytes": "32" 674 | }, 675 | "t_mapping(t_address,t_mapping(t_address,t_uint256))": { 676 | "label": "mapping(address => mapping(address => uint256))", 677 | "numberOfBytes": "32" 678 | }, 679 | "t_mapping(t_address,t_uint256)": { 680 | "label": "mapping(address => uint256)", 681 | "numberOfBytes": "32" 682 | }, 683 | "t_mapping(t_bytes32,t_struct(RoleData)24_storage)": { 684 | "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", 685 | "numberOfBytes": "32" 686 | }, 687 | "t_string_storage": { 688 | "label": "string", 689 | "numberOfBytes": "32" 690 | }, 691 | "t_struct(AccessControlStorage)34_storage": { 692 | "label": "struct AccessControlUpgradeable.AccessControlStorage", 693 | "members": [ 694 | { 695 | "label": "_roles", 696 | "type": "t_mapping(t_bytes32,t_struct(RoleData)24_storage)", 697 | "offset": 0, 698 | "slot": "0" 699 | } 700 | ], 701 | "numberOfBytes": "32" 702 | }, 703 | "t_struct(ERC20Storage)243_storage": { 704 | "label": "struct ERC20Upgradeable.ERC20Storage", 705 | "members": [ 706 | { 707 | "label": "_balances", 708 | "type": "t_mapping(t_address,t_uint256)", 709 | "offset": 0, 710 | "slot": "0" 711 | }, 712 | { 713 | "label": "_allowances", 714 | "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", 715 | "offset": 0, 716 | "slot": "1" 717 | }, 718 | { 719 | "label": "_totalSupply", 720 | "type": "t_uint256", 721 | "offset": 0, 722 | "slot": "2" 723 | }, 724 | { 725 | "label": "_name", 726 | "type": "t_string_storage", 727 | "offset": 0, 728 | "slot": "3" 729 | }, 730 | { 731 | "label": "_symbol", 732 | "type": "t_string_storage", 733 | "offset": 0, 734 | "slot": "4" 735 | } 736 | ], 737 | "numberOfBytes": "160" 738 | }, 739 | "t_struct(InitializableStorage)158_storage": { 740 | "label": "struct Initializable.InitializableStorage", 741 | "members": [ 742 | { 743 | "label": "_initialized", 744 | "type": "t_uint64", 745 | "offset": 0, 746 | "slot": "0" 747 | }, 748 | { 749 | "label": "_initializing", 750 | "type": "t_bool", 751 | "offset": 8, 752 | "slot": "0" 753 | } 754 | ], 755 | "numberOfBytes": "32" 756 | }, 757 | "t_struct(RoleData)24_storage": { 758 | "label": "struct AccessControlUpgradeable.RoleData", 759 | "members": [ 760 | { 761 | "label": "hasRole", 762 | "type": "t_mapping(t_address,t_bool)", 763 | "offset": 0, 764 | "slot": "0" 765 | }, 766 | { 767 | "label": "adminRole", 768 | "type": "t_bytes32", 769 | "offset": 0, 770 | "slot": "1" 771 | } 772 | ], 773 | "numberOfBytes": "64" 774 | }, 775 | "t_uint256": { 776 | "label": "uint256", 777 | "numberOfBytes": "32" 778 | }, 779 | "t_uint64": { 780 | "label": "uint64", 781 | "numberOfBytes": "8" 782 | } 783 | }, 784 | "namespaces": { 785 | "erc7201:openzeppelin.storage.AccessControl": [ 786 | { 787 | "contract": "AccessControlUpgradeable", 788 | "label": "_roles", 789 | "type": "t_mapping(t_bytes32,t_struct(RoleData)24_storage)", 790 | "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61", 791 | "offset": 0, 792 | "slot": "0" 793 | } 794 | ], 795 | "erc7201:openzeppelin.storage.ERC20": [ 796 | { 797 | "contract": "ERC20Upgradeable", 798 | "label": "_balances", 799 | "type": "t_mapping(t_address,t_uint256)", 800 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:38", 801 | "offset": 0, 802 | "slot": "0" 803 | }, 804 | { 805 | "contract": "ERC20Upgradeable", 806 | "label": "_allowances", 807 | "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", 808 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:40", 809 | "offset": 0, 810 | "slot": "1" 811 | }, 812 | { 813 | "contract": "ERC20Upgradeable", 814 | "label": "_totalSupply", 815 | "type": "t_uint256", 816 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:42", 817 | "offset": 0, 818 | "slot": "2" 819 | }, 820 | { 821 | "contract": "ERC20Upgradeable", 822 | "label": "_name", 823 | "type": "t_string_storage", 824 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44", 825 | "offset": 0, 826 | "slot": "3" 827 | }, 828 | { 829 | "contract": "ERC20Upgradeable", 830 | "label": "_symbol", 831 | "type": "t_string_storage", 832 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:45", 833 | "offset": 0, 834 | "slot": "4" 835 | } 836 | ], 837 | "erc7201:openzeppelin.storage.Initializable": [ 838 | { 839 | "contract": "Initializable", 840 | "label": "_initialized", 841 | "type": "t_uint64", 842 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", 843 | "offset": 0, 844 | "slot": "0" 845 | }, 846 | { 847 | "contract": "Initializable", 848 | "label": "_initializing", 849 | "type": "t_bool", 850 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", 851 | "offset": 8, 852 | "slot": "0" 853 | } 854 | ] 855 | } 856 | } 857 | } 858 | } 859 | } 860 | -------------------------------------------------------------------------------- /.openzeppelin/unknown-51888.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": "3.2", 3 | "proxies": [ 4 | { 5 | "address": "0xCBD46A2D6c99A7B8daa2C35DE2aEad37Aa36f506", 6 | "txHash": "0x031534e123202ced0afaef0ad3bc364a11dfb7bbee91cd9aa15b352b1764caa6", 7 | "kind": "transparent" 8 | }, 9 | { 10 | "address": "0x70c4c83e25190a4AE48addDA82362Fd9335f60Ad", 11 | "txHash": "0x157aea88e1b3cbf76d454c2b3ae871b0319c65f2d9f362ee940f744d4b04b171", 12 | "kind": "transparent" 13 | }, 14 | { 15 | "address": "0x7aA7066548cEEAaE9C633970478Db0c6Ad696232", 16 | "txHash": "0xd20f314444cfe44a307b294408b6e8417942c95e619ef4a8e3db662f5158dfaf", 17 | "kind": "transparent" 18 | } 19 | ], 20 | "impls": { 21 | "63bcbf81e8a459ca9fa41a88180f625e31bf429882c5c080ccf278b8808dd2e6": { 22 | "address": "0x1DF0386369DbCD1a189dD36f79846b7c9cD62090", 23 | "txHash": "0xf274e0160ff290376efbaa78e443eaba16a26d9df02b98c8a966f643da1388e3", 24 | "layout": { 25 | "solcVersion": "0.8.20", 26 | "storage": [ 27 | { 28 | "label": "owner", 29 | "offset": 0, 30 | "slot": "0", 31 | "type": "t_address", 32 | "contract": "Auth", 33 | "src": "contracts/Auth.sol:14" 34 | } 35 | ], 36 | "types": { 37 | "t_address": { 38 | "label": "address", 39 | "numberOfBytes": "20" 40 | }, 41 | "t_bool": { 42 | "label": "bool", 43 | "numberOfBytes": "1" 44 | }, 45 | "t_bytes32": { 46 | "label": "bytes32", 47 | "numberOfBytes": "32" 48 | }, 49 | "t_mapping(t_address,t_bool)": { 50 | "label": "mapping(address => bool)", 51 | "numberOfBytes": "32" 52 | }, 53 | "t_mapping(t_address,t_mapping(t_address,t_uint256))": { 54 | "label": "mapping(address => mapping(address => uint256))", 55 | "numberOfBytes": "32" 56 | }, 57 | "t_mapping(t_address,t_uint256)": { 58 | "label": "mapping(address => uint256)", 59 | "numberOfBytes": "32" 60 | }, 61 | "t_mapping(t_bytes32,t_struct(RoleData)24_storage)": { 62 | "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", 63 | "numberOfBytes": "32" 64 | }, 65 | "t_string_storage": { 66 | "label": "string", 67 | "numberOfBytes": "32" 68 | }, 69 | "t_struct(AccessControlStorage)34_storage": { 70 | "label": "struct AccessControlUpgradeable.AccessControlStorage", 71 | "members": [ 72 | { 73 | "label": "_roles", 74 | "type": "t_mapping(t_bytes32,t_struct(RoleData)24_storage)", 75 | "offset": 0, 76 | "slot": "0" 77 | } 78 | ], 79 | "numberOfBytes": "32" 80 | }, 81 | "t_struct(ERC20Storage)243_storage": { 82 | "label": "struct ERC20Upgradeable.ERC20Storage", 83 | "members": [ 84 | { 85 | "label": "_balances", 86 | "type": "t_mapping(t_address,t_uint256)", 87 | "offset": 0, 88 | "slot": "0" 89 | }, 90 | { 91 | "label": "_allowances", 92 | "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", 93 | "offset": 0, 94 | "slot": "1" 95 | }, 96 | { 97 | "label": "_totalSupply", 98 | "type": "t_uint256", 99 | "offset": 0, 100 | "slot": "2" 101 | }, 102 | { 103 | "label": "_name", 104 | "type": "t_string_storage", 105 | "offset": 0, 106 | "slot": "3" 107 | }, 108 | { 109 | "label": "_symbol", 110 | "type": "t_string_storage", 111 | "offset": 0, 112 | "slot": "4" 113 | } 114 | ], 115 | "numberOfBytes": "160" 116 | }, 117 | "t_struct(InitializableStorage)158_storage": { 118 | "label": "struct Initializable.InitializableStorage", 119 | "members": [ 120 | { 121 | "label": "_initialized", 122 | "type": "t_uint64", 123 | "offset": 0, 124 | "slot": "0" 125 | }, 126 | { 127 | "label": "_initializing", 128 | "type": "t_bool", 129 | "offset": 8, 130 | "slot": "0" 131 | } 132 | ], 133 | "numberOfBytes": "32" 134 | }, 135 | "t_struct(RoleData)24_storage": { 136 | "label": "struct AccessControlUpgradeable.RoleData", 137 | "members": [ 138 | { 139 | "label": "hasRole", 140 | "type": "t_mapping(t_address,t_bool)", 141 | "offset": 0, 142 | "slot": "0" 143 | }, 144 | { 145 | "label": "adminRole", 146 | "type": "t_bytes32", 147 | "offset": 0, 148 | "slot": "1" 149 | } 150 | ], 151 | "numberOfBytes": "64" 152 | }, 153 | "t_uint256": { 154 | "label": "uint256", 155 | "numberOfBytes": "32" 156 | }, 157 | "t_uint64": { 158 | "label": "uint64", 159 | "numberOfBytes": "8" 160 | } 161 | }, 162 | "namespaces": { 163 | "erc7201:openzeppelin.storage.AccessControl": [ 164 | { 165 | "contract": "AccessControlUpgradeable", 166 | "label": "_roles", 167 | "type": "t_mapping(t_bytes32,t_struct(RoleData)24_storage)", 168 | "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61", 169 | "offset": 0, 170 | "slot": "0" 171 | } 172 | ], 173 | "erc7201:openzeppelin.storage.ERC20": [ 174 | { 175 | "contract": "ERC20Upgradeable", 176 | "label": "_balances", 177 | "type": "t_mapping(t_address,t_uint256)", 178 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:38", 179 | "offset": 0, 180 | "slot": "0" 181 | }, 182 | { 183 | "contract": "ERC20Upgradeable", 184 | "label": "_allowances", 185 | "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", 186 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:40", 187 | "offset": 0, 188 | "slot": "1" 189 | }, 190 | { 191 | "contract": "ERC20Upgradeable", 192 | "label": "_totalSupply", 193 | "type": "t_uint256", 194 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:42", 195 | "offset": 0, 196 | "slot": "2" 197 | }, 198 | { 199 | "contract": "ERC20Upgradeable", 200 | "label": "_name", 201 | "type": "t_string_storage", 202 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44", 203 | "offset": 0, 204 | "slot": "3" 205 | }, 206 | { 207 | "contract": "ERC20Upgradeable", 208 | "label": "_symbol", 209 | "type": "t_string_storage", 210 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:45", 211 | "offset": 0, 212 | "slot": "4" 213 | } 214 | ], 215 | "erc7201:openzeppelin.storage.Initializable": [ 216 | { 217 | "contract": "Initializable", 218 | "label": "_initialized", 219 | "type": "t_uint64", 220 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", 221 | "offset": 0, 222 | "slot": "0" 223 | }, 224 | { 225 | "contract": "Initializable", 226 | "label": "_initializing", 227 | "type": "t_bool", 228 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", 229 | "offset": 8, 230 | "slot": "0" 231 | } 232 | ] 233 | } 234 | } 235 | }, 236 | "de58389bf1783e3f04f35aceddb11c3ed88133bb9b6acc2dfa33b81f0c65242d": { 237 | "address": "0x07A45D1F9ed2661f8Da3a7C786e79784855Fb8b9", 238 | "txHash": "0xb4bd78b46cb1f02434199a2e058ff660a30c671391488c5f0c204d980aa2033a", 239 | "layout": { 240 | "solcVersion": "0.8.20", 241 | "storage": [ 242 | { 243 | "label": "owner", 244 | "offset": 0, 245 | "slot": "0", 246 | "type": "t_address", 247 | "contract": "Auth", 248 | "src": "contracts/Auth.sol:14" 249 | }, 250 | { 251 | "label": "taskIncentiveAddress", 252 | "offset": 0, 253 | "slot": "1", 254 | "type": "t_address", 255 | "contract": "XLToken", 256 | "src": "contracts/XLToken.sol:21" 257 | }, 258 | { 259 | "label": "ecosystemFundAddress", 260 | "offset": 0, 261 | "slot": "2", 262 | "type": "t_address", 263 | "contract": "XLToken", 264 | "src": "contracts/XLToken.sol:22" 265 | }, 266 | { 267 | "label": "strategicFinanceAddress", 268 | "offset": 0, 269 | "slot": "3", 270 | "type": "t_address", 271 | "contract": "XLToken", 272 | "src": "contracts/XLToken.sol:23" 273 | }, 274 | { 275 | "label": "teamAddress", 276 | "offset": 0, 277 | "slot": "4", 278 | "type": "t_address", 279 | "contract": "XLToken", 280 | "src": "contracts/XLToken.sol:24" 281 | }, 282 | { 283 | "label": "marketingAddress", 284 | "offset": 0, 285 | "slot": "5", 286 | "type": "t_address", 287 | "contract": "XLToken", 288 | "src": "contracts/XLToken.sol:25" 289 | }, 290 | { 291 | "label": "ecosystemStartTime", 292 | "offset": 0, 293 | "slot": "6", 294 | "type": "t_uint256", 295 | "contract": "XLToken", 296 | "src": "contracts/XLToken.sol:38" 297 | }, 298 | { 299 | "label": "strategicFinanceStartTime", 300 | "offset": 0, 301 | "slot": "7", 302 | "type": "t_uint256", 303 | "contract": "XLToken", 304 | "src": "contracts/XLToken.sol:39" 305 | }, 306 | { 307 | "label": "teamStartTime", 308 | "offset": 0, 309 | "slot": "8", 310 | "type": "t_uint256", 311 | "contract": "XLToken", 312 | "src": "contracts/XLToken.sol:40" 313 | }, 314 | { 315 | "label": "ecosystemReleased", 316 | "offset": 0, 317 | "slot": "9", 318 | "type": "t_uint256", 319 | "contract": "XLToken", 320 | "src": "contracts/XLToken.sol:43" 321 | }, 322 | { 323 | "label": "strategicFinanceReleased", 324 | "offset": 0, 325 | "slot": "10", 326 | "type": "t_uint256", 327 | "contract": "XLToken", 328 | "src": "contracts/XLToken.sol:44" 329 | }, 330 | { 331 | "label": "teamReleased", 332 | "offset": 0, 333 | "slot": "11", 334 | "type": "t_uint256", 335 | "contract": "XLToken", 336 | "src": "contracts/XLToken.sol:45" 337 | }, 338 | { 339 | "label": "totalClaimed", 340 | "offset": 0, 341 | "slot": "12", 342 | "type": "t_uint256", 343 | "contract": "XLToken", 344 | "src": "contracts/XLToken.sol:48" 345 | } 346 | ], 347 | "types": { 348 | "t_address": { 349 | "label": "address", 350 | "numberOfBytes": "20" 351 | }, 352 | "t_bool": { 353 | "label": "bool", 354 | "numberOfBytes": "1" 355 | }, 356 | "t_bytes32": { 357 | "label": "bytes32", 358 | "numberOfBytes": "32" 359 | }, 360 | "t_mapping(t_address,t_bool)": { 361 | "label": "mapping(address => bool)", 362 | "numberOfBytes": "32" 363 | }, 364 | "t_mapping(t_address,t_mapping(t_address,t_uint256))": { 365 | "label": "mapping(address => mapping(address => uint256))", 366 | "numberOfBytes": "32" 367 | }, 368 | "t_mapping(t_address,t_uint256)": { 369 | "label": "mapping(address => uint256)", 370 | "numberOfBytes": "32" 371 | }, 372 | "t_mapping(t_bytes32,t_struct(RoleData)24_storage)": { 373 | "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", 374 | "numberOfBytes": "32" 375 | }, 376 | "t_string_storage": { 377 | "label": "string", 378 | "numberOfBytes": "32" 379 | }, 380 | "t_struct(AccessControlStorage)34_storage": { 381 | "label": "struct AccessControlUpgradeable.AccessControlStorage", 382 | "members": [ 383 | { 384 | "label": "_roles", 385 | "type": "t_mapping(t_bytes32,t_struct(RoleData)24_storage)", 386 | "offset": 0, 387 | "slot": "0" 388 | } 389 | ], 390 | "numberOfBytes": "32" 391 | }, 392 | "t_struct(ERC20Storage)243_storage": { 393 | "label": "struct ERC20Upgradeable.ERC20Storage", 394 | "members": [ 395 | { 396 | "label": "_balances", 397 | "type": "t_mapping(t_address,t_uint256)", 398 | "offset": 0, 399 | "slot": "0" 400 | }, 401 | { 402 | "label": "_allowances", 403 | "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", 404 | "offset": 0, 405 | "slot": "1" 406 | }, 407 | { 408 | "label": "_totalSupply", 409 | "type": "t_uint256", 410 | "offset": 0, 411 | "slot": "2" 412 | }, 413 | { 414 | "label": "_name", 415 | "type": "t_string_storage", 416 | "offset": 0, 417 | "slot": "3" 418 | }, 419 | { 420 | "label": "_symbol", 421 | "type": "t_string_storage", 422 | "offset": 0, 423 | "slot": "4" 424 | } 425 | ], 426 | "numberOfBytes": "160" 427 | }, 428 | "t_struct(InitializableStorage)158_storage": { 429 | "label": "struct Initializable.InitializableStorage", 430 | "members": [ 431 | { 432 | "label": "_initialized", 433 | "type": "t_uint64", 434 | "offset": 0, 435 | "slot": "0" 436 | }, 437 | { 438 | "label": "_initializing", 439 | "type": "t_bool", 440 | "offset": 8, 441 | "slot": "0" 442 | } 443 | ], 444 | "numberOfBytes": "32" 445 | }, 446 | "t_struct(RoleData)24_storage": { 447 | "label": "struct AccessControlUpgradeable.RoleData", 448 | "members": [ 449 | { 450 | "label": "hasRole", 451 | "type": "t_mapping(t_address,t_bool)", 452 | "offset": 0, 453 | "slot": "0" 454 | }, 455 | { 456 | "label": "adminRole", 457 | "type": "t_bytes32", 458 | "offset": 0, 459 | "slot": "1" 460 | } 461 | ], 462 | "numberOfBytes": "64" 463 | }, 464 | "t_uint256": { 465 | "label": "uint256", 466 | "numberOfBytes": "32" 467 | }, 468 | "t_uint64": { 469 | "label": "uint64", 470 | "numberOfBytes": "8" 471 | } 472 | }, 473 | "namespaces": { 474 | "erc7201:openzeppelin.storage.AccessControl": [ 475 | { 476 | "contract": "AccessControlUpgradeable", 477 | "label": "_roles", 478 | "type": "t_mapping(t_bytes32,t_struct(RoleData)24_storage)", 479 | "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61", 480 | "offset": 0, 481 | "slot": "0" 482 | } 483 | ], 484 | "erc7201:openzeppelin.storage.ERC20": [ 485 | { 486 | "contract": "ERC20Upgradeable", 487 | "label": "_balances", 488 | "type": "t_mapping(t_address,t_uint256)", 489 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:38", 490 | "offset": 0, 491 | "slot": "0" 492 | }, 493 | { 494 | "contract": "ERC20Upgradeable", 495 | "label": "_allowances", 496 | "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", 497 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:40", 498 | "offset": 0, 499 | "slot": "1" 500 | }, 501 | { 502 | "contract": "ERC20Upgradeable", 503 | "label": "_totalSupply", 504 | "type": "t_uint256", 505 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:42", 506 | "offset": 0, 507 | "slot": "2" 508 | }, 509 | { 510 | "contract": "ERC20Upgradeable", 511 | "label": "_name", 512 | "type": "t_string_storage", 513 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44", 514 | "offset": 0, 515 | "slot": "3" 516 | }, 517 | { 518 | "contract": "ERC20Upgradeable", 519 | "label": "_symbol", 520 | "type": "t_string_storage", 521 | "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:45", 522 | "offset": 0, 523 | "slot": "4" 524 | } 525 | ], 526 | "erc7201:openzeppelin.storage.Initializable": [ 527 | { 528 | "contract": "Initializable", 529 | "label": "_initialized", 530 | "type": "t_uint64", 531 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", 532 | "offset": 0, 533 | "slot": "0" 534 | }, 535 | { 536 | "contract": "Initializable", 537 | "label": "_initializing", 538 | "type": "t_bool", 539 | "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", 540 | "offset": 8, 541 | "slot": "0" 542 | } 543 | ] 544 | } 545 | } 546 | } 547 | } 548 | } 549 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LinkLayerAI XL token 2 | 3 | Redeem XL ERC20 token with point rewards to achieve value circulation 4 | 5 | ## Requirements 6 | 7 | ```shell 8 | node v16.14.0 9 | npm v7.24.2 10 | 11 | [install nvm & node] 12 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash 13 | nvm install 16.14.0 14 | nvm use 16.14.0 15 | 16 | [install npm] 17 | npm install npm@7.24.2 -g 18 | ``` 19 | 20 | ## set up 21 | 22 | ### upgrade plugin 23 | 24 | ```shell 25 | npm i @openzeppelin/hardhat-upgrades 26 | npm install --save-dev @nomicfoundation/hardhat-ethers ethers 27 | ``` 28 | 29 | ## compile 30 | 31 | ```shell 32 | npx hardhat compile 33 | ``` 34 | 35 | ## test 36 | 37 | ```shell 38 | npx hardhat test 39 | ``` 40 | 41 | ## deploy 42 | > 43 | > If there is no change in the implementation, then every time this script is executed, the proxy contract address will change 44 | 45 | ```shell 46 | npx hardhat deployXL --network erbieTestNet 47 | npx hardhat deployXL --network erbieMainNet 48 | ``` 49 | 50 | ```shell 51 | npx hardhat deployL --network erbieTestNet 52 | npx hardhat deployL --network erbieMainNet 53 | ``` 54 | 55 | ## upgrade 56 | > 57 | > Note that a network must be established. If it is for testing, NPX hard hat node can be used, and then -- network localhost 58 | > Otherwise, you will encounter this error. Don't look like an ERC 1967 proxy with a logical contract address 59 | > Contract upgrade, there will be a delay in hre.upgrades.erc1967. getImplementeAddress 60 | 61 | ```shell 62 | npx hardhat upgrade --proxyaddr --network erbieTestNet 63 | npx hardhat upgrade --proxyaddr --network erbieMainNet 64 | 65 | npx hardhat upgradeL --proxyaddr --network erbieTestNet 66 | npx hardhat upgradeL --proxyaddr --network erbieMainNet 67 | ``` 68 | 69 | ## add addr to whitelist 70 | 71 | ```shell 72 | ## grant xl 73 | npx hardhat addXLWhiteList --addr --network erbieTestNet 74 | npx hardhat addXLWhiteList --addr --network erbieMainNet 75 | 76 | ## grant l 77 | npx hardhat addLWhiteList --addr --network erbieTestNet 78 | npx hardhat addXLWhiteList --addr --network erbieMainNet 79 | 80 | 81 | 82 | npx hardhat addXLWhiteList --addr 0xDb85D05039408E9bD4644AB3527CBD2fcbbbD527 --network erbieMainNet 83 | npx hardhat addXLWhiteList --addr 0x651C90B37E88e68aaC134D12DCE52E133f8116b7 --network erbieMainNet 84 | npx hardhat addXLWhiteList --addr 0x1F49b7F54960CA8a56eea5a01be54A5f71185544 --network erbieMainNet 85 | 86 | 87 | npx hardhat addLWhiteList --addr 0xDb85D05039408E9bD4644AB3527CBD2fcbbbD527 --network erbieMainNet 88 | npx hardhat addLWhiteList --addr 0x651C90B37E88e68aaC134D12DCE52E133f8116b7 --network erbieMainNet 89 | npx hardhat addLWhiteList --addr 0x1F49b7F54960CA8a56eea5a01be54A5f71185544 --network erbieMainNet 90 | 91 | 92 | npx hardhat addXLWhiteList --addr 0xDb85D05039408E9bD4644AB3527CBD2fcbbbD527 --network erbieTestNet 93 | npx hardhat addXLWhiteList --addr 0x651C90B37E88e68aaC134D12DCE52E133f8116b7 --network erbieTestNet 94 | npx hardhat addXLWhiteList --addr 0x1F49b7F54960CA8a56eea5a01be54A5f71185544 --network erbieTestNet 95 | 96 | 97 | npx hardhat addLWhiteList --addr 0xDb85D05039408E9bD4644AB3527CBD2fcbbbD527 --network erbieTestNet 98 | npx hardhat addLWhiteList --addr 0x651C90B37E88e68aaC134D12DCE52E133f8116b7 --network erbieTestNet 99 | npx hardhat addLWhiteList --addr 0x1F49b7F54960CA8a56eea5a01be54A5f71185544 --network erbieTestNet 100 | 101 | npx hardhat addLWhiteList --addr 0x8a06b59f2877825898f44DA006DeE79d3f8C6C65 --network erbieMainNet 102 | npx hardhat addLWhiteList --addr 0xaEc7583613030AeBEF7B609baefe66902e13d8Ac --network erbieMainNet 103 | 104 | ``` 105 | 106 | ## claim xl token 107 | 108 | ```shell 109 | npx hardhat claimxl --recipient --amt --network erbieTestNet 110 | npx hardhat addXLWhiteList --addr --network erbieMainNet 111 | 112 | 113 | ## get version 114 | npx hardhat version --network erbieTestNet 115 | npx hardhat version --network erbieMainNet 116 | 117 | ## getbalance 118 | npx hardhat balance --addr
--token --tokenaddress --network 119 | 120 | ### Examples: 121 | #### TestNet 122 | npx hardhat balance --addr 0x123... --token XL --tokenaddress 0x8E37190Bf2d959ffc4Fe0987f5890BBc7Cb3Bb2f --network erbieTestNet 123 | npx hardhat balance --addr 0x123... --token L --tokenaddress 0xCBD46A2D6c99A7B8daa2C35DE2aEad37Aa36f506 --network erbieTestNet 124 | 125 | #### MainNet 126 | npx hardhat balance --addr 0x123... --token XL --tokenaddress 0x5D6C04B0AA084c95b5F4f09fF3e9F9c5120Ef8FD --network erbieMainNet 127 | npx hardhat balance --addr 0x123... --token L --tokenaddress 0x9c5e37716861A7e03976fb996228c00D31Dd40Ea --network erbieMainNet 128 | 129 | ## release token 130 | npx hardhat realease --network erbieMainNet 131 | npx hardhat balance --addr 0x3b06628b73dAE19CE15AD93eE70d97D1f79BcBC7 --network erbieMainNet 132 | npx hardhat balance --addr 0x429F64ef0764F191aA0B23cbb486040285fe73B7 --network erbieMainNet 133 | npx hardhat balance --addr 0x92C07A6549f084D6a774DCA6F2Eb6bc5058Bd1EB --network erbieMainNet 134 | 135 | 136 | ## approve token 137 | npx hardhat approveXL --spender --amount --tokenaddress --network 138 | npx hardhat approveL --spender --amount --tokenaddress --network 139 | 140 | ## Examples: 141 | ### TestNet 142 | npx hardhat approveXL --spender 0x123... --amount 1000000000000000000 --tokenaddress 0x8E37190Bf2d959ffc4Fe0987f5890BBc7Cb3Bb2f --network erbieTestNet 143 | npx hardhat approveL --spender 0x123... --amount 1000000000000000000 --tokenaddress 0xCBD46A2D6c99A7B8daa2C35DE2aEad37Aa36f506 --network erbieTestNet 144 | 145 | ### MainNet 146 | npx hardhat approveXL --spender 0x123... --amount 1000000000000000000 --tokenaddress 0x5D6C04B0AA084c95b5F4f09fF3e9F9c5120Ef8FD --network erbieMainNet 147 | npx hardhat approveL --spender 0x123... --amount 1000000000000000000 --tokenaddress 0x9c5e37716861A7e03976fb996228c00D31Dd40Ea --network erbieMainNet 148 | 149 | ## mint L token 150 | npx hardhat mintL --to --amount --tokenaddress --network 151 | 152 | ### Examples: 153 | #### TestNet 154 | npx hardhat mintL --to 0x123... --amount 10000 --tokenaddress 0xCBD46A2D6c99A7B8daa2C35DE2aEad37Aa36f506 --network erbieTestNet 155 | 156 | #### MainNet 157 | npx hardhat mintL --to 0x123... --amount 10000 --tokenaddress 0x9c5e37716861A7e03976fb996228c00D31Dd40Ea --network erbieMainNet 158 | -------------------------------------------------------------------------------- /contracts/Auth.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; 5 | 6 | contract Auth is AccessControlUpgradeable { 7 | /************* 8 | * Constants * 9 | *************/ 10 | bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); 11 | bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); 12 | bytes32 public constant WHITELISTED_ROLE = keccak256("WHITELISTED_ROLE"); 13 | 14 | address public owner; 15 | 16 | /************* 17 | * Modifiers * 18 | *************/ 19 | 20 | modifier onlySuperOwner() { 21 | require(msg.sender == owner, "Caller is not the owner"); 22 | _; 23 | } 24 | 25 | function initializeAuth(address superOwner) public initializer { 26 | __AccessControl_init(); 27 | 28 | owner = superOwner; 29 | 30 | // admin 31 | _grantRole(DEFAULT_ADMIN_ROLE, superOwner); 32 | 33 | // minter 34 | _grantRole(MINTER_ROLE, superOwner); 35 | 36 | // burner 37 | _grantRole(BURNER_ROLE, superOwner); 38 | 39 | // whitelisted 40 | _grantRole(WHITELISTED_ROLE, superOwner); 41 | } 42 | 43 | /***************************** 44 | * Public Mutating Functions * 45 | *****************************/ 46 | 47 | /** 48 | * @notice Add whitelist 49 | * @param account Added address 50 | */ 51 | function addWhitelisted( 52 | address account 53 | ) public onlyRole(DEFAULT_ADMIN_ROLE) { 54 | _grantRole(WHITELISTED_ROLE, account); 55 | } 56 | 57 | /** 58 | * @notice Remove whitelist 59 | * @param account Removed address 60 | */ 61 | function removeWhitelisted( 62 | address account 63 | ) public onlyRole(DEFAULT_ADMIN_ROLE) { 64 | _revokeRole(WHITELISTED_ROLE, account); 65 | } 66 | 67 | /** 68 | * @notice Check whether the address is whitelisted 69 | * @param account address 70 | */ 71 | function isWhitelisted(address account) public view returns (bool) { 72 | return hasRole(WHITELISTED_ROLE, account); 73 | } 74 | 75 | /** 76 | * @notice dynamically add roles through multi-signature contract addresses 77 | * @param role role 78 | * @param account the address corresponding to the role 79 | */ 80 | function addRole(bytes32 role, address account) external onlySuperOwner { 81 | _grantRole(role, account); 82 | } 83 | 84 | /** 85 | * @notice cancel the authorization to assign a role to a certain address through the multi-signature contract address 86 | * @param role role 87 | * @param account deauthorized address 88 | */ 89 | function revokeRole( 90 | bytes32 role, 91 | address account 92 | ) public override onlySuperOwner { 93 | _revokeRole(role, account); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /contracts/LToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; 5 | import "./Auth.sol"; 6 | 7 | contract LToken is ERC20Upgradeable, Auth { 8 | uint256 public constant MAX_SUPPLY = 100000000000 * 10 ** 18; // 1000 billion 9 | 10 | /********** 11 | * Errors * 12 | **********/ 13 | error InvalidZeroAddress(); 14 | error CallerIsZeroAddress(); 15 | error InvalidErbAmt(uint256 erbAmt); 16 | error ExceedsMaxSupply(uint256 totalSupply, uint256 lAmt); 17 | error InsufficientERBBalance(address from, uint256 balance); 18 | 19 | /********** 20 | * Event * 21 | **********/ 22 | /// @notice The user extracts L tokens and transfers an erb to the user, 23 | /// both of which are completed by the whitelist 24 | /// @param recipient Receive users of L and erb 25 | /// @param lAmt The quantity of L extracted by the user 26 | /// @param erbAmt Number of erbs gifted to users 27 | event Claim(address indexed recipient, uint256 lAmt, uint256 erbAmt); 28 | 29 | function initialize(address superOwner) public initializer { 30 | super.initializeAuth(superOwner); // Auth 31 | __ERC20_init("L", "L"); 32 | } 33 | 34 | receive() external payable {} 35 | 36 | /******************** 37 | ***** Modifiers **** 38 | ********************/ 39 | modifier onlyWhitelisted() { 40 | require( 41 | hasRole(WHITELISTED_ROLE, msg.sender), 42 | "L: Caller is not whitelisted" 43 | ); 44 | _; 45 | } 46 | 47 | /***************************** 48 | * Public Mutating Functions * 49 | *****************************/ 50 | 51 | /// @notice 52 | /// @param to The address of the account to mint tokens to 53 | /// @param amount The amount of tokens to mint 54 | function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { 55 | _mint(to, amount); 56 | } 57 | 58 | /// @notice 59 | /// @param from The address of the account to burn tokens from 60 | /// @param amount The amount of tokens to burn 61 | 62 | function burn(address from, uint256 amount) public onlyRole(BURNER_ROLE) { 63 | _burn(from, amount); 64 | } 65 | 66 | /// @notice The user extracts L tokens and transfers an erb to the user, 67 | /// both of which are completed by the whitelist 68 | /// @param recipient The address of the account to mint tokens to 69 | /// @param _lAmt The amount of tokens to mint 70 | function claim( 71 | address payable recipient, 72 | uint256 _lAmt 73 | ) external payable onlyWhitelisted { 74 | if (msg.value < 0) { 75 | revert InvalidErbAmt(msg.value); 76 | } 77 | 78 | if (address(this).balance < msg.value) { 79 | revert InsufficientERBBalance(address(this), address(this).balance); 80 | } 81 | 82 | if (recipient == address(0)) { 83 | revert InvalidZeroAddress(); 84 | } 85 | 86 | if (msg.sender == address(0)) { 87 | revert CallerIsZeroAddress(); 88 | } 89 | 90 | if (totalSupply() + _lAmt > MAX_SUPPLY) { 91 | revert ExceedsMaxSupply(totalSupply(), _lAmt); 92 | } 93 | 94 | _mint(recipient, _lAmt); 95 | 96 | recipient.transfer(msg.value); 97 | 98 | emit Claim(recipient, _lAmt, msg.value); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /contracts/Punk.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; 5 | import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; 6 | 7 | contract Punk is ERC721Upgradeable,OwnableUpgradeable{ 8 | uint256 public constant MAX_SUPPLY = 10_000_000; 9 | uint256 private _currentTokenId = 1; 10 | string private _baseTokenURI; 11 | 12 | event NFTMinted(address indexed to, uint256 tokenId); 13 | 14 | function initialize( 15 | string memory baseURI_, 16 | string memory name_, 17 | string memory symbol_ 18 | ) public initializer { 19 | __ERC721_init(name_, symbol_); 20 | _baseTokenURI = baseURI_; 21 | } 22 | 23 | function _baseURI() internal view override returns (string memory) { 24 | return _baseTokenURI; 25 | } 26 | 27 | function setBaseURI(string memory baseURI) public onlyOwner { 28 | _baseTokenURI = baseURI; 29 | } 30 | 31 | function tokenURI( 32 | uint256 tokenId 33 | ) public view virtual override returns (string memory) { 34 | _requireOwned(tokenId); 35 | 36 | string memory baseURI = _baseURI(); 37 | return 38 | bytes(baseURI).length > 0 39 | ? string( 40 | abi.encodePacked(baseURI, "/", Strings.toString(tokenId)) 41 | ) 42 | : ""; 43 | } 44 | 45 | function mint(address recipient) public onlyOwner { 46 | require(_currentTokenId <= MAX_SUPPLY, "Max supply reached"); 47 | 48 | _mint(recipient, _currentTokenId); 49 | 50 | emit NFTMinted(recipient, _currentTokenId); 51 | 52 | _currentTokenId++; 53 | } 54 | 55 | function currentTokenId() public view returns (uint256) { 56 | return _currentTokenId; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /contracts/XLToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; 5 | import "@openzeppelin/contracts/utils/math/Math.sol"; 6 | import "./Auth.sol"; 7 | 8 | contract XLToken is ERC20Upgradeable, Auth { 9 | using Math for uint256; 10 | 11 | uint256 public constant MAX_SUPPLY = 10_000_000_000 * 10 ** 18; 12 | 13 | uint256 public constant THREE_YEARS = 3 * 365 days; 14 | uint256 public constant FIVE_YEARS = 5 * 365 days; 15 | uint256 public constant MONTH = 30 days; 16 | uint256 public constant QUARTER = 90 days; 17 | 18 | /****************** 19 | * Assign address * 20 | *****************/ 21 | address public taskIncentiveAddress; // Task and Invitation Incentive Address 22 | address public ecosystemFundAddress; // Ecosystem Fund Address 23 | address public strategicFinanceAddress; // Strategic Financing Address 24 | address public teamAddress; // team address 25 | address public marketingAddress; // marketing address 26 | 27 | /******************** 28 | * Supply Amounts *** 29 | ********************/ 30 | uint256 public constant BONDING_SUPPLY = 6_200_000_000 * 10 ** 18; //62% released through claim 31 | uint256 public constant TASK_INCENTIVE_SUPPLY = 800_000_000 * 10 ** 18; // 8% pre allocation, fully unlocked 32 | uint256 public constant ECOSYSTEM_FUND_SUPPLY = 1_200_000_000 * 10 ** 18; // 12% linear release over 5 years ,released every month 33 | uint256 public constant STRATEGIC_FINANCE_SUPPLY = 1_000_000_000 * 10 ** 18; // 10% linearly released over 3 years,released every month 34 | uint256 public constant TEAM_SUPPLY = 600_000_000 * 10 ** 18; //6% linear release over 5 years,released every quarter 35 | uint256 public constant MARKETING_SUPPLY = 200_000_000 * 10 ** 18; // 2% pre allocation, fully unlocked 36 | 37 | // Start time 38 | uint256 public ecosystemStartTime; 39 | uint256 public strategicFinanceStartTime; 40 | uint256 public teamStartTime; 41 | 42 | // Released amount 43 | uint256 public ecosystemReleased; 44 | uint256 public strategicFinanceReleased; 45 | uint256 public teamReleased; 46 | 47 | // Total claimed amount 48 | uint256 public totalClaimed; 49 | 50 | /********** 51 | * Errors * 52 | **********/ 53 | error InvalidZeroAddress(); 54 | error CallerIsZeroAddress(); 55 | error ExceedsClaimSupply(uint256 claimed, uint256 lAmt); 56 | error InsufficientERBBalance(address from, uint256 balance); 57 | 58 | /********** 59 | * Event * 60 | **********/ 61 | /// @notice The user extracts XL tokens and transfers an erb to the user, 62 | /// both of which are completed by the whitelist 63 | /// @param recipient Receive users of XL and erb 64 | /// @param xlAmt The quantity of XL extracted by the user 65 | /// @param erbAmt Number of erbs gifted to users 66 | event Claim( 67 | address indexed recipient, 68 | uint256 indexed xlAmt, 69 | uint256 indexed erbAmt 70 | ); 71 | 72 | function initialize( 73 | address _superOwner, 74 | address _taskIncentiveAddress, 75 | address _ecosystemFundAddress, 76 | address _strategicFinanceAddress, 77 | address _teamAddress, 78 | address _marketingAddress 79 | ) public initializer { 80 | super.initializeAuth(_superOwner); // Auth 81 | __ERC20_init("XL", "XL"); 82 | taskIncentiveAddress = _taskIncentiveAddress; 83 | ecosystemFundAddress = _ecosystemFundAddress; 84 | strategicFinanceAddress = _strategicFinanceAddress; 85 | teamAddress = _teamAddress; 86 | marketingAddress = _marketingAddress; 87 | 88 | // pre allocated tokens 89 | _mint(taskIncentiveAddress, TASK_INCENTIVE_SUPPLY); 90 | _mint(marketingAddress, MARKETING_SUPPLY); 91 | 92 | ecosystemStartTime = block.timestamp; 93 | strategicFinanceStartTime = block.timestamp; 94 | teamStartTime = block.timestamp; 95 | } 96 | 97 | receive() external payable {} 98 | 99 | /******************** 100 | ***** Modifiers **** 101 | ********************/ 102 | modifier onlyWhitelisted() { 103 | require( 104 | hasRole(WHITELISTED_ROLE, msg.sender), 105 | "XL: Caller is not whitelisted" 106 | ); 107 | _; 108 | } 109 | 110 | /***************************** 111 | * Public Mutating Functions * 112 | *****************************/ 113 | 114 | /// @notice 115 | /// @param to The address of the account to mint tokens to 116 | /// @param amount The amount of tokens to mint 117 | function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { 118 | _mint(to, amount); 119 | } 120 | 121 | /// @notice 122 | /// @param from The address of the account to burn tokens from 123 | /// @param amount The amount of tokens to burn 124 | 125 | function burn(address from, uint256 amount) public onlyRole(BURNER_ROLE) { 126 | _burn(from, amount); 127 | } 128 | 129 | /// @notice The user extracts XL tokens and transfers an erb to the user, 130 | /// both of which are completed by the whitelist 131 | /// @param recipient The address of the account to mint tokens to 132 | /// @param _xlAmt The amount of tokens to mint 133 | function claim( 134 | address payable recipient, 135 | uint256 _xlAmt 136 | ) external payable onlyWhitelisted { 137 | if (address(this).balance < msg.value) { 138 | revert InsufficientERBBalance(address(this), address(this).balance); 139 | } 140 | 141 | if (recipient == address(0)) { 142 | revert InvalidZeroAddress(); 143 | } 144 | 145 | if (msg.sender == address(0)) { 146 | revert CallerIsZeroAddress(); 147 | } 148 | 149 | if (totalClaimed + _xlAmt > BONDING_SUPPLY) { 150 | revert ExceedsClaimSupply(totalClaimed, _xlAmt); 151 | } 152 | 153 | // xl option 154 | totalClaimed += _xlAmt; 155 | _mint(recipient, _xlAmt); 156 | 157 | // erb option 158 | recipient.transfer(msg.value); 159 | 160 | emit Claim(recipient, _xlAmt, msg.value); 161 | } 162 | 163 | /// @notice Releases tokens to designated addresses based on a linear release schedule. 164 | /// @dev This function calculates the amount of tokens to be released for each category (ecosystem, strategic finance, and team) 165 | /// and mints the corresponding tokens to the respective addresses. 166 | /// @dev Requires the caller to be the super owner. 167 | function releaseLinear() external onlySuperOwner { 168 | uint256 ecosystemToRelease = calculateLinearRelease( 169 | ECOSYSTEM_FUND_SUPPLY, 170 | FIVE_YEARS, 171 | ecosystemStartTime, 172 | ecosystemReleased, 173 | MONTH 174 | ); 175 | uint256 strategicToRelease = calculateLinearRelease( 176 | STRATEGIC_FINANCE_SUPPLY, 177 | THREE_YEARS, 178 | strategicFinanceStartTime, 179 | strategicFinanceReleased, 180 | MONTH 181 | ); 182 | uint256 teamToRelease = calculateLinearRelease( 183 | TEAM_SUPPLY, 184 | FIVE_YEARS, 185 | teamStartTime, 186 | teamReleased, 187 | QUARTER 188 | ); 189 | 190 | if (ecosystemToRelease > 0) { 191 | ecosystemReleased = ecosystemReleased + ecosystemToRelease; 192 | _mint(ecosystemFundAddress, ecosystemToRelease); 193 | } 194 | 195 | if (strategicToRelease > 0) { 196 | strategicFinanceReleased = 197 | strategicFinanceReleased + 198 | strategicToRelease; 199 | _mint(strategicFinanceAddress, strategicToRelease); 200 | } 201 | 202 | if (teamToRelease > 0) { 203 | teamReleased = teamReleased + teamToRelease; 204 | _mint(teamAddress, teamToRelease); 205 | } 206 | } 207 | 208 | /// @notice Calculates the amount of tokens to be released linearly over time. 209 | /// @param total The total amount of tokens to be released. 210 | /// @param duration The total duration of the release period. 211 | /// @param startTime The timestamp when the release starts. 212 | /// @param alreadyReleased The amount of tokens already released. 213 | /// @param releaseInterval The interval at which tokens are released (e.g., monthly, quarterly). 214 | /// @return The amount of tokens to be released in the current period. 215 | function calculateLinearRelease( 216 | uint256 total, 217 | uint256 duration, 218 | uint256 startTime, 219 | uint256 alreadyReleased, 220 | uint256 releaseInterval 221 | ) internal view returns (uint256) { 222 | if (block.timestamp <= startTime) return 0; 223 | uint256 elapsedTime = block.timestamp - startTime; 224 | 225 | uint256 totalPeriods = duration / releaseInterval; 226 | uint256 elapsedPeriods = elapsedTime / releaseInterval; 227 | 228 | uint256 totalToRelease = (total * elapsedPeriods) / totalPeriods; 229 | 230 | if (totalToRelease > total) { 231 | totalToRelease = total; 232 | } 233 | 234 | uint256 toRelease = totalToRelease - alreadyReleased; 235 | return toRelease; 236 | } 237 | 238 | function setAddresses( 239 | address _taskIncentiveAddress, 240 | address _ecosystemFundAddress, 241 | address _strategicFinanceAddress, 242 | address _teamAddress, 243 | address _marketingAddress 244 | ) external onlySuperOwner { 245 | taskIncentiveAddress = _taskIncentiveAddress; 246 | ecosystemFundAddress = _ecosystemFundAddress; 247 | strategicFinanceAddress = _strategicFinanceAddress; 248 | teamAddress = _teamAddress; 249 | marketingAddress = _marketingAddress; 250 | } 251 | 252 | function getVersion() public pure returns (string memory) { 253 | return "1.0.0"; 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /contracts/mock/MockERC1155.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | 7 | contract GameItems is ERC1155, Ownable { 8 | uint256 public constant SWORD = 0; 9 | uint256 public constant SHIELD = 1; 10 | uint256 public constant POTION = 2; 11 | uint256 public constant UNIQUE_HAMMER = 3; 12 | 13 | constructor() ERC1155("https://game.example/api/item/{id}.json")Ownable(msg.sender) { 14 | _mint(msg.sender, SWORD, 1000, ""); 15 | _mint(msg.sender, SHIELD, 500, ""); 16 | _mint(msg.sender, POTION, 10000, ""); 17 | _mint(msg.sender, UNIQUE_HAMMER, 1, ""); 18 | } 19 | 20 | function mint( 21 | address account, 22 | uint256 id, 23 | uint256 amount 24 | ) public onlyOwner { 25 | _mint(account, id, amount, ""); 26 | } 27 | 28 | function batchMint( 29 | address to, 30 | uint256[] memory ids, 31 | uint256[] memory amounts 32 | ) public onlyOwner { 33 | _mintBatch(to, ids, amounts, ""); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contracts/mock/MockXLTokenV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; 5 | import "@openzeppelin/contracts/utils/math/Math.sol"; 6 | import "../Auth.sol"; 7 | 8 | contract MockXLTokenV2 is ERC20Upgradeable, Auth { 9 | using Math for uint256; 10 | 11 | uint256 public constant MAX_SUPPLY = 1_000_000_000 * 10 ** 18; 12 | 13 | uint256 public constant THREE_YEARS = 3 * 365 days; 14 | uint256 public constant FIVE_YEARS = 5 * 365 days; 15 | uint256 public constant MONTH = 30 days; 16 | uint256 public constant QUARTER = 90 days; 17 | 18 | /****************** 19 | * Assign address * 20 | *****************/ 21 | address public taskIncentiveAddress; // 10% Task and Invitation Incentive Address 22 | address public ecosystemFundAddress; // 10% Ecosystem Fund Address 23 | address public strategicFinanceAddress; // 8% Strategic Financing Address 24 | address public teamAddress; // 5% team address 25 | address public marketingAddress; // 2% marketing address 26 | 27 | /******************** 28 | * Supply Amounts *** 29 | ********************/ 30 | uint256 public constant BONDING_SUPPLY = 650_000_000 * 10 ** 18; //65% released through claim 31 | uint256 public constant TASK_INCENTIVE_SUPPLY = 100_000_000 * 10 ** 18; // 10% pre allocation, fully unlocked 32 | uint256 public constant ECOSYSTEM_FUND_SUPPLY = 100_000_000 * 10 ** 18; // 10% linear release over 3 years 33 | uint256 public constant STRATEGIC_FINANCE_SUPPLY = 80_000_000 * 10 ** 18; // 8% linearly released over 3 years 34 | uint256 public constant TEAM_SUPPLY = 50_000_000 * 10 ** 18; //5% linear release over 5 years 35 | uint256 public constant MARKETING_SUPPLY = 20_000_000 * 10 ** 18; // 2% pre allocation, fully unlocked 36 | 37 | // Start time 38 | uint256 public ecosystemStartTime; 39 | uint256 public strategicFinanceStartTime; 40 | uint256 public teamStartTime; 41 | 42 | // Released amount 43 | uint256 public ecosystemReleased; 44 | uint256 public strategicFinanceReleased; 45 | uint256 public teamReleased; 46 | 47 | // Total claimed amount 48 | uint256 public totalClaimed; 49 | 50 | /********** 51 | * Errors * 52 | **********/ 53 | error InvalidZeroAddress(); 54 | error ExceedsClaimSupply(uint256 claimed, uint256 lAmt); 55 | error InsufficientERBBalance(address from, uint256 balance); 56 | 57 | /********** 58 | * Event * 59 | **********/ 60 | /// @notice The user extracts XL tokens and transfers an erb to the user, 61 | /// both of which are completed by the whitelist 62 | /// @param recipient Receive users of XL and erb 63 | /// @param xlAmt The quantity of XL extracted by the user 64 | /// @param erbAmt Number of erbs gifted to users 65 | event Claim(address indexed recipient, uint256 xlAmt, uint256 erbAmt); 66 | 67 | function initialize( 68 | address _superOwner, 69 | address _taskIncentiveAddress, 70 | address _ecosystemFundAddress, 71 | address _strategicFinanceAddress, 72 | address _teamAddress, 73 | address _marketingAddress 74 | ) public initializer { 75 | super.initializeAuth(_superOwner); // Auth 76 | __ERC20_init("XL", "XL"); 77 | taskIncentiveAddress = _taskIncentiveAddress; 78 | ecosystemFundAddress = _ecosystemFundAddress; 79 | strategicFinanceAddress = _strategicFinanceAddress; 80 | teamAddress = _teamAddress; 81 | marketingAddress = _marketingAddress; 82 | 83 | // pre allocated tokens 84 | _mint(taskIncentiveAddress, TASK_INCENTIVE_SUPPLY); 85 | _mint(marketingAddress, MARKETING_SUPPLY); 86 | 87 | ecosystemStartTime = block.timestamp; 88 | strategicFinanceStartTime = block.timestamp; 89 | teamStartTime = block.timestamp; 90 | } 91 | 92 | receive() external payable {} 93 | 94 | /******************** 95 | ***** Modifiers **** 96 | ********************/ 97 | modifier onlyWhitelisted() { 98 | require( 99 | hasRole(WHITELISTED_ROLE, msg.sender), 100 | "XL: Caller is not whitelisted" 101 | ); 102 | _; 103 | } 104 | 105 | /***************************** 106 | * Public Mutating Functions * 107 | *****************************/ 108 | 109 | /// @notice 110 | /// @param to The address of the account to mint tokens to 111 | /// @param amount The amount of tokens to mint 112 | function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { 113 | _mint(to, amount); 114 | } 115 | 116 | /// @notice 117 | /// @param from The address of the account to burn tokens from 118 | /// @param amount The amount of tokens to burn 119 | 120 | function burn(address from, uint256 amount) public onlyRole(BURNER_ROLE) { 121 | _burn(from, amount); 122 | } 123 | 124 | /// @notice The user extracts XL tokens and transfers an erb to the user, 125 | /// both of which are completed by the whitelist 126 | /// @param recipient The address of the account to mint tokens to 127 | /// @param _xlAmt The amount of tokens to mint 128 | function claim( 129 | address payable recipient, 130 | uint256 _xlAmt 131 | ) external payable onlyWhitelisted { 132 | if (address(this).balance < msg.value) { 133 | revert InsufficientERBBalance(address(this), address(this).balance); 134 | } 135 | 136 | if (recipient == address(0)) { 137 | revert InvalidZeroAddress(); 138 | } 139 | 140 | if (totalClaimed + _xlAmt > BONDING_SUPPLY) { 141 | revert ExceedsClaimSupply(totalClaimed, _xlAmt); 142 | } 143 | 144 | // xl option 145 | totalClaimed += _xlAmt; 146 | _mint(recipient, _xlAmt); 147 | 148 | // erb option 149 | recipient.transfer(msg.value); 150 | 151 | emit Claim(recipient, _xlAmt, msg.value); 152 | } 153 | 154 | function releaseLinear() external onlySuperOwner { 155 | uint256 ecosystemToRelease = calculateLinearRelease( 156 | ECOSYSTEM_FUND_SUPPLY, 157 | THREE_YEARS, 158 | ecosystemStartTime, 159 | ecosystemReleased, 160 | MONTH 161 | ); 162 | uint256 strategicToRelease = calculateLinearRelease( 163 | STRATEGIC_FINANCE_SUPPLY, 164 | THREE_YEARS, 165 | strategicFinanceStartTime, 166 | strategicFinanceReleased, 167 | MONTH 168 | ); 169 | uint256 teamToRelease = calculateLinearRelease( 170 | TEAM_SUPPLY, 171 | FIVE_YEARS, 172 | teamStartTime, 173 | teamReleased, 174 | QUARTER 175 | ); 176 | 177 | if (ecosystemToRelease > 0) { 178 | ecosystemReleased = ecosystemReleased + ecosystemToRelease; 179 | _mint(ecosystemFundAddress, ecosystemToRelease); 180 | } 181 | 182 | if (strategicToRelease > 0) { 183 | strategicFinanceReleased = 184 | strategicFinanceReleased + 185 | strategicToRelease; 186 | _mint(strategicFinanceAddress, strategicToRelease); 187 | } 188 | 189 | if (teamToRelease > 0) { 190 | teamReleased = teamReleased + teamToRelease; 191 | _mint(teamAddress, teamToRelease); 192 | } 193 | } 194 | 195 | function calculateLinearRelease( 196 | uint256 total, 197 | uint256 duration, 198 | uint256 startTime, 199 | uint256 alreadyReleased, 200 | uint256 releaseInterval 201 | ) internal view returns (uint256) { 202 | if (block.timestamp <= startTime) return 0; 203 | uint256 elapsedTime = block.timestamp - startTime; 204 | 205 | uint256 totalPeriods = duration / releaseInterval; 206 | uint256 elapsedPeriods = elapsedTime / releaseInterval; 207 | 208 | uint256 totalToRelease = (total * elapsedPeriods) / totalPeriods; 209 | 210 | if (totalToRelease > total) { 211 | totalToRelease = total; 212 | } 213 | 214 | uint256 toRelease = totalToRelease - alreadyReleased; 215 | return toRelease; 216 | } 217 | 218 | function setAddresses( 219 | address _taskIncentiveAddress, 220 | address _ecosystemFundAddress, 221 | address _strategicFinanceAddress, 222 | address _teamAddress, 223 | address _marketingAddress 224 | ) external onlySuperOwner { 225 | taskIncentiveAddress = _taskIncentiveAddress; 226 | ecosystemFundAddress = _ecosystemFundAddress; 227 | strategicFinanceAddress = _strategicFinanceAddress; 228 | teamAddress = _teamAddress; 229 | marketingAddress = _marketingAddress; 230 | } 231 | 232 | /// @notice test upgrade 233 | function TestUpgrade() public view returns (uint256) { 234 | return 200; 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { HardhatUserConfig } from "hardhat/config"; 2 | import "@nomicfoundation/hardhat-toolbox"; 3 | import '@openzeppelin/hardhat-upgrades'; 4 | import "./tasks/deploy" 5 | import "./tasks/upgrade" 6 | import "./tasks/addwhitelist" 7 | import "./tasks/claimxl" 8 | import "./tasks/version" 9 | import "./tasks/balance" 10 | import "./tasks/mintnft" 11 | import "./tasks/release" 12 | import "./tasks/approveXL" 13 | import "./tasks/approveL" 14 | import "./tasks/mintL" 15 | import * as dotenv from 'dotenv'; 16 | 17 | dotenv.config(); 18 | 19 | const config: HardhatUserConfig = { 20 | solidity: "0.8.20", 21 | networks: { 22 | erbieTestNet: { 23 | url: "http://192.168.1.235:8560", 24 | accounts: [process.env.PRIVATE_KEY || ""], // if use erbieTestNet, you need to set your private key to .env 25 | chainId: 51888, 26 | }, 27 | erbieMainNet: { 28 | url: "http://192.168.84.240:8560", 29 | accounts: [process.env.PRIVATE_KEY || ""], // if use erbieMainNet, you need to set your private key to .env 30 | chainId: 50888, 31 | } 32 | }, 33 | }; 34 | 35 | export default config; 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linklayer-contracts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "mindcarver", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "@nomicfoundation/hardhat-network-helpers": "^1.0.11", 13 | "@nomicfoundation/hardhat-toolbox": "^5.0.0", 14 | "hardhat": "^2.22.8" 15 | }, 16 | "dependencies": { 17 | "@openzeppelin/contracts": "^5.0.2", 18 | "@openzeppelin/contracts-upgradeable": "^5.0.2", 19 | "@openzeppelin/hardhat-upgrades": "^3.2.1", 20 | "@openzeppelin/upgrades": "^2.8.0", 21 | "dotenv": "^16.4.5" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tasks/addwhitelist.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import { XLToken, LToken } from "../typechain-types" 3 | 4 | task("addXLWhiteList", "Whitelist an address") 5 | .addParam("addr", "The address to whitelist") 6 | .setAction(async (args, hre) => { 7 | const { ethers } = hre; 8 | const [deployer] = await ethers.getSigners(); 9 | 10 | const MyContract = await ethers.getContractFactory("XLToken"); 11 | const contract = MyContract.attach("0x5D6C04B0AA084c95b5F4f09fF3e9F9c5120Ef8FD") as XLToken; //mainnet 12 | //const contract = MyContract.attach("0x8E37190Bf2d959ffc4Fe0987f5890BBc7Cb3Bb2f") as XLToken; // testnet 13 | 14 | 15 | await contract.connect(deployer).addWhitelisted(args.addr); 16 | 17 | console.log(`Address ${args.address} has been whitelisted.`); 18 | }); 19 | 20 | 21 | 22 | task("addLWhiteList", "Whitelist an address") 23 | .addParam("addr", "The address to whitelist") 24 | .setAction(async (args, hre) => { 25 | const { ethers } = hre; 26 | const [deployer] = await ethers.getSigners(); 27 | 28 | const MyContract = await ethers.getContractFactory("LToken"); 29 | //const contract = MyContract.attach("0xB014083f30Dc82AC18E82e9112c66455D26bC517") as LToken; // testnet 30 | const contract = MyContract.attach("0x9c5e37716861A7e03976fb996228c00D31Dd40Ea") as LToken; // mainnet 31 | 32 | await contract.connect(deployer).addWhitelisted(args.addr); 33 | 34 | console.log(`Address ${args.address} has been whitelisted.`); 35 | }); -------------------------------------------------------------------------------- /tasks/approveL.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import { LToken } from "../typechain-types" 3 | 4 | task("approveL", "Approve a contract address to spend L tokens") 5 | .addParam("spender", "Contract address to approve") 6 | .addParam("amount", "Amount of tokens to approve (in wei)") 7 | .addParam("tokenaddress", "Address of the L token contract") 8 | .setAction(async (args, hre) => { 9 | try { 10 | const { ethers, network } = hre; 11 | const [deployer] = await ethers.getSigners(); 12 | 13 | console.log("Approving L tokens with account:", deployer.address); 14 | console.log("Network:", network.name); 15 | 16 | const MyContract = await ethers.getContractFactory("LToken"); 17 | const contractAddress = args.tokenaddress; 18 | 19 | console.log(`Using L token contract at: ${contractAddress}`); 20 | const contract = MyContract.attach(contractAddress) as LToken; 21 | 22 | console.log(`Approving ${args.amount} L tokens to be spent by ${args.spender}`); 23 | 24 | const tx = await contract.approve(args.spender, args.amount); 25 | await tx.wait(); 26 | 27 | const allowance = await contract.allowance(deployer.address, args.spender); 28 | console.log(`Approval successful. Current allowance: ${allowance}`); 29 | } catch (error) { 30 | console.error("Error occurred:", error); 31 | throw error; 32 | } 33 | }); -------------------------------------------------------------------------------- /tasks/approveXL.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import { XLToken } from "../typechain-types" 3 | 4 | task("approveXL", "Approve a contract address to spend XL tokens") 5 | .addParam("spender", "Contract address to approve") 6 | .addParam("amount", "Amount of tokens to approve (in wei)") 7 | .addParam("tokenaddress", "Address of the XL token contract") 8 | .setAction(async (args, hre) => { 9 | try { 10 | const { ethers, network } = hre; 11 | const [deployer] = await ethers.getSigners(); 12 | 13 | console.log("Approving XL tokens with account:", deployer.address); 14 | console.log("Network:", network.name); 15 | 16 | const MyContract = await ethers.getContractFactory("XLToken"); 17 | const contractAddress = args.tokenaddress; 18 | 19 | console.log(`Using XL token contract at: ${contractAddress}`); 20 | const contract = MyContract.attach(contractAddress) as XLToken; 21 | 22 | console.log(`Approving ${args.amount} XL tokens to be spent by ${args.spender}`); 23 | 24 | const tx = await contract.approve(args.spender, args.amount); 25 | await tx.wait(); 26 | 27 | const allowance = await contract.allowance(deployer.address, args.spender); 28 | console.log(`Approval successful. Current allowance: ${allowance}`); 29 | } catch (error) { 30 | console.error("Error occurred:", error); 31 | throw error; 32 | } 33 | }); -------------------------------------------------------------------------------- /tasks/balance.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import { XLToken, LToken } from "../typechain-types" 3 | 4 | task("balance", "Get token balance for an address") 5 | .addParam("addr", "Address to query balance for") 6 | .addParam("token", "Token type (XL or L)") 7 | .addParam("tokenaddress", "Token contract address") 8 | .setAction(async (args, hre) => { 9 | const { ethers } = hre; 10 | const [deployer] = await ethers.getSigners(); 11 | 12 | if (args.token.toUpperCase() === "XL") { 13 | const MyContract = await ethers.getContractFactory("XLToken"); 14 | const contract = MyContract.attach(args.tokenaddress) as XLToken; 15 | const balance = await contract.balanceOf(args.addr); 16 | console.log(`XL balance for ${args.addr}: ${balance}`); 17 | } else if (args.token.toUpperCase() === "L") { 18 | const MyContract = await ethers.getContractFactory("LToken"); 19 | const contract = MyContract.attach(args.tokenaddress) as LToken; 20 | const balance = await contract.balanceOf(args.addr); 21 | console.log(`L balance for ${args.addr}: ${balance}`); 22 | } else { 23 | console.error("Invalid token type. Use 'XL' or 'L'"); 24 | } 25 | }); -------------------------------------------------------------------------------- /tasks/claimxl.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import { XLToken,LToken } from "../typechain-types" 3 | 4 | task("claimxl", "claim xl token") 5 | .addParam("recipient", "recipient") 6 | .addParam("amt", "xl amount") 7 | .setAction(async (args, hre) => { 8 | const { ethers } = hre; 9 | const [deployer] = await ethers.getSigners(); 10 | 11 | const MyContract = await ethers.getContractFactory("XLToken"); 12 | const contract = MyContract.attach("0xCBD46A2D6c99A7B8daa2C35DE2aEad37Aa36f506") as XLToken; 13 | 14 | const amtconvert = ethers.parseEther(args.amt); 15 | 16 | await contract.connect(deployer).claim(args.recipient, amtconvert,{ value: ethers.parseEther("88") }); 17 | console.log(`claim ${args.amt} xl token to ${args.recipient}`); 18 | 19 | const balance = await contract.balanceOf(args.recipient); 20 | console.log(`balance: ${balance}`); 21 | }); -------------------------------------------------------------------------------- /tasks/deploy.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import { XLToken, LToken, Punk, GameItems } from "../typechain-types" 3 | 4 | 5 | task("deployXL", "deploy xl token contract") 6 | .setAction(async (args, hre) => { 7 | let token: XLToken; 8 | const { ethers } = hre; 9 | const [deployer] = await ethers.getSigners(); 10 | 11 | const taskIncentiveAddress = "0x4a13c2a6fF127C8843c274EbAaeAF8cCc6dB5dE0" 12 | const ecosystemFundAddress = "0x3b06628b73dAE19CE15AD93eE70d97D1f79BcBC7" 13 | const strategicFinanceAddress = "0x429F64ef0764F191aA0B23cbb486040285fe73B7" 14 | const teamAddress = "0x92C07A6549f084D6a774DCA6F2Eb6bc5058Bd1EB" 15 | const marketingAddress = "0xdD81a1a26434C757739D547582D62cB4cf56e08c" 16 | 17 | 18 | const XLToken = await ethers.getContractFactory("XLToken"); 19 | 20 | token = await hre.upgrades.deployProxy(XLToken, [deployer.address, 21 | taskIncentiveAddress, ecosystemFundAddress, strategicFinanceAddress, 22 | teamAddress, marketingAddress]) as unknown as XLToken; 23 | await token.waitForDeployment(); 24 | 25 | // proxy address 0x5D6C04B0AA084c95b5F4f09fF3e9F9c5120Ef8FD mainnet 26 | // proxy address 0x8E37190Bf2d959ffc4Fe0987f5890BBc7Cb3Bb2f testnet 27 | console.log("XL deployed to:", await token.getAddress()); 28 | 29 | // implementation address 0x8601C4af66E72d2fb89BcB57a4a8d1e4727a22ED mainnet 30 | // implementation address 0x085b5a830aA2bA07F56C302Fe6Df265f62A11392 testnet 31 | console.log("XL implementation address:", await hre.upgrades.erc1967.getImplementationAddress(await token.getAddress())); 32 | }) 33 | 34 | task("deployL", "deploy l token contract") 35 | .setAction(async (args, hre) => { 36 | let token: LToken; 37 | const { ethers } = hre; 38 | const [deployer] = await ethers.getSigners(); 39 | const LToken = await ethers.getContractFactory("LToken"); 40 | 41 | token = await hre.upgrades.deployProxy(LToken, [deployer.address]) as unknown as LToken; 42 | await token.waitForDeployment(); 43 | 44 | // proxy address 0x9c5e37716861A7e03976fb996228c00D31Dd40Ea mainnet 45 | // proxy address 0xCBD46A2D6c99A7B8daa2C35DE2aEad37Aa36f506 testnet 46 | console.log("L deployed to:", await token.getAddress()); 47 | 48 | // implementation address 0x92F33Df758937393E5b3949e1a61C9aCeb734A84 mainnet 49 | // implementation address 0x1DF0386369DbCD1a189dD36f79846b7c9cD62090 testnet 50 | console.log("L implementation address:", await hre.upgrades.erc1967.getImplementationAddress(await token.getAddress())); 51 | }) 52 | 53 | 54 | 55 | // 0xcE1CC1Aa4e1CeE97b13c9E650A7Be66345D7D04f 56 | // npx hardhat deploynft --network erbieTestNet 57 | task("deploynft", "deploy nft contract") 58 | .setAction(async (args, hre) => { 59 | const { ethers } = hre; 60 | const [deployer] = await ethers.getSigners(); 61 | const Punk = await ethers.getContractFactory("Punk"); 62 | const nft = await Punk.connect(deployer).deploy() as Punk; 63 | await nft.waitForDeployment(); 64 | console.log("nft deployed to:", await nft.getAddress()); 65 | }) 66 | 67 | 68 | 69 | 70 | 71 | // npx hardhat deployerc1155 --network erbieTestNet 72 | // 0x03CFF07122b8e82418bd9152763516f7141a2c39 73 | task("deployerc1155", "deploy erc1155 test contract") 74 | .setAction(async (args, hre) => { 75 | const { ethers } = hre; 76 | const [deployer] = await ethers.getSigners(); 77 | const gameItemsFac = await ethers.getContractFactory("GameItems"); 78 | const gameItems = await gameItemsFac.connect(deployer).deploy() as GameItems; 79 | await gameItems.waitForDeployment(); 80 | console.log("erc1155 deployed to:", await gameItems.getAddress()); 81 | }) -------------------------------------------------------------------------------- /tasks/mintL.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import { LToken } from "../typechain-types" 3 | 4 | task("mintL", "Mint L tokens to a specified address (requires MINTER_ROLE)") 5 | .addParam("to", "Address to receive the minted tokens") 6 | .addParam("amount", "Amount of tokens to mint (in wei)") 7 | .addParam("tokenaddress", "Address of the L token contract") 8 | .setAction(async (args, hre) => { 9 | const { ethers } = hre; 10 | const [deployer] = await ethers.getSigners(); 11 | 12 | console.log("Minting L tokens with account:", deployer.address); 13 | console.log("Using L token contract at:", args.tokenaddress); 14 | 15 | const MyContract = await ethers.getContractFactory("LToken"); 16 | const contract = MyContract.attach(args.tokenaddress) as LToken; 17 | 18 | console.log(`Minting ${args.amount} L tokens to ${args.to}`); 19 | 20 | try { 21 | const tx = await contract.mint(args.to, args.amount); 22 | await tx.wait(); 23 | 24 | const balance = await contract.balanceOf(args.to); 25 | console.log(`Minting successful. Current balance of ${args.to}: ${balance}`); 26 | } catch (error) { 27 | console.error("Error minting tokens:", error); 28 | console.log("Make sure the caller has the MINTER_ROLE"); 29 | } 30 | }); -------------------------------------------------------------------------------- /tasks/mintnft.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import { Punk,GameItems } from "../typechain-types" 3 | 4 | task("mintnft", "mint nft") 5 | .addParam("recipient", "recipient") 6 | // .addParam("uri", "token uri") 7 | .setAction(async (args, hre) => { 8 | const { ethers } = hre; 9 | const [deployer] = await ethers.getSigners(); 10 | 11 | const MyContract = await ethers.getContractFactory("Punk"); 12 | const nft = MyContract.attach("0xcE1CC1Aa4e1CeE97b13c9E650A7Be66345D7D04f") as Punk; 13 | 14 | await nft.connect(deployer).mintNFT(args.recipient, "test.com"); 15 | console.log("minted"); 16 | }); 17 | 18 | 19 | //npx hardhat minterc1155 --recipient 0x15b1049c7F8Fb1b5F1Cba8236EAc0e77fBEE4E66 --network erbieTestNet 20 | task("minterc1155", "mint erc1155 token") 21 | .addParam("recipient", "recipient") 22 | .setAction(async (args, hre) => { 23 | const { ethers } = hre; 24 | const [deployer] = await ethers.getSigners(); 25 | 26 | const gameItemsFac = await ethers.getContractFactory("GameItems"); 27 | const gameItems = gameItemsFac.attach("0x03CFF07122b8e82418bd9152763516f7141a2c39") as GameItems; 28 | 29 | await gameItems.connect(deployer).mint(args.recipient, 0,88); 30 | console.log("erc1155 minted"); 31 | }); -------------------------------------------------------------------------------- /tasks/release.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { task } from "hardhat/config"; 4 | import { XLToken } from "../typechain-types" 5 | 6 | task("realease", "realease xl token") 7 | .setAction(async (args, hre) => { 8 | const { ethers } = hre; 9 | const [deployer] = await ethers.getSigners(); 10 | 11 | const MyContract = await ethers.getContractFactory("XLToken"); 12 | //const contract = MyContract.attach("0x8E37190Bf2d959ffc4Fe0987f5890BBc7Cb3Bb2f") as XLToken; // testnet xl 13 | const contract = MyContract.attach("0x5D6C04B0AA084c95b5F4f09fF3e9F9c5120Ef8FD") as XLToken; // mainnet xl 14 | 15 | // call releaseLinear method 16 | await contract.connect(deployer).releaseLinear(); 17 | console.log(`----------releaseLinear------------`); 18 | 19 | // ecosystemFundAddress balance 20 | const balance = await contract.balanceOf("0x3b06628b73dAE19CE15AD93eE70d97D1f79BcBC7"); 21 | // strategicFinanceAddress balance 22 | const balance2 = await contract.balanceOf("0x429F64ef0764F191aA0B23cbb486040285fe73B7"); 23 | // 0x92C07A6549f084D6a774DCA6F2Eb6bc5058Bd1EB 24 | const balance3 = await contract.balanceOf("0x92C07A6549f084D6a774DCA6F2Eb6bc5058Bd1EB"); 25 | 26 | console.log(`balance: ${balance}`); 27 | console.log(`balance2: ${balance2}`); 28 | console.log(`balance3: ${balance3}`); 29 | 30 | }); -------------------------------------------------------------------------------- /tasks/upgrade.ts: -------------------------------------------------------------------------------- 1 | import { task, types } from "hardhat/config"; 2 | import { XLToken,LToken } from "../typechain-types" 3 | 4 | 5 | task("upgrade", "upgrade XLToken") 6 | .addParam("proxyaddr", "proxy address") 7 | .setAction(async (args, hre) => { 8 | let token: XLToken; 9 | const { ethers } = hre; 10 | // upgrade XLToken to XLTokenV2 11 | // Keep the contract name unchanged 12 | const XLTokenV2 = await ethers.getContractFactory("XLToken"); 13 | token = await hre.upgrades.upgradeProxy(args.proxyaddr, XLTokenV2) as unknown as XLToken; 14 | console.log("XLToken upgraded to:", await token.getAddress()); 15 | // new impl address 16 | console.log("XLTokenV2 implementation address:", await hre.upgrades.erc1967.getImplementationAddress(await token.getAddress())); 17 | }) 18 | 19 | 20 | task("upgradeL", "upgrade LToken") 21 | .addParam("proxyaddr", "proxy address") 22 | .setAction(async (args, hre) => { 23 | let token: LToken; 24 | const { ethers } = hre; 25 | // upgrade LToken to LTokenV2 26 | // Keep the contract name unchanged 27 | const LTokenV2 = await ethers.getContractFactory("LToken"); 28 | token = await hre.upgrades.upgradeProxy(args.proxyaddr, LTokenV2) as unknown as LToken; 29 | console.log("LToken upgraded to:", await token.getAddress()); 30 | // new impl address 31 | console.log("LTokenV2 implementation address:", await hre.upgrades.erc1967.getImplementationAddress(await token.getAddress())); 32 | }) -------------------------------------------------------------------------------- /tasks/version.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { task } from "hardhat/config"; 4 | import { XLToken, LToken } from "../typechain-types" 5 | 6 | task("version", "get version") 7 | .setAction(async (args, hre) => { 8 | const { ethers } = hre; 9 | const [deployer] = await ethers.getSigners(); 10 | 11 | const MyContract = await ethers.getContractFactory("XLToken"); 12 | //const contract = MyContract.attach("0x8E37190Bf2d959ffc4Fe0987f5890BBc7Cb3Bb2f") as XLToken; // testnet xl 13 | const contract = MyContract.attach("0x5D6C04B0AA084c95b5F4f09fF3e9F9c5120Ef8FD") as XLToken; // mainnet xl 14 | 15 | 16 | const version = await contract.getVersion(); 17 | console.log("version:", version); 18 | }); 19 | 20 | 21 | // 获取totalsupply 22 | task("totalSupply", "get totalSupply") 23 | .setAction(async (args, hre) => { 24 | const { ethers } = hre; 25 | const [deployer] = await ethers.getSigners(); 26 | const MyContract = await ethers.getContractFactory("XLToken"); 27 | const contract = MyContract.attach("0x5D6C04B0AA084c95b5F4f09fF3e9F9c5120Ef8FD") as XLToken; 28 | const totalSupply = await contract.totalSupply(); 29 | console.log("totalSupply:", totalSupply); 30 | }); -------------------------------------------------------------------------------- /test/LToken.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { ethers, upgrades } from "hardhat"; 3 | import { time } from "@nomicfoundation/hardhat-network-helpers"; 4 | import { XLToken,LToken } from "../typechain-types" 5 | 6 | describe("L", function () { 7 | let token: LToken; 8 | let owner: any; 9 | let minter: any; 10 | let burner: any; 11 | let whitelister: any; 12 | 13 | 14 | 15 | beforeEach(async function () { 16 | [owner, minter, burner, whitelister] = await ethers.getSigners(); 17 | const LToken = await ethers.getContractFactory("LToken"); 18 | 19 | 20 | token = await upgrades.deployProxy(LToken, [owner.address]) as unknown as LToken; 21 | await token.waitForDeployment(); 22 | 23 | console.log("L deployed to:", await token.getAddress()); 24 | }); 25 | 26 | describe("Roles", function () { 27 | // The owner has permissions for admin, mint, burner, and whitelist simultaneously 28 | it("Should assign the admin role to the owner", async function () { 29 | expect(await token.hasRole(await token.DEFAULT_ADMIN_ROLE(), owner.address)).to.equal(true); 30 | }); 31 | 32 | it("Should assign the minter role to the minter", async function () { 33 | expect(await token.hasRole(await token.MINTER_ROLE(), owner.address)).to.equal(true); 34 | }); 35 | 36 | it("Should assign the burner role to the burner", async function () { 37 | expect(await token.hasRole(await token.BURNER_ROLE(), owner.address)).to.equal(true); 38 | }); 39 | 40 | it("Should assign the whitelister role to the whitelister", async function () { 41 | expect(await token.hasRole(await token.WHITELISTED_ROLE(), owner.address)).to.equal(true); 42 | }); 43 | 44 | // The owner authorizes Minter, who in turn has Minter's permission 45 | it("Should assign the minter role to the minter", async function () { 46 | await token.grantRole(await token.MINTER_ROLE(), minter.address); 47 | expect(await token.hasRole(await token.MINTER_ROLE(), minter.address)).to.equal(true); 48 | }); 49 | 50 | // addWhitelisted 51 | it("Should assign the whitelister role to the whitelister", async function () { 52 | await token.addWhitelisted(whitelister.address) 53 | expect(await token.hasRole(await token.WHITELISTED_ROLE(), whitelister.address)).to.equal(true); 54 | }); 55 | }); 56 | 57 | describe("Claim", function () { 58 | it("Should fail if the amount of ERB is insufficient", async function () { 59 | const ownerBalanceBefore = await ethers.provider.getBalance(owner.address); 60 | console.log(`Owner balance before: ${ethers.formatEther(ownerBalanceBefore)} ETH`); 61 | 62 | const transaction = await owner.sendTransaction({ 63 | to: whitelister.address, 64 | value: ethers.parseEther("1") 65 | }); 66 | await transaction.wait(); 67 | 68 | const receiverBalance = await ethers.provider.getBalance(whitelister.address); 69 | console.log(`Whitelister balance: ${ethers.formatEther(receiverBalance)} ETH`); 70 | 71 | 72 | await token.mint(whitelister.address, 100); 73 | await token.addWhitelisted(await whitelister.getAddress()); 74 | }); 75 | 76 | it("Should transfer the correct amount of ERB and mint L", async function () { 77 | expect(await token.balanceOf(burner.address)).to.equal(0); 78 | expect(await ethers.provider.getBalance(burner.address)).to.equal(ethers.parseEther("10000")); 79 | 80 | await token.connect(owner).claim(burner.address, 88, { value: ethers.parseEther("1") }) 81 | 82 | expect(await ethers.provider.getBalance(burner.address)).to.equal(ethers.parseEther("10001")); 83 | expect(await token.balanceOf(burner.address)).to.equal(88); 84 | // 打印totoal supply 85 | console.log(`Total supply-------: ${await token.totalSupply()}`); 86 | }); 87 | }); 88 | 89 | }); -------------------------------------------------------------------------------- /test/XLToken.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { ethers, upgrades } from "hardhat"; 3 | import { time } from "@nomicfoundation/hardhat-network-helpers"; 4 | import { XLToken } from "../typechain-types" 5 | import { MockXLTokenV2 } from "../typechain-types/contracts/mock/MockXLTokenV2.sol"; 6 | 7 | describe("XL", function () { 8 | let token: XLToken; 9 | let owner: any; 10 | let minter: any; 11 | let burner: any; 12 | let whitelister: any; 13 | let taskIncentiveAddress: any; 14 | let ecosystemFundAddress: any; 15 | let strategicFinanceAddress: any; 16 | let teamAddress: any; 17 | let marketingAddress: any; 18 | 19 | const TASK_INCENTIVE_SUPPLY = 800_000_000n * 10n ** 18n; 20 | const MARKETING_SUPPLY = 200_000_000n * 10n ** 18n; 21 | 22 | 23 | beforeEach(async function () { 24 | [owner, minter, burner, whitelister, 25 | taskIncentiveAddress, ecosystemFundAddress, 26 | strategicFinanceAddress, teamAddress, marketingAddress] = await ethers.getSigners(); 27 | const XLToken = await ethers.getContractFactory("XLToken"); 28 | 29 | 30 | token = await upgrades.deployProxy(XLToken, [owner.address, taskIncentiveAddress.address, 31 | ecosystemFundAddress.address, strategicFinanceAddress.address, 32 | teamAddress.address, marketingAddress.address]) as unknown as XLToken; 33 | await token.waitForDeployment(); 34 | 35 | console.log("XL deployed to:", await token.getAddress()); 36 | }); 37 | 38 | describe("Deployment", function () { 39 | it("Should assign the initial supply to the taskIncentiveAddress & marketingAddress", async function () { 40 | expect(await token.balanceOf(taskIncentiveAddress.address)).to.equal(TASK_INCENTIVE_SUPPLY); 41 | expect(await token.balanceOf(marketingAddress.address)).to.equal(MARKETING_SUPPLY); 42 | }); 43 | }); 44 | 45 | describe("Roles", function () { 46 | // The owner has permissions for admin, mint, burner, and whitelist simultaneously 47 | it("Should assign the admin role to the owner", async function () { 48 | expect(await token.hasRole(await token.DEFAULT_ADMIN_ROLE(), owner.address)).to.equal(true); 49 | }); 50 | 51 | it("Should assign the minter role to the minter", async function () { 52 | expect(await token.hasRole(await token.MINTER_ROLE(), owner.address)).to.equal(true); 53 | }); 54 | 55 | it("Should assign the burner role to the burner", async function () { 56 | expect(await token.hasRole(await token.BURNER_ROLE(), owner.address)).to.equal(true); 57 | }); 58 | 59 | it("Should assign the whitelister role to the whitelister", async function () { 60 | expect(await token.hasRole(await token.WHITELISTED_ROLE(), owner.address)).to.equal(true); 61 | }); 62 | 63 | // The owner authorizes Minter, who in turn has Minter's permission 64 | it("Should assign the minter role to the minter", async function () { 65 | await token.grantRole(await token.MINTER_ROLE(), minter.address); 66 | expect(await token.hasRole(await token.MINTER_ROLE(), minter.address)).to.equal(true); 67 | }); 68 | }); 69 | 70 | describe("Claim", function () { 71 | it("Should fail if the sender is not whitelisted", async function () { 72 | await expect(token.connect(minter).claim(owner.address, 100, { value: ethers.parseEther("0") })).to.be.revertedWith("XL: Caller is not whitelisted"); 73 | }); 74 | 75 | it("Should fail if the amount of ERB is insufficient", async function () { 76 | const ownerBalanceBefore = await ethers.provider.getBalance(owner.address); 77 | console.log(`Owner balance before: ${ethers.formatEther(ownerBalanceBefore)} ETH`); 78 | 79 | const transaction = await owner.sendTransaction({ 80 | to: whitelister.address, 81 | value: ethers.parseEther("1") 82 | }); 83 | await transaction.wait(); 84 | 85 | const receiverBalance = await ethers.provider.getBalance(whitelister.address); 86 | console.log(`Whitelister balance: ${ethers.formatEther(receiverBalance)} ETH`); 87 | 88 | 89 | await token.mint(whitelister.address, 100); 90 | await token.addWhitelisted(await whitelister.getAddress()); 91 | }); 92 | 93 | it("Should transfer the correct amount of ERB and mint XL", async function () { 94 | expect(await token.balanceOf(burner.address)).to.equal(0); 95 | expect(await ethers.provider.getBalance(burner.address)).to.equal(ethers.parseEther("10000")); 96 | 97 | await token.connect(owner).claim(burner.address, 100, { value: ethers.parseEther("1") }) 98 | 99 | expect(await ethers.provider.getBalance(burner.address)).to.equal(ethers.parseEther("10001")); 100 | expect(await token.balanceOf(burner.address)).to.equal(100); 101 | // 打印totoal supply 102 | console.log(`Total supply: ${await token.totalSupply()}`); 103 | }); 104 | }); 105 | 106 | 107 | describe("releaseLinear", function () { 108 | it("Should normal release in the first month", async function () { 109 | for (let i = 1; i <= 1; i++) { 110 | await time.increase(30 * 24 * 60 * 60); 111 | 112 | await token.connect(owner).releaseLinear(); 113 | 114 | const ecosystemReleased = await token.ecosystemReleased(); 115 | const strategicFinanceReleased = await token.strategicFinanceReleased(); 116 | const teamReleased = await token.teamReleased(); 117 | 118 | expect(ecosystemReleased).to.be.greaterThan(0); 119 | expect(strategicFinanceReleased).to.be.greaterThan(0); 120 | expect(teamReleased).to.be.equal(0); // Released quarterly 121 | 122 | expect(await token.balanceOf(ecosystemFundAddress.address)).to.equal(20_000_000n * 10n ** 18n); 123 | expect(await token.balanceOf(strategicFinanceAddress.address)).to.equal(27777777777777777777777777n); 124 | expect(await token.balanceOf(teamAddress.address)).to.equal(0); 125 | } 126 | }); 127 | 128 | 129 | it("Should multiple calls are invalid", async function () { 130 | await time.increase(30 * 24 * 60 * 60); 131 | for (let i = 1; i <= 4; i++) { 132 | await token.connect(owner).releaseLinear(); 133 | 134 | const ecosystemReleased = await token.ecosystemReleased(); 135 | const strategicFinanceReleased = await token.strategicFinanceReleased(); 136 | const teamReleased = await token.teamReleased(); 137 | 138 | expect(ecosystemReleased).to.be.greaterThan(0); 139 | expect(strategicFinanceReleased).to.be.greaterThan(0); 140 | expect(teamReleased).to.be.equal(0); // Released quarterly 141 | 142 | expect(await token.balanceOf(ecosystemFundAddress.address)).to.equal(20_000_000n * 10n ** 18n); 143 | expect(await token.balanceOf(strategicFinanceAddress.address)).to.equal(27777777777777777777777777n); 144 | expect(await token.balanceOf(teamAddress.address)).to.equal(0); 145 | } 146 | }); 147 | 148 | it("Should all should be released in the fifth year", async function () { 149 | for (let i = 1; i <= 60; i++) { 150 | await time.increase(30 * 24 * 60 * 60); 151 | 152 | await token.connect(owner).releaseLinear(); 153 | } 154 | 155 | const ecosystemReleased = await token.ecosystemReleased(); 156 | const strategicFinanceReleased = await token.strategicFinanceReleased(); 157 | const teamReleased = await token.teamReleased(); 158 | 159 | expect(ecosystemReleased).to.be.greaterThan(0); 160 | expect(strategicFinanceReleased).to.be.greaterThan(0); 161 | expect(teamReleased).to.be.greaterThan(0); // Released quarterly 162 | 163 | expect(await token.balanceOf(ecosystemFundAddress.address)).to.equal(1_200_000_000n * 10n ** 18n); 164 | expect(await token.balanceOf(strategicFinanceAddress.address)).to.equal(1_000_000_000n * 10n ** 18n); 165 | expect(await token.balanceOf(teamAddress.address)).to.equal(600_000_000n * 10n ** 18n); 166 | }); 167 | 168 | 169 | it("Should will not be released again after 5 years", async function () { 170 | for (let i = 1; i <= 80; i++) { 171 | await time.increase(30 * 24 * 60 * 60); 172 | 173 | await token.connect(owner).releaseLinear(); 174 | } 175 | 176 | const ecosystemReleased = await token.ecosystemReleased(); 177 | const strategicFinanceReleased = await token.strategicFinanceReleased(); 178 | const teamReleased = await token.teamReleased(); 179 | 180 | expect(ecosystemReleased).to.be.greaterThan(0); 181 | expect(strategicFinanceReleased).to.be.greaterThan(0); 182 | expect(teamReleased).to.be.greaterThan(0); // Released quarterly 183 | 184 | expect(await token.balanceOf(ecosystemFundAddress.address)).to.equal(1_200_000_000n * 10n ** 18n); 185 | expect(await token.balanceOf(strategicFinanceAddress.address)).to.equal(1_000_000_000n * 10n ** 18n); 186 | expect(await token.balanceOf(teamAddress.address)).to.equal(600_000_000n * 10n ** 18n); 187 | }); 188 | 189 | }); 190 | 191 | // 版本号是1.0.0 192 | describe("Version", function () { 193 | it("Should return version", async function () { 194 | expect(await token.getVersion()).to.equal("1.0.0"); 195 | }); 196 | }); 197 | 198 | 199 | describe("Upgrade", function () { 200 | it("Should upgrade contracts", async function () { 201 | // upgrade XLToken to XLTokenV2 202 | const XLTokenV2 = await ethers.getContractFactory("MockXLTokenV2"); 203 | token = await upgrades.upgradeProxy(await token.getAddress(), XLTokenV2) as unknown as MockXLTokenV2; 204 | console.log("XLTokenV2 deployed to:", await token.getAddress()); 205 | 206 | expect(await token.TestUpgrade()).to.equal(200); 207 | }); 208 | }); 209 | }); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "resolveJsonModule": true 10 | } 11 | } 12 | --------------------------------------------------------------------------------