Skip to content

Commit

Permalink
Add some doc commit to contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
weiqiushi committed Jul 18, 2024
1 parent 320022d commit 447ee36
Show file tree
Hide file tree
Showing 13 changed files with 84 additions and 53 deletions.
16 changes: 6 additions & 10 deletions contracts/PublicDataProof.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,16 @@ library PublicDataProof {
}

function calcDataProof(bytes32 dataMixedHash, bytes32 nonce, uint32 index, bytes16[] calldata m_path, bytes calldata leafdata, bytes32 noise) public pure returns(bytes32,bytes32) {
//先验证index落在MixedHash包含的长度范围内
// First verify that index in the length range contained in the MixedHash.
require(index < (lengthFromMixedHash(dataMixedHash) >> 10) + 1, "invalid index");

//验证leaf_data+index+path 和 dataMixedHash是匹配的,不匹配就revert

HashType hashType = hashTypeFromMixedHash(dataMixedHash);

bytes32 dataHash = _merkleRoot(hashType,m_path,index, _hashLeaf(hashType,leafdata));
//验证leaf_data+index+path 和 dataMixedHash是匹配的,不匹配就revert
// 只比较后192位

// Compare the last 192 bits only
require(dataHash & bytes32(uint256((1 << 192) - 1)) == dataMixedHash & bytes32(uint256((1 << 192) - 1)), "mixhash mismatch");

// 不需要计算插入位置,只是简单的在Leaf的数据后部和头部插入,也足够满足我们的设计目的了?
bytes32 new_root_hash = _merkleRoot(hashType,m_path,index, _hashLeaf(hashType, bytes.concat(leafdata, nonce)));
bytes32 pow_hash = bytes32(0);

Expand All @@ -35,11 +32,10 @@ library PublicDataProof {
}

function lengthFromMixedHash(bytes32 dataMixedHash) public pure returns (uint64) {
//REVIEW 1<<62是常数,会不会每次都消耗GAS计算?
return uint64(uint256(dataMixedHash) >> 192 & ((1 << 62) - 1));
}

// hash的头2bits表示hash算法,00 = sha256, 10 = keccak256
// The first 2 bits of hash represent the hash algorithm,00 = sha256, 10 = keccak256
function hashTypeFromMixedHash(bytes32 dataMixedHash) public pure returns (HashType) {
return HashType(uint8(uint256(dataMixedHash) >> 254));
}
Expand Down Expand Up @@ -102,8 +98,8 @@ library PublicDataProof {
return computedHash;
}

// sha256要比keccak256贵,因为它不是一个EVM内置操作码,而是一个预置的内部合约调用
// 当hash 1kb数据时,sha256要贵160,当hash 两个bytes32时,sha256要贵400
// sha256 is more expensive than keccak256 because it is not an EVM built-in opcode, but a pre-built internal contract call
// When hashing 1kb of data, sha256 is costs 160 more than keccak256, and when hashing two bytes32, sha256 is costs 400 more.
function _merkleRootWithSha256(bytes16[] calldata proof, uint32 leaf_index, bytes16 leaf_hash) internal pure returns (bytes32) {
bytes16 currentHash = leaf_hash;
bytes32 computedHash = 0;
Expand Down
26 changes: 26 additions & 0 deletions contracts/dmc.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

/**
* @title DMCX token contract
* @author [email protected]
* @notice Basically a standard ERC20Burnable contract, add a few modifications to allow certain addresses to mint tokens
*/
contract DMC is ERC20Burnable, Ownable {
mapping (address => bool) allow_minter;

Expand All @@ -12,6 +17,12 @@ contract DMC is ERC20Burnable, Ownable {
_;
}

/**
* @dev Constructor that gives contract itself and init addresses all of tokens
* @param _totalSupply Total supply of DMCX tokens, have been minted to contract itself
* @param initAddress Addresses which will be minted tokens
* @param initAmount The number of tokens to be minted to each address
*/
constructor(uint256 _totalSupply, address[] memory initAddress, uint[] memory initAmount) ERC20("Datamall Coin", "DMCX") Ownable(msg.sender) {
uint256 totalInited = 0;
for (uint i = 0; i < initAddress.length; i++) {
Expand All @@ -21,18 +32,33 @@ contract DMC is ERC20Burnable, Ownable {
_mint(address(this), _totalSupply - totalInited);
}

/**
* @dev Only owner can enable addresses to "mint" tokens, usually it will be the exchange contract
* @param addresses The array of addresses to be enabled as minter
*/

function enableMinter(address[] calldata addresses) public onlyOwner {
for (uint i = 0; i < addresses.length; i++) {
allow_minter[addresses[i]] = true;
}
}

/**
* @dev Only owner can disable addresses to "mint" tokens, it may happened when the old exchange contract is replaced by a new one
* @param addresses The array of addresses to be disabled as minter
*/
function disableMinter(address[] calldata addresses) public onlyOwner {
for (uint i = 0; i < addresses.length; i++) {
allow_minter[addresses[i]] = false;
}
}

/**
* @dev It called "mint", but actually it's just transfer tokens from contract itself to the "to" address
* @dev It ensures that no more token is actually minted than the total supply
* @param to mint to address
* @param amount mint amount
*/
function mint(address to, uint256 amount) public onlyMinter {
this.transfer(to, amount);
}
Expand Down
2 changes: 0 additions & 2 deletions contracts/dmc_bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ contract DMCBridge is Ownable {
* @notice cookie must same as the one used in registerDMC1
*/
function claimDMC2(string calldata cookie) public {
// function implementation goes here
}
bytes32 key = keccak256(abi.encodePacked(msg.sender, cookie));
require(dmc1_to_dmc2[key] > 0, "no dmc1 amount");
uint256 dmc2Amount = dmc1_to_dmc2[key];
Expand Down
5 changes: 2 additions & 3 deletions contracts/erc721_nft_self_bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ contract ERC721NFTSelfBridge is IERCPublicDataContract, Ownable {
struct NFTInfo {
uint256 tokenId;
address nftAddress;
bool inited;
}

mapping (bytes32 => NFTInfo) hashInfo;
Expand All @@ -20,11 +19,11 @@ contract ERC721NFTSelfBridge is IERCPublicDataContract, Ownable {
function setTokenId(bytes32[] calldata dataMixedHash, address[] calldata nftAddress, uint256[] calldata tokenId) public {
for (uint i = 0; i < dataMixedHash.length; i++) {
if (owner() != _msgSender()) {
require(!hashInfo[dataMixedHash[i]].inited, "Already initialized");
require(hashInfo[dataMixedHash[i]].nftAddress == address(0), "Already initialized");
}
require(IERC721(nftAddress[i]).supportsInterface(type(IERC721).interfaceId), "Not ERC721");

hashInfo[dataMixedHash[i]] = NFTInfo(tokenId[i], nftAddress[i], true);
hashInfo[dataMixedHash[i]] = NFTInfo(tokenId[i], nftAddress[i]);
}
}

Expand Down
43 changes: 23 additions & 20 deletions contracts/exchange.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,26 @@ contract Exchange is Initializable, UUPSUpgradeable, OwnableUpgradeable {
address fundationIncome;

bool test_mode;
// 当前周期,也可以看做周期总数

// currect release cycle, also can be seen as the total cycle number
uint256 current_circle;
uint256 current_mine_circle_start;

// 这个周期内还能mint多少DMC
// remain DMCs can be mined in current cycle
uint256 remain_dmc_balance;

// 这个周期的能mint的DMC总量
// total DMCs can be mined in current cycle
uint256 current_circle_dmc_balance;
uint256 current_finish_time;
uint256 public dmc2gwt_rate;

// 总共未mint的DMC总量,这个值会慢慢释放掉
// total DMC balance not be minted in past cycles, it will be minted in future cycles slowly
uint256 total_addtion_dmc_balance;

// 没有挖完的周期总数
// the number of cycle in which the minted DMCs not as much as current_circle_dmc_balance
uint256 addtion_circle_count;

// 周期的最小时长
// min circle time, in seconds
uint256 min_circle_time;

//uint256 total_mine_period = 420;
Expand Down Expand Up @@ -92,13 +93,14 @@ contract Exchange is Initializable, UUPSUpgradeable, OwnableUpgradeable {
}

function _newCycle() internal {
//移动到下一个周期
//move to next cycle
current_circle = current_circle + 1;
current_mine_circle_start = block.timestamp;

remain_dmc_balance = getCircleBalance(current_circle);

if(total_addtion_dmc_balance > 0) {
// if there has some DMCs not be mined in past cycles, we will mint some of them in next cycles
uint256 this_addtion_dmc = total_addtion_dmc_balance / addtion_circle_count;
total_addtion_dmc_balance -= this_addtion_dmc;

Expand All @@ -112,37 +114,37 @@ contract Exchange is Initializable, UUPSUpgradeable, OwnableUpgradeable {

function adjustExchangeRate() internal {
if(block.timestamp >= current_mine_circle_start + min_circle_time) {
//结束当前挖矿周期
//end current cycle, calculate new exchange rate
uint256 old_rate = dmc2gwt_rate;
if(remain_dmc_balance > 0) {
total_addtion_dmc_balance += remain_dmc_balance;
addtion_circle_count += 1;

// console.log("prev cycle dmc balance left %d, total left %d, total left cycle %d", remain_dmc_balance, total_addtion_dmc_balance, addtion_circle_count);

//本周期未挖完,降低dmc2gwt_rate
//there has remaining DMCs in current cycle, decrease DMC -> GWT exchange rate
dmc2gwt_rate = dmc2gwt_rate * (1-remain_dmc_balance/current_circle_dmc_balance);
if (dmc2gwt_rate < old_rate * 4 / 5) {
// 跌幅限制为20%
// we have a limit down as 20%
dmc2gwt_rate = old_rate * 4 / 5;
}
if(dmc2gwt_rate < 210) {
// 最低值为210
// the lowest rate is 210
dmc2gwt_rate = 210;
}
// console.log("decrease dmc2gwt_rate to %d", dmc2gwt_rate);
} else {
if (addtion_circle_count > 0) {
addtion_circle_count -= 1;
}
//本周期挖完了,提高dmc2gwt_rate
// all DMCs in current cycle have been mined, increase DMC -> GWT exchange rate
dmc2gwt_rate = dmc2gwt_rate * (1+(current_finish_time-current_mine_circle_start)/min_circle_time);
if(dmc2gwt_rate > old_rate * 6 / 5) {
// 涨幅限制为20%
// we have a raising limit as 20%
dmc2gwt_rate = old_rate * 6 / 5;
}
// for test
//dmc2gwt_rate = 210;
// dmc2gwt_rate = 210;
// console.log("increase dmc2gwt_rate to %d", dmc2gwt_rate);
}

Expand All @@ -161,7 +163,8 @@ contract Exchange is Initializable, UUPSUpgradeable, OwnableUpgradeable {
if(remain_dmc_balance > amount) {
remain_dmc_balance -= amount;
} else {
// 待确认:我将current_finish_time看作是一轮DMC释放完毕的时间,但这会导致gwt的汇率计算可能与GWT的实际兑换情况无关
// NEED NOTICE: if we have more than one tokens needed to exchanged from DMC,they will share the DMC mint limit in one cycle
// Rate calculation logic above may need be fixed.
current_finish_time = block.timestamp;

real_amount = remain_dmc_balance;
Expand All @@ -179,8 +182,8 @@ contract Exchange is Initializable, UUPSUpgradeable, OwnableUpgradeable {
}

function freeMintGWT() public {
//每个地址只能free mint一次
//每次成功得到210个GWT
//one address only can free mint once
//get 210 GWT
require(!is_free_minted[msg.sender], "already free minted");
require(free_mint_balance > 0, "no free mint balance");

Expand All @@ -205,7 +208,7 @@ contract Exchange is Initializable, UUPSUpgradeable, OwnableUpgradeable {
function enableProdMode() public onlyOwner testEnabled {
test_mode = false;

// 将剩余的DMC还给owner
// return remaining DMCs to owner, those DMCs comes from owner called addFreeDMCTestMintBalance in test mode.
DMC(dmcToken).transfer(msg.sender, DMC(dmcToken).balanceOf(address(this)));

// 如果是首次开启生产模式,初始化第一个周期
Expand Down Expand Up @@ -242,13 +245,13 @@ contract Exchange is Initializable, UUPSUpgradeable, OwnableUpgradeable {
real_gwt_amount = real_dmc_amount * dmc2gwt_rate;
}

//不用立刻转给分红合约,而是等积累一下
// The GWT received from the sender first stored in the contract address.
GWT(gwtToken).transferFrom(msg.sender, address(this), real_gwt_amount);
DMC(dmcToken).mint(msg.sender, real_dmc_amount);
emit DMCMinted(msg.sender, real_dmc_amount, remain_dmc_balance);
}

// 手工将累积的收入打给分红合约
// Manually transfer the remaining GWT to a income distribution contract, usually a DividendContract
function transferIncome() public {
uint256 income = GWT(gwtToken).balanceOf(address(this)) - free_mint_balance;
GWT(gwtToken).approve(fundationIncome, income);
Expand Down
7 changes: 7 additions & 0 deletions contracts/gwt.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@ pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

/**
* @title DMCX token contract
* @author [email protected]
* @notice Basically a standard ERC20Burnable contract, add a few modifications to allow certain addresses to mint tokens
*/

contract GWT is ERC20, Ownable {
mapping (address => bool) allow_minter;

// GWT token has no supply limit, it represents the total storage space in network
constructor(address[] memory initAddress, uint[] memory initAmount) ERC20("Gb storage per Week Token", "GWT") Ownable(msg.sender) {
for (uint i = 0; i < initAddress.length; i++) {
_mint(initAddress[i], initAmount[i]);
Expand Down
6 changes: 6 additions & 0 deletions contracts/luckymint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";

/**
* @title LuckyMint contract for DMCs
* @author [email protected]
* @notice this is a luckymint contract for DMCs, called by our bitcoin inscription backend server
*/

contract LuckyMint is Ownable {
mapping(bytes32 => uint) lucky_mint;
address public dataAdmin;
Expand Down
1 change: 0 additions & 1 deletion contracts/pst_bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import "@openzeppelin/contracts/access/Ownable.sol";
contract PSTBridge is Ownable {
GWT public gwt;

// PST到GWT的兑换
mapping(bytes32 => uint256) public pst_to_gwt;

constructor(address _gwt) Ownable(msg.sender) {
Expand Down
9 changes: 4 additions & 5 deletions contracts/sortedlist.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ library SortedScoreList {
current = self.sorted[current];
}

// 这里其实只会去掉最后一个
// Only the last one will be removed here
if (current != bytes32(0)) {
self.sorted[prev] = bytes32(0);
delete self.scores[current];
Expand Down Expand Up @@ -53,16 +53,15 @@ library SortedScoreList {
return;
}

// 由于max_length有限,这里做两次遍历也并不过多消耗性能
// Since max_length is limited, doing two traversals here doesn't cost so much gas.
_deleteScore(self, mixedHash);

bytes32 currect = self.head;
bytes32 prev = bytes32(0);
uint cur_index = 0;
while (true) {
// 同score的数据先到先占,这里利用了score的默认值为0的特性,这个循环一定会结束
// since the default value of uint256 is 0, the loop will surely end
if (self.scores[currect] < score) {
// TODO: 如果插入的数据是最后一个的话,会变成先插入再删除,这里可以优化
if (prev != bytes32(0)) {
self.sorted[prev] = mixedHash;
}
Expand All @@ -79,7 +78,7 @@ library SortedScoreList {
self.head = mixedHash;
}

// 这里认为,往存储里写一个bytes32 end的值,比遍历要贵
// I think that writing a bytes32 to storage is expensive than traversing the data
_ensureSize(self);
}

Expand Down
2 changes: 1 addition & 1 deletion scripts/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export async function main() {
await (await publicDataStorage.setSysConfig(setConfig)).wait();

let bridge = await (await ethers.getContractFactory("OwnedNFTBridge")).deploy();
await (await publicDataStorage.allowPublicDataContract([await bridge.getAddress()])).wait()
await (await publicDataStorage.allowPublicDataContract(await bridge.getAddress())).wait()
depolyedInfo.Bridge = await bridge.getAddress();
saveInfo();
}
Expand Down
10 changes: 5 additions & 5 deletions scripts/deploy_dmc2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { ethers, upgrades } from "hardhat";
import { DividendContract, Exchange } from "../typechain-types";

/*
DMC address: 0x05F2E406606f82Ec96DcE822B295278795c5053B
GWT address: 0x191Af8663fF88823d6b226621DC4700809D042fa
Dividend address: 0xD1AB647a6D3163bAD9D5C49C8A23Ee2811FC9e50
exchange address: 0x785423901A501Bcef29Ab2a8cAFa25D5a8c027d3
Layer1 DMC Address: 0x910e888698dA0C2eCC97A04A137Aa1CfC1Dfd209
DMC address: 0x848e56Ad13B728a668Af89459851EfD8a89C9F58
GWT address: 0x02F4AAda17e5Bb85d79De9aAC47cC6F3011023e6
Dividend address: 0x940e289E7a846cE3382D7c5a1b718C8CAcd485ff
exchange address: 0x6c8069f7C71F8C265C84cA3666Ab6e68f0832199
PSTBridge address: 0x4ac99EA4CCD7f1743f977583328Bb8BEdfbf1993
*/

async function main() {
Expand Down
3 changes: 2 additions & 1 deletion test/test_dividend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ describe("Devidend", function () {

dmc = await (await ethers.deployContract("DMC", [ethers.parseEther("1000000000"), [signers[0].address], [1000000]])).waitForDeployment()
gwt = await (await ethers.deployContract("GWT", [[], []])).waitForDeployment()
dividend = await(await ethers.deployContract("DividendContract", [await dmc.getAddress(), 1000])).waitForDeployment();
dividend = await upgrades.deployProxy(await ethers.getContractFactory("DividendContract"), [await dmc.getAddress(), 1000, [await gwt.getAddress()]]) as unknown as DividendContract;
//dividend = await(await ethers.deployContract("DividendContract", [await dmc.getAddress(), 1000, [await gwt.getAddress()]])).waitForDeployment();

// 给signers[0] 1000个GWT
await (await gwt.enableMinter([signers[0].address])).wait()
Expand Down
Loading

0 comments on commit 447ee36

Please sign in to comment.