Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

smart contract #638

Merged
merged 24 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9bdf57d
minter contract
CoderZhi Sep 16, 2024
1856138
add events and address some TODOs
CoderZhi Sep 17, 2024
d69b362
assign tasks in batch
CoderZhi Sep 17, 2024
8414755
fix difficulty update bug
CoderZhi Sep 17, 2024
5480c2c
Merge remote-tracking branch 'origin/develop' into minter
huangzhiran Sep 18, 2024
73f4d01
change taskID type from uint64 to byte32
huangzhiran Sep 18, 2024
ed333cb
add DAO,TaskManager,Minter deploy script
huangzhiran Sep 18, 2024
21b1cc4
add back project id and fix a few bugs
CoderZhi Sep 19, 2024
82afc51
change difficulty to nbits
CoderZhi Sep 19, 2024
3b1bd73
task manager add minter as operator
huangzhiran Sep 20, 2024
dfaa6f1
add block reward distributor and update block minter
CoderZhi Sep 25, 2024
b886818
introduce scrypt hash
CoderZhi Sep 26, 2024
adb0046
implement scrypt precompiled contract
CoderZhi Sep 27, 2024
ed4209b
emit events and receive coin
CoderZhi Sep 27, 2024
399e1b7
allow owner to withdraw
CoderZhi Sep 27, 2024
8aa6d12
fix encode bug
CoderZhi Sep 30, 2024
fa85c49
update default nbits
CoderZhi Sep 30, 2024
38b43b7
Merge remote-tracking branch 'origin/develop' into minter
huangzhiran Sep 30, 2024
832d54d
fix taskManager type, set distributor operator, set blockReward
huangzhiran Sep 30, 2024
b2dbab9
add block header validator and fix unit test
CoderZhi Oct 1, 2024
6872727
update w3bstream task manager
CoderZhi Oct 2, 2024
506cfd1
new prover contract which removes erc721
CoderZhi Oct 3, 2024
6a0cf05
update balance instead of sending erc20 tokens
CoderZhi Oct 3, 2024
8d84519
address comment
CoderZhi Oct 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions smartcontracts/contracts/Scrypt.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract Scrypt {
function hash(
bytes calldata password,
bytes calldata salt,
uint64 N,
uint32 r,
uint32 p,
uint32 keyLen,
uint32 mode
) external view returns (bytes memory retval) {
bytes memory input = abi.encode(password, salt, N, r, p, keyLen, mode);
uint length = input.length;
assembly {
if iszero(staticcall(gas(), 0x8002, add(input, 0x20), length, 0, 0)) {
revert(0x0, 0x0)
}
if iszero(eq(returndatasize(), keyLen)) {
revert(0x0, 0x0)
}
mstore(retval, returndatasize()) // Store the length.
let o := add(retval, 0x20)
returndatacopy(o, 0x00, returndatasize()) // Copy the returndata.
mstore(0x40, add(o, returndatasize())) // Allocate the memory.
}

return retval;
}
}
128 changes: 128 additions & 0 deletions smartcontracts/contracts/W3bstreamBlockHeaderValidator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {BlockHeader, IBlockHeaderValidator, IScrypt} from "./interfaces/IBlockHeaderValidator.sol";

