├── .dockerignore ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Dockerfile ├── README.md ├── build └── contracts │ ├── ERC20.json │ ├── GitToken.json │ ├── GitTokenLib.json │ ├── GitTokenRegistry.json │ ├── Migrations.json │ ├── Ownable.json │ └── SafeMath.json ├── contracts ├── ERC20.sol ├── GitToken.sol ├── GitTokenLib.sol ├── GitTokenRegistry.sol ├── Migrations.sol ├── Ownable.sol └── SafeMath.sol ├── gittoken.config.js ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── package.json ├── test ├── test_executeBid.js ├── test_initializeAuction.js ├── test_registerToken.js ├── test_rewardContribution.js ├── test_transfer.js └── test_verifyContributor.js └── truffle.js /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | language: node_js 4 | 5 | node_js: 6 | - "7" 7 | 8 | services: 9 | - docker 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 |
5 |
6 |

GitToken Contracts Change Log

7 |
8 |
9 |

10 | 11 | --- 12 | 13 | ### DATE: *October 6, 2017* 14 | ### COMMIT: *ff0fb3f097e0edefbf4d7c4e05cd368def47bcfd* 15 | ### VERSION: *0.0.39* 16 | 17 | - Breaking Changes! Removed reward value mappings from GitTokenLib.sol 18 | - Planning to remove auction methods from GitToken.sol & GitTokenLib.sol 19 | 20 | --- 21 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:6.11.0 2 | 3 | RUN npm i -g truffle 4 | 5 | WORKDIR /gittoken-contracts 6 | 7 | ADD . . 8 | 9 | RUN npm install 10 | 11 | CMD ["truffle", "test"] 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 |
5 |
6 | 7 | 8 | 9 | 10 |
11 |
12 |

