mirror of git3://git3.w3q/git3-contract
parent
480d10da6e
commit
7b498b35c1
@ -0,0 +1,150 @@
|
||||
//SPDX-License-Identifier: Unlicense
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
// import "hardhat/console.sol";
|
||||
import "./Git3HubStorage.sol";
|
||||
|
||||
contract Git3Hub_SLI is Git3HubStorage_SLI {
|
||||
event RepoCreated(bytes repoName, address owner);
|
||||
event RepoOwnerTransfer(bytes repoName, address oldOwner, address newOwner);
|
||||
event PushRef(bytes repoName, bytes ref);
|
||||
|
||||
constructor() Git3HubStorage_SLI() {}
|
||||
|
||||
modifier onlyOwner(bytes memory repoName) {
|
||||
require(repoNameToOwner[repoName] == msg.sender, "only owner");
|
||||
_;
|
||||
}
|
||||
|
||||
function createRepo(bytes memory repoName) external {
|
||||
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(
|
||||
repoNameToOwner[repoName] == address(0),
|
||||
"RepoName already exist"
|
||||
);
|
||||
repoNameToOwner[repoName] = msg.sender;
|
||||
emit RepoCreated(repoName, msg.sender);
|
||||
}
|
||||
|
||||
function transferOwnership(
|
||||
bytes memory repoName,
|
||||
address newOwner
|
||||
) external onlyOwner(repoName) {
|
||||
require(newOwner != address(0), "newOwner must not be zero address");
|
||||
repoNameToOwner[repoName] = newOwner;
|
||||
emit RepoOwnerTransfer(repoName, msg.sender, newOwner);
|
||||
}
|
||||
|
||||
function download(
|
||||
bytes memory repoName,
|
||||
bytes memory path
|
||||
) external view returns (bytes memory) {
|
||||
return pathToHash[keccak256(bytes.concat(repoName, "/", path))];
|
||||
}
|
||||
|
||||
function upload(
|
||||
bytes memory repoName,
|
||||
bytes memory path,
|
||||
bytes calldata data
|
||||
) external payable onlyOwner(repoName) {
|
||||
pathToHash[keccak256(bytes.concat(repoName, "/", path))] = data;
|
||||
}
|
||||
|
||||
function remove(
|
||||
bytes memory repoName,
|
||||
bytes memory path
|
||||
) external onlyOwner(repoName) {
|
||||
// The actually process of remove will remove all the chunks
|
||||
pathToHash[keccak256(bytes.concat(repoName, "/", path))] = "";
|
||||
}
|
||||
|
||||
function listRefs(
|
||||
bytes memory repoName
|
||||
) external view returns (refData[] memory list) {
|
||||
list = new refData[](repoNameToRefs[repoName].length);
|
||||
for (uint index = 0; index < repoNameToRefs[repoName].length; index++) {
|
||||
list[index] = _convertRefInfo(
|
||||
repoName,
|
||||
nameToRefInfo[repoNameToRefs[repoName][index]]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function setRef(
|
||||
bytes memory repoName,
|
||||
bytes memory ref,
|
||||
bytes20 refHash
|
||||
) external onlyOwner(repoName) {
|
||||
bytes memory fullName = bytes.concat(repoName, "/", ref);
|
||||
// only execute `sload` once to reduce gas consumption
|
||||
refInfo memory srs;
|
||||
srs = nameToRefInfo[fullName];
|
||||
uint256 refsLen = repoNameToRefs[repoName].length;
|
||||
|
||||
if (srs.hash == bytes20(0)) {
|
||||
// store refHash for the first time
|
||||
require(
|
||||
refsLen <= uint256(uint96(int96(-1))),
|
||||
"Refs exceed valid length"
|
||||
);
|
||||
|
||||
nameToRefInfo[fullName].hash = refHash;
|
||||
nameToRefInfo[fullName].index = uint96(refsLen);
|
||||
|
||||
repoNameToRefs[repoName].push(fullName);
|
||||
} else {
|
||||
// only update refHash
|
||||
nameToRefInfo[fullName].hash = refHash;
|
||||
}
|
||||
emit PushRef(repoName, ref);
|
||||
}
|
||||
|
||||
function delRef(
|
||||
bytes memory repoName,
|
||||
bytes memory ref
|
||||
) external onlyOwner(repoName) {
|
||||
bytes memory fullName = bytes.concat(repoName, "/", ref);
|
||||
// only execute `sload` once to reduce gas consumption
|
||||
refInfo memory srs;
|
||||
srs = nameToRefInfo[fullName];
|
||||
uint256 refsLen = repoNameToRefs[repoName].length;
|
||||
|
||||
require(
|
||||
srs.hash != bytes20(0),
|
||||
"Reference of this name does not exist"
|
||||
);
|
||||
require(srs.index < refsLen, "System Error: Invalid index");
|
||||
|
||||
if (srs.index < refsLen - 1) {
|
||||
repoNameToRefs[repoName][srs.index] = repoNameToRefs[repoName][
|
||||
refsLen - 1
|
||||
];
|
||||
nameToRefInfo[repoNameToRefs[repoName][refsLen - 1]].index = srs
|
||||
.index;
|
||||
}
|
||||
repoNameToRefs[repoName].pop();
|
||||
delete nameToRefInfo[fullName];
|
||||
}
|
||||
|
||||
function _convertRefInfo(
|
||||
bytes memory repoName,
|
||||
refInfo memory info
|
||||
) internal view returns (refData memory res) {
|
||||
res.hash = info.hash;
|
||||
res.name = repoNameToRefs[repoName][info.index];
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
//SPDX-License-Identifier: Unlicense
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract Git3HubStorage_SLI {
|
||||
struct refInfo {
|
||||
bytes20 hash;
|
||||
uint96 index;
|
||||
}
|
||||
|
||||
struct refData {
|
||||
bytes20 hash;
|
||||
bytes name;
|
||||
}
|
||||
// FileStorage Storage Layout
|
||||
mapping(bytes32 => bytes) public pathToHash;
|
||||
|
||||
|
||||
// Git3Hub Storage Layout
|
||||
mapping(bytes => address) public repoNameToOwner;
|
||||
mapping(bytes => refInfo) public nameToRefInfo; // dev => {hash: 0x1234..., index: 1 }
|
||||
mapping(bytes => bytes[]) public repoNameToRefs; // [main, dev, test, staging]
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
//SPDX-License-Identifier: Unlicense
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract Hello{
|
||||
string public abc;
|
||||
|
||||
constructor(){
|
||||
abc="Hello World";
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
//SPDX-License-Identifier: Unlicense
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract Git3HubStorage {
|
||||
contract Git3HubStorage_ES {
|
||||
struct refInfo {
|
||||
bytes20 hash;
|
||||
uint96 index;
|
@ -0,0 +1,51 @@
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
async function main() {
|
||||
let provider = ethers.provider;
|
||||
let [operator] = await ethers.getSigners();
|
||||
let nonce = await operator.getTransactionCount();
|
||||
console.log(operator.address, nonce, await operator.getBalance());
|
||||
|
||||
let price = await provider.getFeeData();
|
||||
let net = await provider.getNetwork();
|
||||
console.log(price, net.chainId);
|
||||
|
||||
const Git3 = await ethers.getContractFactory("Git3Hub_SLI");
|
||||
const git3 = await Git3.deploy({
|
||||
nonce: nonce,
|
||||
type: 2,
|
||||
maxFeePerGas: price.maxFeePerGas!,
|
||||
maxPriorityFeePerGas: price.maxPriorityFeePerGas!,
|
||||
gasLimit: 3000000,
|
||||
});
|
||||
|
||||
let logicReceipt = await git3.deployed();
|
||||
console.log(logicReceipt.deployTransaction.hash);
|
||||
nonce++;
|
||||
|
||||
let factory1 = await ethers.getContractFactory("UpgradeableProxy");
|
||||
// Proxy don't need to init Git3 contract because the constructor is empty.
|
||||
let initSelector = "0x";
|
||||
|
||||
let proxyInstance = await factory1
|
||||
.connect(operator)
|
||||
.deploy(git3.address, operator.address, initSelector, {
|
||||
nonce: nonce,
|
||||
type: 2,
|
||||
maxFeePerGas: price.maxFeePerGas,
|
||||
maxPriorityFeePerGas: price.maxPriorityFeePerGas,
|
||||
});
|
||||
let proxyReceipt = await proxyInstance.deployed();
|
||||
console.log(proxyReceipt.deployTransaction.hash);
|
||||
|
||||
// console.log({logicReceipt,proxyReceipt});
|
||||
console.log("Logic Contract", git3.address);
|
||||
console.log("Proxy Contract", proxyInstance.address);
|
||||
}
|
||||
|
||||
// We recommend this pattern to be able to use async/await everywhere
|
||||
// and properly handle errors.
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
@ -0,0 +1,24 @@
|
||||
import hre from "hardhat";
|
||||
const { ethers } = hre;
|
||||
import fs from "fs";
|
||||
|
||||
async function main() {
|
||||
const accounts = await ethers.getSigners();
|
||||
console.log(accounts[0].address);
|
||||
|
||||
const Git3 = await hre.ethers.getContractAt(
|
||||
"Git3Hub_SLI",
|
||||
"0xF56A1dd941667911896B9B872AC79E56cfc6a3dB"
|
||||
);
|
||||
|
||||
let res = await Git3.download(
|
||||
Buffer.from("h1"),
|
||||
Buffer.from("objects/9f/2781f252bddce27d26a4e9ae4acf965f09ba9f")
|
||||
);
|
||||
console.log(res);
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
Loading…
Reference in new issue