contract W3bstreamBlockHeaderValidator is IBlockHeaderValidator, Ownable {
event OperatorSet(address operator);
event TargetDurationSet(uint256 duration);
event NBitsSet(uint32 nbits);

uint32 public constant MAX_EXPONENT = 0x1c;
uint32 public constant UPPER_BOUND = 0xffff00;
uint32 public constant LOWER_BOUND = 0x8000;
// uint256 public constant MAX_TARGET = 0x00000000ffff0000000000000000000000000000000000000000000000000000;

address public operator;
IScrypt public scrypt;
uint256 public targetDuration;
uint32 public currentNBits;
bool public useAdhocNBits;

uint256 private _currentTarget;
uint256[10] private _durations;
uint256 private _durationSum;
uint256 private _durationNum;
uint256 private _durationIndex;

constructor(IScrypt _scrypt) Ownable() {
scrypt = _scrypt;
_setTargetDuration(12);
_setAdhocNBits(0x1c7fffff);
}

function validate(BlockHeader calldata header) public view returns (bytes memory) {
require(header.nbits == currentNBits, "invalid nbits");
bytes memory encodedHeader = abi.encodePacked(header.meta, header.prevhash, header.merkleRoot, header.nbits, header.nonce);
bytes memory headerHash = scrypt.hash(encodedHeader, encodedHeader, 1024, 1, 1, 32, 224);
require(headerHash.length == 32, "invalid header hash length");
require(uint256(bytes32(headerHash)) <= _currentTarget, "invalid proof of work");
return encodedHeader;
}

function setOperator(address _operator) public onlyOwner {
operator = _operator;
emit OperatorSet(_operator);
}

function setTargetDuration(uint256 duration) public onlyOwner {
_setTargetDuration(duration);
}

function _setTargetDuration(uint256 duration) internal {
targetDuration = duration;
emit TargetDurationSet(duration);
}

function setAdhocNBits(uint32 nbits) public onlyOwner {
_setAdhocNBits(nbits);
}

function _setAdhocNBits(uint32 nbits) internal {
if (nbits == 0) {
useAdhocNBits = false;
return;
}
_setNBits(nbits);
useAdhocNBits = true;
}

function updateDuration(uint256 duration) public {
require(msg.sender == operator, "not operator");
_durationSum += duration - _durations[_durationIndex];
_durations[_durationIndex] = duration;
_durationIndex = (_durationIndex + 1) % _durations.length;
if (_durationNum < _durations.length) {
_durationNum++;
return;
}
if (useAdhocNBits) {
return;
}
uint32 nbits = uint32(currentNBits);
uint32 next = _nextNBits(nbits, targetDuration * _durationNum, _durationSum);
if (next != nbits) {
_setNBits(next);
}
}

function _nextNBits(uint32 nbits, uint256 expectedSum, uint256 sum) internal pure returns (uint32) {
if (sum * 5 > expectedSum * 6) {
(uint32 exponent, uint32 coefficient) = decodeNBits(nbits);
if (coefficient < UPPER_BOUND) {
return (exponent << 24) | uint32(coefficient + 1);
}
if (exponent < MAX_EXPONENT) {
return ((exponent + 1) << 24) | LOWER_BOUND;
}
} else if (expectedSum * 4 > sum * 5) {
(uint32 exponent, uint32 coefficient) = decodeNBits(nbits);
if (coefficient > LOWER_BOUND) {
return (exponent << 24) | uint32(coefficient - 1);
}
if (exponent > 0) {
return ((exponent - 1) << 24) | UPPER_BOUND;
}
}
return nbits;
}

function _setNBits(uint32 nbits) internal {
uint256 target = nbitsToTarget(nbits);
currentNBits = nbits;
_currentTarget = target;
emit NBitsSet(nbits);
}

function decodeNBits(uint32 nbits) internal pure returns (uint32, uint32) {
return (nbits >> 24, nbits & 0x00ffffff);
}

function nbitsToTarget(uint32 nbits) public pure returns (uint256) {
(uint32 exponent, uint256 coefficient) = decodeNBits(nbits);
require(exponent <= MAX_EXPONENT, "invalid nbits");
require(coefficient >= LOWER_BOUND && coefficient <= UPPER_BOUND, "invalid nbits");
return coefficient << (8 * (exponent - 3));
}
}
82 changes: 82 additions & 0 deletions smartcontracts/contracts/W3bstreamBlockMinter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {BlockHeader, IBlockHeaderValidator} from "./interfaces/IBlockHeaderValidator.sol";
import {ITaskManager, TaskAssignment} from "./interfaces/ITaskManager.sol";

interface IDAO {
function tip() external view returns (uint256, bytes32, uint256);
function mint(bytes32 hash, uint256 timestamp) external;
}

interface IBlockRewardDistributor {
function distribute(address recipient, uint256 amount) external;
}

struct Sequencer {
address addr;
address operator;
address beneficiary;
}