13 | 14 | # GitToken Solidity Smart Contracts 15 | 16 | - GitToken.sol 17 | - GitTokenLib.sol 18 | - GitTokenRegistry.sol 19 | - GitTokenAuction.sol (TBW) 20 | - GitTokenExchange.sol (TBW) 21 | 22 | 23 | ## GitToken.sol & GitTokenLib.sol 24 | 25 | The GitToken contracts adhere to the Ethereum ERC20 Standard Token specification. 26 | 27 | The GitToken contracts provide methods for issuing and distributing ERC20 tokens to GitHub contributors in return 28 | for contributions made toward an Organization's repository. 29 | 30 | 31 | ## GitTokenRegistry.sol 32 | 33 | The GitToken Registry maintains a public record of organizations using GitToken contracts. 34 | 35 | Additionally, any GitToken project wanting to use the GitToken Exchange contract must be registered. 36 | 37 | 38 | ## GitTokenAuction.sol (To Be Written) 39 | 40 | ## GitTokenExchange.sol (To Be Written) 41 | -------------------------------------------------------------------------------- /build/contracts/ERC20.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "ERC20", 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "inputs": [ 7 | { 8 | "name": "spender", 9 | "type": "address" 10 | }, 11 | { 12 | "name": "value", 13 | "type": "uint256" 14 | } 15 | ], 16 | "name": "approve", 17 | "outputs": [], 18 | "payable": false, 19 | "type": "function" 20 | }, 21 | { 22 | "constant": false, 23 | "inputs": [ 24 | { 25 | "name": "from", 26 | "type": "address" 27 | }, 28 | { 29 | "name": "to", 30 | "type": "address" 31 | }, 32 | { 33 | "name": "value", 34 | "type": "uint256" 35 | } 36 | ], 37 | "name": "transferFrom", 38 | "outputs": [], 39 | "payable": false, 40 | "type": "function" 41 | }, 42 | { 43 | "constant": true, 44 | "inputs": [ 45 | { 46 | "name": "who", 47 | "type": "address" 48 | } 49 | ], 50 | "name": "balanceOf", 51 | "outputs": [ 52 | { 53 | "name": "", 54 | "type": "uint256" 55 | } 56 | ], 57 | "payable": false, 58 | "type": "function" 59 | }, 60 | { 61 | "constant": false, 62 | "inputs": [ 63 | { 64 | "name": "to", 65 | "type": "address" 66 | }, 67 | { 68 | "name": "value", 69 | "type": "uint256" 70 | } 71 | ], 72 | "name": "transfer", 73 | "outputs": [], 74 | "payable": false, 75 | "type": "function" 76 | }, 77 | { 78 | "constant": true, 79 | "inputs": [ 80 | { 81 | "name": "owner", 82 | "type": "address" 83 | }, 84 | { 85 | "name": "spender", 86 | "type": "address" 87 | } 88 | ], 89 | "name": "allowance", 90 | "outputs": [ 91 | { 92 | "name": "", 93 | "type": "uint256" 94 | } 95 | ], 96 | "payable": false, 97 | "type": "function" 98 | } 99 | ], 100 | "unlinked_binary": "0x", 101 | "networks": {}, 102 | "schema_version": "0.0.5", 103 | "updated_at": 1505688288331 104 | } -------------------------------------------------------------------------------- /build/contracts/GitToken.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "GitToken", 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "inputs": [ 7 | { 8 | "name": "_initialPrice", 9 | "type": "uint256" 10 | }, 11 | { 12 | "name": "_delay", 13 | "type": "uint256" 14 | }, 15 | { 16 | "name": "_tokenLimitFactor", 17 | "type": "uint256" 18 | }, 19 | { 20 | "name": "_lockTokens", 21 | "type": "bool" 22 | } 23 | ], 24 | "name": "initializeAuction", 25 | "outputs": [ 26 | { 27 | "name": "", 28 | "type": "bool" 29 | } 30 | ], 31 | "payable": false, 32 | "type": "function" 33 | }, 34 | { 35 | "constant": true, 36 | "inputs": [], 37 | "name": "name", 38 | "outputs": [ 39 | { 40 | "name": "_name", 41 | "type": "string" 42 | } 43 | ], 44 | "payable": false, 45 | "type": "function" 46 | }, 47 | { 48 | "constant": false, 49 | "inputs": [ 50 | { 51 | "name": "_spender", 52 | "type": "address" 53 | }, 54 | { 55 | "name": "_value", 56 | "type": "uint256" 57 | } 58 | ], 59 | "name": "approve", 60 | "outputs": [ 61 | { 62 | "name": "", 63 | "type": "bool" 64 | } 65 | ], 66 | "payable": false, 67 | "type": "function" 68 | }, 69 | { 70 | "constant": true, 71 | "inputs": [], 72 | "name": "totalSupply", 73 | "outputs": [ 74 | { 75 | "name": "_supply", 76 | "type": "uint256" 77 | } 78 | ], 79 | "payable": false, 80 | "type": "function" 81 | }, 82 | { 83 | "constant": true, 84 | "inputs": [ 85 | { 86 | "name": "_username", 87 | "type": "string" 88 | } 89 | ], 90 | "name": "getContributorAddress", 91 | "outputs": [ 92 | { 93 | "name": "_contributorAddress", 94 | "type": "address" 95 | } 96 | ], 97 | "payable": false, 98 | "type": "function" 99 | }, 100 | { 101 | "constant": false, 102 | "inputs": [ 103 | { 104 | "name": "_from", 105 | "type": "address" 106 | }, 107 | { 108 | "name": "_to", 109 | "type": "address" 110 | }, 111 | { 112 | "name": "_value", 113 | "type": "uint256" 114 | } 115 | ], 116 | "name": "transferFrom", 117 | "outputs": [ 118 | { 119 | "name": "", 120 | "type": "bool" 121 | } 122 | ], 123 | "payable": false, 124 | "type": "function" 125 | }, 126 | { 127 | "constant": true, 128 | "inputs": [], 129 | "name": "organization", 130 | "outputs": [ 131 | { 132 | "name": "_organization", 133 | "type": "string" 134 | } 135 | ], 136 | "payable": false, 137 | "type": "function" 138 | }, 139 | { 140 | "constant": true, 141 | "inputs": [], 142 | "name": "decimals", 143 | "outputs": [ 144 | { 145 | "name": "_decimals", 146 | "type": "uint256" 147 | } 148 | ], 149 | "payable": false, 150 | "type": "function" 151 | }, 152 | { 153 | "constant": true, 154 | "inputs": [], 155 | "name": "getTokenLockUntilDate", 156 | "outputs": [ 157 | { 158 | "name": "_lockedUntil", 159 | "type": "uint256" 160 | } 161 | ], 162 | "payable": false, 163 | "type": "function" 164 | }, 165 | { 166 | "constant": true, 167 | "inputs": [ 168 | { 169 | "name": "_contributorAddress", 170 | "type": "address" 171 | } 172 | ], 173 | "name": "getContributorUsername", 174 | "outputs": [ 175 | { 176 | "name": "_username", 177 | "type": "string" 178 | } 179 | ], 180 | "payable": false, 181 | "type": "function" 182 | }, 183 | { 184 | "constant": false, 185 | "inputs": [ 186 | { 187 | "name": "_rewardValue", 188 | "type": "uint256" 189 | }, 190 | { 191 | "name": "_rewardType", 192 | "type": "string" 193 | } 194 | ], 195 | "name": "setRewardValue", 196 | "outputs": [ 197 | { 198 | "name": "", 199 | "type": "bool" 200 | } 201 | ], 202 | "payable": false, 203 | "type": "function" 204 | }, 205 | { 206 | "constant": true, 207 | "inputs": [ 208 | { 209 | "name": "", 210 | "type": "address" 211 | } 212 | ], 213 | "name": "owner", 214 | "outputs": [ 215 | { 216 | "name": "", 217 | "type": "bool" 218 | } 219 | ], 220 | "payable": false, 221 | "type": "function" 222 | }, 223 | { 224 | "constant": true, 225 | "inputs": [ 226 | { 227 | "name": "_holder", 228 | "type": "address" 229 | } 230 | ], 231 | "name": "balanceOf", 232 | "outputs": [ 233 | { 234 | "name": "_balance", 235 | "type": "uint256" 236 | } 237 | ], 238 | "payable": false, 239 | "type": "function" 240 | }, 241 | { 242 | "constant": true, 243 | "inputs": [ 244 | { 245 | "name": "_username", 246 | "type": "string" 247 | } 248 | ], 249 | "name": "getUnclaimedRewards", 250 | "outputs": [ 251 | { 252 | "name": "_value", 253 | "type": "uint256" 254 | } 255 | ], 256 | "payable": false, 257 | "type": "function" 258 | }, 259 | { 260 | "constant": true, 261 | "inputs": [ 262 | { 263 | "name": "_rewardType", 264 | "type": "string" 265 | }, 266 | { 267 | "name": "_reservedType", 268 | "type": "string" 269 | } 270 | ], 271 | "name": "getRewardDetails", 272 | "outputs": [ 273 | { 274 | "name": "_rewardValue", 275 | "type": "uint256" 276 | }, 277 | { 278 | "name": "_reservedValue", 279 | "type": "uint256" 280 | } 281 | ], 282 | "payable": false, 283 | "type": "function" 284 | }, 285 | { 286 | "constant": true, 287 | "inputs": [], 288 | "name": "symbol", 289 | "outputs": [ 290 | { 291 | "name": "_symbol", 292 | "type": "string" 293 | } 294 | ], 295 | "payable": false, 296 | "type": "function" 297 | }, 298 | { 299 | "constant": false, 300 | "inputs": [ 301 | { 302 | "name": "_to", 303 | "type": "address" 304 | }, 305 | { 306 | "name": "_value", 307 | "type": "uint256" 308 | } 309 | ], 310 | "name": "transfer", 311 | "outputs": [ 312 | { 313 | "name": "", 314 | "type": "bool" 315 | } 316 | ], 317 | "payable": false, 318 | "type": "function" 319 | }, 320 | { 321 | "constant": false, 322 | "inputs": [ 323 | { 324 | "name": "_auctionRound", 325 | "type": "uint256" 326 | }, 327 | { 328 | "name": "_exchangeRate", 329 | "type": "uint256" 330 | } 331 | ], 332 | "name": "executeBid", 333 | "outputs": [ 334 | { 335 | "name": "", 336 | "type": "bool" 337 | } 338 | ], 339 | "payable": true, 340 | "type": "function" 341 | }, 342 | { 343 | "constant": true, 344 | "inputs": [], 345 | "name": "getAuctionRound", 346 | "outputs": [ 347 | { 348 | "name": "", 349 | "type": "uint256" 350 | } 351 | ], 352 | "payable": false, 353 | "type": "function" 354 | }, 355 | { 356 | "constant": false, 357 | "inputs": [ 358 | { 359 | "name": "_reservedValue", 360 | "type": "uint256" 361 | }, 362 | { 363 | "name": "_rewardType", 364 | "type": "string" 365 | }, 366 | { 367 | "name": "_reservedType", 368 | "type": "string" 369 | } 370 | ], 371 | "name": "setReservedValue", 372 | "outputs": [ 373 | { 374 | "name": "", 375 | "type": "bool" 376 | } 377 | ], 378 | "payable": false, 379 | "type": "function" 380 | }, 381 | { 382 | "constant": false, 383 | "inputs": [ 384 | { 385 | "name": "_contributor", 386 | "type": "address" 387 | }, 388 | { 389 | "name": "_username", 390 | "type": "string" 391 | } 392 | ], 393 | "name": "verifyContributor", 394 | "outputs": [ 395 | { 396 | "name": "", 397 | "type": "bool" 398 | } 399 | ], 400 | "payable": false, 401 | "type": "function" 402 | }, 403 | { 404 | "constant": true, 405 | "inputs": [ 406 | { 407 | "name": "_owner", 408 | "type": "address" 409 | }, 410 | { 411 | "name": "_spender", 412 | "type": "address" 413 | } 414 | ], 415 | "name": "allowance", 416 | "outputs": [ 417 | { 418 | "name": "_allowance", 419 | "type": "uint256" 420 | } 421 | ], 422 | "payable": false, 423 | "type": "function" 424 | }, 425 | { 426 | "constant": false, 427 | "inputs": [ 428 | { 429 | "name": "_username", 430 | "type": "string" 431 | }, 432 | { 433 | "name": "_rewardType", 434 | "type": "string" 435 | }, 436 | { 437 | "name": "_reservedType", 438 | "type": "string" 439 | }, 440 | { 441 | "name": "_rewardBonus", 442 | "type": "uint256" 443 | }, 444 | { 445 | "name": "_deliveryID", 446 | "type": "string" 447 | } 448 | ], 449 | "name": "rewardContributor", 450 | "outputs": [ 451 | { 452 | "name": "", 453 | "type": "bool" 454 | } 455 | ], 456 | "payable": false, 457 | "type": "function" 458 | }, 459 | { 460 | "constant": true, 461 | "inputs": [ 462 | { 463 | "name": "auctionRound", 464 | "type": "uint256" 465 | } 466 | ], 467 | "name": "getAuctionDetails", 468 | "outputs": [ 469 | { 470 | "name": "", 471 | "type": "uint256[11]" 472 | }, 473 | { 474 | "name": "", 475 | "type": "uint256[]" 476 | }, 477 | { 478 | "name": "", 479 | "type": "uint256[]" 480 | } 481 | ], 482 | "payable": false, 483 | "type": "function" 484 | }, 485 | { 486 | "constant": false, 487 | "inputs": [ 488 | { 489 | "name": "newOwner", 490 | "type": "address" 491 | } 492 | ], 493 | "name": "transferOwnership", 494 | "outputs": [], 495 | "payable": false, 496 | "type": "function" 497 | }, 498 | { 499 | "inputs": [ 500 | { 501 | "name": "_contributor", 502 | "type": "address" 503 | }, 504 | { 505 | "name": "_name", 506 | "type": "string" 507 | }, 508 | { 509 | "name": "_username", 510 | "type": "string" 511 | }, 512 | { 513 | "name": "_organization", 514 | "type": "string" 515 | }, 516 | { 517 | "name": "_symbol", 518 | "type": "string" 519 | }, 520 | { 521 | "name": "_decimals", 522 | "type": "uint256" 523 | } 524 | ], 525 | "payable": false, 526 | "type": "constructor" 527 | }, 528 | { 529 | "payable": false, 530 | "type": "fallback" 531 | }, 532 | { 533 | "anonymous": false, 534 | "inputs": [ 535 | { 536 | "indexed": true, 537 | "name": "owner", 538 | "type": "address" 539 | }, 540 | { 541 | "indexed": true, 542 | "name": "spender", 543 | "type": "address" 544 | }, 545 | { 546 | "indexed": false, 547 | "name": "value", 548 | "type": "uint256" 549 | } 550 | ], 551 | "name": "Approval", 552 | "type": "event" 553 | }, 554 | { 555 | "anonymous": false, 556 | "inputs": [ 557 | { 558 | "indexed": true, 559 | "name": "from", 560 | "type": "address" 561 | }, 562 | { 563 | "indexed": true, 564 | "name": "to", 565 | "type": "address" 566 | }, 567 | { 568 | "indexed": false, 569 | "name": "value", 570 | "type": "uint256" 571 | } 572 | ], 573 | "name": "Transfer", 574 | "type": "event" 575 | }, 576 | { 577 | "anonymous": false, 578 | "inputs": [ 579 | { 580 | "indexed": true, 581 | "name": "contributor", 582 | "type": "address" 583 | }, 584 | { 585 | "indexed": false, 586 | "name": "username", 587 | "type": "string" 588 | }, 589 | { 590 | "indexed": false, 591 | "name": "value", 592 | "type": "uint256" 593 | }, 594 | { 595 | "indexed": false, 596 | "name": "reservedValue", 597 | "type": "uint256" 598 | }, 599 | { 600 | "indexed": false, 601 | "name": "date", 602 | "type": "uint256" 603 | }, 604 | { 605 | "indexed": false, 606 | "name": "rewardType", 607 | "type": "string" 608 | }, 609 | { 610 | "indexed": false, 611 | "name": "reservedType", 612 | "type": "string" 613 | } 614 | ], 615 | "name": "Contribution", 616 | "type": "event" 617 | }, 618 | { 619 | "anonymous": false, 620 | "inputs": [ 621 | { 622 | "indexed": true, 623 | "name": "contributor", 624 | "type": "address" 625 | }, 626 | { 627 | "indexed": false, 628 | "name": "username", 629 | "type": "string" 630 | }, 631 | { 632 | "indexed": false, 633 | "name": "date", 634 | "type": "uint256" 635 | } 636 | ], 637 | "name": "ContributorVerified", 638 | "type": "event" 639 | }, 640 | { 641 | "anonymous": false, 642 | "inputs": [ 643 | { 644 | "indexed": false, 645 | "name": "rewardType", 646 | "type": "string" 647 | }, 648 | { 649 | "indexed": false, 650 | "name": "reservedType", 651 | "type": "string" 652 | }, 653 | { 654 | "indexed": false, 655 | "name": "value", 656 | "type": "uint256" 657 | }, 658 | { 659 | "indexed": false, 660 | "name": "date", 661 | "type": "uint256" 662 | } 663 | ], 664 | "name": "RewardValueSet", 665 | "type": "event" 666 | }, 667 | { 668 | "anonymous": false, 669 | "inputs": [ 670 | { 671 | "indexed": false, 672 | "name": "auctionDetails", 673 | "type": "uint256[8]" 674 | } 675 | ], 676 | "name": "Auction", 677 | "type": "event" 678 | }, 679 | { 680 | "anonymous": false, 681 | "inputs": [ 682 | { 683 | "indexed": false, 684 | "name": "bidDetails", 685 | "type": "uint256[9]" 686 | } 687 | ], 688 | "name": "AuctionBid", 689 | "type": "event" 690 | } 691 | ], 692 | "unlinked_binary": "0x606060405234156200001057600080fd5b604051620040473803806200404783398101604052808051919060200180518201919060200180518201919060200180518201919060200180518201919060200180519150505b5b600160a060020a0333166000908152602081905260409020805460ff191660011790555b600160a060020a038616156200015457600160a060020a038616600090815260208181526040808320805460ff19166001179055600b9091529020848051620000ca92916020019062000c55565b5085600c856040518082805190602001908083835b602083106200010157805182525b601f199092019160209182019101620000df565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040519081900390208054600160a060020a031916600160a060020a03929092169190911790555b600060015560038580516200016e92916020019062000c55565b5060048380516200018492916020019062000c55565b5060058280516200019a92916020019062000c55565b5060028190556000600a6040517f6f7267616e697a6174696f6e00000000000000000000000000000000000000008152600c810191909152602c0160405180910390206040517f6d656d6265725f696e76697465640000000000000000000000000000000000008152600e810191909152602e0160405180910390208190555080600a0a613a980260016009016040517f6f7267616e697a6174696f6e00000000000000000000000000000000000000008152600c810191909152602c0160405180910390206040517f6d656d6265725f616464656400000000000000000000000000000000000000008152600c810191909152602c01604051908190039020556109c4600a82900a0260096040517f70696e6700000000000000000000000000000000000000000000000000000000815260048101919091526024016040519081900390205560fa600a82900a0260096040517f636f6d6d69745f636f6d6d656e740000000000000000000000000000000000008152600e810191909152602e01604051908190039020556109c4600a82900a0260096040517f63726561746500000000000000000000000000000000000000000000000000008152600681019190915260260160405190819003902055600060096040517f64656c65746500000000000000000000000000000000000000000000000000008152600681019190915260260160405190819003902055611388600a82900a0260096040517f6465706c6f796d656e74000000000000000000000000000000000000000000008152600a810191909152602a01604051908190039020556064600a82900a0260096040517f6465706c6f796d656e745f7374617475730000000000000000000000000000008152601181019190915260310160405190819003902055611388600a82900a0260096040517f666f726b0000000000000000000000000000000000000000000000000000000081526004810191909152602401604051908190039020556064600a82900a0260096040517f676f6c6c756d0000000000000000000000000000000000000000000000000000815260068101919091526026016040519081900390205560fa600a82900a0260096040517f696e7374616c6c6174696f6e00000000000000000000000000000000000000008152600c810191909152602c01604051908190039020556103e8600a82900a0260096040517f696e7374616c6c6174696f6e5f7265706f7369746f7269657300000000000000815260198101919091526039016040519081900390205560fa600a82900a0260096040517f69737375655f636f6d6d656e74000000000000000000000000000000000000008152600d810191909152602d01604051908190039020556101f4600a82900a0260096040517f697373756573000000000000000000000000000000000000000000000000000081526006810191909152602601604051908190039020556064600a82900a0260096040517f6c6162656c0000000000000000000000000000000000000000000000000000008152600581019190915260250160405190819003902055600060096040517f6d61726b6574706c6163655f707572636861736573000000000000000000000081526015810191909152603501604051908190039020556103e8600a82900a0260096040517f6d656d626572000000000000000000000000000000000000000000000000000081526006810191909152602601604051908190039020556103e8600a82900a0260096040517f6d656d62657273686970000000000000000000000000000000000000000000008152600a810191909152602a016040519081900390205560fa600a82900a0260096040517f6d696c6573746f6e65000000000000000000000000000000000000000000000081526009810191909152602901604051908190039020556103e8600a82900a0260096040517f6f7267616e697a6174696f6e00000000000000000000000000000000000000008152600c810191909152602c0160405190819003902055600060096040517f6f72675f626c6f636b000000000000000000000000000000000000000000000081526009810191909152602901604051908190039020556101f4600a82900a0260096040517f706167655f6275696c64000000000000000000000000000000000000000000008152600a810191909152602a016040519081900390205560fa600a82900a0260096040517f70726f6a6563745f6361726400000000000000000000000000000000000000008152600c810191909152602c01604051908190039020556032600a82900a0260096040517f70726f6a6563745f636f6c756d6e0000000000000000000000000000000000008152600e810191909152602e01604051908190039020556103e8600a82900a0260096040517f70726f6a656374000000000000000000000000000000000000000000000000008152600781019190915260270160405190819003902055612710600a82900a0260096040517f7075626c69630000000000000000000000000000000000000000000000000000815260068101919091526026016040519081900390205560fa600a82900a0260096040517f70756c6c5f726571756573745f7265766965775f636f6d6d656e7400000000008152601b810191909152603b016040519081900390205560fa600a82900a0260096040517f70756c6c5f726571756573745f7265766965770000000000000000000000000081526013810191909152603301604051908190039020556109c4600a82900a0260096040517f70756c6c5f7265717565737400000000000000000000000000000000000000008152600c810191909152602c01604051908190039020556103e8600a82900a0260096040517f707573680000000000000000000000000000000000000000000000000000000081526004810191909152602401604051908190039020556109c4600a82900a0260096040517f7265706f7369746f7279000000000000000000000000000000000000000000008152600a810191909152602a0160405190819003902055611388600a82900a0260096040517f72656c6561736500000000000000000000000000000000000000000000000000815260078101919091526027016040519081900390205560c8600a82900a0260096040517f737461747573000000000000000000000000000000000000000000000000000081526006810191909152602601604051908190039020556107d0600a82900a0260096040517f7465616d0000000000000000000000000000000000000000000000000000000081526004810191909152602401604051908190039020556107d0600a82900a0260096040517f7465616d5f61646400000000000000000000000000000000000000000000000081526008810191909152602801604051908190039020556064600a82900a0260096040517f77617463680000000000000000000000000000000000000000000000000000008152600581019190915260250160405180910390208190555080600a0a619c400260016009016040517f6d696c6573746f6e6500000000000000000000000000000000000000000000008152600981019190915260290160405180910390206040517f636c6f736564000000000000000000000000000000000000000000000000000081526006810191909152602601604051908190039020555b50505050505062000cff565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1062000c9857805160ff191683800117855562000cc8565b8280016001018555821562000cc8579182015b8281111562000cc857825182559160200191906001019062000cab565b5b5062000cd792915062000cdb565b5090565b62000cfc91905b8082111562000cd7576000815560010162000ce2565b5090565b90565b6133388062000d0f6000396000f300606060405236156101465763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166302439dde811461015957806306fdde031461018e578063095ea7b31461021957806318160ddd1461024f5780631e923ded1461027457806323b872dd146102e157806323bd4d7a1461031d578063313ce567146103a857806355d67427146103cd57806355ded44d146103f257806366253c4414610489578063666e1b39146104f357806370a082311461052657806376500a7e1461055757806392956c1e146105ba57806395d89b4114610665578063a9059cbb146106f0578063a9c7c53614610726578063b763831c14610748578063cdf25db31461076d578063d85600ca14610819578063dd62ed3e1461088c578063e9dc1a95146108c3578063f20e5e35146109f7578063f2fde38b14610ad3575b341561015157600080fd5b5b600080fd5b005b341561016457600080fd5b61017a6004356024356044356064351515610af4565b604051901515815260200160405180910390f35b341561019957600080fd5b6101a1610b96565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156101de5780820151818401525b6020016101c5565b50505050905090810190601f16801561020b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561022457600080fd5b61017a600160a060020a0360043516602435610c40565b604051901515815260200160405180910390f35b341561025a57600080fd5b610262610cf6565b60405190815260200160405180910390f35b341561027f57600080fd5b6102c560046024813581810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650610cfd95505050505050565b604051600160a060020a03909116815260200160405180910390f35b34156102ec57600080fd5b61017a600160a060020a0360043581169060243516604435610d78565b604051901515815260200160405180910390f35b341561032857600080fd5b6101a1610e0c565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156101de5780820151818401525b6020016101c5565b50505050905090810190601f16801561020b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156103b357600080fd5b610262610eb6565b60405190815260200160405180910390f35b34156103d857600080fd5b610262610ebd565b60405190815260200160405180910390f35b34156103fd57600080fd5b6101a1600160a060020a0360043516610ec4565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156101de5780820151818401525b6020016101c5565b50505050905090810190601f16801561020b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561049457600080fd5b61017a600480359060446024803590810190830135806020601f82018190048102016040519081016040528181529291906020840183838082843750949650610f9595505050505050565b604051901515815260200160405180910390f35b34156104fe57600080fd5b61017a600160a060020a03600435166110ea565b604051901515815260200160405180910390f35b341561053157600080fd5b610262600160a060020a03600435166110ff565b60405190815260200160405180910390f35b341561056257600080fd5b61026260046024813581810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965061111e95505050505050565b60405190815260200160405180910390f35b34156105c557600080fd5b61064d60046024813581810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284378201915050505050509190803590602001908201803590602001908080601f01602080910402602001604051908101604052818152929190602084018383808284375094965061118f95505050505050565b60405191825260208201526040908101905180910390f35b341561067057600080fd5b6101a16112d1565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156101de5780820151818401525b6020016101c5565b50505050905090810190601f16801561020b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156106fb57600080fd5b61017a600160a060020a036004351660243561137b565b604051901515815260200160405180910390f35b61017a6004356024356113fb565b604051901515815260200160405180910390f35b341561075357600080fd5b610262611473565b60405190815260200160405180910390f35b341561077857600080fd5b61017a600480359060446024803590810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284378201915050505050509190803590602001908201803590602001908080601f01602080910402602001604051908101604052818152929190602084018383808284375094965061147a95505050505050565b604051901515815260200160405180910390f35b341561082457600080fd5b61017a60048035600160a060020a03169060446024803590810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965061168f95505050505050565b604051901515815260200160405180910390f35b341561089757600080fd5b610262600160a060020a036004358116906024351661178a565b60405190815260200160405180910390f35b34156108ce57600080fd5b61017a60046024813581810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284378201915050505050509190803590602001908201803590602001908080601f01602080910402602001604051908101604052818152929190602084018383808284378201915050505050509190803590602001908201803590602001908080601f01602080910402602001604051908101604052818152929190602084018383808284378201915050505050509190803590602001909190803590602001908201803590602001908080601f0160208091040260200160405190810160405281815292919060208401838380828437509496506117b795505050505050565b604051901515815260200160405180910390f35b3415610a0257600080fd5b610a0d600435611b46565b604051808461016080838360005b83811015610a345780820151818401525b602001610a1b565b505050509050018060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015610a7c5780820151818401525b602001610a63565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015610abc5780820151818401525b602001610aa3565b505050509050019550505050505060405180910390f35b3415610ade57600080fd5b610157600160a060020a0360043516611ca5565b005b600160a060020a03331660009081526020819052604081205460ff161515610b1b57600080fd5b7ff2c93682ed3c2de57c1a5b8d87987bc473b3c43950036e9b69234c19b24473ea610b5060018787878763ffffffff611d2b16565b604051808261010080838360005b83811015610b775780820151818401525b602001610b5e565b5050505090500191505060405180910390a15060015b5b949350505050565b610b9e6131a6565b60038054600260001961010060018416150201909116046020601f82018190048102016040519081016040528092919081815260200182805460018160011615610100020316600290048015610c355780601f10610c0a57610100808354040283529160200191610c35565b820191906000526020600020905b815481529060010190602001808311610c1857829003601f168201915b505050505090505b90565b6000600236604414610c5157600080fd5b82158015610c825750600160a060020a033381166000908152600d6020908152604080832093881683529290522054155b1515610c8d57600080fd5b600160a060020a033381166000818152600d6020908152604080832094891680845294909152908190208690557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259086905190815260200160405180910390a35b5b5092915050565b6001545b90565b6000600c826040518082805190602001908083835b60208310610d3257805182525b601f199092019160209182019101610d12565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405190819003902054600160a060020a031690505b919050565b6007546000904211610d8957600080fd5b600336606414610d9857600080fd5b610dab600186868663ffffffff611fb916565b1515610db657600080fd5b83600160a060020a031685600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8560405190815260200160405180910390a3600191505b5b505b9392505050565b610e146131a6565b60048054600260001961010060018416150201909116046020601f82018190048102016040519081016040528092919081815260200182805460018160011615610100020316600290048015610c355780601f10610c0a57610100808354040283529160200191610c35565b820191906000526020600020905b815481529060010190602001808311610c1857829003601f168201915b505050505090505b90565b6002545b90565b6007545b90565b610ecc6131a6565b6001600a01600083600160a060020a0316600160a060020a031681526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610f885780601f10610f5d57610100808354040283529160200191610f88565b820191906000526020600020905b815481529060010190602001808311610f6b57829003601f168201915b505050505090505b919050565b600160a060020a03331660009081526020819052604081205460ff161515610fbc57600080fd5b826009836040518082805190602001908083835b60208310610ff057805182525b601f199092019160209182019101610fd0565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051908190039020557fbab878453bea46cf2222f6dd20b3fa8d80dc6ca2b5d4f854173f07227a21e1a6828442604051808060200180602001858152602001848152602001838103835286818151815260200191508051906020019080838360005b838110156110975780820151818401525b60200161107e565b50505050905090810190601f1680156110c45780820380516001836020036101000a031916815260200191505b5092830390525060008152604090810193509150505180910390a15060015b5b92915050565b60006020819052908152604090205460ff1681565b600160a060020a0381166000908152600e60205260409020545b919050565b6000600f826040518082805190602001908083835b6020831061115357805182525b601f199092019160209182019101611133565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390205490505b919050565b6000806009846040518082805190602001908083835b602083106111c557805182525b601f1990920191602091820191016111a5565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405190819003902054600a856040518082805190602001908083835b6020831061122d57805182525b601f19909201916020918201910161120d565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020846040518082805190602001908083835b6020831061129157805182525b601f199092019160209182019101611271565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902054915091505b9250929050565b6112d96131a6565b60058054600260001961010060018416150201909116046020601f82018190048102016040519081016040528092919081815260200182805460018160011615610100020316600290048015610c355780601f10610c0a57610100808354040283529160200191610c35565b820191906000526020600020905b815481529060010190602001808311610c1857829003601f168201915b505050505090505b90565b600754600090421161138c57600080fd5b61139e6001848463ffffffff61209e16565b15156113a957600080fd5b82600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405190815260200160405180910390a35060015b5b92915050565b60007f71e9115058326fa6f488debb25321c912f2e9df24f42a99f4a976822672ffee46114306001858563ffffffff61212616565b604051808261012080838360005b838110156114575780820151818401525b60200161143e565b5050505090500191505060405180910390a15060015b92915050565b6006545b90565b600160a060020a03331660009081526020819052604081205460ff1615156114a157600080fd5b83600a846040518082805190602001908083835b602083106114d557805182525b601f1990920191602091820191016114b5565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020836040518082805190602001908083835b6020831061153957805182525b601f199092019160209182019101611519565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051908190039020557fbab878453bea46cf2222f6dd20b3fa8d80dc6ca2b5d4f854173f07227a21e1a683838642604051808060200180602001858152602001848152602001838103835287818151815260200191508051906020019080838360005b838110156115e15780820151818401525b6020016115c8565b50505050905090810190601f16801561160e5780820380516001836020036101000a031916815260200191505b50838103825286818151815260200191508051906020019080838360005b838110156116455780820151818401525b60200161162c565b50505050905090810190601f1680156116725780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a15060015b5b9392505050565b600160a060020a03331660009081526020819052604081205460ff1615156116b657600080fd5b6116c86001848463ffffffff61260d16565b15156116d357600080fd5b82600160a060020a03167fce96c271d8db9db4a90e538f30d7ec5a63f116893c4636688d9ce1502b5cc93683426040518080602001838152602001828103825284818151815260200191508051906020019080838360005b838110156117445780820151818401525b60200161172b565b50505050905090810190601f1680156117715780820380516001836020036101000a031916815260200191505b50935050505060405180910390a25060015b5b92915050565b600160a060020a038083166000908152600d60209081526040808320938516835292905220545b92915050565b600160a060020a03331660009081526020819052604081205460ff1615156117de57600080fd5b6117f36001878787878763ffffffff612b9216565b15156117fe57600080fd5b600c866040518082805190602001908083835b6020831061183157805182525b601f199092019160209182019101611811565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405190819003902054600160a060020a03167f40845d10695c318fe58c5b13b891c915e95824c7439f3e860354267b1cf5c41a876119098660098a6040518082805190602001908083835b602083106118c857805182525b601f1990920191602091820191016118a8565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051908190039020549063ffffffff61301d16565b600a896040518082805190602001908083835b6020831061193c57805182525b601f19909201916020918201910161191c565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020886040518082805190602001908083835b602083106119a057805182525b601f199092019160209182019101611980565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902054428a8a6040518080602001878152602001868152602001858152602001806020018060200184810384528a818151815260200191508051906020019080838360005b83811015611a2f5780820151818401525b602001611a16565b50505050905090810190601f168015611a5c5780820380516001836020036101000a031916815260200191505b50848103835286818151815260200191508051906020019080838360005b83811015611a935780820151818401525b602001611a7a565b50505050905090810190601f168015611ac05780820380516001836020036101000a031916815260200191505b50848103825285818151815260200191508051906020019080838360005b83811015611af75780820151818401525b602001611ade565b50505050905090810190601f168015611b245780820380516001836020036101000a031916815260200191505b50995050505050505050505060405180910390a25060015b5b95945050505050565b611b4e6131b8565b611b566131a6565b611b5e6131a6565b6101606040519081016040908152600086815260086020818152838320805486526001810154828701526002810154858701526003810154606087015260048101546080870152600581015460a0870152600681015460c0870152600781015460e0870152808301546101008701526009810154610120870152600a81015461014087015292899052908152600b820180549093600c909301928492828102019051908101604052809291908181526020018280548015611c3e57602002820191906000526020600020905b815481526020019060010190808311611c2a575b5050505050915080805480602002602001604051908101604052809291908181526020018280548015611c9057602002820191906000526020600020905b815481526020019060010190808311611c7c575b505050505090509250925092505b9193909250565b600160a060020a03331660009081526020819052604090205460ff161515611ccc57600080fd5b600160a060020a03811660009081526020819052604090205460ff161515611d2657600160a060020a03808216600090815260208190526040808220805460ff199081166001179091553390931682529020805490911690555b5b5b50565b611d336131f2565b600160a060020a0330166000908152600d87016020526040812054819011611d5a57600080fd5b60008611611d6757600080fd5b600160a060020a0330166000908152600d88016020526040902054861115611d8e57600080fd5b6005870154611da490600163ffffffff61301d16565b600588015560008511611dba576203f480611dbc565b845b6005880154600081815260078a0160205260409020559050611de4428263ffffffff61301d16565b600588018054600090815260078a01602052604080822060019081019490945591548152200154611e1b908263ffffffff61301d16565b6005808901805460009081526007808c016020818152604080852060020197909755600160a060020a0330168452600d8e018152868420548554855291905285832060040155825482528482209093018a90558154815283812060060181905590548152918220015585670de0b6b3a7640000811515611e9757fe5b30600160a060020a03166000908152600d8a01602090815260408083205460058d018054855260078e019093528184209590940490930260089094019390935582548152818120600901819055915482529020600a01849055821515600114611f0857600087600601819055611f39565b60058701546000908152600788016020526040902060020154611f31908263ffffffff61301d16565b876006018190555b5061010060405190810160409081526005808a0154808452600081815260078c01602081815285832060018101548289015260028101549688019690965260068e01546060880152600486015460808801529385015460a0870152600885015460c08701529190529052600a015460e082015291505b5095945050505050565b600160a060020a038084166000908152600c86016020908152604080832033909416835292905290812054611ff4818463ffffffff61303716565b600160a060020a038087166000908152600c89016020908152604080832033851684528252808320949094559187168152600d8901909152205461203e908463ffffffff61301d16565b600160a060020a038086166000908152600d890160205260408082209390935590871681522054612075908463ffffffff61303716565b600160a060020a0386166000908152600d88016020526040902055600191505b50949350505050565b600160a060020a0333166000908152600d840160205260408120546120c9908363ffffffff61303716565b600160a060020a033381166000908152600d870160205260408082209390935590851681522054612100908363ffffffff61301d16565b600160a060020a0384166000908152600d860160205260409020555060015b9392505050565b61212e61321a565b60008381526007850160205260408120600101548190819081904290111561215557600080fd5b60008781526007890160205260409020600201544290101561217657600080fd5b60008781526007890160205260408120600801541161219457600080fd5b600034116121a157600080fd5b60008781526007890160205260409020600b018054600181016121c48382613242565b916000526020600020900160005b503490555060008781526007890160205260409020600c018054600181016121fa8382613242565b916000526020600020900160005b88909190915055506122ef886007016000898152602001908152602001600020600c0180548060200260200160405190810160405280929190818152602001828054801561227557602002820191906000526020600020905b815481526020019060010190808311612261575b50505050508960070160008a8152602001908152602001600020600b018054806020026020016040519081016040528092919081815260200182805480156122dc57602002820191906000526020600020905b8154815260200190600101908083116122c8575b505050505061304e90919063ffffffff16565b600088815260078a016020526040902060060181905586111561231157600080fd5b60008781526007890160205260409020600a8101546006909101546305f5e100909102908790031061234257600080fd5b60008781526007890160205260409020600a81015460049091015461236c9163ffffffff6130fd16565b600088815260078a016020526040902060060154909450670de0b6b3a764000081151561239557fe5b04840292508234116123a85760006123ac565b8234035b915060008211156123e857600160a060020a03331682156108fc0283604051600060405180830381858888f1935050505015156123e857600080fd5b5b81156123f557826123f7565b345b600088815260078a016020526040902060060154909150670de0b6b3a764000081151561242057fe5b048181151561242b57fe5b60058a015460009081526007808c01602052604090912001549190049450612459908263ffffffff61301d16565b600589015460009081526007808b01602052604080832090910192909255888152206008015461248f908263ffffffff61303716565b600088815260078a016020908152604080832060080193909355600160a060020a0330168252600d8b01905220546124cd908563ffffffff61303716565b600160a060020a033081166000908152600d8b016020526040808220939093553390911681522054612505908563ffffffff61301d16565b600160a060020a0333166000908152600d8a01602090815260408083209390935560058b0154825260078b0190522060040154612548908563ffffffff61303716565b6005890154600090815260078a01602052604080822060040192909255888152206009015461257e90600163ffffffff61301d16565b600088815260078a016020526040908190206009019190915561012090519081016040908152888252602080830189905260008a81526007808d01808452848320600681015495870195909552606086018a90526080860187905260a086018890529084015460c0860152908b905290526008015460e08201524261010082015294505b505050509392505050565b6000600160a060020a038316151561262457600080fd5b600084600e01836040518082805190602001908083835b6020831061265b57805182525b601f19909201916020918201910161263b565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390205411156127b85761272984600e01836040518082805190602001908083835b602083106126cd57805182525b601f1990920191602091820191016126ad565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405190819003902054600160a060020a0385166000908152600d870160205260409020549063ffffffff61301d16565b600160a060020a0384166000908152600d860160205260408082209290925590600e8601908490518082805190602001908083835b6020831061277e57805182525b601f19909201916020918201910161275e565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405190819003902055612b86565b82600160a060020a031684600b01836040518082805190602001908083835b602083106127f757805182525b601f1990920191602091820191016127d7565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405190819003902054600160a060020a0316148015906128cc5750600084600d01600086600b01856040518082805190602001908083835b6020831061287b57805182525b601f19909201916020918201910161285b565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405190819003902054600160a060020a03168152602081019190915260400160002054115b15612ac457600160a060020a0383166000908152600a8501602052604090208280516128fc92916020019061326c565b508284600b01836040518082805190602001908083835b6020831061293357805182525b601f199092019160209182019101612913565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051908190039020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055600d84016000600b8601846040518082805190602001908083835b602083106129cd57805182525b601f1990920191602091820191016129ad565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405190819003902054600160a060020a03908116825260208083019390935260409182016000908120549187168152600d8801938490528281209190915591908290600b8801908690518082805190602001908083835b60208310612a7057805182525b601f199092019160209182019101612a50565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405190819003902054600160a060020a03168152602081019190915260400160002055612b86565b600160a060020a0383166000908152600a850160205260409020828051612aef92916020019061326c565b508284600b01836040518082805190602001908083835b60208310612b2657805182525b601f199092019160209182019101612b06565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051908190039020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03929092169190911790555b5b5060015b9392505050565b600080600080612c12868b6008018a6040518082805190602001908083835b602083106118c857805182525b601f1990920191602091820191016118a8565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051908190039020549063ffffffff61301d16565b925089600901886040518082805190602001908083835b60208310612c4957805182525b601f199092019160209182019101612c29565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020876040518082805190602001908083835b60208310612cad57805182525b601f199092019160209182019101612c8d565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902054915089600b01896040518082805190602001908083835b60208310612d1857805182525b601f199092019160209182019101612cf8565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405190819003902054600160a060020a031690506000831180612d675750600082115b1515612d7257600080fd5b89600f01856040518082805190602001908083835b60208310612da757805182525b601f199092019160209182019101612d87565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040519081900390205460ff1615612de957600080fd5b8954612e0d908390612e01908663ffffffff61301d16565b9063ffffffff61301d16565b8a55600160a060020a0330166000908152600d8b016020526040902054612e3a908363ffffffff61301d16565b600160a060020a033081166000908152600d8d01602052604090209190915581161515612f4a57612edb838b600e018b6040518082805190602001908083835b602083106118c857805182525b601f1990920191602091820191016118a8565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051908190039020549063ffffffff61301d16565b8a600e018a6040518082805190602001908083835b60208310612f1057805182525b601f199092019160209182019101612ef0565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405190819003902055612f91565b600160a060020a0381166000908152600d8b016020526040902054612f75908463ffffffff61301d16565b600160a060020a0382166000908152600d8c0160205260409020555b60018a600f01866040518082805190602001908083835b60208310612fc857805182525b601f199092019160209182019101612fa8565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051908190039020805460ff1916911515919091179055600193505b5050509695505050505050565b60008282018381101561302c57fe5b8091505b5092915050565b60008282111561304357fe5b508082035b92915050565b600080600080600080600087511161306257fe5b600088511161306d57fe5b61307688613119565b945060009350600092505b86518310156130e45787838151811061309657fe5b9060200190602002015191508683815181106130ae57fe5b9060200190602002015190506130d6846130d16130cb8585613177565b886130fd565b61301d565b93505b600190920191613081565b600084116130ee57fe5b8395505b505050505092915050565b600080828481151561310b57fe5b0490508091505b5092915050565b60008060008084511161312857fe5b5060009050805b8351811015613162576131578285838151811061314857fe5b9060200190602002015161301d565b91505b60010161312f565b6000821161316c57fe5b8192505b5050919050565b6000828202831580613193575082848281151561319057fe5b04145b151561302c57fe5b8091505b5092915050565b60206040519081016040526000815290565b610160604051908101604052600b815b60008152602001906001900390816131c85790505090565b60206040519081016040526000815290565b6101006040519081016040526008815b60008152602001906001900390816131c85790505090565b6101206040519081016040526009815b60008152602001906001900390816131c85790505090565b815481835581811511613266576000838152602090206132669181019083016132eb565b5b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106132ad57805160ff19168380011785556132da565b828001600101855582156132da579182015b828111156132da5782518255916020019190600101906132bf565b5b506132e79291506132eb565b5090565b610c3d91905b808211156132e757600081556001016132f1565b5090565b905600a165627a7a723058201326a99708eb5b199e37057cfe120e11a2b3c0b754e7bb9d9092a4f0447fce410029", 693 | "networks": { 694 | "9": { 695 | "events": { 696 | "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": { 697 | "anonymous": false, 698 | "inputs": [ 699 | { 700 | "indexed": true, 701 | "name": "owner", 702 | "type": "address" 703 | }, 704 | { 705 | "indexed": true, 706 | "name": "spender", 707 | "type": "address" 708 | }, 709 | { 710 | "indexed": false, 711 | "name": "value", 712 | "type": "uint256" 713 | } 714 | ], 715 | "name": "Approval", 716 | "type": "event" 717 | }, 718 | "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": { 719 | "anonymous": false, 720 | "inputs": [ 721 | { 722 | "indexed": true, 723 | "name": "from", 724 | "type": "address" 725 | }, 726 | { 727 | "indexed": true, 728 | "name": "to", 729 | "type": "address" 730 | }, 731 | { 732 | "indexed": false, 733 | "name": "value", 734 | "type": "uint256" 735 | } 736 | ], 737 | "name": "Transfer", 738 | "type": "event" 739 | }, 740 | "0x40845d10695c318fe58c5b13b891c915e95824c7439f3e860354267b1cf5c41a": { 741 | "anonymous": false, 742 | "inputs": [ 743 | { 744 | "indexed": true, 745 | "name": "contributor", 746 | "type": "address" 747 | }, 748 | { 749 | "indexed": false, 750 | "name": "username", 751 | "type": "string" 752 | }, 753 | { 754 | "indexed": false, 755 | "name": "value", 756 | "type": "uint256" 757 | }, 758 | { 759 | "indexed": false, 760 | "name": "reservedValue", 761 | "type": "uint256" 762 | }, 763 | { 764 | "indexed": false, 765 | "name": "date", 766 | "type": "uint256" 767 | }, 768 | { 769 | "indexed": false, 770 | "name": "rewardType", 771 | "type": "string" 772 | }, 773 | { 774 | "indexed": false, 775 | "name": "reservedType", 776 | "type": "string" 777 | } 778 | ], 779 | "name": "Contribution", 780 | "type": "event" 781 | }, 782 | "0xce96c271d8db9db4a90e538f30d7ec5a63f116893c4636688d9ce1502b5cc936": { 783 | "anonymous": false, 784 | "inputs": [ 785 | { 786 | "indexed": true, 787 | "name": "contributor", 788 | "type": "address" 789 | }, 790 | { 791 | "indexed": false, 792 | "name": "username", 793 | "type": "string" 794 | }, 795 | { 796 | "indexed": false, 797 | "name": "date", 798 | "type": "uint256" 799 | } 800 | ], 801 | "name": "ContributorVerified", 802 | "type": "event" 803 | }, 804 | "0xbab878453bea46cf2222f6dd20b3fa8d80dc6ca2b5d4f854173f07227a21e1a6": { 805 | "anonymous": false, 806 | "inputs": [ 807 | { 808 | "indexed": false, 809 | "name": "rewardType", 810 | "type": "string" 811 | }, 812 | { 813 | "indexed": false, 814 | "name": "reservedType", 815 | "type": "string" 816 | }, 817 | { 818 | "indexed": false, 819 | "name": "value", 820 | "type": "uint256" 821 | }, 822 | { 823 | "indexed": false, 824 | "name": "date", 825 | "type": "uint256" 826 | } 827 | ], 828 | "name": "RewardValueSet", 829 | "type": "event" 830 | }, 831 | "0xf2c93682ed3c2de57c1a5b8d87987bc473b3c43950036e9b69234c19b24473ea": { 832 | "anonymous": false, 833 | "inputs": [ 834 | { 835 | "indexed": false, 836 | "name": "auctionDetails", 837 | "type": "uint256[8]" 838 | } 839 | ], 840 | "name": "Auction", 841 | "type": "event" 842 | }, 843 | "0x71e9115058326fa6f488debb25321c912f2e9df24f42a99f4a976822672ffee4": { 844 | "anonymous": false, 845 | "inputs": [ 846 | { 847 | "indexed": false, 848 | "name": "bidDetails", 849 | "type": "uint256[9]" 850 | } 851 | ], 852 | "name": "AuctionBid", 853 | "type": "event" 854 | } 855 | }, 856 | "links": {}, 857 | "address": "0xe87b912e97fab3bced7e7672f428086a6359eb9a", 858 | "updated_at": 1505716975895 859 | } 860 | }, 861 | "schema_version": "0.0.5", 862 | "updated_at": 1505716975895 863 | } -------------------------------------------------------------------------------- /build/contracts/GitTokenLib.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "GitTokenLib", 3 | "abi": [], 4 | "unlinked_binary": "0x60606040523415600e57600080fd5b5b603680601c6000396000f30060606040525b600080fd00a165627a7a7230582050fc5dfa876a92106a2b6012a30ff13d147cc0575c34ec4f180e7b88e3af0b3a0029", 5 | "networks": { 6 | "9": { 7 | "events": {}, 8 | "links": {}, 9 | "address": "0x3f9546fccbc7f23a17d08003a73dcbe98f5d8e99", 10 | "updated_at": 1505716975894 11 | } 12 | }, 13 | "schema_version": "0.0.5", 14 | "updated_at": 1507234651297 15 | } -------------------------------------------------------------------------------- /build/contracts/GitTokenRegistry.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "GitTokenRegistry", 3 | "abi": [ 4 | { 5 | "constant": true, 6 | "inputs": [ 7 | { 8 | "name": "", 9 | "type": "address" 10 | } 11 | ], 12 | "name": "owner", 13 | "outputs": [ 14 | { 15 | "name": "", 16 | "type": "bool" 17 | } 18 | ], 19 | "payable": false, 20 | "type": "function" 21 | }, 22 | { 23 | "constant": false, 24 | "inputs": [ 25 | { 26 | "name": "_organization", 27 | "type": "string" 28 | }, 29 | { 30 | "name": "_token", 31 | "type": "address" 32 | } 33 | ], 34 | "name": "registerToken", 35 | "outputs": [ 36 | { 37 | "name": "success", 38 | "type": "bool" 39 | } 40 | ], 41 | "payable": false, 42 | "type": "function" 43 | }, 44 | { 45 | "constant": false, 46 | "inputs": [ 47 | { 48 | "name": "newOwner", 49 | "type": "address" 50 | } 51 | ], 52 | "name": "transferOwnership", 53 | "outputs": [], 54 | "payable": false, 55 | "type": "function" 56 | }, 57 | { 58 | "inputs": [ 59 | { 60 | "name": "_owner", 61 | "type": "address" 62 | } 63 | ], 64 | "payable": false, 65 | "type": "constructor" 66 | }, 67 | { 68 | "anonymous": false, 69 | "inputs": [ 70 | { 71 | "indexed": false, 72 | "name": "_organization", 73 | "type": "string" 74 | }, 75 | { 76 | "indexed": false, 77 | "name": "_token", 78 | "type": "address" 79 | }, 80 | { 81 | "indexed": false, 82 | "name": "date", 83 | "type": "uint256" 84 | } 85 | ], 86 | "name": "Registration", 87 | "type": "event" 88 | } 89 | ], 90 | "unlinked_binary": "0x6060604052341561000f57600080fd5b6040516020806103b5833981016040528080519150505b5b600160a060020a0333166000908152602081905260409020805460ff191660011790555b6020604051016040908152600160a060020a0382166000908152602081905220805460ff191660011790555b505b61032d806100886000396000f300606060405263ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663666e1b39811461005357806369f667ed14610086578063f2fde38b146100f6575b600080fd5b341561005e57600080fd5b610072600160a060020a0360043516610117565b604051901515815260200160405180910390f35b341561009157600080fd5b61007260046024813581810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965050509235600160a060020a0316925061012c915050565b604051901515815260200160405180910390f35b341561010157600080fd5b610115600160a060020a036004351661027b565b005b60006020819052908152604090205460ff1681565b6000816001846040518082805190602001908083835b6020831061016257805182525b601f199092019160209182019101610142565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051908190039020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03929092169190911790557f9556c7df9ca896095f13e5a9d68dd39df7400ebb44dd9f952b14c4e986270ebe838342604051600160a060020a03831660208201526040810182905260608082528190810185818151815260200191508051906020019080838360005b838110156102385780820151818401525b60200161021f565b50505050905090810190601f1680156102655780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a15b92915050565b600160a060020a03331660009081526020819052604090205460ff1615156102a257600080fd5b600160a060020a03811660009081526020819052604090205460ff1615156102fc57600160a060020a03808216600090815260208190526040808220805460ff199081166001179091553390931682529020805490911690555b5b5b505600a165627a7a723058208cba08ba7e8df22798517ebf1a0d8b4a7a4c9f2abae8fab4b40e4f721205b1d20029", 91 | "networks": {}, 92 | "schema_version": "0.0.5", 93 | "updated_at": 1505688288337 94 | } -------------------------------------------------------------------------------- /build/contracts/Migrations.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "Migrations", 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "inputs": [ 7 | { 8 | "name": "new_address", 9 | "type": "address" 10 | } 11 | ], 12 | "name": "upgrade", 13 | "outputs": [], 14 | "payable": false, 15 | "type": "function" 16 | }, 17 | { 18 | "constant": true, 19 | "inputs": [], 20 | "name": "last_completed_migration", 21 | "outputs": [ 22 | { 23 | "name": "", 24 | "type": "uint256" 25 | } 26 | ], 27 | "payable": false, 28 | "type": "function" 29 | }, 30 | { 31 | "constant": true, 32 | "inputs": [], 33 | "name": "owner", 34 | "outputs": [ 35 | { 36 | "name": "", 37 | "type": "address" 38 | } 39 | ], 40 | "payable": false, 41 | "type": "function" 42 | }, 43 | { 44 | "constant": false, 45 | "inputs": [ 46 | { 47 | "name": "completed", 48 | "type": "uint256" 49 | } 50 | ], 51 | "name": "setCompleted", 52 | "outputs": [], 53 | "payable": false, 54 | "type": "function" 55 | }, 56 | { 57 | "inputs": [], 58 | "payable": false, 59 | "type": "constructor" 60 | } 61 | ], 62 | "unlinked_binary": "0x6060604052341561000f57600080fd5b5b60008054600160a060020a03191633600160a060020a03161790555b5b6101e58061003c6000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630900f010811461005e578063445df0ac1461007f5780638da5cb5b146100a4578063fdacd576146100d3575b600080fd5b341561006957600080fd5b61007d600160a060020a03600435166100eb565b005b341561008a57600080fd5b610092610182565b60405190815260200160405180910390f35b34156100af57600080fd5b6100b7610188565b604051600160a060020a03909116815260200160405180910390f35b34156100de57600080fd5b61007d600435610197565b005b6000805433600160a060020a039081169116141561017c5781905080600160a060020a031663fdacd5766001546040517c010000000000000000000000000000000000000000000000000000000063ffffffff84160281526004810191909152602401600060405180830381600087803b151561016757600080fd5b6102c65a03f1151561017857600080fd5b5050505b5b5b5050565b60015481565b600054600160a060020a031681565b60005433600160a060020a03908116911614156101b45760018190555b5b5b505600a165627a7a723058200513777b7d45afadbfddd9a39c72c1974abdfa735ca91ae97786404710561a8a0029", 63 | "networks": { 64 | "9": { 65 | "events": {}, 66 | "links": {}, 67 | "address": "0x23b761c6e8ee993df6b887d0a336be3eee0e3718", 68 | "updated_at": 1505716975894 69 | } 70 | }, 71 | "schema_version": "0.0.5", 72 | "updated_at": 1505716975894 73 | } -------------------------------------------------------------------------------- /build/contracts/Ownable.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "Ownable", 3 | "abi": [ 4 | { 5 | "constant": true, 6 | "inputs": [ 7 | { 8 | "name": "", 9 | "type": "address" 10 | } 11 | ], 12 | "name": "owner", 13 | "outputs": [ 14 | { 15 | "name": "", 16 | "type": "bool" 17 | } 18 | ], 19 | "payable": false, 20 | "type": "function" 21 | }, 22 | { 23 | "constant": false, 24 | "inputs": [ 25 | { 26 | "name": "newOwner", 27 | "type": "address" 28 | } 29 | ], 30 | "name": "transferOwnership", 31 | "outputs": [], 32 | "payable": false, 33 | "type": "function" 34 | }, 35 | { 36 | "inputs": [], 37 | "payable": false, 38 | "type": "constructor" 39 | } 40 | ], 41 | "unlinked_binary": "0x6060604052341561000f57600080fd5b5b600160a060020a0333166000908152602081905260409020805460ff191660011790555b5b6101a4806100446000396000f300606060405263ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663666e1b398114610048578063f2fde38b14610088575b600080fd5b341561005357600080fd5b61007473ffffffffffffffffffffffffffffffffffffffff600435166100b6565b604051901515815260200160405180910390f35b341561009357600080fd5b6100b473ffffffffffffffffffffffffffffffffffffffff600435166100cb565b005b60006020819052908152604090205460ff1681565b73ffffffffffffffffffffffffffffffffffffffff331660009081526020819052604090205460ff1615156100ff57600080fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526020819052604090205460ff1615156101735773ffffffffffffffffffffffffffffffffffffffff808216600090815260208190526040808220805460ff199081166001179091553390931682529020805490911690555b5b5b505600a165627a7a723058209818f3db3d9e00685b8bf2ae5aad5bf43d5f2a00ddaa433e087a512923096bf60029", 42 | "networks": {}, 43 | "schema_version": "0.0.5", 44 | "updated_at": 1505688288337 45 | } -------------------------------------------------------------------------------- /build/contracts/SafeMath.json: -------------------------------------------------------------------------------- 1 | { 2 | "contract_name": "SafeMath", 3 | "abi": [], 4 | "unlinked_binary": "0x60606040523415600e57600080fd5b5b603680601c6000396000f30060606040525b600080fd00a165627a7a7230582092e219f3a1f83b210559de1291cf1b448ec185de3a38f786b1cf59bcc7f1e7160029", 5 | "networks": {}, 6 | "schema_version": "0.0.5", 7 | "updated_at": 1507234651298 8 | } -------------------------------------------------------------------------------- /contracts/ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | /** 4 | * @title ERC20 Interface 5 | * @dev Interface version of ERC20 interface 6 | * @dev see https://github.com/ethereum/EIPs/issues/20 7 | */ 8 | contract ERC20 { 9 | function transfer(address to, uint value); 10 | function transferFrom(address from, address to, uint value); 11 | function approve(address spender, uint value); 12 | 13 | function balanceOf(address who) constant returns (uint); 14 | function allowance(address owner, address spender) constant returns (uint); 15 | } 16 | -------------------------------------------------------------------------------- /contracts/GitToken.sol: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2017 GitToken 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 19 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | pragma solidity ^0.4.11; 23 | 24 | import './SafeMath.sol'; 25 | import './GitTokenLib.sol'; 26 | import './Ownable.sol'; 27 | 28 | 29 | /** 30 | * @title GitToken Contract for distributing ERC20 tokens for Git contributions; 31 | * @author Ryan Michael Tate 32 | */ 33 | contract GitToken is Ownable { 34 | 35 | using SafeMath for uint; 36 | using GitTokenLib for GitTokenLib.Data; 37 | GitTokenLib.Data gittoken; 38 | 39 | /** 40 | * ERC20 Approval Event | Emitted when a spender is approved by an owner 41 | * @param owner address Ethereum address of owner of tokens, 42 | * @param spender address Ethereum address of approved spender of tokens, 43 | * @param value uint Number of tokens to approve spender for; 44 | */ 45 | event Approval(address indexed owner, address indexed spender, uint value); 46 | 47 | /** 48 | * ERC20 Transfer Event | Emitted when a transfer is made between accounts 49 | * @param from address Ethereum address of tokens sent from, 50 | * @param to address Ethereum address of tokens sent to, 51 | * @param value uint Number of tokens to transfer; 52 | */ 53 | event Transfer(address indexed from, address indexed to, uint value); 54 | 55 | /** 56 | * Contribution Event | Emitted when a GitHub contribution is broadcasted by web hook, 57 | * @param contributor address Ethereum address of contributor, 58 | * @param username string GitHub username of contributor, 59 | * @param rewardType string GitHub web hook event type (e.g. push, pull_request) 60 | * @param rewardValue uint Number of tokens created and distributed to contributor, 61 | * @param reservedValue uint Number of tokens created and reserved for auction, 62 | * @param date uint Unix timestamp of when the contributor was rewarded, 63 | 64 | */ 65 | event Contribution( 66 | address indexed contributor, 67 | string username, 68 | string rewardType, 69 | uint rewardValue, 70 | uint reservedValue, 71 | uint date 72 | ); 73 | 74 | /** 75 | * ContributionVerified Event | Emitted when a user verifies themselves on the UI using GitHub OAuth 76 | * @param contributor address Ethereum address of verified contributor, 77 | * @param username string GitHub username associated with contributor Ethereum address, 78 | * @param date uint Unix timestamp when user was verified; 79 | */ 80 | event ContributorVerified(address indexed contributor, string username, uint date); 81 | 82 | /* NOTE: Consider removing */ 83 | event Auction(uint[8] auctionDetails); 84 | event AuctionBid(uint[9] bidDetails); 85 | 86 | 87 | /** 88 | * @dev Constructor method for GitToken Contract, 89 | * @param _contributor address Ethereum Address of the primary contributor or organization owner, 90 | * @param _username string GitHub username of the primary contributor or organization owner, 91 | * @param _name string Name of the GitToken contract (name of organization), 92 | * @param _organization string GitHub Organization as it appears in the GitHub organization URL (e.g. https://GitHub.com/git-token), 93 | * @param _symbol string Symbol of the GitToken contract, 94 | * @param _decimals uint Number of decimal representation for token balances; 95 | */ 96 | function GitToken( 97 | address _contributor, 98 | string _username, 99 | string _name, 100 | string _organization, 101 | string _symbol, 102 | uint _decimals 103 | ) { 104 | if (_contributor != 0x0) { 105 | // Set initial contributor username & address 106 | owner[_contributor] = true; 107 | gittoken.contributorUsernames[_contributor] = _username; 108 | gittoken.contributorAddresses[_username] = _contributor; 109 | } 110 | 111 | gittoken.totalSupply = 0; 112 | gittoken.name = _name; 113 | gittoken.organization = _organization; 114 | gittoken.symbol = _symbol; 115 | gittoken.decimals = _decimals; 116 | 117 | } 118 | 119 | /** 120 | * @dev Returns the current total supply of tokens issued 121 | * @return _supply uint Supply of tokens currently issued 122 | * NOTE: Remember to adjust supply for decimals representation (e.g. supply / 10 ** decimals) 123 | */ 124 | function totalSupply() constant returns (uint _supply) { 125 | return gittoken.totalSupply; 126 | } 127 | 128 | /** 129 | * @dev Returns the number of decimal places to adjust token values 130 | * @return _decimals uint Number of decimal places 131 | * NOTE: Remember to adjust token values for decimals representation (e.g. value / 10 ** decimals) 132 | */ 133 | function decimals() constant returns (uint _decimals) { 134 | return gittoken.decimals; 135 | } 136 | 137 | /** 138 | * @dev Returns the string of the GitHub organization associated with the contract 139 | * @return _organization string GitHub organization (e.g. git-token) 140 | * NOTE: This value is used to make GitHub API calls; it must be associated with 141 | * the GitHub organization the web hook has been configured for. 142 | */ 143 | function organization() constant returns (string _organization) { 144 | return gittoken.organization; 145 | } 146 | 147 | /** 148 | * @dev Returns the string of the token contract name 149 | * @return _name string Name of the token contract 150 | */ 151 | function name() constant returns (string _name) { 152 | return gittoken.name; 153 | } 154 | 155 | /** 156 | * @dev Returns the string of the token contract symbol 157 | * @return _symbol string Symbol of the token contract 158 | */ 159 | function symbol() constant returns (string _symbol) { 160 | return gittoken.symbol; 161 | } 162 | 163 | /** 164 | * @dev ERC20 `balanceOf` Method | Returns the balance of tokens associated with the address provided 165 | * @param _holder address Ethereum address to find token balance for 166 | * @return _balance uint Value of tokens held by ethereum address 167 | */ 168 | function balanceOf(address _holder) constant returns (uint _balance) { 169 | return gittoken.balances[_holder]; 170 | } 171 | 172 | /** 173 | * @dev ERC20 `transfer` Method | Transfer tokens to account from sender account 174 | * @param _to address Ethereum address to transfer tokens to, 175 | * @param _value uint Number of tokens to transfer, 176 | * @return bool Returns boolean value if method is called 177 | */ 178 | function transfer( 179 | address _to, 180 | uint _value 181 | ) 182 | externalTokenTransfersLocked 183 | public 184 | returns (bool) 185 | { 186 | require(gittoken._transfer(_to, _value)); 187 | Transfer(msg.sender, _to, _value); 188 | return true; 189 | } 190 | 191 | /** 192 | * @dev ERC20 `transferFrom` Method | Allow approved spender (msg.sender) to transfer tokens from one account to another 193 | * @param _from address Ethereum address to move tokens from, 194 | * @param _to address Ethereum address to move tokens to, 195 | * @param _value uint Number of tokens to move between accounts, 196 | * @return bool Retrusn boolean value if method is called 197 | */ 198 | function transferFrom( 199 | address _from, 200 | address _to, 201 | uint _value 202 | ) 203 | externalTokenTransfersLocked 204 | public 205 | onlyPayloadSize(3) 206 | returns (bool) 207 | { 208 | require(gittoken._transferFrom(_from, _to, _value)); 209 | Transfer(_from, _to, _value); 210 | return true; 211 | } 212 | 213 | /** 214 | * @dev ERC20 `approve` Method | Approve spender to transfer an amount of 215 | * tokens on behalf of another account 216 | * @param _spender address Ethereum address of spender to approve, 217 | * @param _value uint Number of tokens to approve spender to transfer, 218 | * @return bool Returns boolean value is method is called; 219 | * NOTE: Explicitly check if the approved address already has an allowance, 220 | * Ensure the approver must reset the approved value to 0 before changing to the desired amount. 221 | * see: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 222 | */ 223 | function approve( 224 | address _spender, 225 | uint _value 226 | ) 227 | public 228 | onlyPayloadSize(2) 229 | returns (bool) 230 | { 231 | require(_value == 0 && gittoken.allowed[msg.sender][_spender] == 0); 232 | gittoken.allowed[msg.sender][_spender] = _value; 233 | Approval(msg.sender, _spender, _value); 234 | } 235 | 236 | /** 237 | * @dev ERC20 `allowance` Method | Check the spender allowance for a token owner 238 | * @param _owner address Ethereum address of token owner, 239 | * @param _spender address Ethereum address of spender, 240 | * @return _allowance uint Number of tokens allowed by the owner to be 241 | * moved by the spender 242 | */ 243 | function allowance(address _owner, address _spender) constant returns (uint _allowance) { 244 | return gittoken.allowed[_owner][_spender]; 245 | } 246 | 247 | 248 | /** 249 | * @dev Verify contributor Ethereum address associated with GitHub username 250 | * @param _contributor address Ethereum address of GitHub organization contributor, 251 | * @param _username string GitHub username of contributor, 252 | * @return bool Returns boolean value if method is called; 253 | */ 254 | function verifyContributor( 255 | address _contributor, 256 | string _username 257 | ) 258 | onlyOwner 259 | public 260 | returns (bool) 261 | { 262 | require(gittoken._verifyContributor(_contributor, _username)); 263 | ContributorVerified(_contributor, _username, now); 264 | return true; 265 | } 266 | 267 | /** 268 | * @dev Reward contributor when a GitHub web hook event is received 269 | * @param _username string GitHub username of contributor 270 | * @param _rewardType string GitHub Event Reward Type 271 | * @param _rewardValue uint Number of tokens rewarded to contributor 272 | * @param _reservedValue uint Number of tokens reserved for auction 273 | * @param _deliveryID string GitHub delivery ID of web hook request 274 | * @return bool Returns boolean value if method is called 275 | */ 276 | function rewardContributor( 277 | string _username, 278 | string _rewardType, 279 | uint _rewardValue, 280 | uint _reservedValue, 281 | string _deliveryID 282 | ) 283 | onlyOwner 284 | public 285 | returns (bool) { 286 | require(gittoken._rewardContributor(_username, _rewardValue, _reservedValue, _deliveryID)); 287 | Contribution( 288 | gittoken.contributorAddresses[_username], 289 | _username, 290 | _rewardType, 291 | _rewardValue, 292 | _reservedValue, 293 | now 294 | ); 295 | 296 | return true; 297 | } 298 | 299 | /** 300 | * @dev Initialize Auction & broadcast a NewAuction event 301 | * @param _initialPrice uint Token/ETH Exchange Rate (#Tokens / 1 ETH); adjusted for decimal representation; 302 | * @param _delay uint Time in milliseconds to delay each auction period (I - Pre, II - Start, III - End, IV - Post), 303 | * Must be greater than 86400 (1 day in unix time) 304 | * @param _lockTokens bool Boolean value to optionally lock all token transfers until the Post auction date. 305 | * @return bool Returns Boolean value if called from another contract; 306 | */ 307 | function initializeAuction( 308 | uint _initialPrice, 309 | uint _delay, 310 | uint _tokenLimitFactor, 311 | bool _lockTokens 312 | ) onlyOwner public returns (bool) { 313 | Auction(gittoken._initializeAuction(_initialPrice, _delay, _tokenLimitFactor, _lockTokens)); 314 | return true; 315 | } 316 | 317 | function executeBid( 318 | uint _auctionRound, 319 | uint _exchangeRate 320 | ) payable public returns (bool) { 321 | AuctionBid(gittoken._executeBid(_auctionRound, _exchangeRate)); 322 | return true; 323 | } 324 | 325 | function getAuctionRound() constant returns (uint) { 326 | return gittoken.auctionRound; 327 | } 328 | 329 | function getAuctionDetails(uint auctionRound) constant returns(uint[11], uint[], uint[]) { 330 | return ([ 331 | gittoken.auctionDetails[auctionRound].round, 332 | gittoken.auctionDetails[auctionRound].startDate, 333 | gittoken.auctionDetails[auctionRound].endDate, 334 | gittoken.auctionDetails[auctionRound].lockDate, 335 | gittoken.auctionDetails[auctionRound].tokensOffered, 336 | gittoken.auctionDetails[auctionRound].initialPrice, 337 | gittoken.auctionDetails[auctionRound].wtdAvgExRate, 338 | gittoken.auctionDetails[auctionRound].fundsCollected, 339 | gittoken.auctionDetails[auctionRound].fundLimit, 340 | gittoken.auctionDetails[auctionRound].numBids, 341 | gittoken.auctionDetails[auctionRound].tokenLimitFactor 342 | ], 343 | gittoken.auctionDetails[auctionRound].ethValues, 344 | gittoken.auctionDetails[auctionRound].exRateValues 345 | ); 346 | } 347 | 348 | 349 | /** 350 | * @dev Get Ethereum address associated with contributor's GitHub username 351 | * @param _username string GitHub username of the contributor, 352 | * @return _contributorAddress address Ethereum address of the contributor associated 353 | * passed in GitHub username; 354 | */ 355 | function getContributorAddress(string _username) constant returns (address _contributorAddress) { 356 | return gittoken.contributorAddresses[_username]; 357 | } 358 | 359 | /** 360 | * @dev Get GitHub username from contributor's Ethereum address 361 | * @param _contributorAddress address Ethereum address of contributor, 362 | * @return _username string GitHub username associated with contributor address; 363 | */ 364 | function getContributorUsername(address _contributorAddress) constant returns (string _username) { 365 | return gittoken.contributorUsernames[_contributorAddress]; 366 | } 367 | 368 | /** 369 | * @dev Get the date timestamp of when tokens are locked until 370 | * @return _lockedUntil uint Timestamp of when tokens are locked until 371 | */ 372 | function getTokenLockUntilDate() constant returns (uint _lockedUntil) { 373 | return gittoken.lockTokenTransfersUntil; 374 | } 375 | 376 | /** 377 | * @dev Get unclaimed (pre-verified) rewards associated with GitHub username 378 | * @param _username string GitHub username of contributor, 379 | * @return _value uint Number of tokens issued to GitHub username 380 | */ 381 | function getUnclaimedRewards(string _username) constant returns (uint _value) { 382 | return gittoken.unclaimedRewards[_username]; 383 | } 384 | 385 | function () { 386 | revert(); 387 | } 388 | 389 | /** 390 | * @dev This modifier checks the data length to ensure that it matches the padded 391 | * length of the input data provided to the method. 392 | */ 393 | modifier onlyPayloadSize(uint inputLength) { 394 | require(msg.data.length == inputLength * 32 + 4); 395 | _; 396 | } 397 | 398 | /** 399 | * @dev Disallow external token transfers if the current timestamp is less 400 | * than the `lockTokenTransfersUntil` date. 401 | * NOTE: Use `getTokenLockUntilDate` method to check date and mitigate 402 | * cost of gas throwing; 403 | */ 404 | modifier externalTokenTransfersLocked() { 405 | require(now > gittoken.lockTokenTransfersUntil); 406 | _; 407 | } 408 | 409 | 410 | } 411 | -------------------------------------------------------------------------------- /contracts/GitTokenLib.sol: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2017 GitToken 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 19 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | pragma solidity ^0.4.11; 23 | 24 | import './SafeMath.sol'; 25 | /** 26 | * @title GitTokenLib Library for implementing GitToken contract methods 27 | * @author Ryan Michael Tate 28 | */ 29 | library GitTokenLib { 30 | 31 | using SafeMath for uint; 32 | using SafeMath for uint[]; 33 | 34 | struct Auction { 35 | uint round; 36 | uint startDate; 37 | uint endDate; 38 | uint lockDate; 39 | uint tokensOffered; 40 | uint initialPrice; 41 | uint wtdAvgExRate; 42 | uint fundsCollected; 43 | uint fundLimit; 44 | uint numBids; 45 | uint tokenLimitFactor; 46 | uint[] ethValues; 47 | uint[] exRateValues; 48 | } 49 | 50 | /** 51 | * @dev Data Solidity struct for data storage reference 52 | * @notice totalSupply uint Total supply of tokens issued; 53 | * @notice decimals uint Decimal representation of token values; 54 | * @notice name string Name of token; 55 | * @notice organization string GitHub organization name; 56 | * @notice symbol string Symbol of token; 57 | * @notice rewardValues mapping(string => uint256) Mapping of GitHub web hook 58 | * events to reward values; 59 | * @notice reservedValues mapping(string => mapping(string => uint256)) Double 60 | * mapping of GitHub web hook events and subtypes to reward values; 61 | * @notice contributorUsernames mapping(address => string) Mapping of Ethereum 62 | * addresses to GitHub usernames; 63 | * @notice contributorAddresses mapping(string => address) Mapping of GitHub 64 | * usernames to Ethereum addresses; 65 | * @notice allowed mapping(address => mapping(address => uint)) Double mapping 66 | *of Ethereum address to address of spender of an uint amount of tokens; 67 | * @notice balances mapping(address => uint) Mapping of Ethereum address to an 68 | * amount of tokens held; 69 | * @notice unclaimedRewards mapping(string => uint) Mapping of GitHub usernames 70 | * unclaimed (pre-verified) amount of tokens; 71 | * @notice receivedDelivery mapping(string => bool) Mapping of GitHub delivery 72 | * web hook IDs to boolean values; used to prevent/mitigate replay attack risk; 73 | */ 74 | struct Data { 75 | uint totalSupply; 76 | uint decimals; 77 | string name; 78 | string organization; 79 | string symbol; 80 | uint auctionRound; 81 | uint lockTokenTransfersUntil; 82 | mapping(uint => Auction) auctionDetails; 83 | mapping(address => string) contributorUsernames; 84 | mapping(string => address) contributorAddresses; 85 | mapping(address => mapping(address => uint)) allowed; 86 | mapping(address => uint) balances; 87 | mapping(string => uint) unclaimedRewards; 88 | mapping(string => bool) receivedDelivery; 89 | } 90 | 91 | 92 | /** 93 | * @dev Internal transfer method for GitToken ERC20 transfer method 94 | * @param self Data Use the Data struct as the contract storage and reference 95 | * @param _to address Ethereum address of account to transfer tokens to 96 | * @param _value uint Amount of tokens to transfer 97 | * @return bool Returns boolean value when called from the parent contract; 98 | */ 99 | function _transfer(Data storage self, address _to, uint _value) internal returns (bool) { 100 | self.balances[msg.sender] = self.balances[msg.sender].sub(_value); 101 | self.balances[_to] = self.balances[_to].add(_value); 102 | return true; 103 | } 104 | 105 | /** 106 | * @dev Internal transferFrom method for GitToken ERC20 transfer method 107 | * @param self Data Use the Data struct as the contract storage and reference 108 | * @param _from address Ethereum address to move tokens from, 109 | * @param _to address Ethereum address to move tokens to, 110 | * @param _value uint Number of tokens to move between accounts, 111 | * @return bool Returns boolean value when called from the parent contract; 112 | */ 113 | function _transferFrom( 114 | Data storage self, 115 | address _from, 116 | address _to, 117 | uint _value 118 | ) internal returns (bool) { 119 | // Check if msg.sender has sufficient allowance; 120 | // Check is handled by SafeMath library _allowance.sub(_value); 121 | uint _allowance = self.allowed[_from][msg.sender]; 122 | self.allowed[_from][msg.sender] = _allowance.sub(_value); 123 | 124 | // Update balances 125 | self.balances[_to] = self.balances[_to].add(_value); 126 | self.balances[_from] = self.balances[_from].sub(_value); 127 | 128 | return true; 129 | } 130 | 131 | /** 132 | * @dev Internal rewardContributor method for GitToken contract rewardContributor method 133 | * @param self Data Use the Data struct as the contract storage and reference 134 | * @param _username string GitHub username of contributor 135 | * @param _rewardValue uint Number of tokens rewarded to contributor 136 | * @param _reservedValue uint Number of tokens reserved for auction 137 | * @param _deliveryID string GitHub delivery ID of web hook request 138 | * @return bool Returns boolean value when called from the parent contract; 139 | */ 140 | function _rewardContributor ( 141 | Data storage self, 142 | string _username, 143 | uint _rewardValue, 144 | uint _reservedValue, 145 | string _deliveryID 146 | ) internal returns (bool) { 147 | 148 | // Get the contributor Ethereum address from GitHub username 149 | address _contributor = self.contributorAddresses[_username]; 150 | 151 | // If no value is created, then throw the transaction; 152 | require(_rewardValue > 0 || _reservedValue > 0); 153 | 154 | // If the GitHub web hook event ID has already occured, then throw the transaction; 155 | require(self.receivedDelivery[_deliveryID] == false); 156 | // Update totalSupply with the added values created, including the reserved supply for auction; 157 | self.totalSupply = self.totalSupply.add(_rewardValue).add(_reservedValue); 158 | 159 | // Add to the balance of reserved tokens held for auction by the contract 160 | self.balances[address(this)] = self.balances[address(this)].add(_reservedValue); 161 | 162 | // If the contributor is not yet verified, increase the unclaimed rewards for the user until the user verifies herself/himself; 163 | if (_contributor == 0x0){ 164 | self.unclaimedRewards[_username] = self.unclaimedRewards[_username].add(_rewardValue); 165 | } else { 166 | // If the contributor's address is set, update the contributor's balance; 167 | self.balances[_contributor] = self.balances[_contributor].add(_rewardValue); 168 | } 169 | 170 | // Set the received deliveries for this event to true to prevent/mitigate event replay attacks; 171 | self.receivedDelivery[_deliveryID] = true; 172 | 173 | // Return true to parent contract 174 | return true; 175 | } 176 | 177 | /** 178 | * @dev Internal method for GitToken contract verifyContributor method 179 | * @param self Data Use the Data struct as the contract storage and reference 180 | * @param _contributor address Ethereum address of GitHub organization contributor, 181 | * @param _username string GitHub username of contributor, 182 | * @return bool Returns boolean value when called from the parent contract; 183 | */ 184 | function _verifyContributor( 185 | Data storage self, 186 | address _contributor, 187 | string _username 188 | ) internal returns (bool) { 189 | 190 | // If the contributor address does not exist, then throw the transaction 191 | require(_contributor != 0x0); 192 | 193 | if (self.unclaimedRewards[_username] > 0) { 194 | // Transfer all previously unclaimed rewards of an username to an address; 195 | // Add to existing balance in case contributor has multiple usernames 196 | self.balances[_contributor] = self.balances[_contributor].add(self.unclaimedRewards[_username]); 197 | self.unclaimedRewards[_username] = 0; 198 | } else if ( 199 | self.contributorAddresses[_username] != _contributor && 200 | self.balances[self.contributorAddresses[_username]] > 0 201 | ) { 202 | // Update the contributor address for the user 203 | self.contributorUsernames[_contributor] = _username; 204 | self.contributorAddresses[_username] = _contributor; 205 | 206 | // if the user switches his/her registered account to another account, 207 | // the balance of the prior account should be moved to the new account 208 | self.balances[_contributor] = self.balances[self.contributorAddresses[_username]]; 209 | 210 | // Set the balance of the prior account to 0 after moving the balance; 211 | self.balances[self.contributorAddresses[_username]] = 0; 212 | } else { 213 | // establish username and address with contract; 214 | self.contributorUsernames[_contributor] = _username; 215 | self.contributorAddresses[_username] = _contributor; 216 | } 217 | return true; 218 | } 219 | 220 | /** 221 | * @dev Internal Initialize Auction 222 | * @param _initialPrice uint Token/ETH Exchange Rate (#Tokens / 1 ETH) 223 | * @param _delay uint Time in milliseconds to delay each auction period (I - Pre, II - Start, III - End, IV - Post) 224 | * @param _lockTokens bool Boolean value to optionally lock all token transfers until the Post auction date. 225 | * @return uint[8] AuctionData 226 | */ 227 | function _initializeAuction( 228 | Data storage self, 229 | uint _initialPrice, 230 | uint _delay, 231 | uint _tokenLimitFactor, 232 | bool _lockTokens 233 | ) internal returns(uint[8]) { 234 | // Ensure the contract has enough tokens to move to auction; 235 | 236 | require(self.balances[address(this)] > 0); 237 | require(_initialPrice > 0); 238 | require(_initialPrice <= self.balances[address(this)]); 239 | 240 | self.auctionRound = self.auctionRound.add(1); 241 | 242 | /*uint delay = _delay > 60*60*24 ? _delay : 60*60*24*3;*/ 243 | uint delay = _delay > 0 ? _delay : 60*60*24*3; 244 | self.auctionDetails[self.auctionRound].round = self.auctionRound; 245 | self.auctionDetails[self.auctionRound].startDate = now.add(delay); 246 | self.auctionDetails[self.auctionRound].endDate = self.auctionDetails[self.auctionRound].startDate.add(delay); 247 | self.auctionDetails[self.auctionRound].tokensOffered = self.balances[address(this)]; 248 | self.auctionDetails[self.auctionRound].initialPrice = _initialPrice; 249 | self.auctionDetails[self.auctionRound].wtdAvgExRate = 0; 250 | self.auctionDetails[self.auctionRound].fundsCollected = 0; 251 | self.auctionDetails[self.auctionRound].fundLimit = self.balances[address(this)] * (10**18 / _initialPrice); 252 | self.auctionDetails[self.auctionRound].numBids = 0; 253 | self.auctionDetails[self.auctionRound].tokenLimitFactor = _tokenLimitFactor; 254 | 255 | _lockTokens == true ? 256 | self.lockTokenTransfersUntil = self.auctionDetails[self.auctionRound].endDate.add(delay) : 257 | self.lockTokenTransfersUntil = 0; 258 | 259 | return ([ 260 | self.auctionRound, 261 | self.auctionDetails[self.auctionRound].startDate, 262 | self.auctionDetails[self.auctionRound].endDate, 263 | self.lockTokenTransfersUntil, 264 | self.auctionDetails[self.auctionRound].tokensOffered, 265 | self.auctionDetails[self.auctionRound].initialPrice, 266 | self.auctionDetails[self.auctionRound].fundLimit, 267 | self.auctionDetails[self.auctionRound].tokenLimitFactor 268 | ]); 269 | } 270 | 271 | 272 | 273 | /** 274 | * @dev Internal 275 | */ 276 | function _executeBid( 277 | Data storage self, 278 | uint _auctionRound, 279 | uint _exRate 280 | ) internal returns (uint[9] bidData) { 281 | require(self.auctionDetails[_auctionRound].startDate <= now); 282 | require(self.auctionDetails[_auctionRound].endDate >= now); 283 | require(self.auctionDetails[_auctionRound].fundLimit > 0); 284 | require(msg.value > 0); 285 | 286 | self.auctionDetails[_auctionRound].ethValues.push(msg.value); 287 | self.auctionDetails[_auctionRound].exRateValues.push(_exRate); 288 | 289 | self.auctionDetails[_auctionRound].wtdAvgExRate = 290 | self.auctionDetails[_auctionRound].ethValues.wtdAvg( 291 | self.auctionDetails[_auctionRound].exRateValues 292 | ); 293 | 294 | require(_exRate <= self.auctionDetails[_auctionRound].wtdAvgExRate); 295 | 296 | require( 297 | (self.auctionDetails[_auctionRound].wtdAvgExRate - _exRate) < self.auctionDetails[_auctionRound].tokenLimitFactor * 10**8 298 | ); 299 | 300 | uint _adjTokens = self.auctionDetails[_auctionRound].tokensOffered.div(self.auctionDetails[_auctionRound].tokenLimitFactor); 301 | uint adjEth = _adjTokens * (10**18 / self.auctionDetails[_auctionRound].wtdAvgExRate); 302 | uint refundAmount = msg.value > adjEth ? msg.value - adjEth : 0; 303 | 304 | if (refundAmount > 0) { msg.sender.transfer(refundAmount); } 305 | 306 | uint _ethPaid = refundAmount == 0 ? msg.value : adjEth; 307 | 308 | _adjTokens = _ethPaid / (10**18 / self.auctionDetails[_auctionRound].wtdAvgExRate); 309 | 310 | self.auctionDetails[self.auctionRound].fundsCollected = 311 | self.auctionDetails[self.auctionRound].fundsCollected.add(_ethPaid); 312 | 313 | self.auctionDetails[_auctionRound].fundLimit = 314 | self.auctionDetails[_auctionRound].fundLimit.sub(_ethPaid); 315 | 316 | self.balances[address(this)] = self.balances[address(this)].sub(_adjTokens); 317 | self.balances[msg.sender] = self.balances[msg.sender].add(_adjTokens); 318 | 319 | self.auctionDetails[self.auctionRound].tokensOffered = 320 | self.auctionDetails[self.auctionRound].tokensOffered.sub(_adjTokens); 321 | 322 | self.auctionDetails[_auctionRound].numBids = 323 | self.auctionDetails[_auctionRound].numBids.add(1); 324 | 325 | 326 | return ([ 327 | _auctionRound, 328 | _exRate, 329 | self.auctionDetails[_auctionRound].wtdAvgExRate, 330 | _adjTokens, 331 | _ethPaid, 332 | refundAmount, 333 | self.auctionDetails[_auctionRound].fundsCollected, 334 | self.auctionDetails[_auctionRound].fundLimit, 335 | now 336 | ]); 337 | } 338 | 339 | } 340 | -------------------------------------------------------------------------------- /contracts/GitTokenRegistry.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | import './Ownable.sol'; 4 | 5 | contract GitTokenRegistry is Ownable { 6 | 7 | struct Registry { 8 | mapping(string => address) organizations; 9 | } 10 | 11 | Registry registry; 12 | 13 | event Registration(string _organization, address _token, uint date); 14 | 15 | function GitTokenRegistry(address _owner) { 16 | registry = Registry({}); 17 | owner[_owner] = true; 18 | } 19 | 20 | function registerToken(string _organization, address _token) returns (bool success) { 21 | registry.organizations[_organization] = _token; 22 | Registration(_organization, _token, now); 23 | return success; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.4; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | modifier restricted() { 8 | if (msg.sender == owner) _; 9 | } 10 | 11 | function Migrations() { 12 | owner = msg.sender; 13 | } 14 | 15 | function setCompleted(uint completed) restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contracts/Ownable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | /** 5 | * @title Ownable 6 | * @dev The Ownable contract has an owner address, and provides basic authorization control 7 | * functions, this simplifies the implementation of "user permissions". 8 | */ 9 | contract Ownable { 10 | mapping(address => bool) public owner; 11 | 12 | 13 | /** 14 | * @dev The Ownable constructor sets the original `owner` of the contract to the sender 15 | * account. 16 | */ 17 | function Ownable() { 18 | owner[msg.sender] = true; 19 | } 20 | 21 | 22 | /** 23 | * @dev Throws if called by any account other than the owner. 24 | */ 25 | modifier onlyOwner() { 26 | require(owner[msg.sender]); 27 | _; 28 | } 29 | 30 | 31 | /** 32 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 33 | * @param newOwner The address to transfer ownership to. 34 | */ 35 | function transferOwnership(address newOwner) onlyOwner { 36 | if (!owner[newOwner]) { 37 | owner[newOwner] = true; 38 | owner[msg.sender] = false; 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /contracts/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | /** 4 | * Math operations with safety checks 5 | */ 6 | library SafeMath { 7 | function mul(uint a, uint b) internal returns (uint) { 8 | uint c = a * b; 9 | assert(a == 0 || c / a == b); 10 | return c; 11 | } 12 | 13 | function div(uint a, uint b) internal returns (uint) { 14 | // assert(b > 0); // Solidity automatically throws when dividing by 0 15 | uint c = a / b; 16 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 17 | return c; 18 | } 19 | 20 | function sub(uint a, uint b) internal returns (uint) { 21 | assert(b <= a); 22 | return a - b; 23 | } 24 | 25 | function add(uint a, uint b) internal returns (uint) { 26 | uint c = a + b; 27 | assert(c >= a); 28 | return c; 29 | } 30 | 31 | function max64(uint64 a, uint64 b) internal constant returns (uint64) { 32 | return a >= b ? a : b; 33 | } 34 | 35 | function min64(uint64 a, uint64 b) internal constant returns (uint64) { 36 | return a < b ? a : b; 37 | } 38 | 39 | function max256(uint256 a, uint256 b) internal constant returns (uint256) { 40 | return a >= b ? a : b; 41 | } 42 | 43 | function min256(uint256 a, uint256 b) internal constant returns (uint256) { 44 | return a < b ? a : b; 45 | } 46 | 47 | function sum(uint[] _values) internal constant returns (uint) { 48 | assert(_values.length > 0); 49 | uint s = 0; 50 | for (uint i = 0; i < _values.length; i++) { 51 | s = add(s, _values[i]); 52 | } 53 | assert(s > 0); 54 | return s; 55 | } 56 | 57 | function wtdAvg(uint[] _weights, uint[] _values) internal constant returns (uint) { 58 | 59 | assert(_values.length > 0); 60 | assert(_weights.length > 0); 61 | 62 | uint s = sum(_weights); 63 | uint m = 0; 64 | 65 | for (uint i = 0; i < _values.length; i++) { 66 | uint w = _weights[i]; 67 | uint x = _values[i]; 68 | m = add(m, div(mul(w, x), s)); 69 | } 70 | 71 | assert(m > 0); 72 | return m; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /gittoken.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * NOTE CHANGE THE FOLLOWING CONFIGURATIONS FOR YOUR PROJECT 3 | */ 4 | 5 | module.exports = { 6 | contributorAddress: '0x48299b423342db084b49d97c8b09392f6156cdc7', 7 | /* NOTE Email is case sensitive, and saved as a string in the contract */ 8 | username: 'Ryanmtate', 9 | // Name of Token 10 | name: 'GitToken', 11 | // organization is your github organization url 12 | organization: 'git-token', 13 | // symbol is the desired symbol for your ERC20-compatible GitToken 14 | symbol: 'GTK', 15 | decimals: 8 16 | } 17 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | const GitTokenLib = artifacts.require('./GitTokenLib.sol'); 2 | const GitToken = artifacts.require('./GitToken.sol'); 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(GitTokenLib); 6 | deployer.link(GitTokenLib, GitToken); 7 | deployer.deploy( 8 | GitToken, 9 | "0x8da299e2184ea12624cd588006e24a78f2f90594", 10 | "GitToken", 11 | "ryanmtate", 12 | "git-token", 13 | "GTK", 14 | 8 15 | ) 16 | }; 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gittoken-contracts", 3 | "version": "0.0.39", 4 | "description": "GitToken Solidity Smart Contracts", 5 | "main": "", 6 | "scripts": { 7 | "test": "truffle test", 8 | "build": "truffle build", 9 | "deploy": "rm -rf ./build/* && truffle migrate --reset" 10 | }, 11 | "devDependencies": { 12 | "babel-core": "^6.24.1", 13 | "babel-loader": "^7.0.0", 14 | "babel-plugin-inline-import": "^2.0.5", 15 | "babel-plugin-transform-runtime": "^6.23.0", 16 | "babel-preset-env": "^1.5.1", 17 | "babel-preset-react": "^6.24.1", 18 | "babel-preset-stage-0": "^6.24.1", 19 | "babel-runtime": "^6.23.0", 20 | "chai": "^4.1.1" 21 | }, 22 | "keywords": [ 23 | "GitToken", 24 | "Ethereum", 25 | "ERC20", 26 | "GitHub", 27 | "Git" 28 | ], 29 | "author": "GitToken", 30 | "license": "MIT", 31 | "dependencies": { 32 | "bluebird": "^3.5.0", 33 | "ethereumjs-testrpc": "^4.1.3", 34 | "truffle": "^3.4.11", 35 | "web3": "^0.19.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/test_executeBid.js: -------------------------------------------------------------------------------- 1 | // TODO Refactor this test for the GitTokenAuction contract 2 | 3 | 4 | // var GitToken = artifacts.require("./GitToken.sol"); 5 | // var Promise = require("bluebird") 6 | // const { contributorAddress, username, name, organization, symbol, decimals } = require('../gittoken.config') 7 | // const { networks: { development: { host, port } } } = require('../truffle.js'); 8 | // 9 | // var Web3 = require('web3') 10 | // var web3 = new Web3(new Web3.providers.HttpProvider(`http://${host}:${port}`)) 11 | // 12 | // function initContract() { 13 | // return new Promise((resolve, reject) => { 14 | // GitToken.new( 15 | // contributorAddress, 16 | // username, 17 | // name, 18 | // organization, 19 | // symbol, 20 | // decimals 21 | // ).then(function(gittoken) { 22 | // resolve(gittoken) 23 | // }).catch(function(error) { 24 | // reject(error) 25 | // }) 26 | // }) 27 | // } 28 | // 29 | // contract('GitToken', function(accounts) { 30 | // describe('GitToken::executeBid', function() { 31 | // 32 | // it("Should create a reserved supply of tokens, initialize a new auction, and execute a bid.", function() { 33 | // var gittoken; 34 | // var auctionRound; 35 | // var startDate; 36 | // var endDate; 37 | // var tokensOffered; 38 | // var initialExRate; 39 | // var fundLimit; 40 | // var fundsCollected; 41 | // 42 | // var exRate; 43 | // var wtdAvgExRate; 44 | // var tokensTransferred; 45 | // var etherPaid; 46 | // var refundAmount; 47 | // 48 | // return initContract().then((contract) => { 49 | // gittoken = contract 50 | // 51 | // return gittoken.verifyContributor(contributorAddress, username) 52 | // }).then(function(event) { 53 | // const { logs } = event 54 | // assert.equal(logs.length, 1, "Expect a logged event") 55 | // assert.equal(logs[0]['event'], "ContributorVerified", "Expected a `ContributorVerified` event") 56 | // 57 | // return gittoken.rewardContributor(username, "milestone_closed", 1000, 15000, "00000000-0000-0000-0000-000000000000") 58 | // }).then(function(event){ 59 | // const { logs } = event 60 | // assert.equal(logs.length, 1, "Expect a logged event") 61 | // assert.equal(logs[0]['event'], "Contribution", "Expected a `Contribution` event") 62 | // 63 | // return gittoken.initializeAuction(5000 * Math.pow(10, decimals), 1, 20, true) 64 | // }).then(function(event){ 65 | // const { logs } = event 66 | // 67 | // 68 | // auctionRound = logs[0]['args']['auctionDetails'][0] 69 | // startDate = logs[0]['args']['auctionDetails'][1] 70 | // endDate = logs[0]['args']['auctionDetails'][2] 71 | // tokensOffered = logs[0]['args']['auctionDetails'][4] 72 | // initialExRate = logs[0]['args']['auctionDetails'][5] 73 | // fundLimit = logs[0]['args']['auctionDetails'][6] 74 | // 75 | // 76 | // assert.equal(8, logs[0]['args']['auctionDetails'].length, "Expected the length of auctionDetails to be 9") 77 | // assert.equal(fundLimit, tokensOffered * (1e18 / initialExRate), "Expected the fund limit to equal tokensOffered * (1e18 / initialExRate)") 78 | // assert.equal(logs.length, 1, "Expected a logged event") 79 | // assert.equal(logs[0]['event'], "Auction", "Expected a `Auction` event") 80 | // assert.equal(auctionRound, 1, "Expected Auction Round to be 1") 81 | // 82 | // let delay = new Date(startDate * 1000).getTime() - new Date().getTime() 83 | // return Promise.delay(delay, gittoken.executeBid(auctionRound.toNumber(), 5000 * Math.pow(10, decimals), { 84 | // from: accounts[0], 85 | // value: 1e18, 86 | // gasPrice: 1e9 87 | // })) 88 | // 89 | // }).then(function(event) { 90 | // const { logs } = event 91 | // 92 | // auctionRound = logs[0]['args']['bidDetails'][0] 93 | // exRate = logs[0]['args']['bidDetails'][1] 94 | // wtdAvgExRate = logs[0]['args']['bidDetails'][2] 95 | // tokensTransferred = logs[0]['args']['bidDetails'][3] 96 | // etherPaid = logs[0]['args']['bidDetails'][4] 97 | // refundAmount = logs[0]['args']['bidDetails'][5] 98 | // fundsCollected = logs[0]['args']['bidDetails'][6] 99 | // fundLimit = logs[0]['args']['bidDetails'][7] 100 | // date = logs[0]['args']['bidDetails'][8] 101 | // 102 | // assert.equal(9, logs[0]['args']['bidDetails'].length, "Expected the length of bidDetails to be 9") 103 | // assert.equal(logs.length, 1, "Expected a logged event") 104 | // assert.equal(logs[0]['event'], "AuctionBid", "Expected a `AuctionBid` event") 105 | // assert.equal(fundsCollected, 4e17, "Expected funds collected to be equal to 0.4 ETH") 106 | // assert.isAtLeast(date.toNumber(), startDate.toNumber(), "Expected bid date to be greater than or equal to the start date") 107 | // 108 | // return gittoken.balanceOf(accounts[0]) 109 | // }).then(function(balance) { 110 | // assert.equal(balance, tokensTransferred.toNumber(), `Expected the ${balance} of the user to be ${tokensTransferred}`) 111 | // 112 | // return web3.eth.getBalance(gittoken.address) 113 | // }).then(function(balance) { 114 | // 115 | // assert.equal(balance, fundsCollected, `Expected the ${balance} of the contract to be ${fundsCollected}`) 116 | // 117 | // return gittoken.getAuctionDetails(auctionRound.toNumber()) 118 | // }).then((auctionDetails) => { 119 | // 120 | // assert.equal(wtdAvgExRate, auctionDetails[0][6].toNumber(), "Expected wtdAvgExRate to equal auction details value"); 121 | // assert.equal(fundsCollected, auctionDetails[0][7].toNumber(), "Expected funds collected to equal auction details value"); 122 | // assert.equal(fundLimit, auctionDetails[0][8].toNumber(), "Expected fund limit to equal auction details value"); 123 | // 124 | // }).catch(function(error) { 125 | // assert.equal(error, null, error.message) 126 | // }) 127 | // }).timeout(20000); 128 | // 129 | // }) 130 | // }) 131 | -------------------------------------------------------------------------------- /test/test_initializeAuction.js: -------------------------------------------------------------------------------- 1 | // TODO Refactor this test for the GitTokenAuction contract 2 | 3 | // var GitToken = artifacts.require("./GitToken.sol"); 4 | // var Promise = require("bluebird") 5 | // const { contributorAddress, username, name, organization, symbol, decimals } = require('../gittoken.config') 6 | // 7 | // 8 | // function initContract() { 9 | // return new Promise((resolve, reject) => { 10 | // GitToken.new( 11 | // contributorAddress, 12 | // username, 13 | // name, 14 | // organization, 15 | // symbol, 16 | // decimals 17 | // ).then(function(gittoken) { 18 | // resolve(gittoken) 19 | // }).catch(function(error) { 20 | // reject(error) 21 | // }) 22 | // }) 23 | // } 24 | // 25 | // contract('GitToken', function(accounts) { 26 | // describe('GitToken::initializeAuction', function() { 27 | // 28 | // it("Should create a reserved supply of tokens, initialize a new auction, and lock external token transfers.", function() { 29 | // var gittoken; 30 | // return initContract().then((contract) => { 31 | // gittoken = contract 32 | // 33 | // return gittoken.verifyContributor(accounts[0], username) 34 | // }).then(function(event) { 35 | // const { logs } = event 36 | // assert.equal(logs.length, 1, "Expect a logged event") 37 | // assert.equal(logs[0]['event'], "ContributorVerified", "Expected a `ContributorVerified` event") 38 | // 39 | // return gittoken.rewardContributor(username, "organization", "member_added", 0, "00000000-0000-0000-0000-000000000000") 40 | // }).then(function(event){ 41 | // const { logs } = event 42 | // assert.equal(logs.length, 1, "Expect a logged event") 43 | // assert.equal(logs[0]['event'], "Contribution", "Expected a `Contribution` event") 44 | // 45 | // return gittoken.initializeAuction(5000 * Math.pow(10, decimals), 0, 20, true) 46 | // }).then(function(event){ 47 | // const { logs } = event 48 | // assert.equal(logs.length, 1, "Expect a logged event") 49 | // assert.equal(logs[0]['event'], "Auction", "Expected a `Auction` event") 50 | // 51 | // return gittoken.transfer("0x8CB2CeBB0070b231d4BA4D3b747acAebDFbbD142", 100e8) 52 | // }).then(function(event) { 53 | // const { logs } = event 54 | // assert.equal(logs.length, 0, "Expected the transfer event to fail until auction end date has passed") 55 | // 56 | // return gittoken.balanceOf(accounts[0]) 57 | // }).then(function(balance) { 58 | // assert(balance.toNumber(), 1000 * Math.pow(10, decimals), "Expected the balance of the user to be 1000 * Math.pow(10, decimals)") 59 | // }).catch(function(error) { 60 | // assert.equal(error, null, error.message) 61 | // }) 62 | // }) 63 | // 64 | // it("Should create a reserved supply of tokens, initialize a new auction, and allow external token transfers.", function() { 65 | // var gittoken; 66 | // return initContract().then((contract) => { 67 | // gittoken = contract 68 | // 69 | // return gittoken.verifyContributor(accounts[0], username) 70 | // }).then(function(event) { 71 | // const { logs } = event 72 | // assert.equal(logs.length, 1, "Expect a logged event") 73 | // assert.equal(logs[0]['event'], "ContributorVerified", "Expected a `ContributorVerified` event") 74 | // 75 | // return gittoken.rewardContributor(username, "organization", "member_added", 0, "00000000-0000-0000-0000-000000000000") 76 | // }).then(function(event){ 77 | // const { logs } = event 78 | // assert.equal(logs.length, 1, "Expect a logged event") 79 | // assert.equal(logs[0]['event'], "Contribution", "Expected a `Contribution` event") 80 | // 81 | // return gittoken.initializeAuction(5000 * Math.pow(10, decimals), 0, 20, false) 82 | // }).then(function(event){ 83 | // const { logs } = event 84 | // assert.equal(logs.length, 1, "Expect a logged event") 85 | // assert.equal(logs[0]['event'], "Auction", "Expected a `Auction` event") 86 | // 87 | // return gittoken.transfer("0x8CB2CeBB0070b231d4BA4D3b747acAebDFbbD142", 100e8) 88 | // }).then(function(event) { 89 | // const { logs } = event 90 | // assert.equal(logs.length, 1, "Expect a logged event") 91 | // assert.equal(logs[0]['event'], "Transfer", "Expected a `Transfer` event") 92 | // 93 | // return gittoken.balanceOf(accounts[0]) 94 | // }).then(function(balance) { 95 | // assert(balance.toNumber(), 1000 * Math.pow(10, decimals), "Expected the balance of the user to be 1000") 96 | // }).catch(function(error) { 97 | // assert.equal(error, null, error.message) 98 | // }) 99 | // }) 100 | // 101 | // it("Should not allow an exchange rate greater than the total token supply", function() { 102 | // var gittoken; 103 | // return initContract().then((contract) => { 104 | // gittoken = contract 105 | // 106 | // return gittoken.verifyContributor(accounts[0], username) 107 | // }).then(function(event) { 108 | // const { logs } = event 109 | // assert.equal(logs.length, 1, "Expect a logged event") 110 | // assert.equal(logs[0]['event'], "ContributorVerified", "Expected a `ContributorVerified` event") 111 | // 112 | // return gittoken.rewardContributor(username, "organization", "member_added", 0, "00000000-0000-0000-0000-000000000000") 113 | // }).then(function(event){ 114 | // const { logs } = event 115 | // assert.equal(logs.length, 1, "Expect a logged event") 116 | // assert.equal(logs[0]['event'], "Contribution", "Expected a `Contribution` event") 117 | // 118 | // return gittoken.initializeAuction(20000 * Math.pow(10, decimals), 0, 20, false) 119 | // }).then(function(event){ 120 | // const { logs } = event 121 | // assert.equal(logs.length, 0, "Expected no events from transaction") 122 | // 123 | // }).catch(function(error) { 124 | // assert.equal(error, null, error.message) 125 | // }) 126 | // }) 127 | // 128 | // }) 129 | // }) 130 | -------------------------------------------------------------------------------- /test/test_registerToken.js: -------------------------------------------------------------------------------- 1 | var GitTokenRegistry = artifacts.require("./GitTokenRegistry.sol"); 2 | var Promise = require("bluebird") 3 | const { contributorAddress } = require('../gittoken.config') 4 | 5 | 6 | function initContract() { 7 | return new Promise((resolve, reject) => { 8 | GitTokenRegistry.new(contributorAddress).then(function(registry) { 9 | resolve(registry) 10 | }).catch(function(error) { 11 | reject(error) 12 | }) 13 | }) 14 | } 15 | 16 | contract('GitTokenRegistry', function(accounts) { 17 | describe('GitTokenRegistry::registerToken', function() { 18 | 19 | it("Should register an organization token and emit a Registration event.", function() { 20 | var registry; 21 | return initContract().then((contract) => { 22 | registry = contract 23 | return registry.registerToken('git-token', '0x8CB2CeBB0070b231d4BA4D3b747acAebDFbbD142') 24 | }).then(function(event) { 25 | const { logs } = event 26 | assert.equal(logs.length, 1, "Expect a logged event") 27 | assert.equal(logs[0]['event'], "Registration", "Expected a `Registration` event") 28 | 29 | }).catch(function(error) { 30 | assert.equal(error, null, error.message) 31 | }) 32 | }) 33 | 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /test/test_rewardContribution.js: -------------------------------------------------------------------------------- 1 | var GitToken = artifacts.require("./GitToken.sol"); 2 | var Promise = require("bluebird") 3 | const { contributorAddress, username, name, organization, symbol, decimals } = require('../gittoken.config') 4 | 5 | 6 | function initContract() { 7 | return new Promise((resolve, reject) => { 8 | GitToken.new( 9 | contributorAddress, 10 | username, 11 | name, 12 | organization, 13 | symbol, 14 | decimals 15 | ).then(function(gittoken) { 16 | resolve(gittoken) 17 | }).catch(function(error) { 18 | reject(error) 19 | }) 20 | }) 21 | } 22 | 23 | function toBigNumber(value, decimals) { 24 | return value * Math.pow(10, decimals) 25 | } 26 | 27 | contract('GitToken', function(accounts) { 28 | describe('GitToken::rewardContributor', function() { 29 | it("Should reward a non-verified contributor for organization_member_added, verify the contributor, update the contributor's balance, then show 0 unclaimed rewards for the contributor", function() { 30 | var gittoken; 31 | return initContract().then((contract) => { 32 | gittoken = contract 33 | 34 | return gittoken.rewardContributor('NewUser', "organization_member_added", toBigNumber(2500, decimals), toBigNumber(2500, decimals), "00000000-0000-0000-0000-000000000000") 35 | }).then(function(event){ 36 | const { logs } = event 37 | // console.log('logs', JSON.stringify(logs, null, 2)) 38 | assert.equal(logs.length, 1, "Expect a logged event") 39 | assert.equal(logs[0]['event'], "Contribution", "Expected a `Contribution` event") 40 | 41 | return gittoken.getUnclaimedRewards('NewUser') 42 | }).then(function(unclaimedRewards) { 43 | assert.equal(unclaimedRewards.toNumber(), toBigNumber(2500, decimals), "Expected Unclaimed Rewards of contributor to be 2500") 44 | 45 | return gittoken.verifyContributor(contributorAddress, 'NewUser') 46 | }).then(function(event) { 47 | const { logs } = event 48 | assert.equal(logs[0]['event'], "ContributorVerified", "Expected a `ContributorVerified` event") 49 | 50 | return gittoken.balanceOf.call(contributorAddress) 51 | }).then(function(balance) { 52 | assert.equal(balance.toNumber(), toBigNumber(2500, decimals), "Expected balance of contributor to be 2500") 53 | 54 | return gittoken.getUnclaimedRewards('NewUser') 55 | }).then(function(unclaimedRewards) { 56 | assert.equal(unclaimedRewards.toNumber(), 0, "Expected Unclaimed Rewards of contributor to be 0") 57 | 58 | }).catch(function(error) { 59 | assert.equal(error, null, error.message) 60 | }) 61 | }) 62 | 63 | it("Should reward a pre-verified contributor for organization_member_added, update the contributor's balance, then show 0 unclaimed rewards for the contributor", function() { 64 | var gittoken; 65 | return initContract().then((contract) => { 66 | gittoken = contract 67 | 68 | return gittoken.rewardContributor(username, "organization_member_added", toBigNumber(2500, decimals), toBigNumber(2500, decimals), "00000000-0000-0000-0000-000000000000") 69 | }).then(function(event){ 70 | const { logs } = event 71 | // console.log('logs', JSON.stringify(logs, null, 2)) 72 | assert.equal(logs.length, 1, "Expect a logged event") 73 | assert.equal(logs[0]['event'], "Contribution", "Expected a `Contribution` event") 74 | 75 | return gittoken.balanceOf.call(contributorAddress) 76 | }).then(function(balance) { 77 | assert.equal(balance.toNumber(), toBigNumber(2500, decimals), "Expected balance of contributor to be 2500") 78 | 79 | return gittoken.getUnclaimedRewards(username) 80 | }).then(function(unclaimedRewards) { 81 | assert.equal(unclaimedRewards.toNumber(), 0, "Expected Unclaimed Rewards of contributor to be 0") 82 | 83 | }).catch(function(error) { 84 | assert.equal(error, null, error.message) 85 | }) 86 | }) 87 | 88 | it("Should prevent duplicate GitHub web hook events from rewarding tokens", function() { 89 | var gittoken; 90 | return initContract().then((contract) => { 91 | gittoken = contract 92 | 93 | return gittoken.verifyContributor(contributorAddress, username) 94 | }).then(function(event) { 95 | const { logs } = event 96 | assert.equal(logs[0]['event'], "ContributorVerified", "Expected a `ContributorVerified` event") 97 | 98 | return gittoken.rewardContributor(username, "organization_member_added", toBigNumber(2500, decimals), toBigNumber(2500, decimals), "00000000-0000-0000-0000-000000000000") 99 | }).then(function(event){ 100 | const { logs } = event 101 | assert.equal(logs.length, 1, "Expect a logged event") 102 | assert.equal(logs[0]['event'], "Contribution", "Expected a `Contribution` event") 103 | 104 | return gittoken.rewardContributor(username, "organization_member_added", toBigNumber(2500, decimals), toBigNumber(2500, decimals), "00000000-0000-0000-0000-000000000000") 105 | }).then(function(event){ 106 | const { logs } = event 107 | assert.equal(logs.length, 0, "Expected a thrown event") 108 | 109 | return gittoken.balanceOf(contributorAddress) 110 | }).then(function(balance) { 111 | assert.equal(balance.toNumber(), toBigNumber(2500, decimals), "Expected balance to be 2500") 112 | 113 | }).catch(function(error) { 114 | assert.notEqual(error, null, error.message) 115 | }) 116 | }) 117 | 118 | }) 119 | }) 120 | -------------------------------------------------------------------------------- /test/test_transfer.js: -------------------------------------------------------------------------------- 1 | var GitToken = artifacts.require("./GitToken.sol"); 2 | var Promise = require("bluebird") 3 | const { contributorAddress, username, name, organization, symbol, decimals } = require('../gittoken.config') 4 | 5 | 6 | function initContract() { 7 | return new Promise((resolve, reject) => { 8 | GitToken.new( 9 | contributorAddress, 10 | username, 11 | name, 12 | organization, 13 | symbol, 14 | decimals 15 | ).then(function(gittoken) { 16 | resolve(gittoken) 17 | }).catch(function(error) { 18 | reject(error) 19 | }) 20 | }) 21 | } 22 | 23 | function toBigNumber(value, decimals) { 24 | return value * Math.pow(10, decimals) 25 | } 26 | 27 | contract('GitToken', function(accounts) { 28 | describe('GitToken::transfer', function() { 29 | 30 | it("Should reward a contributor and allow that contributor to transfer one unit of the token", function() { 31 | var gittoken; 32 | return initContract().then((contract) => { 33 | gittoken = contract 34 | return gittoken.verifyContributor(accounts[0], username) 35 | }).then(function(event) { 36 | const { logs } = event 37 | assert.equal(logs.length, 1, "Expect a logged event") 38 | assert.equal(logs[0]['event'], "ContributorVerified", "Expected a `ContributorVerified` event") 39 | 40 | return gittoken.rewardContributor(username, "organization_member_added", toBigNumber(2500, decimals), toBigNumber(2500, decimals), "00000000-0000-0000-0000-000000000000") 41 | }).then(function(event){ 42 | const { logs } = event 43 | assert.equal(logs.length, 1, "Expect a logged event") 44 | assert.equal(logs[0]['event'], "Contribution", "Expected a `Contribution` event") 45 | 46 | return gittoken.transfer("0x8CB2CeBB0070b231d4BA4D3b747acAebDFbbD142", 1e8) 47 | }).then(function(event) { 48 | const { logs } = event 49 | assert.equal(logs.length, 1, "Expect a logged event") 50 | assert.equal(logs[0]['event'], "Transfer", "Expected a `Transfer` event") 51 | 52 | }).catch(function(error) { 53 | assert.equal(error, null, error.message) 54 | }) 55 | }) 56 | 57 | }) 58 | }) 59 | -------------------------------------------------------------------------------- /test/test_verifyContributor.js: -------------------------------------------------------------------------------- 1 | var GitToken = artifacts.require("./GitToken.sol"); 2 | var Promise = require("bluebird") 3 | const { contributorAddress, username, name, organization, symbol, decimals } = require('../gittoken.config') 4 | 5 | 6 | function initContract() { 7 | return new Promise((resolve, reject) => { 8 | GitToken.new( 9 | contributorAddress, 10 | username, 11 | name, 12 | organization, 13 | symbol, 14 | decimals 15 | ).then(function(gittoken) { 16 | resolve(gittoken) 17 | }).catch(function(error) { 18 | reject(error) 19 | }) 20 | }) 21 | } 22 | 23 | function toBigNumber(value, decimals) { 24 | return value * Math.pow(10, decimals) 25 | } 26 | 27 | contract('GitToken', function(accounts) { 28 | describe('GitToken::verifyContributor', function() { 29 | 30 | it("Should verify the contributor, reward the contributor, update the contributor's balance, and show 0 unclaimed rewards for the contributor", function() { 31 | var gittoken; 32 | return initContract().then((contract) => { 33 | gittoken = contract 34 | 35 | return gittoken.verifyContributor(contributorAddress, username) 36 | }).then(function(event) { 37 | const { logs } = event 38 | assert.equal(logs[0]['event'], "ContributorVerified", "Expected a `ContributorVerified` event") 39 | 40 | return gittoken.rewardContributor(username, "organization_member_added", toBigNumber(2500, decimals), toBigNumber(2500, decimals), "00000000-0000-0000-0000-000000000000") 41 | }).then(function(event){ 42 | const { logs } = event 43 | assert.equal(logs.length, 1, "Expect a logged event") 44 | assert.equal(logs[0]['event'], "Contribution", "Expected a `Contribution` event") 45 | 46 | return gittoken.balanceOf.call(contributorAddress) 47 | }).then(function(balance) { 48 | assert.equal(balance.toNumber(), toBigNumber(2500, decimals), "Expected balance of contributor to be toBigNumber(2500, decimals)") 49 | 50 | return gittoken.getUnclaimedRewards(username) 51 | }).then(function(unclaimedRewards) { 52 | assert.equal(unclaimedRewards.toNumber(), 0, "Expected Unclaimed Rewards of contributor to be 0") 53 | 54 | }).catch(function(error) { 55 | assert.equal(error, null, error.message) 56 | }) 57 | }) 58 | }) 59 | }) 60 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "138.68.225.133", 5 | port: 8745, 6 | network_id: "*", // Match any network id 7 | gasPrice: 4e9, // 20 Gwei gas price; lower == slower, cheaper; higher == faster, costly 8 | gas: 47e5 9 | } 10 | } 11 | }; 12 | --------------------------------------------------------------------------------