From c83c8276ea00b54ed60d97a882000323ae2bd06e Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Thu, 11 May 2017 03:38:15 -0300 Subject: [PATCH 01/10] separated repository reg and user reg. --- contracts/src/GitHubAPIReg.sol | 87 ++++++++++ .../src/{GitHubAPI.sol => GitHubOracle.sol} | 76 ++------- contracts/src/GitHubRegisterEth.sol | 160 ------------------ contracts/src/GitHubRepositoryReg.sol | 81 +++++++++ contracts/src/GitHubUserReg.sol | 81 +++++++++ contracts/src/NameRegistry.sol | 5 + 6 files changed, 267 insertions(+), 223 deletions(-) create mode 100644 contracts/src/GitHubAPIReg.sol rename contracts/src/{GitHubAPI.sol => GitHubOracle.sol} (68%) delete mode 100644 contracts/src/GitHubRegisterEth.sol create mode 100644 contracts/src/GitHubRepositoryReg.sol create mode 100644 contracts/src/GitHubUserReg.sol create mode 100644 contracts/src/NameRegistry.sol diff --git a/contracts/src/GitHubAPIReg.sol b/contracts/src/GitHubAPIReg.sol new file mode 100644 index 0000000..71966e8 --- /dev/null +++ b/contracts/src/GitHubAPIReg.sol @@ -0,0 +1,87 @@ +//Author: Ricardo Guilherme Schmidt <3esmit@gmail.com> +pragma solidity ^0.4.11; + +import "lib/ethereans/management/Owned.sol"; + +contract GitHubAPIReg is Owned, usingOraclize { + string credentials = ""; + + event OracleEvent(bytes32 myid, string result, bytes proof); + + function GitHubAPI(){ + oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); + } + + //owner management + function setAPICredentials(string _client_id, string _client_secret) only_owner { + credentials = strConcat("?client_id=",_client_id,"&client_secret=",_client_secret,""); + } + + function clearAPICredentials() only_owner { + credentials = ""; + } + + 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 _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 constant 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 constant returns (uint){ + return val - (val < 58 ? 48 : (val < 97 ? 55 : 87)); + } + +} \ No newline at end of file diff --git a/contracts/src/GitHubAPI.sol b/contracts/src/GitHubOracle.sol similarity index 68% rename from contracts/src/GitHubAPI.sol rename to contracts/src/GitHubOracle.sol index 4049bc1..c8fec8e 100644 --- a/contracts/src/GitHubAPI.sol +++ b/contracts/src/GitHubOracle.sol @@ -7,14 +7,11 @@ import "lib/ethereans/management/Owned.sol"; contract GitHubAPI{ - function register(address _sender, string _github_user, string _gistid) payable; function updateCommits(string _full_name, string _branch, bytes20 _commitid) payable; - function addRepository(string _full_name) payable; function updateIssue(string _full_name, string _issue) payable; } contract DGitI { - function __register(address addrLoaded, uint256 userId, string login); function __addRepository(uint256 projectId, string full_name, string default_branch); function __setHead(uint256 projectId, string branch, bytes20 head); function __setTail(uint256 projectId, string branch, bytes20 tail); @@ -23,49 +20,29 @@ contract DGitI { function __setIssuePoints(uint256 projectId, uint256 issueId, uint256 userId, uint256 points); } -contract GitHubAPIOraclize is GitHubAPI, Owned, usingOraclize{ +contract GitHubOracle is GitHubAPI, Owned, usingOraclize{ using StringLib for string; DGitI dGit - string private cred = "f94095ba1d48038d4a81,36ae0e8b1bc5ad261c936e8f7f730f6c827c221f"; - string private credentials = "?client_id=f94095ba1d48038d4a81&client_secret=36ae0e8b1bc5ad261c936e8f7f730f6c827c221f"; - string private script = "QmU6pSQMDSg8do9eZLAfjzZYcC9JpsMZeB4ZoteGkSe94y"; + string private cred = ""; + string private script = ""; - enum OracleType { ADD_REPOSITORY, SET_USER, CLAIM_COMMIT, CLAIM_CONTINUE, UPDATE_ISSUE } + enum OracleType { CLAIM_COMMIT, CLAIM_CONTINUE, UPDATE_ISSUE } mapping (bytes32 => OracleType) claimType; //temporary db enumerating oraclize calls mapping (bytes32 => CommitClaim) commitClaim; //temporary db for oraclize commit token claim calls - mapping (bytes32 => UserClaim) userClaim; //temporary db for oraclize user register queries - //stores temporary data for oraclize user register request - struct UserClaim { - address sender; - string githubid; - } //stores temporary data for oraclize repository commit claim struct CommitClaim { string repository; bytes20 commitid; } - function GitHubAPIOraclize(){ + function GitHubOracle(string _script){ + script = _script; dGit = DGitI(msg.sender); oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); } - //register or change a github user ethereum address. 100000000000000000 - function register(address _sender, string _github_user, string _gistid) - payable only_owner{ - bytes32 ocid = oraclize_query("nested", StringLib.concat("[identity] ${[URL] https://gist.githubusercontent.com/",_github_user,"/",_gistid,"/raw/}, ${[URL] json(https://api.github.com/gists/").concat(_gistid,credentials,").owner.[id,login]}")); - claimType[ocid] = OracleType.SET_USER; - userClaim[ocid] = UserClaim({sender: _sender, githubid: _github_user}); - } - - function addRepository(string _repository) - payable only_owner{ - bytes32 ocid = oraclize_query("URL", StringLib.concat("json(https://api.github.com/repos/",_repository,credentials,").$.id,full_name,default_branch"),4000000); - claimType[ocid] = OracleType.ADD_REPOSITORY; - } - function updateCommits(string _repository, string _branch, bytes20 _commitid) payable only_owner{ bytes32 ocid = oraclize_query("computation", [script, "update-new",_repository.concat(",", _branch,",",toString(_commitid)),cred]); @@ -86,13 +63,9 @@ contract GitHubAPIOraclize is GitHubAPI, Owned, usingOraclize{ event OracleEvent(bytes32 myid, string result, bytes proof); //oraclize response callback function __callback(bytes32 myid, string result, bytes proof) { - OracleEvent(myid,result,proof); + OracleEvent(myid, result, proof); if (msg.sender != oraclize.cbAddress()){ throw; - }else if(claimType[myid]==OracleType.SET_USER){ - _register(myid, result); - }else if(claimType[myid] == OracleType.ADD_REPOSITORY){ - _addRepository(myid, result); }else if(claimType[myid]==OracleType.CLAIM_COMMIT){ _updateCommits(myid, result, false); }else if(claimType[myid]==OracleType.CLAIM_CONTINUE){ @@ -103,24 +76,7 @@ contract GitHubAPIOraclize is GitHubAPI, Owned, usingOraclize{ delete claimType[myid]; //should always be deleted } - function _register(bytes32 myid, string result) - internal { - uint256 userId; string memory login; address addrLoaded; - uint8 utype; //TODO - bytes memory v = bytes(result); - uint8 pos = 0; - (addrLoaded,pos) = JSONLib.getNextAddr(v,pos); - (userId,pos) = JSONLib.getNextUInt(v,pos); - (login,pos) = JSONLib.getNextString(v,pos); - if(userClaim[myid].sender == addrLoaded){ - dGit.__register(addrLoaded, userId, login); - } - delete userClaim[myid]; //should always be deleted - } - - - function _addRepository(bytes32 myid, string result) internal //[85743750, "ethereans/TheEtherian", "master"] - { + function _addRepository(bytes32 myid, string result) internal {//[85743750, "ethereans/TheEtherian", "master"] bytes memory v = bytes(result); uint8 pos = 0; string memory temp; @@ -133,8 +89,7 @@ contract GitHubAPIOraclize is GitHubAPI, Owned, usingOraclize{ dGit.__addRepository(projectId,full_name,default_branch); } - function _updateCommits(bytes32 myid, string result, bool continuing) - internal { + function _updateCommits(bytes32 myid, string result, bool continuing) internal { bytes memory v = bytes(result); uint8 pos = 0; string memory temp; @@ -168,8 +123,7 @@ contract GitHubAPIOraclize is GitHubAPI, Owned, usingOraclize{ } } - function _updateIssue(bytes32 myid, string result) - internal { + function _updateIssue(bytes32 myid, string result) internal { bytes memory v = bytes(result); uint8 pos = 0; string memory temp; @@ -195,20 +149,16 @@ contract GitHubAPIOraclize is GitHubAPI, Owned, usingOraclize{ } //owner management - function setAPICredentials(string _client_id, string _client_secret) - only_owner { + function setAPICredentials(string _client_id, string _client_secret) only_owner { cred = StringLib.concat(_client_id,",", _client_secret); - credentials = StringLib.concat("?client_id=",_client_id,"&client_secret="+_client_secret); } function setScript(string _script) only_owner{ script = _script; } - function clearAPICredentials() - only_owner { + function clearAPICredentials() only_owner { cred = ""; - credentials = ""; } function toString(bytes20 self) internal constant returns (string) { @@ -233,7 +183,7 @@ contract GitHubAPIOraclize is GitHubAPI, Owned, usingOraclize{ library QueryFactory { function newGitHubAPI() returns (GitHubAPI){ - return new GitHubAPIOraclize(); + return new GitHubOracle(); } } \ No newline at end of file diff --git a/contracts/src/GitHubRegisterEth.sol b/contracts/src/GitHubRegisterEth.sol deleted file mode 100644 index b67bd92..0000000 --- a/contracts/src/GitHubRegisterEth.sol +++ /dev/null @@ -1,160 +0,0 @@ -//Author: Ricardo Guilherme Schmidt <3esmit@gmail.com> -pragma solidity ^0.4.11; - -import "lib/oraclize/oraclizeAPI_0.4.sol"; -import "lib/ethereans/management/Owned.sol"; - -contract GitHubRegisterEth is Owned, usingOraclize{ - string private credentials = ""; - mapping (bytes32 => UserClaim) userClaim; //temporary db for oraclize user register queries - mapping (bytes32 => uint256) indexes; - mapping (uint256 => User) users; - - event RegisterUpdated(string name); - - //stores temporary data for oraclize user register request - struct UserClaim { - address sender; - string login; - } - - struct User { - address addr; - string login; - } - - function GitHubRegisterEth(){ - oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); - } - - function register(string _github_user, string _gistid) payable { - bytes32 ocid = oraclize_query("nested", _getQuery(_github_user, _gistid)); - userClaim[ocid] = UserClaim({sender: msg.sender, login: _github_user}); - } - - function getAddr(uint256 _id) public constant returns(address addr) { - return users[_id].addr; - } - - function getName(address _addr) public constant returns(string name){ - return users[indexes[sha3(_addr)]].login; - } - - function getAddr(string _name) public constant returns(address addr) { - return users[indexes[sha3(_name)]].addr; - } - - event OracleEvent(bytes32 myid, string result, bytes proof); - - //oraclize response callback - function __callback(bytes32 myid, string result, bytes proof) { - OracleEvent(myid,result,proof); - if (msg.sender != oraclize.cbAddress()){ - throw; - }else { - _register(myid, result); - } - } - - function _register(bytes32 myid, string result) internal { - bytes memory v = bytes(result); - uint8 pos = 0; - address addrLoaded; - string memory login; - uint256 userId; - (addrLoaded,pos) = getNextAddr(v,pos); - (login,pos) = getNextString(v,pos); - (userId,pos) = getNextUInt(v,pos); - if(userClaim[myid].sender == addrLoaded && sha3(userClaim[myid].login) == sha3(login)){ - RegisterUpdated(login); - if(users[userId].addr != 0x0){ - delete indexes[sha3(users[userId].login)]; - delete indexes[sha3(users[userId].addr)]; - } - indexes[sha3(addrLoaded)] = userId; - indexes[sha3(login)] = userId; - users[userId].addr = addrLoaded; - users[userId].login = login; - } - delete userClaim[myid]; //should always be deleted - } - - //owner management - function setAPICredentials(string _client_id, string _client_secret) only_owner { - credentials = strConcat("?client_id=",_client_id,"&client_secret=",_client_secret,""); - } - - function clearAPICredentials() only_owner { - credentials = ""; - } - - //internal helper functions - function _getQuery(string _github_user, string _gistid) internal constant returns (string){ - string memory a = strConcat("[identity] ${[URL] https://gist.githubusercontent.com/", _github_user,"/",_gistid,"/raw/registereth.txt}, ${[URL] json(https://api.github.com/gists/"); - return strConcat(a, _gistid, credentials, ").owner.[login,id]}",""); - } - - 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 _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 constant 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 constant returns (uint){ - return val - (val < 58 ? 48 : (val < 97 ? 55 : 87)); - } - -} \ No newline at end of file diff --git a/contracts/src/GitHubRepositoryReg.sol b/contracts/src/GitHubRepositoryReg.sol new file mode 100644 index 0000000..6381c05 --- /dev/null +++ b/contracts/src/GitHubRepositoryReg.sol @@ -0,0 +1,81 @@ +//Author: Ricardo Guilherme Schmidt <3esmit@gmail.com> +pragma solidity ^0.4.11; + +import "GitHubAPIReg.sol"; +import "NameRegistry.sol"; +import "GitRepository.sol"; + +contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg { + + mapping (uint256 => Repository) repositories; + + event UpdatedRepository(address addr, uint256 projectId, string full_name, string default_branch); + + struct Repository { + address addr; + string full_name; + string branch; + } + + function GitHubRepositoryReg(){ + oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); + } + + function setRepository(string _repository, bool create) payable only_owner{ + oraclize_query("URL", getQuery(_repository), create? 4000000 : 1000000); + } + + function getAddr(uint256 _id) public constant returns(address addr) { + return repositories[_id].addr; + } + + function getName(address _addr) public constant returns(string name){ + return repositories[indexes[sha3(_addr)]].login; + } + + function getAddr(string _name) public constant returns(address addr) { + return repositories[indexes[sha3(_name)]].addr; + } + + //oraclize response callback + function __callback(bytes32 myid, string result, bytes proof) { + OracleEvent(myid,result,proof); + if (msg.sender != oraclize.cbAddress()){ + throw; + }else { + _setRepository(myid, result); + } + } + + function _setRepository(bytes32 myid, string result) internal //[85743750, "ethereans/TheEtherian", "master"] + { + bytes memory v = bytes(result); + uint8 pos = 0; + string memory temp; + uint256 projectId; + (projectId,pos) = getNextUInt(v,pos); + string memory full_name; + (full_name,pos) = getNextString(v,pos); + string memory default_branch; + (default_branch,pos) = getNextString(v,pos); + address repoAddr = repositories[projectId].addr; + if(repoAddr == 0x0){ + repoAddr = address(GitFactory.newGitRepository(projectId, full_name, default_branch)); + indexes[sha3(repoAddr)] = projectId; + indexes[sha3(full_name)] = projectId; + NewRepository(repoAddr, projectId, full_name, default_branch); + repositories[projectId] = Repository(addr: repoAddr, full_name: full_name, default_branch: default_branch);| + }else{ + bytes32 _new = sha3(full_name); + bytes32 _old = sha3(repositories[projectId].full_name); + if(_new != _old){ + _updateIndex(_old, _new); + } + } + } + //internal helper functions + function _getQuery(string _repository) internal constant returns (string){ + return strConcat("json(https://api.github.com/repos/",_repository,credentials,").$.id,full_name,default_branch"); + } + +} \ No newline at end of file diff --git a/contracts/src/GitHubUserReg.sol b/contracts/src/GitHubUserReg.sol new file mode 100644 index 0000000..0f016dc --- /dev/null +++ b/contracts/src/GitHubUserReg.sol @@ -0,0 +1,81 @@ +//Author: Ricardo Guilherme Schmidt <3esmit@gmail.com> +pragma solidity ^0.4.11; + +import "GitHubAPIReg.sol"; +import "NameRegistry.sol"; + +contract GitHubUserReg is NameRegistry, GitHubAPIReg { + + mapping (bytes32 => UserClaim) userClaim; //temporary db for oraclize user register queries + mapping (uint256 => User) users; + + event RegisterUpdated(string name); + + //stores temporary data for oraclize user register request + struct UserClaim { + address sender; + string login; + } + + struct User { + address addr; + string login; + } + + function register(string _github_user, string _gistid) payable { + bytes32 ocid = oraclize_query("nested", _getQuery(_github_user, _gistid)); + userClaim[ocid] = UserClaim({sender: msg.sender, login: _github_user}); + } + + function getAddr(uint256 _id) public constant returns(address addr) { + return users[_id].addr; + } + + function getName(address _addr) public constant returns(string name){ + return users[indexes[sha3(_addr)]].login; + } + + function getAddr(string _name) public constant returns(address addr) { + return users[indexes[sha3(_name)]].addr; + } + + //oraclize response callback + function __callback(bytes32 myid, string result, bytes proof) { + OracleEvent(myid, result, proof); + if (msg.sender != oraclize.cbAddress()){ + throw; + }else { + _register(myid, result); + } + } + + function _register(bytes32 myid, string result) internal { + bytes memory v = bytes(result); + uint8 pos = 0; + address addrLoaded; + string memory login; + uint256 userId; + (addrLoaded,pos) = getNextAddr(v,pos); + (login,pos) = getNextString(v,pos); + (userId,pos) = getNextUInt(v,pos); + if(userClaim[myid].sender == addrLoaded && sha3(userClaim[myid].login) == sha3(login)){ + RegisterUpdated(login); + if(users[userId].addr != 0x0){ + delete indexes[sha3(users[userId].login)]; + delete indexes[sha3(users[userId].addr)]; + } + indexes[sha3(addrLoaded)] = userId; + indexes[sha3(login)] = userId; + users[userId].addr = addrLoaded; + users[userId].login = login; + } + delete userClaim[myid]; //should always be deleted + } + + //internal helper functions + function _getQuery(string _github_user, string _gistid) internal constant returns (string){ + string memory a = strConcat("[identity] ${[URL] https://gist.githubusercontent.com/", _github_user,"/",_gistid,"/raw/registereth.txt}, ${[URL] json(https://api.github.com/gists/"); + return strConcat(a, _gistid, credentials, ").owner.[login,id]}",""); + } + +} \ No newline at end of file diff --git a/contracts/src/NameRegistry.sol b/contracts/src/NameRegistry.sol new file mode 100644 index 0000000..e308ef0 --- /dev/null +++ b/contracts/src/NameRegistry.sol @@ -0,0 +1,5 @@ +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); +} \ No newline at end of file From 3c4b9ae76648f69fe3efbd202b4110110acfd76e Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Thu, 11 May 2017 16:56:39 -0300 Subject: [PATCH 02/10] fixed contracts scope --- contracts/src/DGit.sol | 96 ------------- contracts/src/GitHubOracle.sol | 247 ++++++++++----------------------- contracts/src/GitHubPoints.sol | 189 +++++++++++++++++++++++++ 3 files changed, 266 insertions(+), 266 deletions(-) delete mode 100644 contracts/src/DGit.sol create mode 100644 contracts/src/GitHubPoints.sol diff --git a/contracts/src/DGit.sol b/contracts/src/DGit.sol deleted file mode 100644 index 436468e..0000000 --- a/contracts/src/DGit.sol +++ /dev/null @@ -1,96 +0,0 @@ -pragma solidity ^0.4.8; - -/** - * Contract that oracle github API - * - * GitHubOracle register users and create GitHubToken contracts - * Registration requires user create a gist with only their account address - * GitHubOracle will create one GitHubToken contract per repository - * GitHubToken mint tokens by commit only for registered users in GitHubOracle - * GitHubToken is a LockableCoin, that accept donatations and can be withdrawn by Token Holders - * The lookups are done by Oraclize that charge a small fee - * The contract itself will never charge any fee - * - * By Ricardo Guilherme Schmidt - * Released under GPLv3 License - */ - -import "lib/oraclize/oraclizeAPI_0.4.sol"; -import "lib/ethereans/management/Owned.sol"; -import "./DGitDB.sol"; -import "./GitHubAPI.sol"; -import "./GitRepository.sol"; - -contract DGit is Owned, DGitI { - - DGitDBI public db; - GitHubAPI public gitHubApi; - - function initialize() only_owner { - db = DBFactory.newStorage(); - gitHubApi = QueryFactory.newGitHubAPI(); - } - - function register(string _github_user, string _gistid) payable{ - gitHubApi.register.value(msg.value)(msg.sender,_github_user,_gistid); - } - function updateCommits(string _repository) payable{ - gitHubApi.updateCommits.value(msg.value)(_repository,db.getClaimedHead(_repository)); - } - function addRepository(string _repository) payable{ - gitHubApi.addRepository.value(msg.value)(_repository); - } - function updateIssue(string _repository, string issue) payable{ - gitHubApi.updateIssue.value(msg.value)(_repository,issue); - } - function getRepository(uint projectId) constant returns (address){ - return db.getRepositoryAddress(projectId); - } - function getRepository(string full_name) constant returns (address){ - return db.getRepositoryAddress(full_name); - } - - modifier only_gitapi{ - if (msg.sender != address(gitHubApi)) throw; - _; - } - - event UserSet(string githubLogin); - function __register(address addrLoaded, uint256 userId, string login) - only_gitapi { - UserSet(login); - db.addUser(userId, login, 0, addrLoaded); - } - - event GitRepositoryRegistered(uint256 projectId, string full_name, uint256 watchers, uint256 subscribers); - function __setRepository(uint256 projectId, string full_name, uint256 watchers, uint256 subscribers) only_gitapi //[83725290, "ethereans/github-token", 4, 2] - { - uint256 ownerId; string memory name; //TODO - address repository = db.getRepositoryAddress(projectId); - if(repository == 0x0){ - GitRepositoryRegistered(projectId,full_name,watchers,subscribers); - repository = GitFactory.newGitRepository(projectId,full_name); - db.addRepository(projectId,ownerId,name,full_name,repository); - } - GitRepositoryI(repository).setStats(subscribers,watchers); - } - - event NewPoints(string repository, uint userId, uint total); - function __newPoints(string repository, uint userId, uint total) - only_gitapi { - NewPoints(repository,userId,total); - GitRepositoryI repoaddr = GitRepositoryI(db.getRepositoryAddress(repository)); - if(!repoaddr.claim(db.getUserAddress(userId), total)){ //try to claim points - db.setPending(repository, userId, total); //set as a pending points - } - } - - //claims pending points - function claimPending(uint repoId, uint userId){ - GitRepositoryI repoaddr = GitRepositoryI(db.getRepositoryAddress(repoId)); - uint total = db.claimPending(repoId,userId); - if(!repoaddr.claim(db.getUserAddress(userId), total)) throw; - - } - -} \ No newline at end of file diff --git a/contracts/src/GitHubOracle.sol b/contracts/src/GitHubOracle.sol index c8fec8e..436468e 100644 --- a/contracts/src/GitHubOracle.sol +++ b/contracts/src/GitHubOracle.sol @@ -1,189 +1,96 @@ -pragma solidity ^0.4.9; +pragma solidity ^0.4.8; +/** + * Contract that oracle github API + * + * GitHubOracle register users and create GitHubToken contracts + * Registration requires user create a gist with only their account address + * GitHubOracle will create one GitHubToken contract per repository + * GitHubToken mint tokens by commit only for registered users in GitHubOracle + * GitHubToken is a LockableCoin, that accept donatations and can be withdrawn by Token Holders + * The lookups are done by Oraclize that charge a small fee + * The contract itself will never charge any fee + * + * By Ricardo Guilherme Schmidt + * Released under GPLv3 License + */ + import "lib/oraclize/oraclizeAPI_0.4.sol"; -import "lib/StringLib.sol"; -import "lib/JSONLib.sol"; import "lib/ethereans/management/Owned.sol"; +import "./DGitDB.sol"; +import "./GitHubAPI.sol"; +import "./GitRepository.sol"; +contract DGit is Owned, DGitI { -contract GitHubAPI{ - function updateCommits(string _full_name, string _branch, bytes20 _commitid) payable; - function updateIssue(string _full_name, string _issue) payable; -} + DGitDBI public db; + GitHubAPI public gitHubApi; -contract DGitI { - function __addRepository(uint256 projectId, string full_name, string default_branch); - function __setHead(uint256 projectId, string branch, bytes20 head); - function __setTail(uint256 projectId, string branch, bytes20 tail); - function __newPoints(uint256 projectId, uint256 userId, uint total); - function __setIssue(uint256 projectId, uint256 issueId, bool state, uint256 closedAt); - function __setIssuePoints(uint256 projectId, uint256 issueId, uint256 userId, uint256 points); -} + function initialize() only_owner { + db = DBFactory.newStorage(); + gitHubApi = QueryFactory.newGitHubAPI(); + } -contract GitHubOracle is GitHubAPI, Owned, usingOraclize{ - using StringLib for string; - DGitI dGit - - string private cred = ""; - string private script = ""; - - enum OracleType { CLAIM_COMMIT, CLAIM_CONTINUE, UPDATE_ISSUE } - mapping (bytes32 => OracleType) claimType; //temporary db enumerating oraclize calls - mapping (bytes32 => CommitClaim) commitClaim; //temporary db for oraclize commit token claim calls - - //stores temporary data for oraclize repository commit claim - struct CommitClaim { - string repository; - bytes20 commitid; + function register(string _github_user, string _gistid) payable{ + gitHubApi.register.value(msg.value)(msg.sender,_github_user,_gistid); + } + function updateCommits(string _repository) payable{ + gitHubApi.updateCommits.value(msg.value)(_repository,db.getClaimedHead(_repository)); + } + function addRepository(string _repository) payable{ + gitHubApi.addRepository.value(msg.value)(_repository); + } + function updateIssue(string _repository, string issue) payable{ + gitHubApi.updateIssue.value(msg.value)(_repository,issue); + } + function getRepository(uint projectId) constant returns (address){ + return db.getRepositoryAddress(projectId); + } + function getRepository(string full_name) constant returns (address){ + return db.getRepositoryAddress(full_name); + } + + modifier only_gitapi{ + if (msg.sender != address(gitHubApi)) throw; + _; } - function GitHubOracle(string _script){ - script = _script; - dGit = DGitI(msg.sender); - oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); + event UserSet(string githubLogin); + function __register(address addrLoaded, uint256 userId, string login) + only_gitapi { + UserSet(login); + db.addUser(userId, login, 0, addrLoaded); } - function updateCommits(string _repository, string _branch, bytes20 _commitid) - payable only_owner{ - bytes32 ocid = oraclize_query("computation", [script, "update-new",_repository.concat(",", _branch,",",toString(_commitid)),cred]); - claimType[ocid] = OracleType.CLAIM_COMMIT; - commitClaim[ocid] = CommitClaim( { repository: _repository, commitid:_commitid}); - } - - function continueUpdateCommits(string _repository, string _branch, bytes20 _lastCommit,bytes20 _limitCommit) - payable only_owner{ - bytes32 ocid = oraclize_query("computation", [script, "update-old",_repository.concat(",", _branch,",",toString(_lastCommit)).concat(",",toString(_limitCommit)),cred]); - claimType[ocid] = OracleType.CLAIM_CONTINUE; - } - - function updateIssue(string _repository, string issue) payable only_owner{ - bytes32 ocid = oraclize_query("computation", [script, "issue-update",_repository.concat(",",issue),cred]); - } - - event OracleEvent(bytes32 myid, string result, bytes proof); - //oraclize response callback - function __callback(bytes32 myid, string result, bytes proof) { - OracleEvent(myid, result, proof); - if (msg.sender != oraclize.cbAddress()){ - throw; - }else if(claimType[myid]==OracleType.CLAIM_COMMIT){ - _updateCommits(myid, result, false); - }else if(claimType[myid]==OracleType.CLAIM_CONTINUE){ - _updateCommits(myid, result, true); - }else if(claimType[myid] == OracleType.UPDATE_ISSUE){ - _updateIssue(myid, result); + event GitRepositoryRegistered(uint256 projectId, string full_name, uint256 watchers, uint256 subscribers); + function __setRepository(uint256 projectId, string full_name, uint256 watchers, uint256 subscribers) only_gitapi //[83725290, "ethereans/github-token", 4, 2] + { + uint256 ownerId; string memory name; //TODO + address repository = db.getRepositoryAddress(projectId); + if(repository == 0x0){ + GitRepositoryRegistered(projectId,full_name,watchers,subscribers); + repository = GitFactory.newGitRepository(projectId,full_name); + db.addRepository(projectId,ownerId,name,full_name,repository); } - delete claimType[myid]; //should always be deleted + GitRepositoryI(repository).setStats(subscribers,watchers); } - function _addRepository(bytes32 myid, string result) internal {//[85743750, "ethereans/TheEtherian", "master"] - bytes memory v = bytes(result); - uint8 pos = 0; - string memory temp; - uint256 projectId; - (projectId,pos) = JSONLib.getNextUInt(v,pos); - string memory full_name; - (full_name,pos) = JSONLib.getNextString(v,pos); - string memory default_branch; - (default_branch,pos) = JSONLib.getNextString(v,pos); - dGit.__addRepository(projectId,full_name,default_branch); - } - - function _updateCommits(bytes32 myid, string result, bool continuing) internal { - bytes memory v = bytes(result); - uint8 pos = 0; - string memory temp; - uint256 projectId; - (projectId,pos) = JSONLib.getNextUInt(v,pos); - string memory branch; - (branch,pos) = JSONLib.getNextString(v,pos); - (temp,pos) = JSONLib.getNextString(v,pos); - bytes20 head = temp.toBytes20(); - (temp,pos) = JSONLib.getNextString(v,pos); - bytes20 tail = temp.toBytes20(); - uint numAuthors; - (numAuthors,pos) = JSONLib.getNextUInt(v,pos); - uint userId; - uint points; - dGit.__setHead(projectId,branch,head); - if(continuing){ - dGit.__setTail(projectId,branch,tail); - }else{ - bytes20 oldCommit = commitUpdate[myid].commitid; - if(oldCommit == 0x0){ - dGit.__setTail(projectId,branch,tail); - }else if (oldCommit != tail){ - //TODO: acceptContinueUpdateUntilLimit(tail,oldCommit) - } - } - for(uint i; i < numAuthors; i++){ - (userId,pos) = JSONLib.getNextUInt(v,pos); - (points,pos) = JSONLib.getNextUInt(v,pos); - dGit.__newPoints(projectId,userId,points); - } + event NewPoints(string repository, uint userId, uint total); + function __newPoints(string repository, uint userId, uint total) + only_gitapi { + NewPoints(repository,userId,total); + GitRepositoryI repoaddr = GitRepositoryI(db.getRepositoryAddress(repository)); + if(!repoaddr.claim(db.getUserAddress(userId), total)){ //try to claim points + db.setPending(repository, userId, total); //set as a pending points + } } - function _updateIssue(bytes32 myid, string result) internal { - bytes memory v = bytes(result); - uint8 pos = 0; - string memory temp; - uint256 projectId; - (projectId,pos) = JSONLib.getNextUInt(v,pos); - uint256 issueId; - (issueId,pos) = JSONLib.getNextUInt(v,pos); - bool state; - (temp,pos) = JSONLib.getNextString(v,pos); - state = (temp.compare("open") == 0); - uint256 closedAt; - (closedAt,pos) = JSONLib.getNextUInt(v,pos); - uint numAuthors; - (numAuthors,pos) = JSONLib.getNextUInt(v,pos); - uint userId; - uint points; - dGit.__setIssue(projectId,issueId,state,closedAt); - for(uint i; i < numAuthors; i++){ - (userId,pos) = JSONLib.getNextUInt(v,pos); - (points,pos) = JSONLib.getNextUInt(v,pos); - dGit.__setIssuePoints(projectId,issueId,userId,points); - } - } - - //owner management - function setAPICredentials(string _client_id, string _client_secret) only_owner { - cred = StringLib.concat(_client_id,",", _client_secret); - } - - function setScript(string _script) only_owner{ - script = _script; - } - - function clearAPICredentials() only_owner { - cred = ""; - } - - function toString(bytes20 self) internal constant returns (string) { - bytes memory bytesString = new bytes(20); - uint charCount = 0; - for (uint j = 0; j < 20; j++) { - byte char = byte(bytes20(uint(self) * 2 ** (8 * j))); - if (char != 0) { - bytesString[charCount] = char; - charCount++; - } - } - bytes memory bytesStringTrimmed = new bytes(charCount); - for (j = 0; j < charCount; j++) { - bytesStringTrimmed[j] = bytesString[j]; - } - return string(bytesStringTrimmed); - } - -} - -library QueryFactory { - - function newGitHubAPI() returns (GitHubAPI){ - return new GitHubOracle(); + //claims pending points + function claimPending(uint repoId, uint userId){ + GitRepositoryI repoaddr = GitRepositoryI(db.getRepositoryAddress(repoId)); + uint total = db.claimPending(repoId,userId); + if(!repoaddr.claim(db.getUserAddress(userId), total)) throw; + } } \ No newline at end of file diff --git a/contracts/src/GitHubPoints.sol b/contracts/src/GitHubPoints.sol new file mode 100644 index 0000000..c8fec8e --- /dev/null +++ b/contracts/src/GitHubPoints.sol @@ -0,0 +1,189 @@ +pragma solidity ^0.4.9; + +import "lib/oraclize/oraclizeAPI_0.4.sol"; +import "lib/StringLib.sol"; +import "lib/JSONLib.sol"; +import "lib/ethereans/management/Owned.sol"; + + +contract GitHubAPI{ + function updateCommits(string _full_name, string _branch, bytes20 _commitid) payable; + function updateIssue(string _full_name, string _issue) payable; +} + +contract DGitI { + function __addRepository(uint256 projectId, string full_name, string default_branch); + function __setHead(uint256 projectId, string branch, bytes20 head); + function __setTail(uint256 projectId, string branch, bytes20 tail); + function __newPoints(uint256 projectId, uint256 userId, uint total); + function __setIssue(uint256 projectId, uint256 issueId, bool state, uint256 closedAt); + function __setIssuePoints(uint256 projectId, uint256 issueId, uint256 userId, uint256 points); +} + +contract GitHubOracle is GitHubAPI, Owned, usingOraclize{ + using StringLib for string; + DGitI dGit + + string private cred = ""; + string private script = ""; + + enum OracleType { CLAIM_COMMIT, CLAIM_CONTINUE, UPDATE_ISSUE } + mapping (bytes32 => OracleType) claimType; //temporary db enumerating oraclize calls + mapping (bytes32 => CommitClaim) commitClaim; //temporary db for oraclize commit token claim calls + + //stores temporary data for oraclize repository commit claim + struct CommitClaim { + string repository; + bytes20 commitid; + } + + function GitHubOracle(string _script){ + script = _script; + dGit = DGitI(msg.sender); + oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); + } + + function updateCommits(string _repository, string _branch, bytes20 _commitid) + payable only_owner{ + bytes32 ocid = oraclize_query("computation", [script, "update-new",_repository.concat(",", _branch,",",toString(_commitid)),cred]); + claimType[ocid] = OracleType.CLAIM_COMMIT; + commitClaim[ocid] = CommitClaim( { repository: _repository, commitid:_commitid}); + } + + function continueUpdateCommits(string _repository, string _branch, bytes20 _lastCommit,bytes20 _limitCommit) + payable only_owner{ + bytes32 ocid = oraclize_query("computation", [script, "update-old",_repository.concat(",", _branch,",",toString(_lastCommit)).concat(",",toString(_limitCommit)),cred]); + claimType[ocid] = OracleType.CLAIM_CONTINUE; + } + + function updateIssue(string _repository, string issue) payable only_owner{ + bytes32 ocid = oraclize_query("computation", [script, "issue-update",_repository.concat(",",issue),cred]); + } + + event OracleEvent(bytes32 myid, string result, bytes proof); + //oraclize response callback + function __callback(bytes32 myid, string result, bytes proof) { + OracleEvent(myid, result, proof); + if (msg.sender != oraclize.cbAddress()){ + throw; + }else if(claimType[myid]==OracleType.CLAIM_COMMIT){ + _updateCommits(myid, result, false); + }else if(claimType[myid]==OracleType.CLAIM_CONTINUE){ + _updateCommits(myid, result, true); + }else if(claimType[myid] == OracleType.UPDATE_ISSUE){ + _updateIssue(myid, result); + } + delete claimType[myid]; //should always be deleted + } + + function _addRepository(bytes32 myid, string result) internal {//[85743750, "ethereans/TheEtherian", "master"] + bytes memory v = bytes(result); + uint8 pos = 0; + string memory temp; + uint256 projectId; + (projectId,pos) = JSONLib.getNextUInt(v,pos); + string memory full_name; + (full_name,pos) = JSONLib.getNextString(v,pos); + string memory default_branch; + (default_branch,pos) = JSONLib.getNextString(v,pos); + dGit.__addRepository(projectId,full_name,default_branch); + } + + function _updateCommits(bytes32 myid, string result, bool continuing) internal { + bytes memory v = bytes(result); + uint8 pos = 0; + string memory temp; + uint256 projectId; + (projectId,pos) = JSONLib.getNextUInt(v,pos); + string memory branch; + (branch,pos) = JSONLib.getNextString(v,pos); + (temp,pos) = JSONLib.getNextString(v,pos); + bytes20 head = temp.toBytes20(); + (temp,pos) = JSONLib.getNextString(v,pos); + bytes20 tail = temp.toBytes20(); + uint numAuthors; + (numAuthors,pos) = JSONLib.getNextUInt(v,pos); + uint userId; + uint points; + dGit.__setHead(projectId,branch,head); + if(continuing){ + dGit.__setTail(projectId,branch,tail); + }else{ + bytes20 oldCommit = commitUpdate[myid].commitid; + if(oldCommit == 0x0){ + dGit.__setTail(projectId,branch,tail); + }else if (oldCommit != tail){ + //TODO: acceptContinueUpdateUntilLimit(tail,oldCommit) + } + } + for(uint i; i < numAuthors; i++){ + (userId,pos) = JSONLib.getNextUInt(v,pos); + (points,pos) = JSONLib.getNextUInt(v,pos); + dGit.__newPoints(projectId,userId,points); + } + } + + function _updateIssue(bytes32 myid, string result) internal { + bytes memory v = bytes(result); + uint8 pos = 0; + string memory temp; + uint256 projectId; + (projectId,pos) = JSONLib.getNextUInt(v,pos); + uint256 issueId; + (issueId,pos) = JSONLib.getNextUInt(v,pos); + bool state; + (temp,pos) = JSONLib.getNextString(v,pos); + state = (temp.compare("open") == 0); + uint256 closedAt; + (closedAt,pos) = JSONLib.getNextUInt(v,pos); + uint numAuthors; + (numAuthors,pos) = JSONLib.getNextUInt(v,pos); + uint userId; + uint points; + dGit.__setIssue(projectId,issueId,state,closedAt); + for(uint i; i < numAuthors; i++){ + (userId,pos) = JSONLib.getNextUInt(v,pos); + (points,pos) = JSONLib.getNextUInt(v,pos); + dGit.__setIssuePoints(projectId,issueId,userId,points); + } + } + + //owner management + function setAPICredentials(string _client_id, string _client_secret) only_owner { + cred = StringLib.concat(_client_id,",", _client_secret); + } + + function setScript(string _script) only_owner{ + script = _script; + } + + function clearAPICredentials() only_owner { + cred = ""; + } + + function toString(bytes20 self) internal constant returns (string) { + bytes memory bytesString = new bytes(20); + uint charCount = 0; + for (uint j = 0; j < 20; j++) { + byte char = byte(bytes20(uint(self) * 2 ** (8 * j))); + if (char != 0) { + bytesString[charCount] = char; + charCount++; + } + } + bytes memory bytesStringTrimmed = new bytes(charCount); + for (j = 0; j < charCount; j++) { + bytesStringTrimmed[j] = bytesString[j]; + } + return string(bytesStringTrimmed); + } + +} + +library QueryFactory { + + function newGitHubAPI() returns (GitHubAPI){ + return new GitHubOracle(); + } + +} \ No newline at end of file From a20380df038cf821f1d2971bc7767268e844891e Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Fri, 12 May 2017 13:19:29 -0300 Subject: [PATCH 03/10] development --- contracts/src/GitHubAPIReg.sol | 17 +- contracts/src/GitHubOracle.sol | 89 ++-- contracts/src/GitHubPoints.sol | 24 +- contracts/src/GitHubRepositoryReg.sol | 32 +- contracts/src/GitHubUserReg.sol | 10 +- contracts/src/GitRepository.sol | 10 - contracts/src/NameRegistry.sol | 16 +- contracts/src/oraclize/oraclizeAPI_0.4.sol | 521 +++++++++++++++++++++ 8 files changed, 615 insertions(+), 104 deletions(-) create mode 100644 contracts/src/oraclize/oraclizeAPI_0.4.sol diff --git a/contracts/src/GitHubAPIReg.sol b/contracts/src/GitHubAPIReg.sol index 71966e8..d2c052f 100644 --- a/contracts/src/GitHubAPIReg.sol +++ b/contracts/src/GitHubAPIReg.sol @@ -1,14 +1,19 @@ -//Author: Ricardo Guilherme Schmidt <3esmit@gmail.com> -pragma solidity ^0.4.11; - +/** + * GitHubAPIReg.sol + * Abstract Logic for GitHubOracle Registries. + * Ricardo Guilherme Schmidt <3esmit@gmail.com> + */ import "lib/ethereans/management/Owned.sol"; +import "lib/oraclize/oraclizeAPI_0.4.sol"; + +pragma solidity ^0.4.11; contract GitHubAPIReg is Owned, usingOraclize { string credentials = ""; event OracleEvent(bytes32 myid, string result, bytes proof); - function GitHubAPI(){ + function GitHubAPIReg(){ oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); } @@ -21,7 +26,7 @@ contract GitHubAPIReg is Owned, usingOraclize { credentials = ""; } - function getNextString(bytes _str, uint8 _pos) internal constant returns (string,uint8) { + function getNextString(bytes _str, uint8 _pos) internal constant returns (string, uint8) { uint8 start = 0; uint8 end = 0; uint strl =_str.length; @@ -43,7 +48,7 @@ contract GitHubAPIReg is Owned, usingOraclize { return (string(str),_pos); } - function getNextUInt(bytes _str, uint8 _pos) internal constant returns (uint,uint8) { + function getNextUInt(bytes _str, uint8 _pos) internal constant returns (uint, uint8) { uint val = 0; uint strl =_str.length; for (; strl > _pos; _pos++) { diff --git a/contracts/src/GitHubOracle.sol b/contracts/src/GitHubOracle.sol index 436468e..e95df9c 100644 --- a/contracts/src/GitHubOracle.sol +++ b/contracts/src/GitHubOracle.sol @@ -1,8 +1,6 @@ -pragma solidity ^0.4.8; - /** + * GitHubOracle.sol * Contract that oracle github API - * * GitHubOracle register users and create GitHubToken contracts * Registration requires user create a gist with only their account address * GitHubOracle will create one GitHubToken contract per repository @@ -17,37 +15,49 @@ pragma solidity ^0.4.8; import "lib/oraclize/oraclizeAPI_0.4.sol"; import "lib/ethereans/management/Owned.sol"; -import "./DGitDB.sol"; -import "./GitHubAPI.sol"; -import "./GitRepository.sol"; +import "GitHubUserReg.sol"; +import "GitHubRepositoryReg.sol"; +import "GitHubPoints.sol"; -contract DGit is Owned, DGitI { +pragma solidity ^0.4.11; - DGitDBI public db; - GitHubAPI public gitHubApi; +contract GitHubOracle is Owned, DGitI { + GitHubUserReg public userReg; + GitHubRepositoryReg public repositoryReg; + GitHubPoints public gitHubPoints; + + mapping (uint256 => Repository) repositories; + mapping (uint256 => mapping (uint256 => uint256)) pendingPoints; + + struct Repository { + bytes20 head; + bytes20 tail; + } + function initialize() only_owner { - db = DBFactory.newStorage(); - gitHubApi = QueryFactory.newGitHubAPI(); + userReg = QueryFactory.newUserReg(); + repositoryReg = QueryFactory.newRepositoryReg(); + gitHubPoints = QueryFactory.newPointsOracle(); } function register(string _github_user, string _gistid) payable{ - gitHubApi.register.value(msg.value)(msg.sender,_github_user,_gistid); + userReg.register.value(msg.value)(msg.sender,_github_user,_gistid); } function updateCommits(string _repository) payable{ - gitHubApi.updateCommits.value(msg.value)(_repository,db.getClaimedHead(_repository)); + gitHubPoints.updateCommits.value(msg.value)(_repository,db.getClaimedHead(_repository)); } function addRepository(string _repository) payable{ - gitHubApi.addRepository.value(msg.value)(_repository); + repositoryReg.addRepository.value(msg.value)(_repository); } function updateIssue(string _repository, string issue) payable{ - gitHubApi.updateIssue.value(msg.value)(_repository,issue); + gitHubPoints.updateIssue.value(msg.value)(_repository,issue); } function getRepository(uint projectId) constant returns (address){ - return db.getRepositoryAddress(projectId); + return repositoryReg.getAddr(projectId); } function getRepository(string full_name) constant returns (address){ - return db.getRepositoryAddress(full_name); + return repositoryReg.getAddr(full_name); } modifier only_gitapi{ @@ -55,42 +65,29 @@ contract DGit is Owned, DGitI { _; } - event UserSet(string githubLogin); - function __register(address addrLoaded, uint256 userId, string login) - only_gitapi { - UserSet(login); - db.addUser(userId, login, 0, addrLoaded); - } - - event GitRepositoryRegistered(uint256 projectId, string full_name, uint256 watchers, uint256 subscribers); - function __setRepository(uint256 projectId, string full_name, uint256 watchers, uint256 subscribers) only_gitapi //[83725290, "ethereans/github-token", 4, 2] - { - uint256 ownerId; string memory name; //TODO - address repository = db.getRepositoryAddress(projectId); - if(repository == 0x0){ - GitRepositoryRegistered(projectId,full_name,watchers,subscribers); - repository = GitFactory.newGitRepository(projectId,full_name); - db.addRepository(projectId,ownerId,name,full_name,repository); - } - GitRepositoryI(repository).setStats(subscribers,watchers); - } + event NewPoints(uint repoId, uint userId, uint total, bool claimed); - event NewPoints(string repository, uint userId, uint total); - function __newPoints(string repository, uint userId, uint total) + function __newPoints(uint repoId, uint userId, uint total) only_gitapi { - NewPoints(repository,userId,total); - GitRepositoryI repoaddr = GitRepositoryI(db.getRepositoryAddress(repository)); - if(!repoaddr.claim(db.getUserAddress(userId), total)){ //try to claim points - db.setPending(repository, userId, total); //set as a pending points + GitRepositoryI repoaddr = GitRepositoryI(repositoryReg.getAddr(repoId)); + bool claimed = repoaddr.claim(db.getUserAddress(userId), total); + if(!claimed){ //try to claim points + addPending(repoId, userId, total); //set as a pending points } + NewPoints(repository,userId,total,claimed); } //claims pending points function claimPending(uint repoId, uint userId){ - GitRepositoryI repoaddr = GitRepositoryI(db.getRepositoryAddress(repoId)); - uint total = db.claimPending(repoId,userId); - if(!repoaddr.claim(db.getUserAddress(userId), total)) throw; - + GitRepositoryI repoaddr = GitRepositoryI(repositoryReg.getAddr(repoId)); + uint total = pending[_userId][_repoId]; + delete pending[_userId][_repoId]; + if(repoaddr.claim(gitHubUserRegistry.getAddr(userId), total)) { + NewPoints(repository,userId,total,true); + } else throw; } + function addPending(uint256 _repoid, uint256 _userid, uint256 _points) internal { + pending[_userId][_repoId] += _points; + } } \ No newline at end of file diff --git a/contracts/src/GitHubPoints.sol b/contracts/src/GitHubPoints.sol index c8fec8e..0bee26f 100644 --- a/contracts/src/GitHubPoints.sol +++ b/contracts/src/GitHubPoints.sol @@ -5,14 +5,7 @@ import "lib/StringLib.sol"; import "lib/JSONLib.sol"; import "lib/ethereans/management/Owned.sol"; - -contract GitHubAPI{ - function updateCommits(string _full_name, string _branch, bytes20 _commitid) payable; - function updateIssue(string _full_name, string _issue) payable; -} - contract DGitI { - function __addRepository(uint256 projectId, string full_name, string default_branch); function __setHead(uint256 projectId, string branch, bytes20 head); function __setTail(uint256 projectId, string branch, bytes20 tail); function __newPoints(uint256 projectId, uint256 userId, uint total); @@ -20,7 +13,7 @@ contract DGitI { function __setIssuePoints(uint256 projectId, uint256 issueId, uint256 userId, uint256 points); } -contract GitHubOracle is GitHubAPI, Owned, usingOraclize{ +contract GitHubPoints is Owned, usingOraclize{ using StringLib for string; DGitI dGit @@ -37,7 +30,7 @@ contract GitHubOracle is GitHubAPI, Owned, usingOraclize{ bytes20 commitid; } - function GitHubOracle(string _script){ + function GitHubPoints(string _script){ script = _script; dGit = DGitI(msg.sender); oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); @@ -76,19 +69,6 @@ contract GitHubOracle is GitHubAPI, Owned, usingOraclize{ delete claimType[myid]; //should always be deleted } - function _addRepository(bytes32 myid, string result) internal {//[85743750, "ethereans/TheEtherian", "master"] - bytes memory v = bytes(result); - uint8 pos = 0; - string memory temp; - uint256 projectId; - (projectId,pos) = JSONLib.getNextUInt(v,pos); - string memory full_name; - (full_name,pos) = JSONLib.getNextString(v,pos); - string memory default_branch; - (default_branch,pos) = JSONLib.getNextString(v,pos); - dGit.__addRepository(projectId,full_name,default_branch); - } - function _updateCommits(bytes32 myid, string result, bool continuing) internal { bytes memory v = bytes(result); uint8 pos = 0; diff --git a/contracts/src/GitHubRepositoryReg.sol b/contracts/src/GitHubRepositoryReg.sol index 6381c05..a40b53a 100644 --- a/contracts/src/GitHubRepositoryReg.sol +++ b/contracts/src/GitHubRepositoryReg.sol @@ -1,28 +1,29 @@ -//Author: Ricardo Guilherme Schmidt <3esmit@gmail.com> -pragma solidity ^0.4.11; +/** + * GitHubRepositoryReg.sol + * Registers the master branch of a Repository for GitHubOracle tracking. + * Ricardo Guilherme Schmidt <3esmit@gmail.com> + */ import "GitHubAPIReg.sol"; import "NameRegistry.sol"; import "GitRepository.sol"; +pragma solidity ^0.4.11; + contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg { mapping (uint256 => Repository) repositories; - event UpdatedRepository(address addr, uint256 projectId, string full_name, string default_branch); + event NewRepository(address addr, uint256 projectId, string full_name, string default_branch); struct Repository { address addr; - string full_name; + string name; string branch; } - function GitHubRepositoryReg(){ - oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); - } - - function setRepository(string _repository, bool create) payable only_owner{ - oraclize_query("URL", getQuery(_repository), create? 4000000 : 1000000); + function register(string _repository) payable { + oraclize_query("URL", _getQuery(_repository), getAddr(_repository) == 0x00? 4000000 : 1000000); } function getAddr(uint256 _id) public constant returns(address addr) { @@ -30,7 +31,7 @@ contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg { } function getName(address _addr) public constant returns(string name){ - return repositories[indexes[sha3(_addr)]].login; + return repositories[indexes[sha3(_addr)]].name; } function getAddr(string _name) public constant returns(address addr) { @@ -51,7 +52,6 @@ contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg { { bytes memory v = bytes(result); uint8 pos = 0; - string memory temp; uint256 projectId; (projectId,pos) = getNextUInt(v,pos); string memory full_name; @@ -60,14 +60,14 @@ contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg { (default_branch,pos) = getNextString(v,pos); address repoAddr = repositories[projectId].addr; if(repoAddr == 0x0){ - repoAddr = address(GitFactory.newGitRepository(projectId, full_name, default_branch)); + //repoAddr = address(GitFactory.newGitRepository(projectId, full_name, default_branch)); indexes[sha3(repoAddr)] = projectId; indexes[sha3(full_name)] = projectId; - NewRepository(repoAddr, projectId, full_name, default_branch); - repositories[projectId] = Repository(addr: repoAddr, full_name: full_name, default_branch: default_branch);| + NewRepository(repoAddr, projectId, full_name, default_branch); + repositories[projectId] = Repository({addr: repoAddr, name: full_name, branch: default_branch}); }else{ bytes32 _new = sha3(full_name); - bytes32 _old = sha3(repositories[projectId].full_name); + bytes32 _old = sha3(repositories[projectId].name); if(_new != _old){ _updateIndex(_old, _new); } diff --git a/contracts/src/GitHubUserReg.sol b/contracts/src/GitHubUserReg.sol index 0f016dc..4ebd032 100644 --- a/contracts/src/GitHubUserReg.sol +++ b/contracts/src/GitHubUserReg.sol @@ -1,9 +1,13 @@ -//Author: Ricardo Guilherme Schmidt <3esmit@gmail.com> -pragma solidity ^0.4.11; - +/** + * GitHubUserReg.sol + * Registers GitHub user login to an address + * Ricardo Guilherme Schmidt <3esmit@gmail.com> + */ import "GitHubAPIReg.sol"; import "NameRegistry.sol"; +pragma solidity ^0.4.11; + contract GitHubUserReg is NameRegistry, GitHubAPIReg { mapping (bytes32 => UserClaim) userClaim; //temporary db for oraclize user register queries diff --git a/contracts/src/GitRepository.sol b/contracts/src/GitRepository.sol index 870b1e1..327707e 100644 --- a/contracts/src/GitRepository.sol +++ b/contracts/src/GitRepository.sol @@ -23,7 +23,6 @@ import "./GitRepositoryToken.sol"; contract GitRepositoryI { function claim(address _user, uint _total) returns (bool) ; - function setStats(uint256 _subscribers, uint256 _watchers); } contract GitRepository is GitRepositoryI, Owned { @@ -36,9 +35,6 @@ contract GitRepository is GitRepositoryI, Owned { string public name; uint256 public uid; - uint256 public subscribers; - uint256 public watchers; - function () payable { donationBank.deposit(); donators[msg.sender] += msg.value; @@ -65,12 +61,6 @@ contract GitRepository is GitRepositoryI, Owned { } } - function setStats(uint256 _subscribers, uint256 _watchers) - only_owner { - subscribers = _subscribers; - watchers = _watchers; - } - function bountyState(uint issue, bool open) only_owner { if (open) bountyBank.open(issue); else bountyBank.close(issue); diff --git a/contracts/src/NameRegistry.sol b/contracts/src/NameRegistry.sol index e308ef0..5d0e948 100644 --- a/contracts/src/NameRegistry.sol +++ b/contracts/src/NameRegistry.sol @@ -1,5 +1,19 @@ -contract NameRegistry{ +/** + * NameRegistry.sol + * Interface for Name Registries. + * Ricardo Guilherme Schmidt <3esmit@gmail.com> + */ +pragma solidity ^0.4.11; + +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 _updateIndex(bytes32 _old, bytes32 _new) internal { + indexes[_new] = indexes[_old]; + delete indexes[_old]; + } } \ No newline at end of file diff --git a/contracts/src/oraclize/oraclizeAPI_0.4.sol b/contracts/src/oraclize/oraclizeAPI_0.4.sol new file mode 100644 index 0000000..ec30239 --- /dev/null +++ b/contracts/src/oraclize/oraclizeAPI_0.4.sol @@ -0,0 +1,521 @@ +// +/* +Copyright (c) 2015-2016 Oraclize SRL +Copyright (c) 2016 Oraclize LTD + + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + + + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + + + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +pragma solidity ^0.4.0;//please import oraclizeAPI_pre0.4.sol when solidity < 0.4.0 + +contract OraclizeI { + address public cbAddress; + function query(uint _timestamp, string _datasource, string _arg) payable returns (bytes32 _id); + function query_withGasLimit(uint _timestamp, string _datasource, string _arg, uint _gaslimit) payable returns (bytes32 _id); + function query2(uint _timestamp, string _datasource, string _arg1, string _arg2) payable returns (bytes32 _id); + function query2_withGasLimit(uint _timestamp, string _datasource, string _arg1, string _arg2, uint _gaslimit) payable returns (bytes32 _id); + function queryN(uint _timestamp, string _datasource, bytes _argN) payable returns (bytes32 _id); + function queryN_withGasLimit(uint _timestamp, string _datasource, bytes _argN, uint _gaslimit) payable returns (bytes32 _id); + function getPrice(string _datasource) returns (uint _dsprice); + function getPrice(string _datasource, uint gaslimit) returns (uint _dsprice); + function useCoupon(string _coupon); + function setProofType(byte _proofType); + function setConfig(bytes32 _config); + function setCustomGasPrice(uint _gasPrice); +} +contract OraclizeAddrResolverI { + function getAddress() returns (address _addr); +} +contract usingOraclize { + uint constant day = 60*60*24; + uint constant week = 60*60*24*7; + uint constant month = 60*60*24*30; + byte constant proofType_NONE = 0x00; + byte constant proofType_TLSNotary = 0x10; + byte constant proofStorage_IPFS = 0x01; + uint8 constant networkID_auto = 0; + uint8 constant networkID_mainnet = 1; + uint8 constant networkID_testnet = 2; + uint8 constant networkID_morden = 2; + uint8 constant networkID_consensys = 161; + + OraclizeAddrResolverI OAR; + + OraclizeI oraclize; + modifier oraclizeAPI { + if((address(OAR)==0)||(getCodeSize(address(OAR))==0)) oraclize_setNetwork(networkID_auto); + oraclize = OraclizeI(OAR.getAddress()); + _; + } + modifier coupon(string code){ + oraclize = OraclizeI(OAR.getAddress()); + oraclize.useCoupon(code); + _; + } + + function oraclize_setNetwork(uint8 networkID) internal returns(bool){ + if (getCodeSize(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed)>0){ //mainnet + OAR = OraclizeAddrResolverI(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed); + return true; + } + if (getCodeSize(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1)>0){ //ropsten testnet + OAR = OraclizeAddrResolverI(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1); + return true; + } + if (getCodeSize(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e)>0){ //kovan testnet + OAR = OraclizeAddrResolverI(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e); + return true; + } + if (getCodeSize(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475)>0){ //ethereum-bridge + OAR = OraclizeAddrResolverI(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475); + return true; + } + if (getCodeSize(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF)>0){ //ether.camp ide + OAR = OraclizeAddrResolverI(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF); + return true; + } + if (getCodeSize(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA)>0){ //browser-solidity + OAR = OraclizeAddrResolverI(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA); + return true; + } + return false; + } + + function __callback(bytes32 myid, string result) { + __callback(myid, result, new bytes(0)); + } + function __callback(bytes32 myid, string result, bytes proof) { + } + + function oraclize_getPrice(string datasource) oraclizeAPI internal returns (uint){ + return oraclize.getPrice(datasource); + } + + function oraclize_getPrice(string datasource, uint gaslimit) oraclizeAPI internal returns (uint){ + return oraclize.getPrice(datasource, gaslimit); + } + + function oraclize_query(string datasource, string arg) oraclizeAPI internal returns (bytes32 id){ + uint price = oraclize.getPrice(datasource); + if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price + return oraclize.query.value(price)(0, datasource, arg); + } + function oraclize_query(uint timestamp, string datasource, string arg) oraclizeAPI internal returns (bytes32 id){ + uint price = oraclize.getPrice(datasource); + if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price + return oraclize.query.value(price)(timestamp, datasource, arg); + } + function oraclize_query(uint timestamp, string datasource, string arg, uint gaslimit) oraclizeAPI internal returns (bytes32 id){ + uint price = oraclize.getPrice(datasource, gaslimit); + if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price + return oraclize.query_withGasLimit.value(price)(timestamp, datasource, arg, gaslimit); + } + function oraclize_query(string datasource, string arg, uint gaslimit) oraclizeAPI internal returns (bytes32 id){ + uint price = oraclize.getPrice(datasource, gaslimit); + if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price + return oraclize.query_withGasLimit.value(price)(0, datasource, arg, gaslimit); + } + function oraclize_query(string datasource, string arg1, string arg2) oraclizeAPI internal returns (bytes32 id){ + uint price = oraclize.getPrice(datasource); + if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price + return oraclize.query2.value(price)(0, datasource, arg1, arg2); + } + function oraclize_query(uint timestamp, string datasource, string arg1, string arg2) oraclizeAPI internal returns (bytes32 id){ + uint price = oraclize.getPrice(datasource); + if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price + return oraclize.query2.value(price)(timestamp, datasource, arg1, arg2); + } + function oraclize_query(uint timestamp, string datasource, string arg1, string arg2, uint gaslimit) oraclizeAPI internal returns (bytes32 id){ + uint price = oraclize.getPrice(datasource, gaslimit); + if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price + return oraclize.query2_withGasLimit.value(price)(timestamp, datasource, arg1, arg2, gaslimit); + } + function oraclize_query(string datasource, string arg1, string arg2, uint gaslimit) oraclizeAPI internal returns (bytes32 id){ + uint price = oraclize.getPrice(datasource, gaslimit); + if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price + return oraclize.query2_withGasLimit.value(price)(0, datasource, arg1, arg2, gaslimit); + } + function oraclize_query(string datasource, string[] argN) oraclizeAPI internal returns (bytes32 id){ + uint price = oraclize.getPrice(datasource); + if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price + bytes memory args = stra2cbor(argN); + return oraclize.queryN.value(price)(0, datasource, args); + } + function oraclize_query(uint timestamp, string datasource, string[] argN) oraclizeAPI internal returns (bytes32 id){ + uint price = oraclize.getPrice(datasource); + if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price + bytes memory args = stra2cbor(argN); + return oraclize.queryN.value(price)(timestamp, datasource, args); + } + function oraclize_query(uint timestamp, string datasource, string[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){ + uint price = oraclize.getPrice(datasource, gaslimit); + if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price + bytes memory args = stra2cbor(argN); + return oraclize.queryN_withGasLimit.value(price)(timestamp, datasource, args, gaslimit); + } + function oraclize_query(string datasource, string[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){ + uint price = oraclize.getPrice(datasource, gaslimit); + if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price + bytes memory args = stra2cbor(argN); + return oraclize.queryN_withGasLimit.value(price)(0, datasource, args, gaslimit); + } + function oraclize_query(string datasource, string[1] args) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](1); + dynargs[0] = args[0]; + return oraclize_query(datasource, dynargs); + } + function oraclize_query(uint timestamp, string datasource, string[1] args) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](1); + dynargs[0] = args[0]; + return oraclize_query(timestamp, datasource, dynargs); + } + function oraclize_query(uint timestamp, string datasource, string[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](1); + dynargs[0] = args[0]; + return oraclize_query(timestamp, datasource, dynargs, gaslimit); + } + function oraclize_query(string datasource, string[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](1); + dynargs[0] = args[0]; + return oraclize_query(datasource, dynargs, gaslimit); + } + + function oraclize_query(string datasource, string[2] args) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](2); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + return oraclize_query(datasource, dynargs); + } + function oraclize_query(uint timestamp, string datasource, string[2] args) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](2); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + return oraclize_query(timestamp, datasource, dynargs); + } + function oraclize_query(uint timestamp, string datasource, string[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](2); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + return oraclize_query(timestamp, datasource, dynargs, gaslimit); + } + function oraclize_query(string datasource, string[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](2); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + return oraclize_query(datasource, dynargs, gaslimit); + } + function oraclize_query(string datasource, string[3] args) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](3); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + dynargs[2] = args[2]; + return oraclize_query(datasource, dynargs); + } + function oraclize_query(uint timestamp, string datasource, string[3] args) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](3); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + dynargs[2] = args[2]; + return oraclize_query(timestamp, datasource, dynargs); + } + function oraclize_query(uint timestamp, string datasource, string[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](3); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + dynargs[2] = args[2]; + return oraclize_query(timestamp, datasource, dynargs, gaslimit); + } + function oraclize_query(string datasource, string[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](3); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + dynargs[2] = args[2]; + return oraclize_query(datasource, dynargs, gaslimit); + } + + function oraclize_query(string datasource, string[4] args) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](4); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + dynargs[2] = args[2]; + dynargs[3] = args[3]; + return oraclize_query(datasource, dynargs); + } + function oraclize_query(uint timestamp, string datasource, string[4] args) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](4); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + dynargs[2] = args[2]; + dynargs[3] = args[3]; + return oraclize_query(timestamp, datasource, dynargs); + } + function oraclize_query(uint timestamp, string datasource, string[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](4); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + dynargs[2] = args[2]; + dynargs[3] = args[3]; + return oraclize_query(timestamp, datasource, dynargs, gaslimit); + } + function oraclize_query(string datasource, string[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](4); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + dynargs[2] = args[2]; + dynargs[3] = args[3]; + return oraclize_query(datasource, dynargs, gaslimit); + } + function oraclize_query(string datasource, string[5] args) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](5); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + dynargs[2] = args[2]; + dynargs[3] = args[3]; + dynargs[4] = args[4]; + return oraclize_query(datasource, dynargs); + } + function oraclize_query(uint timestamp, string datasource, string[5] args) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](5); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + dynargs[2] = args[2]; + dynargs[3] = args[3]; + dynargs[4] = args[4]; + return oraclize_query(timestamp, datasource, dynargs); + } + function oraclize_query(uint timestamp, string datasource, string[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](5); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + dynargs[2] = args[2]; + dynargs[3] = args[3]; + dynargs[4] = args[4]; + return oraclize_query(timestamp, datasource, dynargs, gaslimit); + } + function oraclize_query(string datasource, string[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) { + string[] memory dynargs = new string[](5); + dynargs[0] = args[0]; + dynargs[1] = args[1]; + dynargs[2] = args[2]; + dynargs[3] = args[3]; + dynargs[4] = args[4]; + return oraclize_query(datasource, dynargs, gaslimit); + } + + function oraclize_cbAddress() oraclizeAPI internal returns (address){ + return oraclize.cbAddress(); + } + function oraclize_setProof(byte proofP) oraclizeAPI internal { + return oraclize.setProofType(proofP); + } + function oraclize_setCustomGasPrice(uint gasPrice) oraclizeAPI internal { + return oraclize.setCustomGasPrice(gasPrice); + } + function oraclize_setConfig(bytes32 config) oraclizeAPI internal { + return oraclize.setConfig(config); + } + + function getCodeSize(address _addr) constant internal returns(uint _size) { + assembly { + _size := extcodesize(_addr) + } + } + + function parseAddr(string _a) internal returns (address){ + bytes memory tmp = bytes(_a); + uint160 iaddr = 0; + uint160 b1; + uint160 b2; + for (uint i=2; i<2+2*20; i+=2){ + iaddr *= 256; + b1 = uint160(tmp[i]); + b2 = uint160(tmp[i+1]); + if ((b1 >= 97)&&(b1 <= 102)) b1 -= 87; + else if ((b1 >= 48)&&(b1 <= 57)) b1 -= 48; + if ((b2 >= 97)&&(b2 <= 102)) b2 -= 87; + else if ((b2 >= 48)&&(b2 <= 57)) b2 -= 48; + iaddr += (b1*16+b2); + } + return address(iaddr); + } + + function strCompare(string _a, string _b) internal returns (int) { + bytes memory a = bytes(_a); + bytes memory b = bytes(_b); + uint minLength = a.length; + if (b.length < minLength) minLength = b.length; + for (uint i = 0; i < minLength; i ++) + if (a[i] < b[i]) + return -1; + else if (a[i] > b[i]) + return 1; + if (a.length < b.length) + return -1; + else if (a.length > b.length) + return 1; + else + return 0; + } + + function indexOf(string _haystack, string _needle) internal returns (int) { + bytes memory h = bytes(_haystack); + bytes memory n = bytes(_needle); + if(h.length < 1 || n.length < 1 || (n.length > h.length)) + return -1; + else if(h.length > (2**128 -1)) + return -1; + else + { + uint subindex = 0; + for (uint i = 0; i < h.length; i ++) + { + if (h[i] == n[0]) + { + subindex = 1; + while(subindex < n.length && (i + subindex) < h.length && h[i + subindex] == n[subindex]) + { + subindex++; + } + if(subindex == n.length) + return int(i); + } + } + return -1; + } + } + + function strConcat(string _a, string _b, string _c, string _d, string _e) internal returns (string) { + bytes memory _ba = bytes(_a); + bytes memory _bb = bytes(_b); + bytes memory _bc = bytes(_c); + bytes memory _bd = bytes(_d); + bytes memory _be = bytes(_e); + string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length); + bytes memory babcde = bytes(abcde); + uint k = 0; + for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i]; + for (i = 0; i < _bb.length; i++) babcde[k++] = _bb[i]; + for (i = 0; i < _bc.length; i++) babcde[k++] = _bc[i]; + for (i = 0; i < _bd.length; i++) babcde[k++] = _bd[i]; + for (i = 0; i < _be.length; i++) babcde[k++] = _be[i]; + return string(babcde); + } + + function strConcat(string _a, string _b, string _c, string _d) internal returns (string) { + return strConcat(_a, _b, _c, _d, ""); + } + + function strConcat(string _a, string _b, string _c) internal returns (string) { + return strConcat(_a, _b, _c, "", ""); + } + + function strConcat(string _a, string _b) internal returns (string) { + return strConcat(_a, _b, "", "", ""); + } + + // parseInt + function parseInt(string _a) internal returns (uint) { + return parseInt(_a, 0); + } + + // parseInt(parseFloat*10^_b) + function parseInt(string _a, uint _b) internal returns (uint) { + bytes memory bresult = bytes(_a); + uint mint = 0; + bool decimals = false; + for (uint i=0; i= 48)&&(bresult[i] <= 57)){ + if (decimals){ + if (_b == 0) break; + else _b--; + } + mint *= 10; + mint += uint(bresult[i]) - 48; + } else if (bresult[i] == 46) decimals = true; + } + if (_b > 0) mint *= 10**_b; + return mint; + } + + function uint2str(uint i) internal returns (string){ + if (i == 0) return "0"; + uint j = i; + uint len; + while (j != 0){ + len++; + j /= 10; + } + bytes memory bstr = new bytes(len); + uint k = len - 1; + while (i != 0){ + bstr[k--] = byte(48 + i % 10); + i /= 10; + } + return string(bstr); + } + + function stra2cbor(string[] arr) internal returns (bytes) { + uint arrlen = arr.length; + + // get correct cbor output length + uint outputlen = 0; + bytes[] memory elemArray = new bytes[](arrlen); + for (uint i = 0; i < arrlen; i++) { + elemArray[i] = (bytes(arr[i])); + outputlen += elemArray[i].length + (elemArray[i].length - 1)/23 + 3; //+3 accounts for paired identifier types + } + uint ctr = 0; + uint cborlen = arrlen + 0x80; + outputlen += byte(cborlen).length; + bytes memory res = new bytes(outputlen); + + while (byte(cborlen).length > ctr) { + res[ctr] = byte(cborlen)[ctr]; + ctr++; + } + for (i = 0; i < arrlen; i++) { + res[ctr] = 0x5F; + ctr++; + for (uint x = 0; x < elemArray[i].length; x++) { + // if there's a bug with larger strings, this may be the culprit + if (x % 23 == 0) { + uint elemcborlen = elemArray[i].length - x >= 24 ? 23 : elemArray[i].length - x; + elemcborlen += 0x40; + uint lctr = ctr; + while (byte(elemcborlen).length > ctr - lctr) { + res[ctr] = byte(elemcborlen)[ctr - lctr]; + ctr++; + } + } + res[ctr] = elemArray[i][x]; + ctr++; + } + res[ctr] = 0xFF; + ctr++; + } + return res; + } +} +// From e60b174750dce825d2ca7708e309d41824a0214f Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Mon, 15 May 2017 20:19:56 -0300 Subject: [PATCH 04/10] added id to abstract nameregistry --- contracts/src/NameRegistry.sol | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/contracts/src/NameRegistry.sol b/contracts/src/NameRegistry.sol index 5d0e948..bef006e 100644 --- a/contracts/src/NameRegistry.sol +++ b/contracts/src/NameRegistry.sol @@ -3,14 +3,22 @@ * Interface for Name Registries. * Ricardo Guilherme Schmidt <3esmit@gmail.com> */ -pragma solidity ^0.4.11; +pragma solidity ^0.4.9; 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[sha3(_addr)]; + } + + function getId(string _name) public constant returns(uint256 id) { + return indexes[sha3(_name)]; + } function _updateIndex(bytes32 _old, bytes32 _new) internal { indexes[_new] = indexes[_old]; From 13dac09ba3a9b4f3af256122839170781307e7aa Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Mon, 15 May 2017 20:21:12 -0300 Subject: [PATCH 05/10] removed libs, routines cleanup --- contracts/src/GitHubPoints.sol | 167 ++++++++++++++++++++++----------- 1 file changed, 114 insertions(+), 53 deletions(-) diff --git a/contracts/src/GitHubPoints.sol b/contracts/src/GitHubPoints.sol index 0bee26f..bbc7e31 100644 --- a/contracts/src/GitHubPoints.sol +++ b/contracts/src/GitHubPoints.sol @@ -1,10 +1,8 @@ -pragma solidity ^0.4.9; - import "lib/oraclize/oraclizeAPI_0.4.sol"; -import "lib/StringLib.sol"; -import "lib/JSONLib.sol"; import "lib/ethereans/management/Owned.sol"; +pragma solidity ^0.4.11; + contract DGitI { function __setHead(uint256 projectId, string branch, bytes20 head); function __setTail(uint256 projectId, string branch, bytes20 tail); @@ -14,15 +12,14 @@ contract DGitI { } contract GitHubPoints is Owned, usingOraclize{ - using StringLib for string; - DGitI dGit - + string private cred = ""; string private script = ""; enum OracleType { CLAIM_COMMIT, CLAIM_CONTINUE, UPDATE_ISSUE } mapping (bytes32 => OracleType) claimType; //temporary db enumerating oraclize calls - mapping (bytes32 => CommitClaim) commitClaim; //temporary db for oraclize commit token claim calls + mapping (bytes32 => bytes20) commitClaim; //temporary db for oraclize commit token claim calls + mapping (bytes32 => Request) request; //temporary db //stores temporary data for oraclize repository commit claim struct CommitClaim { @@ -30,27 +27,46 @@ contract GitHubPoints is Owned, usingOraclize{ bytes20 commitid; } - function GitHubPoints(string _script){ - script = _script; - dGit = DGitI(msg.sender); - oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); + struct Request { + address caller; + OracleType ot; } - function updateCommits(string _repository, string _branch, bytes20 _commitid) - payable only_owner{ - bytes32 ocid = oraclize_query("computation", [script, "update-new",_repository.concat(",", _branch,",",toString(_commitid)),cred]); + function start(string _repository, string _branch, string _cred) payable only_owner { + if(bytes(_cred).length == 0) _cred = cred; + bytes32 ocid = oraclize_query("computation", [script, "update-new", strConcat(_repository, ",", _branch), _cred]); claimType[ocid] = OracleType.CLAIM_COMMIT; - commitClaim[ocid] = CommitClaim( { repository: _repository, commitid:_commitid}); + request[ocid].caller = msg.sender; + request[ocid].ot = OracleType.CLAIM_COMMIT; } - function continueUpdateCommits(string _repository, string _branch, bytes20 _lastCommit,bytes20 _limitCommit) + function update(string _repository, string _branch, bytes20 _commitid, string _cred) payable only_owner { + if(bytes(_cred).length == 0) _cred = cred; + bytes32 ocid = oraclize_query("computation", [script, "update-new", strConcat(_repository, ",", _branch, ",", toString(_commitid)), _cred]); + claimType[ocid] = OracleType.CLAIM_COMMIT; + commitClaim[ocid] = _commitid; + request[ocid].caller = msg.sender; + request[ocid].ot = OracleType.CLAIM_COMMIT; + } + + function resume(string _repository, string _branch, bytes20 _lastCommit, bytes20 _limitCommit, string _cred) payable only_owner{ - bytes32 ocid = oraclize_query("computation", [script, "update-old",_repository.concat(",", _branch,",",toString(_lastCommit)).concat(",",toString(_limitCommit)),cred]); + if(bytes(_cred).length == 0) _cred = cred; + string memory query = strConcat(_repository,",", _branch,",",toString(_lastCommit)); + query = strConcat(",",toString(_limitCommit)); + bytes32 ocid = oraclize_query("computation", [script, "update-old",query,_cred]); claimType[ocid] = OracleType.CLAIM_CONTINUE; + commitClaim[ocid] = _lastCommit; + request[ocid].caller = msg.sender; + request[ocid].ot = OracleType.CLAIM_CONTINUE; } - function updateIssue(string _repository, string issue) payable only_owner{ - bytes32 ocid = oraclize_query("computation", [script, "issue-update",_repository.concat(",",issue),cred]); + function issue(string _repository, string issue, string _cred) + payable only_owner{ + if(bytes(_cred).length == 0) _cred = cred; + bytes32 ocid = oraclize_query("computation", [script, "issue-update",strConcat(_repository,",",issue),_cred]); + request[ocid].caller = msg.sender; + request[ocid].ot = OracleType.UPDATE_ISSUE; } event OracleEvent(bytes32 myid, string result, bytes proof); @@ -59,78 +75,82 @@ contract GitHubPoints is Owned, usingOraclize{ OracleEvent(myid, result, proof); if (msg.sender != oraclize.cbAddress()){ throw; - }else if(claimType[myid]==OracleType.CLAIM_COMMIT){ - _updateCommits(myid, result, false); - }else if(claimType[myid]==OracleType.CLAIM_CONTINUE){ - _updateCommits(myid, result, true); }else if(claimType[myid] == OracleType.UPDATE_ISSUE){ _updateIssue(myid, result); + }else{ + _updateCommits(commitClaim[myid], result,claimType[myid]==OracleType.CLAIM_CONTINUE); } delete claimType[myid]; //should always be deleted } - function _updateCommits(bytes32 myid, string result, bool continuing) internal { + function _updateCommits(bytes20 oldCommit, string result, bool resume) internal { + DGitI dGit = DGitI(owner); bytes memory v = bytes(result); uint8 pos = 0; string memory temp; uint256 projectId; - (projectId,pos) = JSONLib.getNextUInt(v,pos); + (projectId,pos) = getNextUInt(v,pos); string memory branch; - (branch,pos) = JSONLib.getNextString(v,pos); - (temp,pos) = JSONLib.getNextString(v,pos); - bytes20 head = temp.toBytes20(); - (temp,pos) = JSONLib.getNextString(v,pos); - bytes20 tail = temp.toBytes20(); - uint numAuthors; - (numAuthors,pos) = JSONLib.getNextUInt(v,pos); - uint userId; - uint points; + (branch,pos) = getNextString(v,pos); + (temp,pos) = getNextString(v,pos); + bytes20 head = toBytes20(temp); + (temp,pos) = getNextString(v,pos); + bytes20 tail = toBytes20(temp); dGit.__setHead(projectId,branch,head); - if(continuing){ + if(resume){ dGit.__setTail(projectId,branch,tail); }else{ - bytes20 oldCommit = commitUpdate[myid].commitid; if(oldCommit == 0x0){ dGit.__setTail(projectId,branch,tail); }else if (oldCommit != tail){ //TODO: acceptContinueUpdateUntilLimit(tail,oldCommit) } } + uint numAuthors; + (numAuthors,pos) = getNextUInt(v,pos); + uint userId; + uint points; for(uint i; i < numAuthors; i++){ - (userId,pos) = JSONLib.getNextUInt(v,pos); - (points,pos) = JSONLib.getNextUInt(v,pos); + (userId,pos) = getNextUInt(v,pos); + (points,pos) = getNextUInt(v,pos); dGit.__newPoints(projectId,userId,points); } } function _updateIssue(bytes32 myid, string result) internal { + DGitI dGit = DGitI(request[myid].caller); bytes memory v = bytes(result); uint8 pos = 0; string memory temp; uint256 projectId; - (projectId,pos) = JSONLib.getNextUInt(v,pos); + (projectId,pos) = getNextUInt(v,pos); uint256 issueId; - (issueId,pos) = JSONLib.getNextUInt(v,pos); + (issueId,pos) = getNextUInt(v,pos); bool state; - (temp,pos) = JSONLib.getNextString(v,pos); - state = (temp.compare("open") == 0); + (temp,pos) = getNextString(v,pos); + state = (sha3("open") == sha3(temp)); uint256 closedAt; - (closedAt,pos) = JSONLib.getNextUInt(v,pos); + (closedAt,pos) = getNextUInt(v,pos); uint numAuthors; - (numAuthors,pos) = JSONLib.getNextUInt(v,pos); + (numAuthors,pos) = getNextUInt(v,pos); uint userId; uint points; dGit.__setIssue(projectId,issueId,state,closedAt); for(uint i; i < numAuthors; i++){ - (userId,pos) = JSONLib.getNextUInt(v,pos); - (points,pos) = JSONLib.getNextUInt(v,pos); + (userId,pos) = getNextUInt(v,pos); + (points,pos) = getNextUInt(v,pos); dGit.__setIssuePoints(projectId,issueId,userId,points); } } //owner management - function setAPICredentials(string _client_id, string _client_secret) only_owner { - cred = StringLib.concat(_client_id,",", _client_secret); + function GitHubPoints(string _script){ + script = _script; + oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); + } + + function setAPICredentials(string _client_id_comma_client_secret) only_owner { + cred = _client_id_comma_client_secret; } function setScript(string _script) only_owner{ @@ -140,7 +160,12 @@ contract GitHubPoints is Owned, usingOraclize{ function clearAPICredentials() only_owner { cred = ""; } - + + function toBytes20(string memory source) internal constant returns (bytes20 result) { + assembly { + result := mload(add(source, 20)) + } + } function toString(bytes20 self) internal constant returns (string) { bytes memory bytesString = new bytes(20); uint charCount = 0; @@ -157,13 +182,49 @@ contract GitHubPoints is Owned, usingOraclize{ } return string(bytesStringTrimmed); } + + 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 _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); + } } -library QueryFactory { +library GitHubPointsFactory { - function newGitHubAPI() returns (GitHubAPI){ - return new GitHubOracle(); + function create() returns (GitHubPoints){ + return new GitHubPoints(""); } } \ No newline at end of file From 3379a789e478bbc4fee3d3c4ff6d7b227dd8226f Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Mon, 15 May 2017 20:22:55 -0300 Subject: [PATCH 06/10] added factory, added branch getter and public repositories --- contracts/src/GitHubRepositoryReg.sol | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/contracts/src/GitHubRepositoryReg.sol b/contracts/src/GitHubRepositoryReg.sol index a40b53a..784b698 100644 --- a/contracts/src/GitHubRepositoryReg.sol +++ b/contracts/src/GitHubRepositoryReg.sol @@ -4,9 +4,9 @@ * Ricardo Guilherme Schmidt <3esmit@gmail.com> */ -import "GitHubAPIReg.sol"; -import "NameRegistry.sol"; -import "GitRepository.sol"; +import "./GitHubAPIReg.sol"; +import "./NameRegistry.sol"; +import "./GitRepository.sol"; pragma solidity ^0.4.11; @@ -37,6 +37,10 @@ contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg { function getAddr(string _name) public constant returns(address addr) { return repositories[indexes[sha3(_name)]].addr; } + + function getBranch(uint256 _id) public constant returns(string branch) { + return repositories[_id].branch; + } //oraclize response callback function __callback(bytes32 myid, string result, bytes proof) { @@ -78,4 +82,11 @@ contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg { return strConcat("json(https://api.github.com/repos/",_repository,credentials,").$.id,full_name,default_branch"); } +} +library GitHubRepositoryRegFactory { + + function create() returns (GitHubRepositoryReg){ + return new GitHubRepositoryReg(); + } + } \ No newline at end of file From 316cc587d753ca7a0ad3765aa03345002cf6f704 Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Mon, 15 May 2017 20:23:15 -0300 Subject: [PATCH 07/10] public repositories --- contracts/src/GitHubRepositoryReg.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/src/GitHubRepositoryReg.sol b/contracts/src/GitHubRepositoryReg.sol index 784b698..f70ba6b 100644 --- a/contracts/src/GitHubRepositoryReg.sol +++ b/contracts/src/GitHubRepositoryReg.sol @@ -12,7 +12,7 @@ pragma solidity ^0.4.11; contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg { - mapping (uint256 => Repository) repositories; + mapping (uint256 => Repository) public repositories; event NewRepository(address addr, uint256 projectId, string full_name, string default_branch); From df7ee028e1cacae92b63efc70dc23f373c5952ce Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Mon, 15 May 2017 20:23:29 -0300 Subject: [PATCH 08/10] cleanup --- contracts/src/GitHubOracle.sol | 55 ++++++++++++++++------------------ 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/contracts/src/GitHubOracle.sol b/contracts/src/GitHubOracle.sol index e95df9c..77360da 100644 --- a/contracts/src/GitHubOracle.sol +++ b/contracts/src/GitHubOracle.sol @@ -15,9 +15,9 @@ import "lib/oraclize/oraclizeAPI_0.4.sol"; import "lib/ethereans/management/Owned.sol"; -import "GitHubUserReg.sol"; -import "GitHubRepositoryReg.sol"; -import "GitHubPoints.sol"; +import "./GitHubUserReg.sol"; +import "./GitHubRepositoryReg.sol"; +import "./GitHubPoints.sol"; pragma solidity ^0.4.11; @@ -28,7 +28,7 @@ contract GitHubOracle is Owned, DGitI { GitHubPoints public gitHubPoints; mapping (uint256 => Repository) repositories; - mapping (uint256 => mapping (uint256 => uint256)) pendingPoints; + mapping (uint256 => mapping (uint256 => uint256)) pending; struct Repository { bytes20 head; @@ -36,22 +36,19 @@ contract GitHubOracle is Owned, DGitI { } function initialize() only_owner { - userReg = QueryFactory.newUserReg(); - repositoryReg = QueryFactory.newRepositoryReg(); - gitHubPoints = QueryFactory.newPointsOracle(); + userReg = GitHubUserRegFactory.create(); + repositoryReg = GitHubRepositoryRegFactory.create(); + gitHubPoints = GitHubPointsFactory.create(); } - function register(string _github_user, string _gistid) payable{ - userReg.register.value(msg.value)(msg.sender,_github_user,_gistid); + function updateCommits(string _repository, string _token) payable{ + uint256 repoId = repositoryReg.getId(_repository); + if(repoId == 0) throw; + gitHubPoints.updateCommits.value(msg.value)(_repository, "master", repositories[repoId].head,_token); } - function updateCommits(string _repository) payable{ - gitHubPoints.updateCommits.value(msg.value)(_repository,db.getClaimedHead(_repository)); - } - function addRepository(string _repository) payable{ - repositoryReg.addRepository.value(msg.value)(_repository); - } - function updateIssue(string _repository, string issue) payable{ - gitHubPoints.updateIssue.value(msg.value)(_repository,issue); + + function updateIssue(string _repository, string issue, string _token) payable{ + gitHubPoints.updateIssue.value(msg.value)(_repository,issue,_token); } function getRepository(uint projectId) constant returns (address){ return repositoryReg.getAddr(projectId); @@ -60,34 +57,32 @@ contract GitHubOracle is Owned, DGitI { return repositoryReg.getAddr(full_name); } - modifier only_gitapi{ - if (msg.sender != address(gitHubApi)) throw; - _; - } - event NewPoints(uint repoId, uint userId, uint total, bool claimed); function __newPoints(uint repoId, uint userId, uint total) - only_gitapi { + only_owner { GitRepositoryI repoaddr = GitRepositoryI(repositoryReg.getAddr(repoId)); - bool claimed = repoaddr.claim(db.getUserAddress(userId), total); + bool claimed = repoaddr.claim(userReg.getAddr(userId), total); if(!claimed){ //try to claim points addPending(repoId, userId, total); //set as a pending points } - NewPoints(repository,userId,total,claimed); + NewPoints(repoId,userId,total,claimed); } //claims pending points - function claimPending(uint repoId, uint userId){ - GitRepositoryI repoaddr = GitRepositoryI(repositoryReg.getAddr(repoId)); + function claimPending(uint _repoId, uint _userId){ + GitRepositoryI repoaddr = GitRepositoryI(repositoryReg.getAddr(_repoId)); uint total = pending[_userId][_repoId]; delete pending[_userId][_repoId]; - if(repoaddr.claim(gitHubUserRegistry.getAddr(userId), total)) { - NewPoints(repository,userId,total,true); + if(repoaddr.claim(userReg.getAddr(_userId), total)) { + NewPoints(_repoId,_userId,total,true); } else throw; } - function addPending(uint256 _repoid, uint256 _userid, uint256 _points) internal { + function addPending(uint256 _repoId, uint256 _userId, uint256 _points) internal { pending[_userId][_repoId] += _points; } + + + } \ No newline at end of file From f53c46bd0d68d6be317abdb3d30171bd1f81a6c6 Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Thu, 18 May 2017 16:03:48 -0300 Subject: [PATCH 09/10] implemented nested queries for scripts support encryption. --- contracts/lib/strings.sol | 711 +++++++++++++++++++++++++++++++++ contracts/src/GitHubPoints.sol | 100 ++++- 2 files changed, 798 insertions(+), 13 deletions(-) create mode 100644 contracts/lib/strings.sol diff --git a/contracts/lib/strings.sol b/contracts/lib/strings.sol new file mode 100644 index 0000000..aa335d7 --- /dev/null +++ b/contracts/lib/strings.sol @@ -0,0 +1,711 @@ +/* + * @title String & slice utility library for Solidity contracts. + * @author Nick Johnson + * + * @dev Functionality in this library is largely implemented using an + * abstraction called a 'slice'. A slice represents a part of a string - + * anything from the entire string to a single character, or even no + * characters at all (a 0-length slice). Since a slice only has to specify + * an offset and a length, copying and manipulating slices is a lot less + * expensive than copying and manipulating the strings they reference. + * + * To further reduce gas costs, most functions on slice that need to return + * a slice modify the original one instead of allocating a new one; for + * instance, `s.split(".")` will return the text up to the first '.', + * modifying s to only contain the remainder of the string after the '.'. + * In situations where you do not want to modify the original slice, you + * can make a copy first with `.copy()`, for example: + * `s.copy().split(".")`. Try and avoid using this idiom in loops; since + * Solidity has no memory management, it will result in allocating many + * short-lived slices that are later discarded. + * + * Functions that return two slices come in two versions: a non-allocating + * version that takes the second slice as an argument, modifying it in + * place, and an allocating version that allocates and returns the second + * slice; see `nextRune` for example. + * + * Functions that have to copy string data will return strings rather than + * slices; these can be cast back to slices for further processing if + * required. + * + * For convenience, some functions are provided with non-modifying + * variants that create a new slice and return both; for instance, + * `s.splitNew('.')` leaves s unmodified, and returns two values + * corresponding to the left and right parts of the string. + */ +pragma solidity ^0.4.11; + +library strings { + struct slice { + uint _len; + uint _ptr; + } + + function memcpy(uint dest, uint src, uint len) private { + // Copy word-length chunks while possible + for(; len >= 32; len -= 32) { + assembly { + mstore(dest, mload(src)) + } + dest += 32; + src += 32; + } + + // Copy remaining bytes + uint mask = 256 ** (32 - len) - 1; + assembly { + let srcpart := and(mload(src), not(mask)) + let destpart := and(mload(dest), mask) + mstore(dest, or(destpart, srcpart)) + } + } + + /* + * @dev Returns a slice containing the entire string. + * @param self The string to make a slice from. + * @return A newly allocated slice containing the entire string. + */ + function toSlice(string self) internal returns (slice) { + uint ptr; + assembly { + ptr := add(self, 0x20) + } + return slice(bytes(self).length, ptr); + } + + /* + * @dev Returns the length of a null-terminated bytes32 string. + * @param self The value to find the length of. + * @return The length of the string, from 0 to 32. + */ + function len(bytes32 self) internal returns (uint) { + uint ret; + if (self == 0) + return 0; + if (self & 0xffffffffffffffffffffffffffffffff == 0) { + ret += 16; + self = bytes32(uint(self) / 0x100000000000000000000000000000000); + } + if (self & 0xffffffffffffffff == 0) { + ret += 8; + self = bytes32(uint(self) / 0x10000000000000000); + } + if (self & 0xffffffff == 0) { + ret += 4; + self = bytes32(uint(self) / 0x100000000); + } + if (self & 0xffff == 0) { + ret += 2; + self = bytes32(uint(self) / 0x10000); + } + if (self & 0xff == 0) { + ret += 1; + } + return 32 - ret; + } + + /* + * @dev Returns a slice containing the entire bytes32, interpreted as a + * null-termintaed utf-8 string. + * @param self The bytes32 value to convert to a slice. + * @return A new slice containing the value of the input argument up to the + * first null. + */ + function toSliceB32(bytes32 self) internal returns (slice ret) { + // Allocate space for `self` in memory, copy it there, and point ret at it + assembly { + let ptr := mload(0x40) + mstore(0x40, add(ptr, 0x20)) + mstore(ptr, self) + mstore(add(ret, 0x20), ptr) + } + ret._len = len(self); + } + + /* + * @dev Returns a new slice containing the same data as the current slice. + * @param self The slice to copy. + * @return A new slice containing the same data as `self`. + */ + function copy(slice self) internal returns (slice) { + return slice(self._len, self._ptr); + } + + /* + * @dev Copies a slice to a new string. + * @param self The slice to copy. + * @return A newly allocated string containing the slice's text. + */ + function toString(slice self) internal returns (string) { + var ret = new string(self._len); + uint retptr; + assembly { retptr := add(ret, 32) } + + memcpy(retptr, self._ptr, self._len); + return ret; + } + + /* + * @dev Returns the length in runes of the slice. Note that this operation + * takes time proportional to the length of the slice; avoid using it + * in loops, and call `slice.empty()` if you only need to know whether + * the slice is empty or not. + * @param self The slice to operate on. + * @return The length of the slice in runes. + */ + function len(slice self) internal returns (uint) { + // Starting at ptr-31 means the LSB will be the byte we care about + var ptr = self._ptr - 31; + var end = ptr + self._len; + for (uint len = 0; ptr < end; len++) { + uint8 b; + assembly { b := and(mload(ptr), 0xFF) } + if (b < 0x80) { + ptr += 1; + } else if(b < 0xE0) { + ptr += 2; + } else if(b < 0xF0) { + ptr += 3; + } else if(b < 0xF8) { + ptr += 4; + } else if(b < 0xFC) { + ptr += 5; + } else { + ptr += 6; + } + } + return len; + } + + /* + * @dev Returns true if the slice is empty (has a length of 0). + * @param self The slice to operate on. + * @return True if the slice is empty, False otherwise. + */ + function empty(slice self) internal returns (bool) { + return self._len == 0; + } + + /* + * @dev Returns a positive number if `other` comes lexicographically after + * `self`, a negative number if it comes before, or zero if the + * contents of the two slices are equal. Comparison is done per-rune, + * on unicode codepoints. + * @param self The first slice to compare. + * @param other The second slice to compare. + * @return The result of the comparison. + */ + function compare(slice self, slice other) internal returns (int) { + uint shortest = self._len; + if (other._len < self._len) + shortest = other._len; + + var selfptr = self._ptr; + var otherptr = other._ptr; + for (uint idx = 0; idx < shortest; idx += 32) { + uint a; + uint b; + assembly { + a := mload(selfptr) + b := mload(otherptr) + } + if (a != b) { + // Mask out irrelevant bytes and check again + uint mask = ~(2 ** (8 * (32 - shortest + idx)) - 1); + var diff = (a & mask) - (b & mask); + if (diff != 0) + return int(diff); + } + selfptr += 32; + otherptr += 32; + } + return int(self._len) - int(other._len); + } + + /* + * @dev Returns true if the two slices contain the same text. + * @param self The first slice to compare. + * @param self The second slice to compare. + * @return True if the slices are equal, false otherwise. + */ + function equals(slice self, slice other) internal returns (bool) { + return compare(self, other) == 0; + } + + /* + * @dev Extracts the first rune in the slice into `rune`, advancing the + * slice to point to the next rune and returning `self`. + * @param self The slice to operate on. + * @param rune The slice that will contain the first rune. + * @return `rune`. + */ + function nextRune(slice self, slice rune) internal returns (slice) { + rune._ptr = self._ptr; + + if (self._len == 0) { + rune._len = 0; + return rune; + } + + uint len; + uint b; + // Load the first byte of the rune into the LSBs of b + assembly { b := and(mload(sub(mload(add(self, 32)), 31)), 0xFF) } + if (b < 0x80) { + len = 1; + } else if(b < 0xE0) { + len = 2; + } else if(b < 0xF0) { + len = 3; + } else { + len = 4; + } + + // Check for truncated codepoints + if (len > self._len) { + rune._len = self._len; + self._ptr += self._len; + self._len = 0; + return rune; + } + + self._ptr += len; + self._len -= len; + rune._len = len; + return rune; + } + + /* + * @dev Returns the first rune in the slice, advancing the slice to point + * to the next rune. + * @param self The slice to operate on. + * @return A slice containing only the first rune from `self`. + */ + function nextRune(slice self) internal returns (slice ret) { + nextRune(self, ret); + } + + /* + * @dev Returns the number of the first codepoint in the slice. + * @param self The slice to operate on. + * @return The number of the first codepoint in the slice. + */ + function ord(slice self) internal returns (uint ret) { + if (self._len == 0) { + return 0; + } + + uint word; + uint len; + uint div = 2 ** 248; + + // Load the rune into the MSBs of b + assembly { word:= mload(mload(add(self, 32))) } + var b = word / div; + if (b < 0x80) { + ret = b; + len = 1; + } else if(b < 0xE0) { + ret = b & 0x1F; + len = 2; + } else if(b < 0xF0) { + ret = b & 0x0F; + len = 3; + } else { + ret = b & 0x07; + len = 4; + } + + // Check for truncated codepoints + if (len > self._len) { + return 0; + } + + for (uint i = 1; i < len; i++) { + div = div / 256; + b = (word / div) & 0xFF; + if (b & 0xC0 != 0x80) { + // Invalid UTF-8 sequence + return 0; + } + ret = (ret * 64) | (b & 0x3F); + } + + return ret; + } + + /* + * @dev Returns the keccak-256 hash of the slice. + * @param self The slice to hash. + * @return The hash of the slice. + */ + function keccak(slice self) internal returns (bytes32 ret) { + assembly { + ret := sha3(mload(add(self, 32)), mload(self)) + } + } + + /* + * @dev Returns true if `self` starts with `needle`. + * @param self The slice to operate on. + * @param needle The slice to search for. + * @return True if the slice starts with the provided text, false otherwise. + */ + function startsWith(slice self, slice needle) internal returns (bool) { + if (self._len < needle._len) { + return false; + } + + if (self._ptr == needle._ptr) { + return true; + } + + bool equal; + assembly { + let len := mload(needle) + let selfptr := mload(add(self, 0x20)) + let needleptr := mload(add(needle, 0x20)) + equal := eq(sha3(selfptr, len), sha3(needleptr, len)) + } + return equal; + } + + /* + * @dev If `self` starts with `needle`, `needle` is removed from the + * beginning of `self`. Otherwise, `self` is unmodified. + * @param self The slice to operate on. + * @param needle The slice to search for. + * @return `self` + */ + function beyond(slice self, slice needle) internal returns (slice) { + if (self._len < needle._len) { + return self; + } + + bool equal = true; + if (self._ptr != needle._ptr) { + assembly { + let len := mload(needle) + let selfptr := mload(add(self, 0x20)) + let needleptr := mload(add(needle, 0x20)) + equal := eq(sha3(selfptr, len), sha3(needleptr, len)) + } + } + + if (equal) { + self._len -= needle._len; + self._ptr += needle._len; + } + + return self; + } + + /* + * @dev Returns true if the slice ends with `needle`. + * @param self The slice to operate on. + * @param needle The slice to search for. + * @return True if the slice starts with the provided text, false otherwise. + */ + function endsWith(slice self, slice needle) internal returns (bool) { + if (self._len < needle._len) { + return false; + } + + var selfptr = self._ptr + self._len - needle._len; + + if (selfptr == needle._ptr) { + return true; + } + + bool equal; + assembly { + let len := mload(needle) + let needleptr := mload(add(needle, 0x20)) + equal := eq(sha3(selfptr, len), sha3(needleptr, len)) + } + + return equal; + } + + /* + * @dev If `self` ends with `needle`, `needle` is removed from the + * end of `self`. Otherwise, `self` is unmodified. + * @param self The slice to operate on. + * @param needle The slice to search for. + * @return `self` + */ + function until(slice self, slice needle) internal returns (slice) { + if (self._len < needle._len) { + return self; + } + + var selfptr = self._ptr + self._len - needle._len; + bool equal = true; + if (selfptr != needle._ptr) { + assembly { + let len := mload(needle) + let needleptr := mload(add(needle, 0x20)) + equal := eq(sha3(selfptr, len), sha3(needleptr, len)) + } + } + + if (equal) { + self._len -= needle._len; + } + + return self; + } + + // Returns the memory address of the first byte of the first occurrence of + // `needle` in `self`, or the first byte after `self` if not found. + function findPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private returns (uint) { + uint ptr; + uint idx; + + if (needlelen <= selflen) { + if (needlelen <= 32) { + // Optimized assembly for 68 gas per byte on short strings + assembly { + let mask := not(sub(exp(2, mul(8, sub(32, needlelen))), 1)) + let needledata := and(mload(needleptr), mask) + let end := add(selfptr, sub(selflen, needlelen)) + ptr := selfptr + loop: + jumpi(exit, eq(and(mload(ptr), mask), needledata)) + ptr := add(ptr, 1) + jumpi(loop, lt(sub(ptr, 1), end)) + ptr := add(selfptr, selflen) + exit: + } + return ptr; + } else { + // For long needles, use hashing + bytes32 hash; + assembly { hash := sha3(needleptr, needlelen) } + ptr = selfptr; + for (idx = 0; idx <= selflen - needlelen; idx++) { + bytes32 testHash; + assembly { testHash := sha3(ptr, needlelen) } + if (hash == testHash) + return ptr; + ptr += 1; + } + } + } + return selfptr + selflen; + } + + // Returns the memory address of the first byte after the last occurrence of + // `needle` in `self`, or the address of `self` if not found. + function rfindPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private returns (uint) { + uint ptr; + + if (needlelen <= selflen) { + if (needlelen <= 32) { + // Optimized assembly for 69 gas per byte on short strings + assembly { + let mask := not(sub(exp(2, mul(8, sub(32, needlelen))), 1)) + let needledata := and(mload(needleptr), mask) + ptr := add(selfptr, sub(selflen, needlelen)) + loop: + jumpi(ret, eq(and(mload(ptr), mask), needledata)) + ptr := sub(ptr, 1) + jumpi(loop, gt(add(ptr, 1), selfptr)) + ptr := selfptr + jump(exit) + ret: + ptr := add(ptr, needlelen) + exit: + } + return ptr; + } else { + // For long needles, use hashing + bytes32 hash; + assembly { hash := sha3(needleptr, needlelen) } + ptr = selfptr + (selflen - needlelen); + while (ptr >= selfptr) { + bytes32 testHash; + assembly { testHash := sha3(ptr, needlelen) } + if (hash == testHash) + return ptr + needlelen; + ptr -= 1; + } + } + } + return selfptr; + } + + /* + * @dev Modifies `self` to contain everything from the first occurrence of + * `needle` to the end of the slice. `self` is set to the empty slice + * if `needle` is not found. + * @param self The slice to search and modify. + * @param needle The text to search for. + * @return `self`. + */ + function find(slice self, slice needle) internal returns (slice) { + uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr); + self._len -= ptr - self._ptr; + self._ptr = ptr; + return self; + } + + /* + * @dev Modifies `self` to contain the part of the string from the start of + * `self` to the end of the first occurrence of `needle`. If `needle` + * is not found, `self` is set to the empty slice. + * @param self The slice to search and modify. + * @param needle The text to search for. + * @return `self`. + */ + function rfind(slice self, slice needle) internal returns (slice) { + uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr); + self._len = ptr - self._ptr; + return self; + } + + /* + * @dev Splits the slice, setting `self` to everything after the first + * occurrence of `needle`, and `token` to everything before it. If + * `needle` does not occur in `self`, `self` is set to the empty slice, + * and `token` is set to the entirety of `self`. + * @param self The slice to split. + * @param needle The text to search for in `self`. + * @param token An output parameter to which the first token is written. + * @return `token`. + */ + function split(slice self, slice needle, slice token) internal returns (slice) { + uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr); + token._ptr = self._ptr; + token._len = ptr - self._ptr; + if (ptr == self._ptr + self._len) { + // Not found + self._len = 0; + } else { + self._len -= token._len + needle._len; + self._ptr = ptr + needle._len; + } + return token; + } + + /* + * @dev Splits the slice, setting `self` to everything after the first + * occurrence of `needle`, and returning everything before it. If + * `needle` does not occur in `self`, `self` is set to the empty slice, + * and the entirety of `self` is returned. + * @param self The slice to split. + * @param needle The text to search for in `self`. + * @return The part of `self` up to the first occurrence of `delim`. + */ + function split(slice self, slice needle) internal returns (slice token) { + split(self, needle, token); + } + + /* + * @dev Splits the slice, setting `self` to everything before the last + * occurrence of `needle`, and `token` to everything after it. If + * `needle` does not occur in `self`, `self` is set to the empty slice, + * and `token` is set to the entirety of `self`. + * @param self The slice to split. + * @param needle The text to search for in `self`. + * @param token An output parameter to which the first token is written. + * @return `token`. + */ + function rsplit(slice self, slice needle, slice token) internal returns (slice) { + uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr); + token._ptr = ptr; + token._len = self._len - (ptr - self._ptr); + if (ptr == self._ptr) { + // Not found + self._len = 0; + } else { + self._len -= token._len + needle._len; + } + return token; + } + + /* + * @dev Splits the slice, setting `self` to everything before the last + * occurrence of `needle`, and returning everything after it. If + * `needle` does not occur in `self`, `self` is set to the empty slice, + * and the entirety of `self` is returned. + * @param self The slice to split. + * @param needle The text to search for in `self`. + * @return The part of `self` after the last occurrence of `delim`. + */ + function rsplit(slice self, slice needle) internal returns (slice token) { + rsplit(self, needle, token); + } + + /* + * @dev Counts the number of nonoverlapping occurrences of `needle` in `self`. + * @param self The slice to search. + * @param needle The text to search for in `self`. + * @return The number of occurrences of `needle` found in `self`. + */ + function count(slice self, slice needle) internal returns (uint count) { + uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr) + needle._len; + while (ptr <= self._ptr + self._len) { + count++; + ptr = findPtr(self._len - (ptr - self._ptr), ptr, needle._len, needle._ptr) + needle._len; + } + } + + /* + * @dev Returns True if `self` contains `needle`. + * @param self The slice to search. + * @param needle The text to search for in `self`. + * @return True if `needle` is found in `self`, false otherwise. + */ + function contains(slice self, slice needle) internal returns (bool) { + return rfindPtr(self._len, self._ptr, needle._len, needle._ptr) != self._ptr; + } + + /* + * @dev Returns a newly allocated string containing the concatenation of + * `self` and `other`. + * @param self The first slice to concatenate. + * @param other The second slice to concatenate. + * @return The concatenation of the two strings. + */ + function concat(slice self, slice other) internal returns (string) { + var ret = new string(self._len + other._len); + uint retptr; + assembly { retptr := add(ret, 32) } + memcpy(retptr, self._ptr, self._len); + memcpy(retptr + self._len, other._ptr, other._len); + return ret; + } + + /* + * @dev Joins an array of slices, using `self` as a delimiter, returning a + * newly allocated string. + * @param self The delimiter to use. + * @param parts A list of slices to join. + * @return A newly allocated string containing all the slices in `parts`, + * joined with `self`. + */ + function join(slice self, slice[] parts) internal returns (string) { + if (parts.length == 0) + return ""; + + uint len = self._len * (parts.length - 1); + 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++) { + memcpy(retptr, parts[i]._ptr, parts[i]._len); + retptr += parts[i]._len; + if (i < parts.length - 1) { + memcpy(retptr, self._ptr, self._len); + retptr += self._len; + } + } + + return ret; + } +} diff --git a/contracts/src/GitHubPoints.sol b/contracts/src/GitHubPoints.sol index bbc7e31..8e97251 100644 --- a/contracts/src/GitHubPoints.sol +++ b/contracts/src/GitHubPoints.sol @@ -1,5 +1,6 @@ import "lib/oraclize/oraclizeAPI_0.4.sol"; import "lib/ethereans/management/Owned.sol"; +import "lib/strings.sol"; pragma solidity ^0.4.11; @@ -31,32 +32,34 @@ contract GitHubPoints is Owned, usingOraclize{ address caller; OracleType ot; } - + + function _query_start(string _repository, string _branch, string _cred) internal { + strConcat("[computation] ['", script, "', 'update-new', '", _repository, strConcat("','", _branch,"', '", _cred,"']")) + } + function start(string _repository, string _branch, string _cred) payable only_owner { if(bytes(_cred).length == 0) _cred = cred; - bytes32 ocid = oraclize_query("computation", [script, "update-new", strConcat(_repository, ",", _branch), _cred]); + bytes32 ocid = oraclize_query("nested", _query_start(_repository,_branch,_cred)); claimType[ocid] = OracleType.CLAIM_COMMIT; request[ocid].caller = msg.sender; request[ocid].ot = OracleType.CLAIM_COMMIT; } - function update(string _repository, string _branch, bytes20 _commitid, string _cred) payable only_owner { + function update(string _repository, string _branch, string _commitid, string _cred) payable only_owner { if(bytes(_cred).length == 0) _cred = cred; - bytes32 ocid = oraclize_query("computation", [script, "update-new", strConcat(_repository, ",", _branch, ",", toString(_commitid)), _cred]); + bytes32 ocid = oraclize_query("nested", _query_update(_repository,_branch,_commitid,_cred)); claimType[ocid] = OracleType.CLAIM_COMMIT; - commitClaim[ocid] = _commitid; + commitClaim[ocid] = toBytes20(_commitid); request[ocid].caller = msg.sender; request[ocid].ot = OracleType.CLAIM_COMMIT; } - function resume(string _repository, string _branch, bytes20 _lastCommit, bytes20 _limitCommit, string _cred) + function resume(string _repository, string _branch, string _lastCommit, string _limitCommit, string _cred) payable only_owner{ if(bytes(_cred).length == 0) _cred = cred; - string memory query = strConcat(_repository,",", _branch,",",toString(_lastCommit)); - query = strConcat(",",toString(_limitCommit)); - bytes32 ocid = oraclize_query("computation", [script, "update-old",query,_cred]); + bytes32 ocid = oraclize_query("nested", _query_resume(_repository,_branch,_lastCommit,_limitCommit,_cred)); claimType[ocid] = OracleType.CLAIM_CONTINUE; - commitClaim[ocid] = _lastCommit; + commitClaim[ocid] = toBytes20(_lastCommit); request[ocid].caller = msg.sender; request[ocid].ot = OracleType.CLAIM_CONTINUE; } @@ -64,7 +67,7 @@ contract GitHubPoints is Owned, usingOraclize{ function issue(string _repository, string issue, string _cred) payable only_owner{ if(bytes(_cred).length == 0) _cred = cred; - bytes32 ocid = oraclize_query("computation", [script, "issue-update",strConcat(_repository,",",issue),_cred]); + bytes32 ocid = oraclize_query("nested", _query_issue(_repository,_issue,_cred)); request[ocid].caller = msg.sender; request[ocid].ot = OracleType.UPDATE_ISSUE; } @@ -160,12 +163,83 @@ contract GitHubPoints is Owned, usingOraclize{ function clearAPICredentials() only_owner { cred = ""; } - + + function _query_script(string command, string args, string cred) internal returns (string) { + strings.slice memory comma = strings.toSlice("', '"); + strings.slice [] memory cm = new strings.slice[](4); + cm[0] = script.toSlice(); + cm[1] = command.toSlice(); + cm[2] = args.toSlice(); + cm[3] = cred.toSlice(); + string memory array = comma.join(cm); + cm = new strings.slice[](3); + cm[0] = strings.toSlice("[computation] ['"); + cm[1] = array.toSlice(); + cm[2] = strings.toSlice("']"); + return strings.toSlice("").join(cm); + } + + function _query_start(string _repository, string _branch, string _cred) internal returns (string) { + strings.slice memory comma = strings.toSlice(","); + strings.slice [] memory cm = new strings.slice[](2); + cm[0] = _repository.toSlice(); + cm[1] = _branch.toSlice(); + return _query_script("update",comma.join(cm),_cred); + } + + function _query_update(string _repository, string _branch, string _lastCommit, string _cred) internal returns (string) { + strings.slice memory comma = strings.toSlice(","); + strings.slice [] memory cm = new strings.slice[](3); + cm[0] = _repository.toSlice(); + cm[1] = _branch.toSlice(); + cm[2] = _lastCommit.toSlice(); + return _query_script("update",comma.join(cm),_cred); + } + + function _query_resume(string _repository, string _branch, string _lastCommit, string _limitCommit, string _cred) internal constant returns (string){ + strings.slice memory comma = strings.toSlice(","); + strings.slice [] memory cm = new strings.slice[](4); + cm[0] = _repository.toSlice(); + cm[1] = _branch.toSlice(); + cm[2] = _lastCommit.toSlice(); + cm[3] = _limitCommit.toSlice(); + return _query_script("resume",comma.join(cm),_cred); + } + + function _query_issue(string _repository, string _issue, string _cred) internal returns(string){ + strings.slice memory comma = strings.toSlice(","); + strings.slice [] memory cm = new strings.slice[](2); + cm[0] = _repository.toSlice(); + cm[1] = _issue.toSlice(); + return _query_script("resume",comma.join(cm),_cred); + } + + //"ethereans/TheEtherian","master","client,secret" + function query_start(string _repository, string _branch, string _cred) constant returns (string) { + return _query_start(_repository,_branch,_cred); + } + + //"ethereans/TheEtherian","master","3258ebfded07a6e35d400994db507e456e194716","client,secret" + function query_update(string _repository, string _branch, string _lastCommit, string _cred) constant returns (string) { + return _query_update(_repository,_branch,_lastCommit,_cred); + } + + //"ethereans/TheEtherian","master","3258ebfded07a6e35d400994db507e456e194716","3acd26bf0f1f68ac2d7d26bfceb624bb0f01593a","client,secret" + function query_resume(string _repository, string _branch, string _lastCommit, string _limitCommit, string _cred) constant returns (string) { + return _query_resume(_repository,_branch,_lastCommit,_limitCommit,_cred); + } + + //"ethereans/TheEtherian","1","client,secret" + function query_issue(string _repository, string _issue, string _cred) constant returns (string) { + return _query_issue(_repository,_issue,_cred); + } + function toBytes20(string memory source) internal constant returns (bytes20 result) { assembly { result := mload(add(source, 20)) } } + function toString(bytes20 self) internal constant returns (string) { bytes memory bytesString = new bytes(20); uint charCount = 0; @@ -182,7 +256,7 @@ contract GitHubPoints is Owned, usingOraclize{ } return string(bytesStringTrimmed); } - + function getNextString(bytes _str, uint8 _pos) internal constant returns (string, uint8) { uint8 start = 0; uint8 end = 0; From dbe8c45bef875f284fbb1a88ff96b1d10e53aa51 Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Fri, 19 May 2017 16:06:53 -0300 Subject: [PATCH 10/10] archictecture build ok --- contracts/src/BountyBank.sol | 12 +- contracts/src/GitHubAPIReg.sol | 19 ++- contracts/src/GitHubOracle.sol | 80 +++++++----- contracts/src/GitHubPoints.sol | 167 +++++++++++--------------- contracts/src/GitHubRepositoryReg.sol | 31 +++-- contracts/src/GitHubUserReg.sol | 33 +++-- contracts/src/GitRepository.sol | 28 ++--- contracts/src/GitRepositoryToken.sol | 8 +- contracts/src/NameRegistry.sol | 2 +- 9 files changed, 208 insertions(+), 172 deletions(-) diff --git a/contracts/src/BountyBank.sol b/contracts/src/BountyBank.sol index 5a97762..46bf276 100644 --- a/contracts/src/BountyBank.sol +++ b/contracts/src/BountyBank.sol @@ -1,7 +1,7 @@ -pragma solidity ^0.4.9; - -import "lib/ethereans/management/Owned.sol"; - +import "Owned.sol"; + +pragma solidity ^0.4.11; + contract BountyBank is Owned { enum State {CLOSED, OPEN, CLAIMED} @@ -42,10 +42,10 @@ contract BountyBank is Owned { bounties[num].points += points; } - function close(uint num) only_owner { + function close(uint num, uint _closedAt) only_owner { if(bounties[num].state == State.CLAIMED) throw; bounties[num].state = State.CLOSED; - bounties[num].closedAt = now; + bounties[num].closedAt = _closedAt; } function claim(uint num){ diff --git a/contracts/src/GitHubAPIReg.sol b/contracts/src/GitHubAPIReg.sol index d2c052f..c062c9b 100644 --- a/contracts/src/GitHubAPIReg.sol +++ b/contracts/src/GitHubAPIReg.sol @@ -3,13 +3,17 @@ * Abstract Logic for GitHubOracle Registries. * Ricardo Guilherme Schmidt <3esmit@gmail.com> */ -import "lib/ethereans/management/Owned.sol"; -import "lib/oraclize/oraclizeAPI_0.4.sol"; +import "Owned.sol"; +import "oraclizeAPI_0.4.sol"; +import "strings.sol"; pragma solidity ^0.4.11; contract GitHubAPIReg is Owned, usingOraclize { - string credentials = ""; + using strings for string; + using strings for strings.slice; + + string cred = ""; event OracleEvent(bytes32 myid, string result, bytes proof); @@ -19,11 +23,16 @@ contract GitHubAPIReg is Owned, usingOraclize { //owner management function setAPICredentials(string _client_id, string _client_secret) only_owner { - credentials = strConcat("?client_id=",_client_id,"&client_secret=",_client_secret,""); + 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() only_owner { - credentials = ""; + cred = ""; } function getNextString(bytes _str, uint8 _pos) internal constant returns (string, uint8) { diff --git a/contracts/src/GitHubOracle.sol b/contracts/src/GitHubOracle.sol index 77360da..ee17e58 100644 --- a/contracts/src/GitHubOracle.sol +++ b/contracts/src/GitHubOracle.sol @@ -13,8 +13,8 @@ * Released under GPLv3 License */ -import "lib/oraclize/oraclizeAPI_0.4.sol"; -import "lib/ethereans/management/Owned.sol"; +import "oraclizeAPI_0.4.sol"; +import "Owned.sol"; import "./GitHubUserReg.sol"; import "./GitHubRepositoryReg.sol"; import "./GitHubPoints.sol"; @@ -29,44 +29,70 @@ contract GitHubOracle is Owned, DGitI { mapping (uint256 => Repository) repositories; mapping (uint256 => mapping (uint256 => uint256)) pending; - + + modifier oraclized { + if(msg.sender != address(gitHubPoints)) throw; + _; + } + struct Repository { - bytes20 head; - bytes20 tail; + string head; + string tail; + mapping (string => string) pending; } function initialize() only_owner { - userReg = GitHubUserRegFactory.create(); - repositoryReg = GitHubRepositoryRegFactory.create(); - gitHubPoints = GitHubPointsFactory.create(); + if(address(userReg) == 0x0){ + userReg = GHUserReg.create(); + }else if(address(repositoryReg) == 0x0){ + repositoryReg = GHRepoReg.create(); + }else if(address(gitHubPoints) == 0x0){ + gitHubPoints = GHPoints.create(); + }else throw; } - function updateCommits(string _repository, string _token) payable{ + function update(string _repository, string _token) payable { uint256 repoId = repositoryReg.getId(_repository); if(repoId == 0) throw; - gitHubPoints.updateCommits.value(msg.value)(_repository, "master", repositories[repoId].head,_token); + gitHubPoints.update.value(msg.value)(_repository, "master", repositories[repoId].head,_token); } - function updateIssue(string _repository, string issue, string _token) payable{ - gitHubPoints.updateIssue.value(msg.value)(_repository,issue,_token); + function issue(string _repository, string _issue, string _token) payable { + gitHubPoints.issue.value(msg.value)(_repository,_issue,_token); + } + + function __pendingScan(uint256 _projectId, string _lastCommit, string _pendingTail) oraclized { + repositories[_projectId].pending[_pendingTail] = _lastCommit; + } + + function __setHead(uint256 _projectId, string _head) oraclized { + repositories[_projectId].head = _head; + } + + function __setTail(uint256 _projectId, string _tail) oraclized { + repositories[_projectId].tail = _tail; + } + + function __setIssue(uint256 _projectId, uint256 _issueId, bool _state, uint256 _closedAt) oraclized { + GitRepositoryI repo = GitRepositoryI(repositoryReg.getAddr(_projectId)); + repo.setBounty(_issueId, _state, _closedAt); + } + + function __setIssuePoints(uint256 _projectId, uint256 _issueId, uint256 _userId, uint256 _points) oraclized { + GitRepositoryI repo = GitRepositoryI(repositoryReg.getAddr(_projectId)); + repo.setBountyPoints(_issueId, userReg.getAddr(_userId), _points); } - function getRepository(uint projectId) constant returns (address){ - return repositoryReg.getAddr(projectId); - } - function getRepository(string full_name) constant returns (address){ - return repositoryReg.getAddr(full_name); - } event NewPoints(uint repoId, uint userId, uint total, bool claimed); - function __newPoints(uint repoId, uint userId, uint total) + function __newPoints(uint _repoId, uint _userId, uint _points) only_owner { - GitRepositoryI repoaddr = GitRepositoryI(repositoryReg.getAddr(repoId)); - bool claimed = repoaddr.claim(userReg.getAddr(userId), total); + GitRepositoryI repoaddr = GitRepositoryI(repositoryReg.getAddr(_repoId)); + bool claimed = repoaddr.claim(userReg.getAddr(_userId), _points); if(!claimed){ //try to claim points - addPending(repoId, userId, total); //set as a pending points + pending[_userId][_repoId] += _points; //set as a pending points } - NewPoints(repoId,userId,total,claimed); + NewPoints(_repoId, _userId, _points, claimed); } //claims pending points @@ -78,11 +104,5 @@ contract GitHubOracle is Owned, DGitI { NewPoints(_repoId,_userId,total,true); } else throw; } - - function addPending(uint256 _repoId, uint256 _userId, uint256 _points) internal { - pending[_userId][_repoId] += _points; - } - - - + } \ No newline at end of file diff --git a/contracts/src/GitHubPoints.sol b/contracts/src/GitHubPoints.sol index 8e97251..c7946bf 100644 --- a/contracts/src/GitHubPoints.sol +++ b/contracts/src/GitHubPoints.sol @@ -1,26 +1,29 @@ -import "lib/oraclize/oraclizeAPI_0.4.sol"; -import "lib/ethereans/management/Owned.sol"; -import "lib/strings.sol"; +import "oraclizeAPI_0.4.sol"; +import "Owned.sol"; +import "strings.sol"; pragma solidity ^0.4.11; contract DGitI { - function __setHead(uint256 projectId, string branch, bytes20 head); - function __setTail(uint256 projectId, string branch, bytes20 tail); + function __setHead(uint256 projectId, string head); + function __setTail(uint256 projectId, string tail); function __newPoints(uint256 projectId, uint256 userId, uint total); + function __pendingScan(uint256 projectId, string lastCommit, string pendingTail); function __setIssue(uint256 projectId, uint256 issueId, bool state, uint256 closedAt); function __setIssuePoints(uint256 projectId, uint256 issueId, uint256 userId, uint256 points); } contract GitHubPoints is Owned, usingOraclize{ - + + using strings for string; + using strings for strings.slice; + string private cred = ""; string private script = ""; - enum OracleType { CLAIM_COMMIT, CLAIM_CONTINUE, UPDATE_ISSUE } - mapping (bytes32 => OracleType) claimType; //temporary db enumerating oraclize calls - mapping (bytes32 => bytes20) commitClaim; //temporary db for oraclize commit token claim calls - mapping (bytes32 => Request) request; //temporary db + enum Command { UPDATE, RESUME, ISSUE } + mapping (bytes32 => Command) command; //temporary db enumerating oraclize calls + mapping (bytes32 => string) lastCommits; //temporary db for oraclize commit token claim calls //stores temporary data for oraclize repository commit claim struct CommitClaim { @@ -28,86 +31,62 @@ contract GitHubPoints is Owned, usingOraclize{ bytes20 commitid; } - struct Request { - address caller; - OracleType ot; - } - - function _query_start(string _repository, string _branch, string _cred) internal { - strConcat("[computation] ['", script, "', 'update-new', '", _repository, strConcat("','", _branch,"', '", _cred,"']")) - } - - function start(string _repository, string _branch, string _cred) payable only_owner { + function update(string _repository, string _branch, string _lastCommit, string _cred) payable only_owner { if(bytes(_cred).length == 0) _cred = cred; - bytes32 ocid = oraclize_query("nested", _query_start(_repository,_branch,_cred)); - claimType[ocid] = OracleType.CLAIM_COMMIT; - request[ocid].caller = msg.sender; - request[ocid].ot = OracleType.CLAIM_COMMIT; - } - - function update(string _repository, string _branch, string _commitid, string _cred) payable only_owner { - if(bytes(_cred).length == 0) _cred = cred; - bytes32 ocid = oraclize_query("nested", _query_update(_repository,_branch,_commitid,_cred)); - claimType[ocid] = OracleType.CLAIM_COMMIT; - commitClaim[ocid] = toBytes20(_commitid); - request[ocid].caller = msg.sender; - request[ocid].ot = OracleType.CLAIM_COMMIT; + bytes32 ocid = oraclize_query("nested", _query_update(_repository,_branch,_lastCommit,_cred)); + command[ocid] = Command.UPDATE; + lastCommits[ocid] = _lastCommit; } function resume(string _repository, string _branch, string _lastCommit, string _limitCommit, string _cred) - payable only_owner{ + payable only_owner { if(bytes(_cred).length == 0) _cred = cred; bytes32 ocid = oraclize_query("nested", _query_resume(_repository,_branch,_lastCommit,_limitCommit,_cred)); - claimType[ocid] = OracleType.CLAIM_CONTINUE; - commitClaim[ocid] = toBytes20(_lastCommit); - request[ocid].caller = msg.sender; - request[ocid].ot = OracleType.CLAIM_CONTINUE; + command[ocid] = Command.RESUME; + lastCommits[ocid] = _lastCommit; } - function issue(string _repository, string issue, string _cred) - payable only_owner{ + function issue(string _repository, string _issue, string _cred) + payable only_owner { if(bytes(_cred).length == 0) _cred = cred; + command[ocid] = Command.ISSUE; bytes32 ocid = oraclize_query("nested", _query_issue(_repository,_issue,_cred)); - request[ocid].caller = msg.sender; - request[ocid].ot = OracleType.UPDATE_ISSUE; } event OracleEvent(bytes32 myid, string result, bytes proof); //oraclize response callback function __callback(bytes32 myid, string result, bytes proof) { OracleEvent(myid, result, proof); - if (msg.sender != oraclize.cbAddress()){ - throw; - }else if(claimType[myid] == OracleType.UPDATE_ISSUE){ - _updateIssue(myid, result); - }else{ - _updateCommits(commitClaim[myid], result,claimType[myid]==OracleType.CLAIM_CONTINUE); + if (msg.sender != oraclize.cbAddress()) throw; + Command comm = command[myid]; + if(comm == Command.UPDATE) { + _update(lastCommits[myid], result); + }else if(comm == Command.ISSUE) { + _issue(result); + }else if (comm == Command.RESUME) { + _resume(lastCommits[myid], result); + delete lastCommits[myid]; } - delete claimType[myid]; //should always be deleted + delete command[myid]; } - function _updateCommits(bytes20 oldCommit, string result, bool resume) internal { + function _update(string _lastCommit, string result) internal { DGitI dGit = DGitI(owner); bytes memory v = bytes(result); uint8 pos = 0; string memory temp; uint256 projectId; (projectId,pos) = getNextUInt(v,pos); - string memory branch; - (branch,pos) = getNextString(v,pos); - (temp,pos) = getNextString(v,pos); - bytes20 head = toBytes20(temp); - (temp,pos) = getNextString(v,pos); - bytes20 tail = toBytes20(temp); - dGit.__setHead(projectId,branch,head); - if(resume){ - dGit.__setTail(projectId,branch,tail); - }else{ - if(oldCommit == 0x0){ - dGit.__setTail(projectId,branch,tail); - }else if (oldCommit != tail){ - //TODO: acceptContinueUpdateUntilLimit(tail,oldCommit) - } + (temp,pos) = getNextString(v,pos); //branch + (temp,pos) = getNextString(v,pos); //head + dGit.__setHead(projectId,temp); //head + + (temp,pos) = getNextString(v,pos); //tail + if(bytes(_lastCommit).length == 0){ + dGit.__setTail(projectId,temp); + } + if (sha3(_lastCommit) != sha3(temp)){ //update didn't reached _lastCommit + dGit.__pendingScan(projectId,_lastCommit,temp); } uint numAuthors; (numAuthors,pos) = getNextUInt(v,pos); @@ -119,9 +98,34 @@ contract GitHubPoints is Owned, usingOraclize{ dGit.__newPoints(projectId,userId,points); } } + + function _resume(string _lastCommit, string result) internal { + DGitI dGit = DGitI(owner); + bytes memory v = bytes(result); + uint8 pos = 0; + string memory temp; + uint256 projectId; + (projectId,pos) = getNextUInt(v,pos); + string memory branch; + (branch,pos) = getNextString(v,pos); + string memory head; + (head,pos) = getNextString(v,pos); + string memory tail; + (tail,pos) = getNextString(v,pos); + dGit.__setTail(projectId,tail); + uint numAuthors; + (numAuthors,pos) = getNextUInt(v,pos); + uint userId; + uint points; + for(uint i; i < numAuthors; i++){ + (userId,pos) = getNextUInt(v,pos); + (points,pos) = getNextUInt(v,pos); + dGit.__newPoints(projectId,userId,points); + } + } - function _updateIssue(bytes32 myid, string result) internal { - DGitI dGit = DGitI(request[myid].caller); + function _issue(string result) internal { + DGitI dGit = DGitI(owner); bytes memory v = bytes(result); uint8 pos = 0; string memory temp; @@ -178,14 +182,6 @@ contract GitHubPoints is Owned, usingOraclize{ cm[2] = strings.toSlice("']"); return strings.toSlice("").join(cm); } - - function _query_start(string _repository, string _branch, string _cred) internal returns (string) { - strings.slice memory comma = strings.toSlice(","); - strings.slice [] memory cm = new strings.slice[](2); - cm[0] = _repository.toSlice(); - cm[1] = _branch.toSlice(); - return _query_script("update",comma.join(cm),_cred); - } function _query_update(string _repository, string _branch, string _lastCommit, string _cred) internal returns (string) { strings.slice memory comma = strings.toSlice(","); @@ -214,25 +210,6 @@ contract GitHubPoints is Owned, usingOraclize{ return _query_script("resume",comma.join(cm),_cred); } - //"ethereans/TheEtherian","master","client,secret" - function query_start(string _repository, string _branch, string _cred) constant returns (string) { - return _query_start(_repository,_branch,_cred); - } - - //"ethereans/TheEtherian","master","3258ebfded07a6e35d400994db507e456e194716","client,secret" - function query_update(string _repository, string _branch, string _lastCommit, string _cred) constant returns (string) { - return _query_update(_repository,_branch,_lastCommit,_cred); - } - - //"ethereans/TheEtherian","master","3258ebfded07a6e35d400994db507e456e194716","3acd26bf0f1f68ac2d7d26bfceb624bb0f01593a","client,secret" - function query_resume(string _repository, string _branch, string _lastCommit, string _limitCommit, string _cred) constant returns (string) { - return _query_resume(_repository,_branch,_lastCommit,_limitCommit,_cred); - } - - //"ethereans/TheEtherian","1","client,secret" - function query_issue(string _repository, string _issue, string _cred) constant returns (string) { - return _query_issue(_repository,_issue,_cred); - } function toBytes20(string memory source) internal constant returns (bytes20 result) { assembly { @@ -295,7 +272,7 @@ contract GitHubPoints is Owned, usingOraclize{ } } -library GitHubPointsFactory { +library GHPoints { function create() returns (GitHubPoints){ return new GitHubPoints(""); diff --git a/contracts/src/GitHubRepositoryReg.sol b/contracts/src/GitHubRepositoryReg.sol index f70ba6b..0df676d 100644 --- a/contracts/src/GitHubRepositoryReg.sol +++ b/contracts/src/GitHubRepositoryReg.sol @@ -7,11 +7,14 @@ import "./GitHubAPIReg.sol"; import "./NameRegistry.sol"; import "./GitRepository.sol"; +import "strings.sol"; pragma solidity ^0.4.11; contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg { - + using strings for string; + using strings for strings.slice; + mapping (uint256 => Repository) public repositories; event NewRepository(address addr, uint256 projectId, string full_name, string default_branch); @@ -22,8 +25,10 @@ contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg { string branch; } - function register(string _repository) payable { - oraclize_query("URL", _getQuery(_repository), getAddr(_repository) == 0x00? 4000000 : 1000000); + function register(string _repository, string _cred) payable { + if(bytes(_cred).length == 0) _cred = cred; + uint gas = getAddr(_repository) == 0x00? 4000000 : 1000000; + oraclize_query("URL", _query_script(_repository,_cred), gas); } function getAddr(uint256 _id) public constant returns(address addr) { @@ -48,11 +53,11 @@ contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg { if (msg.sender != oraclize.cbAddress()){ throw; }else { - _setRepository(myid, result); + _setRepository(result); } } - function _setRepository(bytes32 myid, string result) internal //[85743750, "ethereans/TheEtherian", "master"] + function _setRepository(string result) internal //[85743750, "ethereans/TheEtherian", "master"] { bytes memory v = bytes(result); uint8 pos = 0; @@ -64,7 +69,9 @@ contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg { (default_branch,pos) = getNextString(v,pos); address repoAddr = repositories[projectId].addr; if(repoAddr == 0x0){ - //repoAddr = address(GitFactory.newGitRepository(projectId, full_name, default_branch)); + GitRepositoryI repo = GitFactory.newGitRepository(projectId, full_name); + repo.setOwner(owner); + repoAddr = address(repo); indexes[sha3(repoAddr)] = projectId; indexes[sha3(full_name)] = projectId; NewRepository(repoAddr, projectId, full_name, default_branch); @@ -78,12 +85,16 @@ contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg { } } //internal helper functions - function _getQuery(string _repository) internal constant returns (string){ - return strConcat("json(https://api.github.com/repos/",_repository,credentials,").$.id,full_name,default_branch"); + function _query_script(string _repository, string _cred) internal returns (string) { + strings.slice [] memory cm = new strings.slice[](5); + cm[0] = strings.toSlice("json(https://api.github.com/repos/"); + cm[1] = _repository.toSlice(); + cm[2] = _cred.toSlice(); + cm[4] = strings.toSlice(").$.id,full_name,default_branch"); + return strings.toSlice("").join(cm); } - } -library GitHubRepositoryRegFactory { +library GHRepoReg { function create() returns (GitHubRepositoryReg){ return new GitHubRepositoryReg(); diff --git a/contracts/src/GitHubUserReg.sol b/contracts/src/GitHubUserReg.sol index 4ebd032..553fc81 100644 --- a/contracts/src/GitHubUserReg.sol +++ b/contracts/src/GitHubUserReg.sol @@ -5,11 +5,14 @@ */ import "GitHubAPIReg.sol"; import "NameRegistry.sol"; +import "strings.sol"; pragma solidity ^0.4.11; contract GitHubUserReg is NameRegistry, GitHubAPIReg { - + using strings for string; + using strings for strings.slice; + mapping (bytes32 => UserClaim) userClaim; //temporary db for oraclize user register queries mapping (uint256 => User) users; @@ -26,8 +29,9 @@ contract GitHubUserReg is NameRegistry, GitHubAPIReg { string login; } - function register(string _github_user, string _gistid) payable { - bytes32 ocid = oraclize_query("nested", _getQuery(_github_user, _gistid)); + function register(string _github_user, string _gistid, string _cred) payable { + if(bytes(_cred).length == 0) _cred = cred; + bytes32 ocid = oraclize_query("nested", _query_script(_github_user, _gistid,_cred)); userClaim[ocid] = UserClaim({sender: msg.sender, login: _github_user}); } @@ -76,10 +80,25 @@ contract GitHubUserReg is NameRegistry, GitHubAPIReg { delete userClaim[myid]; //should always be deleted } - //internal helper functions - function _getQuery(string _github_user, string _gistid) internal constant returns (string){ - string memory a = strConcat("[identity] ${[URL] https://gist.githubusercontent.com/", _github_user,"/",_gistid,"/raw/registereth.txt}, ${[URL] json(https://api.github.com/gists/"); - return strConcat(a, _gistid, credentials, ").owner.[login,id]}",""); + function _query_script(string _github_user, string _gistid, string _cred) internal returns (string) { + strings.slice [] memory cm = new strings.slice[](8); + cm[0] = strings.toSlice("[identity] ${[URL] https://gist.githubusercontent.com/"); + cm[1] = _github_user.toSlice(); + cm[2] = strings.toSlice("/"); + cm[3] = _gistid.toSlice(); + cm[4] = strings.toSlice("/raw/register.txt}, ${[URL] json(https://api.github.com/gists/"); + cm[5] = _gistid.toSlice(); + cm[6] = _cred.toSlice(); + cm[7] = strings.toSlice(").owner.[login,id]}"); + return strings.toSlice("").join(cm); + } + +} + +library GHUserReg{ + + function create() returns (GitHubUserReg){ + return new GitHubUserReg(); } } \ No newline at end of file diff --git a/contracts/src/GitRepository.sol b/contracts/src/GitRepository.sol index 327707e..2e58298 100644 --- a/contracts/src/GitRepository.sol +++ b/contracts/src/GitRepository.sol @@ -1,5 +1,3 @@ -pragma solidity ^0.4.8; - /** * Contract that mint tokens by github commit stats * @@ -15,17 +13,20 @@ pragma solidity ^0.4.8; * Released under GPLv3 License */ -import "lib/ethereans/bank/CollaborationBank.sol"; -import "lib/ethereans/management/Owned.sol"; +import "CollaborationBank.sol"; +import "Owned.sol"; import "./BountyBank.sol"; import "./GitRepositoryToken.sol"; +pragma solidity ^0.4.11; -contract GitRepositoryI { +contract GitRepositoryI is Owned{ function claim(address _user, uint _total) returns (bool) ; + function setBounty(uint256 _issueId, bool _state, uint256 _closedAt); + function setBountyPoints(uint256 _issueId, address _claimer, uint256 _points); } -contract GitRepository is GitRepositoryI, Owned { +contract GitRepository is GitRepositoryI { GitRepositoryToken public token; CollaborationBank public donationBank; @@ -49,7 +50,6 @@ contract GitRepository is GitRepositoryI, Owned { bountyBank = new BountyBank(); } - //oracle claim request function claim(address _user, uint _total) only_owner returns (bool) { @@ -61,15 +61,15 @@ contract GitRepository is GitRepositoryI, Owned { } } - function bountyState(uint issue, bool open) only_owner { - if (open) bountyBank.open(issue); - else bountyBank.close(issue); - } - - function bountyState(uint issue, address claimer, uint points) only_owner { - bountyBank.setClaimer(issue,claimer,points); + function setBounty(uint256 _issueId, bool _state, uint256 _closedAt) only_owner { + if (_state) bountyBank.open(_issueId); + else bountyBank.close(_issueId,_closedAt); } + function setBountyPoints(uint256 _issueId, address _claimer, uint256 _points) only_owner { + bountyBank.setClaimer(_issueId,_claimer,_points); + } + } library GitFactory { diff --git a/contracts/src/GitRepositoryToken.sol b/contracts/src/GitRepositoryToken.sol index 3a9b81d..5098d21 100644 --- a/contracts/src/GitRepositoryToken.sol +++ b/contracts/src/GitRepositoryToken.sol @@ -1,5 +1,3 @@ -pragma solidity ^0.4.8; - /** * Contract that mint tokens by github commit stats * @@ -15,8 +13,10 @@ pragma solidity ^0.4.8; * Released under GPLv3 License */ -import "lib/ethereans/token/LockerToken.sol"; -import "lib/ethereans/management/Owned.sol"; +import "LockerToken.sol"; +import "Owned.sol"; + +pragma solidity ^0.4.11; contract GitRepositoryToken is LockerToken { diff --git a/contracts/src/NameRegistry.sol b/contracts/src/NameRegistry.sol index bef006e..33494fc 100644 --- a/contracts/src/NameRegistry.sol +++ b/contracts/src/NameRegistry.sol @@ -3,7 +3,7 @@ * Interface for Name Registries. * Ricardo Guilherme Schmidt <3esmit@gmail.com> */ -pragma solidity ^0.4.9; +pragma solidity ^0.4.11; contract NameRegistry { function getAddr(uint256 _id) public constant returns(address addr);