contract W3bstreamBlockMinter is OwnableUpgradeable {
event BlockRewardSet(uint256 reward);
event TaskAllowanceSet(uint256 allowance);
event TargetDurationSet(uint256 duration);
event NBitsSet(uint32 nbits);

IDAO public dao;
ITaskManager public taskManager;
IBlockRewardDistributor public distributor;
IBlockHeaderValidator public headerValidator;

uint256 public blockReward;
uint256 public taskAllowance;

function initialize(IDAO _dao, ITaskManager _taskManager, IBlockRewardDistributor _distributor, IBlockHeaderValidator _headerValidator) public initializer {
__Ownable_init();
dao = _dao;
taskManager = _taskManager;
distributor = _distributor;
headerValidator = _headerValidator;
_setBlockReward(1000000000000000000);
_setTaskAllowance(720);
}

function mint(
BlockHeader calldata header,
Sequencer calldata coinbase,
TaskAssignment[] calldata assignments
) public {
require(coinbase.operator == msg.sender, "invalid operator");
(, bytes32 tiphash, uint256 tipTimestamp) = dao.tip();
require(tipTimestamp != block.number);
require(header.prevhash == tiphash, "invalid prevhash");
require(header.merkleRoot == keccak256(abi.encode(coinbase.addr, coinbase.operator, coinbase.beneficiary)), "invalid merkle root");
bytes memory encodedHeader = headerValidator.validate(header);
bytes32 blockHash = keccak256(abi.encode(encodedHeader, assignments));
taskManager.assign(assignments, coinbase.beneficiary, block.number + taskAllowance);
headerValidator.updateDuration(block.number - tipTimestamp);
dao.mint(blockHash, block.number);
distributor.distribute(coinbase.beneficiary, blockReward);
}

function setBlockReward(uint256 reward) public onlyOwner {
_setBlockReward(reward);
}

function _setBlockReward(uint256 reward) internal {
blockReward = reward;
emit BlockRewardSet(reward);
}

function setTaskAllowance(uint256 allowance) public onlyOwner {
_setTaskAllowance(allowance);
}

function _setTaskAllowance(uint256 allowance) internal {
taskAllowance = allowance;
emit TaskAllowanceSet(allowance);
}
}
49 changes: 49 additions & 0 deletions smartcontracts/contracts/W3bstreamBlockRewardDistributor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract W3bstreamBlockRewardDistributor is OwnableUpgradeable {
event Distributed(address indexed recipient, uint256 amount);
event Withdrawn(uint256 amount);
event OperatorSet(address indexed operator);
event Topup(uint256 amount);
address public operator;

modifier onlyOperator() {
require(msg.sender == operator, "not operator");
_;
}

receive() external payable {
emit Topup(msg.value);
}

function initialize() public initializer {
__Ownable_init();
}

function setOperator(address _operator) public onlyOwner {
operator = _operator;
emit OperatorSet(_operator);
}

function distribute(address recipient, uint256 amount) public onlyOperator {
if (amount == 0) {
return;
}
if (amount > address(this).balance) {
revert("insufficient balance");
}
(bool success, ) = recipient.call{value: amount}("");
require(success, "transfer failed");
emit Distributed(recipient, amount);
}

function withdraw(uint256 amount) public onlyOwner {
require(amount <= address(this).balance, "insufficient balance");
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "transfer failed");
emit Withdrawn(amount);
}
}
34 changes: 34 additions & 0 deletions smartcontracts/contracts/W3bstreamDAO.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract W3bstreamDAO is OwnableUpgradeable {
struct Block {
bytes32 hash;
uint256 timestamp;
}
event BlockAdded(uint256 indexed num, bytes32 hash, uint256 timestamp);

Block[] public blocks;

function initialize(bytes32 genesis) public initializer {
__Ownable_init();
_mint(genesis, block.number);
}

function mint(bytes32 hash, uint256 timestamp) public onlyOwner {
_mint(hash, timestamp);
}

function tip() public view returns (uint256, bytes32, uint256) {
uint256 blocknum = blocks.length - 1;
Block storage tipblock = blocks[blocknum];
return (blocknum, tipblock.hash, tipblock.timestamp);
}

function _mint(bytes32 hash, uint256 timestamp) internal {
blocks.push(Block({timestamp: timestamp, hash: hash}));
emit BlockAdded(blocks.length - 1, hash, timestamp);
}
}
Loading
Loading