mirror of git3://git3.w3q/git3-contract
parent
7b498b35c1
commit
7e9084de37
@ -0,0 +1,97 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
// import "hardhat/console.sol";
|
||||||
|
// import "@openzeppelin/contracts/access/Ownable.sol";
|
||||||
|
|
||||||
|
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
|
||||||
|
import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
|
||||||
|
import "./Repository.sol";
|
||||||
|
contract Hub is AccessControlEnumerableUpgradeable{
|
||||||
|
// AccessController public accessController;
|
||||||
|
|
||||||
|
mapping(bytes=>address) public nameToRepository;
|
||||||
|
bytes[] public repoNames;
|
||||||
|
|
||||||
|
bytes32 public constant CREATOR = bytes32(uint256(1));
|
||||||
|
bytes32 public constant MANAGER = bytes32(uint256(2));
|
||||||
|
bytes32 public constant CONTRIBUTOR = bytes32(uint256(3));
|
||||||
|
bytes32[] public RoleList = [CREATOR,MANAGER,CONTRIBUTOR];
|
||||||
|
// mapping(bytes32=>address)public executors;
|
||||||
|
|
||||||
|
bool public permissionless;
|
||||||
|
|
||||||
|
function openPermissonlessJoin(bool open) public {
|
||||||
|
require(hasRole(CREATOR, _msgSender()));
|
||||||
|
permissionless = open;
|
||||||
|
}
|
||||||
|
|
||||||
|
function memberShip() public view returns(bool){
|
||||||
|
if (hasRole(CREATOR, _msgSender())){
|
||||||
|
return true;
|
||||||
|
}else if (hasRole(MANAGER, _msgSender())){
|
||||||
|
return true;
|
||||||
|
}else if (hasRole(CONTRIBUTOR, _msgSender())){
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//createRepository can be invoked by anyone within Hub
|
||||||
|
function createRepository(bytes memory repoName) public returns(address){
|
||||||
|
require(hasRole(CREATOR, _msgSender()));
|
||||||
|
require(
|
||||||
|
repoName.length > 0 && repoName.length <= 100,
|
||||||
|
"RepoName length must be 1-100"
|
||||||
|
);
|
||||||
|
for (uint i; i < repoName.length; i++) {
|
||||||
|
bytes1 char = repoName[i];
|
||||||
|
require(
|
||||||
|
(char >= 0x61 && char <= 0x7A) || //a-z
|
||||||
|
(char >= 0x41 && char <= 0x5A) || //A-Z
|
||||||
|
(char >= 0x30 && char <= 0x39) || //0-9
|
||||||
|
(char == 0x2D || char == 0x2E || char == 0x5F), //-._
|
||||||
|
"RepoName must be alphanumeric or -._"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
require(
|
||||||
|
nameToRepository[repoName] == address(0),
|
||||||
|
"RepoName already exist"
|
||||||
|
);
|
||||||
|
address repo = address(new Repository(repoName));
|
||||||
|
nameToRepository[repoName] = repo;
|
||||||
|
repoNames.push(repoName);
|
||||||
|
return repo;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteRepository(bytes memory repoName) public returns(address){
|
||||||
|
require(nameToRepository[repoName]!=address(0),"repoName do not exist");
|
||||||
|
address repoAddr = nameToRepository[repoName];
|
||||||
|
delete(nameToRepository[repoName]);
|
||||||
|
// todo:remove repoName from repoNames
|
||||||
|
return repoAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMember( bytes32 senderRole , bytes32 role,address member) public{
|
||||||
|
require(hasRole(senderRole, _msgSender()));
|
||||||
|
require(senderRole>role);
|
||||||
|
grantRole(role, member);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function deleteMember(bytes32 senderRole ,bytes32 role,address member) public{
|
||||||
|
require(hasRole(CREATOR, _msgSender()));
|
||||||
|
require(hasRole(senderRole, _msgSender()));
|
||||||
|
require(senderRole>role);
|
||||||
|
revokeRole(role, member);
|
||||||
|
}
|
||||||
|
|
||||||
|
// permissionlessJoin can be invoked by everyone who want to join this hub
|
||||||
|
function permissionlessJoin() public{
|
||||||
|
require(permissionless,"permissionless join no open");
|
||||||
|
grantRole(CONTRIBUTOR, _msgSender());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
// import "hardhat/console.sol";
|
||||||
|
// import "@openzeppelin/contracts/access/Ownable.sol";
|
||||||
|
import "./Hub.sol";
|
||||||
|
|
||||||
|
contract HubFactory {
|
||||||
|
function createHub() public returns(Hub){
|
||||||
|
Hub hub = new Hub();
|
||||||
|
return hub;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "./storage/IStorageLayer.sol";
|
||||||
|
import "./RepositoryAccess.sol";
|
||||||
|
|
||||||
|
contract Repository is RepositoryAccess{
|
||||||
|
|
||||||
|
struct refInfo {
|
||||||
|
bytes20 hash;
|
||||||
|
uint96 index;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct refData {
|
||||||
|
bytes20 hash;
|
||||||
|
bytes name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes repositoryName;
|
||||||
|
address creator;
|
||||||
|
address[] public contributorList;
|
||||||
|
|
||||||
|
mapping(bytes => refInfo) public branchToRefInfo; // dev => {hash: 0x1234..., index: 1 }
|
||||||
|
bytes[] public branchs; // 有几条branch,就有几个reference
|
||||||
|
|
||||||
|
IStorageLayer public storageManager;
|
||||||
|
bytes32 constant public ETHSTORAGEID_LAYER = bytes32(keccak256("ETHSTORAGE"));
|
||||||
|
bytes32 constant public NFTSTORAGE_LAYER = bytes32(keccak256("NFTSTORAGE"));
|
||||||
|
constructor(bytes memory repoName){
|
||||||
|
creator = msg.sender;
|
||||||
|
repositoryName = repoName;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier onlyCreator() {
|
||||||
|
require(address(storageManager) == msg.sender, "only creator");
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
function listBranchs() external view returns (refData[] memory list) {
|
||||||
|
list = new refData[](branchs.length);
|
||||||
|
for (uint index = 0; index < branchs.length; index++) {
|
||||||
|
list[index] = _convertToRefData(
|
||||||
|
branchToRefInfo[branchs[index]]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createBranch(bytes memory branch,bytes20 refHash) public onlyCreator {
|
||||||
|
bytes memory fullname = bytes.concat(repositoryName,"/",branch);
|
||||||
|
require(refHash!=bytes20(0),"reference hash don't allow to set 0x0" );
|
||||||
|
require(branchToRefInfo[fullname].hash == bytes20(0),"branch already exists");
|
||||||
|
branchToRefInfo[fullname].hash = refHash;
|
||||||
|
branchToRefInfo[fullname].index = uint96(branchs.length);
|
||||||
|
branchs.push(fullname);
|
||||||
|
|
||||||
|
// add branch owner
|
||||||
|
this.addBranchOperator(fullname,msg.sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function updateBranch(
|
||||||
|
bytes memory branch,
|
||||||
|
bytes20 refHash
|
||||||
|
)external onlyBranchOperator(branch){
|
||||||
|
bytes memory fullname = bytes.concat(repositoryName,"/",branch);
|
||||||
|
require(refHash!=bytes20(0),"reference hash don't allow to set 0x0" );
|
||||||
|
require(branchToRefInfo[fullname].hash != bytes20(0),"branch do not exist");
|
||||||
|
branchToRefInfo[fullname].hash = refHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeBranch(
|
||||||
|
bytes memory branch
|
||||||
|
) external {
|
||||||
|
bytes memory fullname = bytes.concat(repositoryName,"/",branch);
|
||||||
|
refInfo memory refI = branchToRefInfo[fullname];
|
||||||
|
require(
|
||||||
|
refI.hash != bytes20(0),
|
||||||
|
"Reference of this name does not exist"
|
||||||
|
);
|
||||||
|
uint256 lastIndex = branchs.length -1 ;
|
||||||
|
if (refI.index < lastIndex){
|
||||||
|
branchToRefInfo[branchs[lastIndex]].index = refI.index;
|
||||||
|
branchs[refI.index] = branchs[lastIndex];
|
||||||
|
}
|
||||||
|
branchs.pop();
|
||||||
|
delete branchToRefInfo[fullname];
|
||||||
|
}
|
||||||
|
|
||||||
|
function _convertToRefData(
|
||||||
|
refInfo memory info
|
||||||
|
) internal view returns (refData memory res) {
|
||||||
|
res.hash = info.hash;
|
||||||
|
res.name = branchs[info.index];
|
||||||
|
}
|
||||||
|
|
||||||
|
// data storage module
|
||||||
|
|
||||||
|
function setStorageLayer(IStorageLayer addr) external onlyCreator {
|
||||||
|
storageManager = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function upload(
|
||||||
|
bytes20 refHash,
|
||||||
|
bytes calldata data
|
||||||
|
) external payable {
|
||||||
|
storageManager.upload(refHash, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function download(bytes20 refHash) external view returns(bytes32 storageLayerId , bytes memory data){
|
||||||
|
return storageManager.download(refHash);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
|
||||||
|
|
||||||
|
contract RepositoryAccess{
|
||||||
|
using EnumerableSet for EnumerableSet.AddressSet;
|
||||||
|
mapping(bytes => EnumerableSet.AddressSet) BranchOperators;
|
||||||
|
|
||||||
|
modifier onlyBranchOperator(bytes memory branch) {
|
||||||
|
require(BranchOperators[branch].contains(msg.sender),"only branch Operator");
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getBranchOwner(bytes memory branch) internal view returns(address){
|
||||||
|
return BranchOperators[branch].at(0) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addBranchOperator(bytes memory branch, address member) external virtual{
|
||||||
|
require(_getBranchOwner(branch) == msg.sender,"only branch owner");
|
||||||
|
BranchOperators[branch].add(member);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeBranchOperator(bytes memory branch , address member) external virtual{
|
||||||
|
require(_getBranchOwner(branch) == msg.sender,"only branch owner");
|
||||||
|
BranchOperators[branch].remove(member);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
|
||||||
|
interface IStorageLayer{
|
||||||
|
|
||||||
|
function upload(
|
||||||
|
bytes20 refHash,
|
||||||
|
bytes calldata data
|
||||||
|
) external payable ;
|
||||||
|
|
||||||
|
function download(bytes20 refHash) external view returns(bytes32 storageLayerId,bytes memory data);
|
||||||
|
}
|
Loading…
Reference in new issue