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