diff --git a/README.md b/README.md index 619d012..d9ae23f 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,12 @@ -# GitHubOracle +# GitPivot Ethereum application to incentive open-source development in GitHub by opening direct fair payment channels for bounties and indirect payments through tokenization of commits. -This project was formely known as GitHubTokens, created to tokenize contributions of [TheEtherian news platform](https://etherian.world/). - -The project become embraced by [Status Network](status.im) that will integrate it as backend of a trustless [Commiteth](https://github.com/status-im/commiteth). - ## System Features ### Configurable reward modes by project -For a project being accepted by GitHubOracle it must have a file in root of tree called `.gitpoints` with specifing `user-agent:` to `*` or `githuboracle`. +For a project being accepted by GitPivot it must have a file in root of tree called `.gitpoints` with specifing `user-agent:` to `*` or `GitPivot`. Example: @@ -26,8 +22,8 @@ reactions-reward: heart, +1 ### GitHub User Ethereum Address -To control GitHubOracle users need to link their GitHub user login to an ethereum address. -User calls GitHubOracle and passes his username and the gistid, GitHubOracle registers users by loading gistid file called `register.txt` under user `login`. This file must contain only the ethereum address who made the register call, starting with `0x`. +To control GitPivot users need to link their GitHub user login to an ethereum address. +User calls GitPivot and passes his username and the gistid, GitPivot registers users by loading gistid file called `register.txt` under user `login`. This file must contain only the ethereum address who made the register call, starting with `0x`. ### Tokenize project merged contributions @@ -43,7 +39,7 @@ Repositories that enabled tokenizations of contributions also have a DonationBan ### Reward bounties by contribuion in GitHub Issues. -Issues may be tracked by GitHubOracle, accept payments, depending on the `.gitpoints` configuration, positively reacted posts and merged pull requests/commits generate points that allow issue contributors to withdraw a fair share of balances related to the issue. +Issues may be tracked by GitPivot, accept payments, depending on the `.gitpoints` configuration, positively reacted posts and merged pull requests/commits generate points that allow issue contributors to withdraw a fair share of balances related to the issue. ## Network Features diff --git a/contracts/GitHubAPIReg.sol b/contracts/GitHubAPIReg.sol deleted file mode 100644 index 430b4c2..0000000 --- a/contracts/GitHubAPIReg.sol +++ /dev/null @@ -1,108 +0,0 @@ -pragma solidity ^0.4.11; - -import "./common/Controlled.sol"; -import "./common/oraclizeAPI_0.4.sol"; -import "./common/strings.sol"; - - -/** - * @title GitHubAPIReg.sol - * Abstract Logic for GitHubOracle Registries. - * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) - */ -contract GitHubAPIReg is Controlled, usingOraclize { - using strings for string; - using strings for strings.slice; - - string cred = ""; - - event OracleEvent(bytes32 myid, string result, bytes proof); - - function GitHubAPIReg() { - oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); - } - - //owner management - function setAPICredentials(string _client_id, string _client_secret) public onlyController { - strings.slice[] memory cm = new strings.slice[](5); - cm[0] = strings.toSlice("?client_id="); - cm[1] = _client_id.toSlice(); - cm[2] = strings.toSlice("&client_secret="); - cm[4] = _client_secret.toSlice(); - cred = strings.toSlice("").join(cm); - } - - function clearAPICredentials() public onlyController { - cred = ""; - } - - function getNextString(bytes _str, uint8 _pos) internal returns (string, uint8) { - uint8 start = 0; - uint8 end = 0; - uint strl =_str.length; - for (;strl > _pos; _pos++) { - if (_str[_pos] == "\"") { //Found quotation mark - if (_str[_pos-1] != "\\") { //is not escaped - end = start == 0 ? 0: _pos; - start = start == 0 ? (_pos+1) : start; - if(end > 0) { - break; - } - } - } - } - bytes memory str = new bytes(end-start); - for (_pos=0; _pos _pos; _pos++) { - byte bp = _str[_pos]; - if (bp == ",") {//Find ends - _pos++; break; - } else if ((bp >= 48) && (bp <= 57)) { //only ASCII numbers - val *= 10; - val += uint(bp) - 48; - } - } - return (val, _pos); - } - - function getNextAddr(bytes _str, uint8 _pos) internal returns (address, uint8) { - uint160 iaddr = 0; - uint strl =_str.length; - for (;strl > _pos; _pos++) { - byte bp = _str[_pos]; - if (bp == "0") { - if (_str[_pos+1] == "x") { - for (_pos=_pos+2; _pos<2+2*20; _pos+=2) { - iaddr *= 256; - iaddr += (uint160(hexVal(uint160(_str[_pos])))*16+uint160(hexVal(uint160(_str[_pos+1])))); - } - _pos++; - break; - } - }else if (bp == ",") { - _pos++; - break; - } - } - return (address(iaddr), _pos); - } - - function hexVal(uint val) internal returns (uint) { - return val - (val < 58 ? 48 : (val < 97 ? 55 : 87)); - } - -} \ No newline at end of file diff --git a/contracts/GitPivot.sol b/contracts/GitPivot.sol index eee5f83..da5a426 100644 --- a/contracts/GitPivot.sol +++ b/contracts/GitPivot.sol @@ -4,13 +4,13 @@ import "./common/Controlled.sol"; import "./PointsOracle.sol"; import "./UserOracle.sol"; import "./RepositoryOracle.sol"; - +import "./IGitPivot.sol"; /** * @title GitPivot.sol * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) */ -contract GitPivot is Controlled, DGitI { +contract GitPivot is Controlled, IGitPivot { UserOracle public userOracle; RepositoryOracle public repositoryOracle; @@ -40,7 +40,7 @@ contract GitPivot is Controlled, DGitI { function getRepository(string _repository, string _branch) public constant returns (uint repoId) { repoId = repositoryOracle.getId(_repository); require(repoId != 0); - require(repositoryOracle.getBranch(repoId) == keccak256(_branch)); + require(repositoryOracle.branch(repoId) == keccak256(_branch)); } function start(string _repository, string _branch, string _token) public payable { @@ -96,7 +96,7 @@ contract GitPivot is Controlled, DGitI { //claims pending points function claimPending(uint _repoId, uint _userId) public { - GitRepositoryI repoaddr = GitRepositoryI(repositoryOracle.getAddr(_repoId)); + GitRepository repoaddr = GitRepository(repositoryOracle.getAddr(_repoId)); uint total = pending[_userId][_repoId]; delete pending[_userId][_repoId]; require(repoaddr.claim(userOracle.getAddr(_userId), total)); @@ -126,13 +126,6 @@ contract GitPivot is Controlled, DGitI { } } - function upgrade(uint[] _repoIds) public onlyUpgrading onlyController { - uint len = _repoIds.length; - for (uint i = 0; i < len; i++) { - Controlled(repositoryOracle.getAddr(_repoIds[i])).changeController(newContract); - } - } - function pendingScan(uint256 _projectId, string _lastCommit, string _pendingTail) public package { repositories[_projectId].pending[_pendingTail] = _lastCommit; } @@ -154,7 +147,7 @@ contract GitPivot is Controlled, DGitI { public package { - GitRepositoryI repo = GitRepositoryI(repositoryOracle.getAddr(_projectId)); + GitRepository repo = GitRepository(repositoryOracle.getAddr(_projectId)); repo.setBounty(_issueId, _state, _closedAt); } @@ -167,7 +160,7 @@ contract GitPivot is Controlled, DGitI { public package { - GitRepositoryI repo = GitRepositoryI(repositoryOracle.getAddr(_projectId)); + GitRepository repo = GitRepository(repositoryOracle.getAddr(_projectId)); uint len = _userId.length; for (uint i = 0; i < len; i++) { address addr = userOracle.getAddr(_userId[i]); @@ -176,7 +169,7 @@ contract GitPivot is Controlled, DGitI { } function newPoints(uint _repoId, uint[] _userIds, uint[] _points) public package { - GitRepositoryI repo = GitRepositoryI(repositoryOracle.getAddr(_repoId)); + GitRepository repo = GitRepository(repositoryOracle.getAddr(_repoId)); uint len = _userIds.length; for (uint i = 0; i < len; i++) { uint _userId = _userIds[i]; diff --git a/contracts/GitPivotRecoverer.sol b/contracts/GitPivotRecoverer.sol new file mode 100644 index 0000000..5830dea --- /dev/null +++ b/contracts/GitPivotRecoverer.sol @@ -0,0 +1,57 @@ +pragma solidity ^0.4.17; + +import "./deploy/AbstractRecoverer.sol"; + +contract ENS { + function owner(bytes32 node) constant returns (address); + function resolver(bytes32 node) constant returns (Resolver); + function ttl(bytes32 node) constant returns (uint64); + function setOwner(bytes32 node, address owner); + function setSubnodeOwner(bytes32 node, bytes32 label, address owner); + function setResolver(bytes32 node, address resolver); + function setTTL(bytes32 node, uint64 ttl); +} + +contract Resolver { + function addr(bytes32 node) constant returns (address); +} + + +/** + * @title GitPivotRecoverer + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Common Recoverer for GitPivot. + * address resolved from ens recover.gitpivot.eth can set new system. + */ +contract GitPivotRecoverer is BasicSystemStorage { + + /** + * @dev will be callable in emergency state of RecorverableSystem + */ + function recoverSystem(address newSystem) public { + require(msg.sender == consensusContract()); + system = newSystem; + } + + /** + * @dev resolves recover.gitpivot.eth + */ + function consensusContract() public constant returns(address) { + bytes32 node = 0xa33a22622efdf12b4175a11fbc58ec45d4e93a0160952cc8e48867c5c50a3404; //recover.gitpivot.eth //bytes32 node = keccak256("recover", keccak256("gitpivot", keccak256("eth"))); + address ensAddress = 0x314159265dD8dbb310642f98f50C066173C1259b; + if (codeSize(ensAddress) == 0) { + return 0x41CaB970f931F2EC3195C416B8Fa65e99814e7aF; //ensAddress = 0x112234455C3a32FD11230C42E7Bccd4A84e02010; + } + return ENS(ensAddress).resolver(node).addr(node); + } + + function codeSize(address _addr) internal constant returns(uint size) { + if (_addr == 0) { + return 0; + } + assembly { + size := extcodesize(_addr) + } + } + +} \ No newline at end of file diff --git a/contracts/GitRepository.sol b/contracts/GitRepository.sol index 6ae2676..a8c028a 100644 --- a/contracts/GitRepository.sol +++ b/contracts/GitRepository.sol @@ -1,25 +1,16 @@ pragma solidity ^0.4.11; import "./bank/CollaborationBank.sol"; -import "./bank/BountyBank.sol"; import "./common/Controlled.sol"; - - -contract GitRepositoryI is Controlled { - function claim(address _user, uint _total) returns (bool); - function setBounty(uint256 _issueId, bool _state, uint256 _closedAt); - function setBountyPoints(uint256 _issueId, address _claimer, uint256 _points); -} - +import "./IGitRepository.sol"; /** * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) */ -contract GitRepository is TokenController, GitRepositoryI { +contract GitRepository is IGitRepository, Controlled, TokenController { MiniMeToken public token; CollaborationBank public donationBank; - BountyBank public bountyBank; string public name; uint256 public uid; @@ -27,7 +18,6 @@ contract GitRepository is TokenController, GitRepositoryI { function GitRepository(uint256 _uid, string _name) { uid = _uid; name = _name; - bountyBank = new BountyBank(); } function setDonationBank(MiniMeToken _token, uint _epochLenght) public onlyController { @@ -44,14 +34,15 @@ contract GitRepository is TokenController, GitRepositoryI { } function setBounty(uint256 _issueId, bool _state, uint256 _closedAt) public onlyController { - if (_state) - bountyBank.open(_issueId); - else - bountyBank.close(_issueId, _closedAt); + if (_state) { + //TODO: open issue + } else { + //TODO: close issue + } } function setBountyPoints(uint256 _issueId, address _claimer, uint256 _points) public onlyController { - bountyBank.setClaimer(_issueId, _claimer, _points); + //TODO: set points } function proxyPayment(address) public payable returns(bool) { diff --git a/contracts/IGitPivot.sol b/contracts/IGitPivot.sol new file mode 100644 index 0000000..39cf298 --- /dev/null +++ b/contracts/IGitPivot.sol @@ -0,0 +1,44 @@ +/** + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + */ +contract IGitPivot { + + /** + * + */ + function setHead(uint256 projectId, string head) public; + + /** + * + */ + function setTail(uint256 projectId, string tail) public; + + /** + * + */ + function newPoints(uint256 projectId, uint256[] userIds, uint[] totals) public; + + /** + * + */ + function pendingScan(uint256 projectId, string lastCommit, string pendingTail) public; + + /** + * + */ + function setIssue( + uint256 projectId, + uint256 issueId, + bool state, + uint256 closedAt) public; + + /** + * + */ + function setIssuePoints( + uint256 projectId, + uint256 issueId, + uint256[] userIds, + uint256[] points) public; + +} \ No newline at end of file diff --git a/contracts/IGitRepository.sol b/contracts/IGitRepository.sol new file mode 100644 index 0000000..46aa614 --- /dev/null +++ b/contracts/IGitRepository.sol @@ -0,0 +1,8 @@ +pragma solidity ^0.4.11; + + +contract IGitRepository { + function claim(address _user, uint _total) returns (bool); + function setBounty(uint256 _issueId, bool _state, uint256 _closedAt); + function setBountyPoints(uint256 _issueId, address _claimer, uint256 _points); +} \ No newline at end of file diff --git a/contracts/JSONHelper.sol b/contracts/JSONHelper.sol new file mode 100644 index 0000000..e6faef0 --- /dev/null +++ b/contracts/JSONHelper.sol @@ -0,0 +1,110 @@ +pragma solidity ^0.4.11; + +import "./common/strings.sol"; + + +/** + * @title JSONHelper + * Abstract Logic for JSON responses from Oracle + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + */ +contract JSONHelper { + + function getCredentialString(string _clientId, string _clientSecret) internal returns (string cred) { + strings.slice[] memory cm = new strings.slice[](4); + cm[0] = strings.toSlice("?client_id="); + cm[1] = strings.toSlice(_clientId); + cm[2] = strings.toSlice("&client_secret="); + cm[3] = strings.toSlice(_clientSecret); + cred = strings.join(cm); + } + + function getNextString(bytes _str, uint256 _pos) internal pure returns (string str, uint256 next) { + var (start, end) = findStringBounds(_str, _pos); + str = string(copyBytesPart(_str, start, end)); + next = findNextChar(_str, end, ",") + 1; + } + + function getNextAddr(bytes _str, uint256 _pos) internal pure returns (address, uint256) { + uint160 iaddr = 0; + uint len = _str.length; + for (; len > _pos; _pos++) { + byte bp = _str[_pos]; + if (bp == "0") { + if (_str[_pos+1] == "x") { + for (_pos = _pos+2; _pos < 2 + 2 * 20; _pos += 2) { + iaddr *= 256; + iaddr += (uint160(hexVal(uint160(_str[_pos])))*16+uint160(hexVal(uint160(_str[_pos+1])))); + } + _pos++; + break; + } + }else if (bp == ",") { + _pos++; + break; + } + } + return (address(iaddr), _pos); + } + + function getNextUInt(bytes _str, uint256 _pos) internal pure returns (uint, uint256) { + uint val = 0; + uint len = _str.length; + for (; len > _pos; _pos++) { + byte bp = _str[_pos]; + if (bp == ",") {//Find ends + _pos++; + break; + } else if ((bp >= 48) && (bp <= 57)) { //only ASCII numbers + val *= 10; + val += uint(bp) - 48; + } + } + return (val, _pos); + } + + function hexVal(uint val) internal pure returns (uint) { + return val - (val < 58 ? 48 : (val < 97 ? 55 : 87)); + } + + function copyBytesPart(bytes _src, uint256 _start, uint256 _end) private pure returns (bytes res) { + uint256 len = _end - _start; + res = new bytes(len); + for (uint i = 0; i < len; i++) { + res[i] = _src[_start + i]; + } + } + + /** + * @dev Finds next char. Retuns _str length case not found. + */ + function findNextChar(bytes _str, uint256 _start, byte _char) private pure returns(uint256 pos) { + uint256 len = _str.length; + for (pos = _start + 1; pos < len; pos++) { + if (_str[pos] == _char) { + return pos; + } + } + } + + /** + * @dev Finds JSON string bounds: first unescaped " and next unescaped" . Returns 0,0 case not found. + * @param _str The converted to bytes string. + * @param _offset The search offset into _str + */ + function findStringBounds(bytes _str, uint256 _offset) private pure returns (uint256 start, uint256 end) { + uint256 len = _str.length; + for (uint256 _pos = _offset; _pos < len; _pos++) { + if (_str[_pos] == "\"") { + if (_pos == 0 || _str[_pos-1] != "\\") { //is not escaped + end = start == 0 ? 0 : _pos; + start = start == 0 ? (_pos+1) : start; + if (end > 0) { + return (start, end); + } + } + } + } + return (0, 0); + } +} \ No newline at end of file diff --git a/contracts/Migrations.sol b/contracts/Migrations.sol index 1143dec..ab44877 100644 --- a/contracts/Migrations.sol +++ b/contracts/Migrations.sol @@ -1,12 +1,12 @@ pragma solidity ^0.4.4; - contract Migrations { address public owner; uint public last_completed_migration; modifier restricted() { - if (msg.sender == owner) _; + if (msg.sender == owner) + _; } function Migrations() { @@ -21,5 +21,4 @@ contract Migrations { Migrations upgraded = Migrations(new_address); upgraded.setCompleted(last_completed_migration); } - } diff --git a/contracts/PointsOracle.sol b/contracts/PointsOracle.sol index 61cfe80..b2f8b58 100644 --- a/contracts/PointsOracle.sol +++ b/contracts/PointsOracle.sol @@ -1,61 +1,17 @@ pragma solidity ^0.4.10; -import "./common/oraclizeAPI_0.4.sol"; import "./common/Controlled.sol"; import "./common/strings.sol"; +import "./oraclize/oraclizeAPI_0.4.sol"; +import "./JSONHelper.sol"; +import "./IGitPivot.sol"; +import "./deploy/KillableModel.sol"; /** * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) */ -contract GitPivotI { +contract PointsOracle is KillableModel, Controlled, JSONHelper, usingOraclize { - /** - * - */ - function setHead(uint256 projectId, string head) public; - - /** - * - */ - function setTail(uint256 projectId, string tail) public; - - /** - * - */ - function newPoints(uint256 projectId, uint256[] userIds, uint[] totals) public; - - /** - * - */ - function pendingScan(uint256 projectId, string lastCommit, string pendingTail) public; - - /** - * - */ - function setIssue( - uint256 projectId, - uint256 issueId, - bool state, - uint256 closedAt) public; - - /** - * - */ - function setIssuePoints( - uint256 projectId, - uint256 issueId, - uint256[] userIds, - uint256[] points) public; - -} - - -/** - * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) - */ -contract PointsOracle is Controlled, usingOraclize { - - event OracleEvent(bytes32 myid, string result, bytes proof); using strings for string; using strings for strings.slice; @@ -220,7 +176,6 @@ contract PointsOracle is Controlled, usingOraclize { * */ function __callback(bytes32 myid, string result, bytes proof) public { - OracleEvent(myid, result, proof); require (msg.sender == oraclize.cbAddress()); processRequest(bytes(result), request[myid]); delete request[myid]; @@ -232,8 +187,8 @@ contract PointsOracle is Controlled, usingOraclize { function processRequest(bytes v, Request _request) internal { - GitPivotI pivot = GitPivotI(controller); - uint8 pos = 0; + IGitPivot pivot = IGitPivot(controller); + uint256 pos = 0; string memory temp; uint256 projectId; uint256 issueId; @@ -441,60 +396,4 @@ contract PointsOracle is Controlled, usingOraclize { } } - /** - * - */ - function getNextString(bytes _str, uint8 _pos) - internal - constant - returns (string, uint8) - { - uint8 _start = 0; - uint8 end = 0; - uint strl = _str.length; - for (;strl > _pos; _pos++) { - if (_str[_pos] == "\"") { //Found quotation mark - if (_str[_pos-1] != "\\") { //is not escaped - end = _start == 0 ? 0 : _pos; - _start = _start == 0 ? (_pos + 1) : _start; - if (end > 0) - break; - } - } - } - bytes memory str = new bytes(end - _start); - for (_pos = 0; _pos < str.length; _pos++) { - str[_pos] = _str[_start + _pos]; - } - for (_pos = end + 1; _pos < _str.length; _pos++) { - if (_str[_pos] == ",") { - _pos++; - break; - } //end - } - return (string(str), _pos); - } - - /** - * - */ - function getNextUInt(bytes _str, uint8 _continue) - internal - constant - returns (uint val, uint8 _pos) - { - val = 0; - uint strl = _str.length; - for (_pos = _continue; strl > _pos; _pos++) { - byte bp = _str[_pos]; - if (bp == ",") { //Find ends - _pos++; - break; - } else if ((bp >= 48)&&(bp <= 57)) { //only ASCII numbers - val *= 10; - val += uint(bp) - 48; - } - } - return (val, _pos); - } } \ No newline at end of file diff --git a/contracts/RepositoryOracle.sol b/contracts/RepositoryOracle.sol index cd81c3b..671c41c 100644 --- a/contracts/RepositoryOracle.sol +++ b/contracts/RepositoryOracle.sol @@ -1,20 +1,22 @@ pragma solidity ^0.4.11; -import "./GitHubAPIReg.sol"; +import "./JSONHelper.sol"; import "./management/RegistryIndex.sol"; import "./GitRepository.sol"; import "./common/strings.sol"; - +import "./common/Controlled.sol"; +import "./deploy/KillableModel.sol"; +import "./oraclize/oraclizeAPI_0.4.sol"; /** * @title RepositoryOracle * Registers the master branch of a Repository for GitHubOracle tracking. * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)] */ -contract RepositoryOracle is GitHubAPIReg, RegistryIndex { +contract RepositoryOracle is KillableModel, Controlled, RegistryIndex, JSONHelper, usingOraclize { using strings for string; using strings for strings.slice; - + string private cred = ""; mapping (uint256 => bytes32) public branch; event NewRepository(address addr, uint256 projectId, string fullName, string defaultBranch); @@ -33,7 +35,7 @@ contract RepositoryOracle is GitHubAPIReg, RegistryIndex { //oraclize response callback function __callback(bytes32 myid, string result, bytes proof) { - OracleEvent(myid, result, proof); + //OracleEvent(myid, result, proof); require(msg.sender == oraclize.cbAddress()); _setRepository(result); } @@ -42,7 +44,7 @@ contract RepositoryOracle is GitHubAPIReg, RegistryIndex { internal //[85743750, "ethereans/TheEtherian", "master"] { bytes memory v = bytes(result); - uint8 pos = 0; + uint256 pos = 0; uint256 projectId; (projectId, pos) = getNextUInt(v, pos); string memory full_name; @@ -52,13 +54,14 @@ contract RepositoryOracle is GitHubAPIReg, RegistryIndex { address repoAddr = registry[projectId].addr; if (repoAddr == 0x0) { NewRepository(repoAddr, projectId, full_name, default_branch); - GitRepositoryI repo = new GitRepository(projectId, full_name); + GitRepository repo = new GitRepository(projectId, full_name); repo.changeController(controller); repoAddr = address(repo); branch[projectId] = keccak256(default_branch); - setRegistry(repoAddr, projectId, full_name); + setRegistry(projectId, repoAddr, full_name); } else { - updateIndex(repositories[projectId].name, full_name); + revert(); //TODO: update name + //updateIndex(registry[projectId], full_name); } } //internal helper functions diff --git a/contracts/UserOracle.sol b/contracts/UserOracle.sol index 102b0f9..8d57cca 100644 --- a/contracts/UserOracle.sol +++ b/contracts/UserOracle.sol @@ -1,20 +1,24 @@ -pragma solidity ^0.4.11; +pragma solidity ^0.4.17; -import "./GitHubAPIReg.sol"; import "./common/strings.sol"; +import "./deploy/KillableModel.sol"; +import "./JSONHelper.sol"; +import "./oraclize/oraclizeAPI_0.4.sol"; +import "./common/Controlled.sol"; import "./management/RegistryIndex.sol"; + /** * @title GitHubUserReg.sol * Registers GitHub user login to an address * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)] */ -contract UserOracle is GitHubAPIReg, RegistryIndex { +contract UserOracle is KillableModel, Controlled, RegistryIndex, JSONHelper, usingOraclize { using strings for string; using strings for strings.slice; - - mapping (bytes32 => UserClaim) userClaim; //temporary db for oraclize user register queries + string private cred = ""; + mapping (bytes32 => UserClaim) userClaim; //temporary db for oraclize user register queries event RegisterUpdated(string name); @@ -24,8 +28,8 @@ contract UserOracle is GitHubAPIReg, RegistryIndex { string login; } - function register(string _githubUser, string _gistId, string _cred) public payable { + require(watchdog != 0x0); if (bytes(_cred).length == 0) { _cred = cred; } @@ -33,17 +37,16 @@ contract UserOracle is GitHubAPIReg, RegistryIndex { userClaim[ocid] = UserClaim({sender: msg.sender, login: _githubUser}); } - //oraclize response callback function __callback(bytes32 myid, string result, bytes proof) public { - OracleEvent(myid, result, proof); + //OracleEvent(myid, result, proof); require(msg.sender == oraclize.cbAddress()); _register(myid, result); } function _register(bytes32 myid, string result) internal { bytes memory v = bytes(result); - uint8 pos = 0; + uint256 pos = 0; address addrLoaded; string memory login; uint256 userId; diff --git a/contracts/bank/BountyBank.sol b/contracts/bank/BountyBank.sol deleted file mode 100644 index e814bc3..0000000 --- a/contracts/bank/BountyBank.sol +++ /dev/null @@ -1,68 +0,0 @@ -pragma solidity ^0.4.11; - -import "../common/Controlled.sol"; - -/** - * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) - */ -contract BountyBank is Controlled { - - enum State {CLOSED, OPEN, CLAIMED} - - struct Bounty { - State state; - uint closedAt; - mapping (address => uint) deposits; - mapping (address => uint) claimers; - uint balance; - uint points; - } - - mapping (uint => Bounty) bounties; - uint count = 0; - - function deposit(uint num) payable { - require(bounties[num].state == State.OPEN); - require(msg.value > 0); - bounties[num].deposits[msg.sender] += msg.value; - bounties[num].balance += msg.value; - } - - function withdraw(uint num) { - uint value = bounties[num].deposits[msg.sender]; - require(bounties[num].state == State.OPEN && value > 0); - delete bounties[num].deposits[msg.sender]; - msg.sender.transfer(value); - } - - function open(uint num) onlyController { - require(bounties[num].state != State.CLAIMED); - bounties[num].state = State.OPEN; - } - - function setClaimer(uint num, address claimer, uint points) onlyController { - require(bounties[num].state != State.CLAIMED); - bounties[num].claimers[claimer] += points; - bounties[num].points += points; - } - - function close(uint num, uint _closedAt) onlyController { - require(bounties[num].state != State.CLAIMED); - bounties[num].state = State.CLOSED; - bounties[num].closedAt = _closedAt; - } - - function claim(uint num) { - require (bounties[num].state != State.OPEN); - uint totalPoints = bounties[num].points; - require (totalPoints > 0); - uint points = bounties[num].claimers[msg.sender]; - require (points > 0); - delete bounties[num].claimers[msg.sender]; - uint award = (bounties[num].balance / totalPoints)*points; - bounties[num].points -= points; - bounties[num].balance -= award; - msg.sender.transfer(award); - } - -} \ No newline at end of file diff --git a/contracts/bank/CollaborationBank.sol b/contracts/bank/CollaborationBank.sol index 9ff3d38..befab29 100644 --- a/contracts/bank/CollaborationBank.sol +++ b/contracts/bank/CollaborationBank.sol @@ -1,10 +1,13 @@ pragma solidity ^0.4.10; -import "../common/MiniMeToken.sol"; +import "../common/Controlled.sol"; +import "../token/MiniMeToken.sol"; /** + * @title CollaborationBank * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Share profit between tokenholders. */ contract CollaborationBank is Controlled { @@ -21,7 +24,7 @@ contract CollaborationBank is Controlled { uint256 public epochLenght; uint256 public firstEpoch; - function CollaborationBank(MiniMeToken _token, uint _epochLenght) { + function CollaborationBank(MiniMeToken _token, uint _epochLenght) public { epochLenght = _epochLenght; firstEpoch = currentEpoch(); token = _token; diff --git a/contracts/bank/IssueBank.sol b/contracts/bank/IssueBankModel.sol similarity index 71% rename from contracts/bank/IssueBank.sol rename to contracts/bank/IssueBankModel.sol index 406c050..4c5ed05 100644 --- a/contracts/bank/IssueBank.sol +++ b/contracts/bank/IssueBankModel.sol @@ -1,37 +1,51 @@ pragma solidity ^0.4.11; -import "../management/TokenLedger.sol"; +import "../token/TokenLedger.sol"; import "../common/Controlled.sol"; - /** * @title IssueBank * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) - * Enable deposits to be withdrawn by points recievers + * @dev Model (library) contract to set agreement between a repository owner and GitPivot + * about the bounty winners. **/ -contract IssueBank is Controlled, TokenLedger { - enum State {OPEN, REFUND, REWARD, FINALIZED } - State public state; - uint public points; - uint public refundNonce; - mapping (address => Reward) public rewards; - address public repoOwner; - +contract IssueBankModel is Controlled, TokenLedger { + + address public owner; //repository owner + mapping (address => Reward) public rewards; //bounty winners candidates + uint public points; //remaining points to be claimed + State public state; //current issue state + + enum State { OPEN, REFUND, REWARD, FINALIZED } + struct Reward { - bool active; + bool active; // repository owner can activate uint points; } - modifier onlyRepoOwner{ - require (msg.sender == repoOwner); + modifier onlyOwner{ + require (msg.sender == owner); _; } - function IssueBank(address _repoOwner) { - repoOwner = _repoOwner; + /** + * @dev Model Constructor: Generates a locked state for model being unusable + **/ + function IssueBankModel() public { + owner = 0x0; + } + + /** + * @dev Instance Constructor: Actual agreement logic initialization. + * @param _owner Repository owner which will accept bounty winners and finalize issue. + **/ + function IssueBank(address _owner) public { + require(controller == 0x0); + controller = msg.sender; + owner = _owner; state = State.OPEN; } - + /** * @notice deposit ether in bank **/ @@ -54,6 +68,16 @@ contract IssueBank is Controlled, TokenLedger { _reward(_tokens); } + + /** + * @notice Repository owner can replace his address + * @param _newOwner + **/ + function updateOwner(address _newOwner) onlyOwner { + require(_newOwner != 0x0); + owner = _newOwner; + } + /** * @notice only contoller may set reward to a single address. * @param _claimer the beneficiary @@ -84,7 +108,7 @@ contract IssueBank is Controlled, TokenLedger { * @notice only the repo owner may confirm reward of addresses * @param _claimers array of addresses that are eligible to reward **/ - function confirm(address[] _claimers) onlyRepoOwner { + function confirm(address[] _claimers) onlyOwner { uint len = _claimers.length; uint nPoints = 0; for (uint i = 0; i < len; i++) { @@ -100,7 +124,7 @@ contract IssueBank is Controlled, TokenLedger { * @notice only the repo owner may confirm reward of single address * @param _claimer the address that is eligible to reward **/ - function confirm(address _claimer) onlyRepoOwner { + function confirm(address _claimer) onlyOwner { require(!rewards[_claimer].active); rewards[_claimer].active = true; points += rewards[_claimer].points; @@ -110,7 +134,7 @@ contract IssueBank is Controlled, TokenLedger { * @notice only repo owner can close deposits and start reward or refund * If no points confirmed the system will start refund, otherwise reward */ - function close() onlyRepoOwner { + function close() onlyOwner { require(state == State.OPEN); state = points > 0 ? State.REWARD : State.REFUND; } @@ -128,47 +152,51 @@ contract IssueBank is Controlled, TokenLedger { } /** - * @notice Withdraw tokens - * only avaliable in REWARD state and all points claimed. - * + * @notice withdraw remaining tokens and eth send them to repoOwner + * this might be a case when some tokens were 'forgotten' + * or simply sent after finalized. + * @param _tokens the list of tokens to withdraw. **/ function withdraw(address[] _tokens) onlyController { require(state == State.FINALIZED); + if (this.balance > 0) { + owner.send(this.balance); + } uint len = _tokens.length; uint amount; for (uint i = 0; i < len; i++) { - ERC20 token = ERC20(_tokens[i]); - amount = token.balanceOf(this); + address token = _tokens[i]; + amount = updateInternalBalance(token); if (amount > 0) { withdraw( token, - repoOwner, + owner, amount, 0x0 ); } } } + /** - * @notice only controller may kill contract and send all remaining eth and tokens to repo owner - * This can only be done when all rewards are claimed. - **/ - function kill() onlyController { - require(state == State.FINALIZED); - withdraw(tokens); - selfdestruct(repoOwner); - } - /** - * @dev overwriten to only allow refund in correct state. + * @dev overwriten to only allow refund in correct state and to refund eth **/ function refund(address _token) returns (bool success) { require(state == State.REFUND); - success = withdraw( - _token, - msg.sender, - deposits[_token][msg.sender], - msg.sender - ); + if(_token == 0x0){ + uint v = deposits[0x0][msg.sender]; + if (v > 0) { + delete deposits[0x0][msg.sender]; + success = msg.sender.send(v); + } + } else { + success = withdraw( + _token, + msg.sender, + deposits[_token][msg.sender], + msg.sender + ); + } } /** @@ -249,22 +277,4 @@ contract IssueBank is Controlled, TokenLedger { } -} - - -/** - * @title IssueBankFactory - * @author Ricado Guilherme Schmidt <3esmit> - **/ -contract IssueBankFactory { - - /** - * @notice creates new IssueBank with repoOwner as moderator - **/ - function create(address repoOwner) returns(IssueBank) { - IssueBank bank = new IssueBank(repoOwner); - bank.changeController(msg.sender); - return bank; - } - } \ No newline at end of file diff --git a/contracts/common/ECRecover.sol b/contracts/common/ECRecover.sol new file mode 100644 index 0000000..b59ce0f --- /dev/null +++ b/contracts/common/ECRecover.sol @@ -0,0 +1,73 @@ +pragma solidity ^0.4.15; + +// Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d + +library ECRecover { + + // ECRecovery Methods + + // Duplicate Solidity's ecrecover, but catching the CALL return value + function safer_ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal returns (bool, address) { + // We do our own memory management here. Solidity uses memory offset + // 0x40 to store the current end of memory. We write past it (as + // writes are memory extensions), but don't update the offset so + // Solidity will reuse it. The memory used here is only needed for + // this context. + + // FIXME: inline assembly can't access return values + bool ret; + address addr; + + assembly { + let size := mload(0x40) + mstore(size, hash) + mstore(add(size, 32), v) + mstore(add(size, 64), r) + mstore(add(size, 96), s) + + // NOTE: we can reuse the request memory because we deal with + // the return code + ret := call(3000, 1, 0, size, 128, size, 32) + addr := mload(size) + } + + return (ret, addr); + } + + function ecrecovery(bytes32 hash, bytes sig) returns (address) { + bytes32 r; + bytes32 s; + uint8 v; + + if (sig.length != 65) + return (address(0)); + + assembly { + r := mload(add(sig, 32)) + s := mload(add(sig, 64)) + v := byte(0, mload(add(sig, 96))) + + // Alternative solution: + // 'byte' is not working due to the Solidity parser, so lets + // use the second best option, 'and' + // v := and(mload(add(sig, 65)), 255) + } + + // albeit non-transactional signatures are not specified by the YP, one would expect it + // to match the YP range of [27, 28] + // + // geth uses [0, 1] and some clients have followed. This might change, see: + // https://github.com/ethereum/go-ethereum/issues/2053 + if (v < 27) + v += 27; + + if (v != 27 && v != 28) + return (address(0)); + + bool ret; + address addr; + (ret, addr) = safer_ecrecover(hash, v, r, s); + return addr; + } + +} diff --git a/contracts/common/ERC223Receiver.sol b/contracts/common/ERC223Receiver.sol deleted file mode 100644 index 98e69a1..0000000 --- a/contracts/common/ERC223Receiver.sol +++ /dev/null @@ -1,9 +0,0 @@ -pragma solidity ^0.4.14; - -/** - * @title TokenReceiver - * @dev Used by ERC223 - */ -contract ERC223Receiver { - function tokenFallback(address _from, uint _value, bytes _data); -} \ No newline at end of file diff --git a/contracts/common/ERC677.sol b/contracts/common/ERC677.sol deleted file mode 100644 index 8c66b79..0000000 --- a/contracts/common/ERC677.sol +++ /dev/null @@ -1,15 +0,0 @@ -pragma solidity ^0.4.14; - -import "./ERC20.sol"; -import "./ERC677Receiver.sol"; - -contract ERC677 is ERC20 { - function transferAndCall(address receiver, uint amount, bytes data) returns (bool success) { - require(transfer(receiver, amount)); - return _postTransferCall(receiver, amount, data); - } - - function _postTransferCall(address receiver, uint amount, bytes data) internal returns (bool success) { - return ERC677Receiver(receiver).tokenFallback(msg.sender, amount, data); - } -} \ No newline at end of file diff --git a/contracts/common/strings.sol b/contracts/common/strings.sol index 5aff413..bee43e4 100644 --- a/contracts/common/strings.sol +++ b/contracts/common/strings.sol @@ -691,14 +691,15 @@ library strings { return ""; uint _len = self._len * (parts.length - 1); - for(uint i = 0; i < parts.length; i++) + for (uint i = 0; i < parts.length; i++) { _len += parts[i]._len; + } var ret = new string(_len); uint retptr; assembly { retptr := add(ret, 32) } - for(i = 0; i < parts.length; i++) { + for (i = 0; i < parts.length; i++) { memcpy(retptr, parts[i]._ptr, parts[i]._len); retptr += parts[i]._len; if (i < parts.length - 1) { @@ -709,4 +710,33 @@ library strings { return ret; } + + /* + * @dev Joins an array of slices, returning a + * newly allocated string. + * @param parts A list of slices to join. + * @return A newly allocated string containing + * all the slices in `parts` joined. + */ + function join(slice[] parts) internal returns (string) { + uint partslen = parts.length; + if (partslen == 0) + return ""; + + uint _len; + for (uint i = 0; i < partslen; i++) { + _len += parts[i]._len; + } + + var ret = new string(_len); + uint retptr; + assembly { retptr := add(ret, 32) } + + for (i = 0; i < partslen; i++) { + memcpy(retptr, parts[i]._ptr, parts[i]._len); + retptr += parts[i]._len; + } + + return ret; + } } diff --git a/contracts/deploy/AbstractRecoverer.sol b/contracts/deploy/AbstractRecoverer.sol new file mode 100644 index 0000000..a186fc4 --- /dev/null +++ b/contracts/deploy/AbstractRecoverer.sol @@ -0,0 +1,29 @@ +pragma solidity ^0.4.17; + +import "./BasicSystemStorage.sol"; + + +/** + * @title AbstractRecoverer + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Abstract recoverer contract that should be crafted to alter `address system` storage + * in delegated logic contracts. + */ +contract AnstractRecoverer is BasicSystemStorage { + + /** + * @dev will be callable in emergency state of RecorverableSystem + */ + function recoverSystem(address newSystem) public { + require(msg.sender == consensusContract()); + system = newSystem; + } + + /** + * @dev returns the consesus contract, can be a multisig or other DAO + * should be implemented by a child contract + */ + function consensusContract() public constant returns(address); + + +} \ No newline at end of file diff --git a/contracts/deploy/BasicSystemStorage.sol b/contracts/deploy/BasicSystemStorage.sol new file mode 100644 index 0000000..ce95b34 --- /dev/null +++ b/contracts/deploy/BasicSystemStorage.sol @@ -0,0 +1,16 @@ +pragma solidity ^0.4.17; + + +/** + * @title BasicSystemStorage + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Defines system vars in a shared library among Stub and SystemLibraries to + * avoid overwriting wrong storage pointers + */ +contract BasicSystemStorage { + /// protected zone start (RecorverableSystem vars) + address system; + address recover; + address watchdog; + /// protected zone end +} \ No newline at end of file diff --git a/contracts/deploy/DelegatedCall.sol b/contracts/deploy/DelegatedCall.sol new file mode 100644 index 0000000..cbed2b4 --- /dev/null +++ b/contracts/deploy/DelegatedCall.sol @@ -0,0 +1,33 @@ +pragma solidity ^0.4.17; + + +/** + * @title DelegatedCall + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Abstract contract that delegates calls by `delegated` modifier to result of `_target()` + */ +contract DelegatedCall { + /** + * @dev delegates the call of this function + */ + modifier delegated { + require(_target().delegatecall(msg.data)); //require successfull delegate call to remote `_target()` + assembly { + let outSize := returndatasize + let outDataPtr := mload(0x40) //load memory + returndatacopy(outDataPtr, 0, outSize) //copy last return into pointer + return(outDataPtr, outSize) + } + assert(false); //should never reach here + _; //never will execute local logic + } + + /** + * @dev defines the address for delegation of calls + */ + function _target() + internal + constant + returns(address); + +} diff --git a/contracts/deploy/KillableModel.sol b/contracts/deploy/KillableModel.sol new file mode 100644 index 0000000..c05bf51 --- /dev/null +++ b/contracts/deploy/KillableModel.sol @@ -0,0 +1,25 @@ +pragma solidity ^0.4.17; + +import "./BasicSystemStorage.sol"; + + +/** + * @title KillableModel + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev A contract model that can be killed by a watchdog + */ +contract KillableModel is BasicSystemStorage { + + /** + * @dev Library contract constructor initialize watchdog, able to kill the Library in case of + */ + function KillableModel(address _watchdog) public { + watchdog = _watchdog; + } + + function emergencyStop() public { + require(msg.sender == watchdog); + selfdestruct(watchdog); + } + +} \ No newline at end of file diff --git a/contracts/deploy/Migrations.sol b/contracts/deploy/Migrations.sol new file mode 100644 index 0000000..35f205b --- /dev/null +++ b/contracts/deploy/Migrations.sol @@ -0,0 +1,24 @@ +pragma solidity ^0.4.4; + + +contract Migrations { + address public owner; + uint public last_completed_migration; + + modifier restricted() { + if (msg.sender == owner) _; + } + + function Migrations() public { + owner = msg.sender; + } + + function setCompleted(uint _completed) public restricted { + last_completed_migration = _completed; + } + + function upgrade(address _newAddress) public restricted { + Migrations upgraded = Migrations(_newAddress); + upgraded.setCompleted(last_completed_migration); + } +} diff --git a/contracts/deploy/RecoverableSystem.sol b/contracts/deploy/RecoverableSystem.sol new file mode 100644 index 0000000..0883839 --- /dev/null +++ b/contracts/deploy/RecoverableSystem.sol @@ -0,0 +1,56 @@ +pragma solidity ^0.4.17; + +import "./BasicSystemStorage.sol"; +import "./DelegatedCall.sol"; + + +/** + * @title RecoverableSystem + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Contract that recovers from dead system to recoverer. + */ +contract RecoverableSystem is BasicSystemStorage, DelegatedCall { + + function RecoverableSystem(address _system, address _recover) public { + require(isOk(_recover)); + system = _system; + recover = _recover; + } + + /** + * @dev delegatecall everything (but declared functions) to `_target()` + */ + function () public delegated { + //all goes to system (or recover) + } + + /** + * @dev checks if system contains code + */ + function isOk() public constant returns(bool a) { + return isOk(system); + } + + /** + * @dev checks if `_a` contains code + */ + function isOk(address _a) internal constant returns(bool r) { + assembly{ + r := gt(extcodesize(_a), 0) + } + } + + /** + * @dev returns system if system has code, otherwise return recover + */ + function _target() + internal + constant + returns(address) + { + + return isOk() ? system : recover; + } + + +} \ No newline at end of file diff --git a/contracts/management/Archive.sol b/contracts/management/Archive.sol new file mode 100644 index 0000000..c1a0f14 --- /dev/null +++ b/contracts/management/Archive.sol @@ -0,0 +1,115 @@ +pragma solidity ^0.4.15; + +import "../common/Controlled.sol"; + +/** + * @title Archive + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + */ +contract Archive is Controlled { + + mapping(bytes32 => address) addressMap; + mapping(bytes32 => bytes32) bytes32Map; + mapping(bytes32 => uint) uIntMap; + mapping(bytes32 => int) intMap; + mapping(bytes32 => bool) boolMap; + mapping(bytes32 => string) stringMap; + mapping(bytes32 => bytes) bytesMap; + + /** + * Getters + */ + + function getAddress(bytes32 _uid) public constant returns (address) { + return addressMap[_uid]; + } + + function getBytes32(bytes32 _uid) public constant returns (bytes32) { + return bytes32Map[_uid]; + } + + function getUInt(bytes32 _uid) public constant returns (uint) { + return uIntMap[_uid]; + } + + function getInt(bytes32 _uid) public constant returns (int) { + return intMap[_uid]; + } + + function getBoolean(bytes32 _uid) public constant returns (bool) { + return boolMap[_uid]; + } + + function getString(bytes32 _uid) public constant returns (string) { + return stringMap[_uid]; + } + + function getBytes(bytes32 _uid) public constant returns (bytes) { + return bytesMap[_uid]; + } + + /** + * Setters + */ + + function putAddress(bytes32 _uid, address value) public onlyController { + addressMap[_uid] = value; + } + + function putUInt(bytes32 _uid, uint value) public onlyController { + uIntMap[_uid] = value; + } + + function putInt(bytes32 _uid, int value) public onlyController { + intMap[_uid] = value; + } + + function putBoolean(bytes32 _uid, bool value) public onlyController { + boolMap[_uid] = value; + } + + function putBytes32(bytes32 _uid, bytes32 value) public onlyController { + bytes32Map[_uid] = value; + } + + function putString(bytes32 _uid, string value) public onlyController { + stringMap[_uid] = value; + } + + function putBytes(bytes32 _uid, bytes value) public onlyController { + bytesMap[_uid] = value; + } + + /** + * Deleters + */ + + function deleteAddress(bytes32 _uid) public onlyController { + delete addressMap[_uid]; + } + + function deleteBytes32(bytes32 _uid) public onlyController { + delete bytes32Map[_uid]; + } + + function deleteUInt(bytes32 _uid) public onlyController { + delete uIntMap[_uid]; + } + + function deleteInt(bytes32 _uid) public onlyController { + delete intMap[_uid]; + } + + function deleteBoolean(bytes32 _uid) public onlyController { + delete boolMap[_uid]; + } + + function deleteString(bytes32 _uid) public onlyController { + delete stringMap[_uid]; + } + + function deleteBytes(bytes32 _uid) public onlyController { + delete bytesMap[_uid]; + } + +} \ No newline at end of file diff --git a/contracts/management/NameRegistry.sol b/contracts/management/NameRegistry.sol new file mode 100644 index 0000000..f698e42 --- /dev/null +++ b/contracts/management/NameRegistry.sol @@ -0,0 +1,28 @@ + +pragma solidity ^0.4.11; + +/** + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @title NameRegistry + * Interface for Name Registries. + */ +contract NameRegistry { + function getAddr(uint256 _id) public constant returns(address addr); + function getAddr(string _name) public constant returns(address addr); + function getName(address _addr) public constant returns(string name); + + mapping (bytes32 => uint256) indexes; + + function getId(address _addr) public constant returns(uint256 id){ + return indexes[keccak256(_addr)]; + } + + function getId(string _name) public constant returns(uint256 id) { + return indexes[keccak256(_name)]; + } + + function _updateIndex(bytes32 _old, bytes32 _new) internal { + indexes[_new] = indexes[_old]; + delete indexes[_old]; + } +} diff --git a/contracts/common/oraclizeAPI_0.4.sol b/contracts/oraclize/oraclizeAPI_0.4.sol similarity index 97% rename from contracts/common/oraclizeAPI_0.4.sol rename to contracts/oraclize/oraclizeAPI_0.4.sol index bb94a12..811730d 100644 --- a/contracts/common/oraclizeAPI_0.4.sol +++ b/contracts/oraclize/oraclizeAPI_0.4.sol @@ -69,8 +69,12 @@ contract usingOraclize { OraclizeI oraclize; modifier oraclizeAPI { - if((address(OAR)==0)||(getCodeSize(address(OAR))==0)) oraclize_setNetwork(networkID_auto); - oraclize = OraclizeI(OAR.getAddress()); + if((address(OAR)==0)||(getCodeSize(address(OAR))==0)) + oraclize_setNetwork(networkID_auto); + + if(address(oraclize) != OAR.getAddress()) + oraclize = OraclizeI(OAR.getAddress()); + _; } modifier coupon(string code){ @@ -79,7 +83,7 @@ contract usingOraclize { _; } - function oraclize_setNetwork(uint8 /*networkID*/) internal returns(bool){ + function oraclize_setNetwork(uint8 networkID) internal returns(bool){ if (getCodeSize(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed)>0){ //mainnet OAR = OraclizeAddrResolverI(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed); oraclize_setNetworkName("eth_mainnet"); @@ -773,7 +777,7 @@ contract usingOraclize { } bytes[3] memory args = [unonce, nbytes, sessionKeyHash]; bytes32 queryId = oraclize_query(_delay, "random", args, _customGasLimit); - oraclize_randomDS_setCommitment(queryId, keccak256(bytes8(_delay), args[1], sha256(args[0]), args[2])); + oraclize_randomDS_setCommitment(queryId, sha3(bytes8(_delay), args[1], sha256(args[0]), args[2])); return queryId; } @@ -805,10 +809,10 @@ contract usingOraclize { (sigok, signer) = safer_ecrecover(tosignh, 27, sigr, sigs); - if (address(keccak256(pubkey)) == signer) return true; + if (address(sha3(pubkey)) == signer) return true; else { (sigok, signer) = safer_ecrecover(tosignh, 28, sigr, sigs); - return (address(keccak256(pubkey)) == signer); + return (address(sha3(pubkey)) == signer); } } @@ -857,6 +861,16 @@ contract usingOraclize { _; } + function oraclize_randomDS_proofVerify__returnCode(bytes32 _queryId, string _result, bytes _proof) internal returns (uint8){ + // Step 1: the prefix has to match 'LP\x01' (Ledger Proof version 1) + if ((_proof[0] != "L")||(_proof[1] != "P")||(_proof[2] != 1)) return 1; + + bool proofVerified = oraclize_randomDS_proofVerify__main(_proof, _queryId, bytes(_result), oraclize_getNetworkName()); + if (proofVerified == false) return 2; + + return 0; + } + function matchBytes32Prefix(bytes32 content, bytes prefix) internal returns (bool){ bool match_ = true; @@ -875,7 +889,7 @@ contract usingOraclize { uint ledgerProofLength = 3+65+(uint(proof[3+65+1])+2)+32; bytes memory keyhash = new bytes(32); copyBytes(proof, ledgerProofLength, 32, keyhash, 0); - checkok = (keccak256(keyhash) == keccak256(sha256(context_name, queryId))); + checkok = (sha3(keyhash) == sha3(sha256(context_name, queryId))); if (checkok == false) return false; bytes memory sig1 = new bytes(uint(proof[ledgerProofLength+(32+8+1+32)+1])+2); @@ -887,7 +901,7 @@ contract usingOraclize { if (checkok == false) return false; - // Step 4: commitment match verification, keccak256(delay, nbytes, unonce, sessionKeyHash) == commitment in storage. + // Step 4: commitment match verification, sha3(delay, nbytes, unonce, sessionKeyHash) == commitment in storage. // This is to verify that the computed args match with the ones specified in the query. bytes memory commitmentSlice1 = new bytes(8+1+32); copyBytes(proof, ledgerProofLength+32, 8+1+32, commitmentSlice1, 0); @@ -897,7 +911,7 @@ contract usingOraclize { copyBytes(proof, sig2offset-64, 64, sessionPubkey, 0); bytes32 sessionPubkeyHash = sha256(sessionPubkey); - if (oraclize_randomDS_args[queryId] == keccak256(commitmentSlice1, sessionPubkeyHash)){ //unonce, nbytes and sessionKeyHash match + if (oraclize_randomDS_args[queryId] == sha3(commitmentSlice1, sessionPubkeyHash)){ //unonce, nbytes and sessionKeyHash match delete oraclize_randomDS_args[queryId]; } else return false; diff --git a/contracts/common/ApproveAndCallFallBack.sol b/contracts/token/ApproveAndCallFallBack.sol similarity index 100% rename from contracts/common/ApproveAndCallFallBack.sol rename to contracts/token/ApproveAndCallFallBack.sol diff --git a/contracts/common/ERC20.sol b/contracts/token/ERC20.sol similarity index 100% rename from contracts/common/ERC20.sol rename to contracts/token/ERC20.sol diff --git a/contracts/common/ERC223.sol b/contracts/token/ERC223.sol similarity index 100% rename from contracts/common/ERC223.sol rename to contracts/token/ERC223.sol diff --git a/contracts/common/MiniMeToken.sol b/contracts/token/MiniMeToken.sol similarity index 99% rename from contracts/common/MiniMeToken.sol rename to contracts/token/MiniMeToken.sol index 4733c31..ca69817 100644 --- a/contracts/common/MiniMeToken.sol +++ b/contracts/token/MiniMeToken.sol @@ -25,7 +25,7 @@ pragma solidity ^0.4.6; /// affecting the original token /// @dev It is ERC20 compliant, but still needs to under go further testing. -import "./Controlled.sol"; +import "../common/Controlled.sol"; import "./TokenController.sol"; import "./ApproveAndCallFallBack.sol"; @@ -37,13 +37,13 @@ contract MiniMeToken is Controlled { string public name; //The Token's name: e.g. DigixDAO Tokens uint8 public decimals; //Number of decimals of the smallest unit string public symbol; //An identifier: e.g. REP - string public version = 'MMT_0.1'; //An arbitrary versioning scheme + string public version = "MMT_0.1"; //An arbitrary versioning scheme /// @dev `Checkpoint` is the structure that attaches a block number to a /// given value, the block number attached is the one that last changed the /// value - struct Checkpoint { + struct Checkpoint { // `fromBlock` is the block number that the value was generated from uint128 fromBlock; diff --git a/contracts/common/TokenController.sol b/contracts/token/TokenController.sol similarity index 100% rename from contracts/common/TokenController.sol rename to contracts/token/TokenController.sol diff --git a/contracts/management/TokenLedger.sol b/contracts/token/TokenLedger.sol similarity index 90% rename from contracts/management/TokenLedger.sol rename to contracts/token/TokenLedger.sol index 318da0f..4c6aa75 100644 --- a/contracts/management/TokenLedger.sol +++ b/contracts/token/TokenLedger.sol @@ -1,15 +1,17 @@ -pragma solidity ^0.4.14; +pragma solidity ^0.4.17; + +import "./ERC223.sol"; +import "./MiniMeToken.sol"; +import "./TokenReceiver.sol"; + -import "../common/ERC223.sol"; -import "../common/MiniMeToken.sol"; -import "../common/ERC223Receiver.sol"; /** * @title TokenLedger * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) * Abstract contract for tracking token deposits. -* Token transfers that did not approved and called `receiveApproval` can be tracked by +* Token transfers that did not approved and called `receiveApproval` can be tracked by updateInternalBalance **/ -contract TokenLedger is ERC223Receiver, ApproveAndCallFallBack { +contract TokenLedger is TokenReceiver, ApproveAndCallFallBack { event Withdrawn(address indexed token, address indexed reciever, uint value); event Deposited(address indexed token, address indexed sender, uint value, bytes data); @@ -27,9 +29,10 @@ contract TokenLedger is ERC223Receiver, ApproveAndCallFallBack { **/ function updateInternalBalance(address _token) public + returns (uint newBal) { uint oldBal = tokenBalances[_token]; - uint newBal = ERC20(_token).balanceOf(this); + newBal = ERC20(_token).balanceOf(this); require(newBal != oldBal); if (newBal > oldBal) { register(_token, address(this), newBal - oldBal, new bytes(0)); @@ -43,7 +46,10 @@ contract TokenLedger is ERC223Receiver, ApproveAndCallFallBack { * @param _from address incoming token * @param _amount incoming amount **/ - function tokenFallback(address _from, uint _amount, bytes _data) { + function tokenFallback(address _from, uint _amount, bytes _data) + public + returns (bool) + { register(msg.sender, _from, _amount, _data); } @@ -58,7 +64,9 @@ contract TokenLedger is ERC223Receiver, ApproveAndCallFallBack { address _from, uint256 _amount, address _token, - bytes _data) + bytes _data + ) + public { uint _nonce = nonce; ERC20 token = ERC20(_token); diff --git a/contracts/common/ERC677Receiver.sol b/contracts/token/TokenReceiver.sol similarity index 74% rename from contracts/common/ERC677Receiver.sol rename to contracts/token/TokenReceiver.sol index 222a053..40f5bd6 100644 --- a/contracts/common/ERC677Receiver.sol +++ b/contracts/token/TokenReceiver.sol @@ -1,8 +1,8 @@ -pragma solidity ^0.4.14; +pragma solidity ^0.4.17; /** * @title TokenReceiver - * @dev Used by ERC677 + * @dev ERC223 and ERC677 */ contract TokenReceiver { function tokenFallback(address _from, uint _value, bytes _data) public returns (bool); diff --git a/ethpm.json b/ethpm.json index 6118d04..59ffcd7 100644 --- a/ethpm.json +++ b/ethpm.json @@ -1,5 +1,5 @@ { - "package_name": "githuboracle", + "package_name": "gitpivot", "version": "0.0.1", "description": "Tokenize commits and issues", "authors": [ diff --git a/package.json b/package.json index c71bd29..2e1e9e0 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "github-oracle", + "name": "gitpivot", "version": "0.0.1", "description": "Tokenize commits and issues", "main": "index.js", diff --git a/scripts/github-oracle/.Dockerfile.swp b/scripts/ghOracle/.Dockerfile.swp similarity index 100% rename from scripts/github-oracle/.Dockerfile.swp rename to scripts/ghOracle/.Dockerfile.swp diff --git a/scripts/github-oracle/Dockerfile b/scripts/ghOracle/Dockerfile similarity index 100% rename from scripts/github-oracle/Dockerfile rename to scripts/ghOracle/Dockerfile diff --git a/scripts/github-oracle/github_oracle.py b/scripts/ghOracle/ghOracle.py similarity index 100% rename from scripts/github-oracle/github_oracle.py rename to scripts/ghOracle/ghOracle.py