Last active
September 21, 2021 04:36
-
-
Save jessiepathfinder/62ef738b848681f2bf5aef14d9af7abc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// File: patricia_tree/PatriciaTreeFace.sol | |
pragma solidity ^0.5.17; | |
pragma experimental ABIEncoderV2; | |
/* | |
* Interface for patricia trees. | |
* | |
* More info at: https://github.com/chriseth/patricia-trie | |
*/ | |
contract PatriciaTreeFace { | |
function getRootHash() external view returns (bytes32); | |
function getRootEdge() external view returns (Data.Edge memory e); | |
function getNode(bytes32 hash) external view returns (Data.Node memory n); | |
function getProof(bytes calldata key) external view returns (uint branchMask, bytes32[] memory _siblings); | |
function verifyProof(bytes32 rootHash, bytes calldata key, bytes calldata value, uint branchMask, bytes32[] calldata siblings) external pure returns (bool); | |
function insert(bytes calldata key, bytes calldata value) external; | |
} | |
// File: bits/Bits.sol | |
library Bits { | |
uint constant internal ONE = uint(1); | |
uint constant internal ONES = uint(~0); | |
// Sets the bit at the given 'index' in 'self' to '1'. | |
// Returns the modified value. | |
function setBit(uint self, uint8 index) internal pure returns (uint) { | |
return self | ONE << index; | |
} | |
// Sets the bit at the given 'index' in 'self' to '0'. | |
// Returns the modified value. | |
function clearBit(uint self, uint8 index) internal pure returns (uint) { | |
return self & ~(ONE << index); | |
} | |
// Sets the bit at the given 'index' in 'self' to: | |
// '1' - if the bit is '0' | |
// '0' - if the bit is '1' | |
// Returns the modified value. | |
function toggleBit(uint self, uint8 index) internal pure returns (uint) { | |
return self ^ ONE << index; | |
} | |
// Get the value of the bit at the given 'index' in 'self'. | |
function bit(uint self, uint8 index) internal pure returns (uint8) { | |
return uint8(self >> index & 1); | |
} | |
// Check if the bit at the given 'index' in 'self' is set. | |
// Returns: | |
// 'true' - if the value of the bit is '1' | |
// 'false' - if the value of the bit is '0' | |
function bitSet(uint self, uint8 index) internal pure returns (bool) { | |
return self >> index & 1 == 1; | |
} | |
// Checks if the bit at the given 'index' in 'self' is equal to the corresponding | |
// bit in 'other'. | |
// Returns: | |
// 'true' - if both bits are '0' or both bits are '1' | |
// 'false' - otherwise | |
function bitEqual(uint self, uint other, uint8 index) internal pure returns (bool) { | |
return (self ^ other) >> index & 1 == 0; | |
} | |
// Get the bitwise NOT of the bit at the given 'index' in 'self'. | |
function bitNot(uint self, uint8 index) internal pure returns (uint8) { | |
return uint8(1 - (self >> index & 1)); | |
} | |
// Computes the bitwise AND of the bit at the given 'index' in 'self', and the | |
// corresponding bit in 'other', and returns the value. | |
function bitAnd(uint self, uint other, uint8 index) internal pure returns (uint8) { | |
return uint8((self & other) >> index & 1); | |
} | |
// Computes the bitwise OR of the bit at the given 'index' in 'self', and the | |
// corresponding bit in 'other', and returns the value. | |
function bitOr(uint self, uint other, uint8 index) internal pure returns (uint8) { | |
return uint8((self | other) >> index & 1); | |
} | |
// Computes the bitwise XOR of the bit at the given 'index' in 'self', and the | |
// corresponding bit in 'other', and returns the value. | |
function bitXor(uint self, uint other, uint8 index) internal pure returns (uint8) { | |
return uint8((self ^ other) >> index & 1); | |
} | |
// Gets 'numBits' consecutive bits from 'self', starting from the bit at 'startIndex'. | |
// Returns the bits as a 'uint'. | |
// Requires that: | |
// - '0 < numBits <= 256' | |
// - 'startIndex < 256' | |
// - 'numBits + startIndex <= 256' | |
function bits(uint self, uint8 startIndex, uint16 numBits) internal pure returns (uint) { | |
require(0 < numBits && startIndex < 256 && startIndex + numBits <= 256); | |
return self >> startIndex & ONES >> 256 - numBits; | |
} | |
// Computes the index of the highest bit set in 'self'. | |
// Returns the highest bit set as an 'uint8'. | |
// Requires that 'self != 0'. | |
function highestBitSet(uint self) internal pure returns (uint8 highest) { | |
require(self != 0); | |
uint val = self; | |
for (uint8 i = 128; i >= 1; i >>= 1) { | |
if (val & (ONE << i) - 1 << i != 0) { | |
highest += i; | |
val >>= i; | |
} | |
} | |
} | |
// Computes the index of the lowest bit set in 'self'. | |
// Returns the lowest bit set as an 'uint8'. | |
// Requires that 'self != 0'. | |
function lowestBitSet(uint self) internal pure returns (uint8 lowest) { | |
require(self != 0); | |
uint val = self; | |
for (uint8 i = 128; i >= 1; i >>= 1) { | |
if (val & (ONE << i) - 1 == 0) { | |
lowest += i; | |
val >>= i; | |
} | |
} | |
} | |
} | |
// File: patricia_tree/Data.sol | |
/* | |
* Data structures and utilities used in the Patricia Tree. | |
* | |
* More info at: https://github.com/chriseth/patricia-trie | |
*/ | |
library Data { | |
struct Label { | |
bytes32 data; | |
uint length; | |
} | |
struct Edge { | |
bytes32 node; | |
Label label; | |
} | |
struct Node { | |
Edge[2] children; | |
} | |
struct Tree { | |
bytes32 root; | |
Data.Edge rootEdge; | |
mapping(bytes32 => Data.Node) nodes; | |
} | |
// Returns a label containing the longest common prefix of `self` and `label`, | |
// and a label consisting of the remaining part of `label`. | |
function splitCommonPrefix(Label memory self, Label memory other) internal pure returns ( | |
Label memory prefix, | |
Label memory labelSuffix | |
) { | |
return splitAt(self, commonPrefix(self, other)); | |
} | |
// Splits the label at the given position and returns prefix and suffix, | |
// i.e. 'prefix.length == pos' and 'prefix.data . suffix.data == l.data'. | |
function splitAt(Label memory self, uint pos) internal pure returns (Label memory prefix, Label memory suffix) { | |
assert(pos <= self.length && pos <= 256); | |
prefix.length = pos; | |
if (pos == 0) { | |
prefix.data = bytes32(0); | |
} else { | |
prefix.data = bytes32(uint(self.data) & ~uint(1) << 255 - pos); | |
} | |
suffix.length = self.length - pos; | |
suffix.data = self.data << pos; | |
} | |
// Returns the length of the longest common prefix of the two labels. | |
/* | |
function commonPrefix(Label memory self, Label memory other) internal pure returns (uint prefix) { | |
uint length = self.length < other.length ? self.length : other.length; | |
// TODO: This could actually use a "highestBitSet" helper | |
uint diff = uint(self.data ^ other.data); | |
uint mask = uint(1) << 255; | |
for (; prefix < length; prefix++) { | |
if ((mask & diff) != 0) { | |
break; | |
} | |
diff += diff; | |
} | |
} | |
*/ | |
function commonPrefix(Label memory self, Label memory other) internal pure returns (uint prefix) { | |
uint length = self.length < other.length ? self.length : other.length; | |
if (length == 0) { | |
return 0; | |
} | |
uint diff = uint(self.data ^ other.data) & ~uint(0) << 256 - length; // TODO Mask should not be needed. | |
if (diff == 0) { | |
return length; | |
} | |
return 255 - Bits.highestBitSet(diff); | |
} | |
// Returns the result of removing a prefix of length `prefix` bits from the | |
// given label (shifting its data to the left). | |
function removePrefix(Label memory self, uint prefix) internal pure returns (Label memory r) { | |
require(prefix <= self.length); | |
r.length = self.length - prefix; | |
r.data = self.data << prefix; | |
} | |
// Removes the first bit from a label and returns the bit and a | |
// label containing the rest of the label (shifted to the left). | |
function chopFirstBit(Label memory self) internal pure returns (uint firstBit, Label memory tail) { | |
require(self.length > 0); | |
return (uint(self.data >> 255), Label(self.data << 1, self.length - 1)); | |
} | |
function edgeHash(Data.Edge memory self) internal pure returns (bytes32) { | |
return keccak256(abi.encodePacked(self.node, self.label.length, self.label.data)); | |
} | |
// Returns the hash of the encoding of a node. | |
function hash(Data.Node memory self) internal pure returns (bytes32) { | |
return keccak256(abi.encodePacked(edgeHash(self.children[0]), edgeHash(self.children[1]))); | |
} | |
function insertNode(Data.Tree storage tree, Data.Node memory n) internal returns (bytes32 newHash) { | |
bytes32 h = hash(n); | |
tree.nodes[h].children[0] = n.children[0]; | |
tree.nodes[h].children[1] = n.children[1]; | |
return h; | |
} | |
function replaceNode(Data.Tree storage self, bytes32 oldHash, Data.Node memory n) internal returns (bytes32 newHash) { | |
delete self.nodes[oldHash]; | |
return insertNode(self, n); | |
} | |
function insertAtEdge(Tree storage self, Edge memory e, Label memory key, bytes32 value) internal returns (Edge memory) { | |
assert(key.length >= e.label.length); | |
Label memory prefix; | |
Label memory suffix; | |
(prefix, suffix) = splitCommonPrefix(key, e.label); | |
bytes32 newNodeHash; | |
uint head; | |
Label memory tail; | |
if (suffix.length == 0) { | |
// Full match with the key, update operation | |
newNodeHash = value; | |
} else if (prefix.length >= e.label.length) { | |
// Partial match, just follow the path | |
assert(suffix.length > 1); | |
Node memory n = self.nodes[e.node]; | |
(head, tail) = chopFirstBit(suffix); | |
n.children[head] = insertAtEdge(self, n.children[head], tail, value); | |
delete self.nodes[e.node]; | |
newNodeHash = insertNode(self, n); | |
} else { | |
// Mismatch, so let us create a new branch node. | |
(head, tail) = chopFirstBit(suffix); | |
Node memory branchNode; | |
branchNode.children[head] = Edge(value, tail); | |
branchNode.children[1 - head] = Edge(e.node, removePrefix(e.label, prefix.length + 1)); | |
newNodeHash = insertNode(self, branchNode); | |
} | |
return Edge(newNodeHash, prefix); | |
} | |
function insert(Tree storage self, bytes memory key, bytes memory value) internal { | |
Label memory k = Label(keccak256(key), 256); | |
bytes32 valueHash = keccak256(value); | |
Edge memory e; | |
if (self.root == 0) { | |
// Empty Trie | |
e.label = k; | |
e.node = valueHash; | |
} else { | |
e = insertAtEdge(self, self.rootEdge, k, valueHash); | |
} | |
self.root = edgeHash(e); | |
self.rootEdge = e; | |
} | |
} | |
//OpenZeppelin Ownable Smart contract | |
contract Ownable { | |
address private _owner; | |
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); | |
/** | |
* @dev The Ownable constructor sets the original `owner` of the contract to the sender | |
* account. | |
*/ | |
constructor () internal { | |
_owner = msg.sender; | |
emit OwnershipTransferred(address(0), _owner); | |
} | |
/** | |
* @return the address of the owner. | |
*/ | |
function owner() public view returns (address) { | |
return _owner; | |
} | |
/** | |
* @dev Throws if called by any account other than the owner. | |
*/ | |
modifier onlyOwner() { | |
require(isOwner()); | |
_; | |
} | |
/** | |
* @return true if `msg.sender` is the owner of the contract. | |
*/ | |
function isOwner() public view returns (bool) { | |
return msg.sender == _owner; | |
} | |
/** | |
* @dev Allows the current owner to relinquish control of the contract. | |
* @notice Renouncing to ownership will leave the contract without an owner. | |
* It will not be possible to call the functions with the `onlyOwner` | |
* modifier anymore. | |
*/ | |
function renounceOwnership() public onlyOwner { | |
emit OwnershipTransferred(_owner, address(0)); | |
_owner = address(0); | |
} | |
/** | |
* @dev Allows the current owner to transfer control of the contract to a newOwner. | |
* @param newOwner The address to transfer ownership to. | |
*/ | |
function transferOwnership(address newOwner) public onlyOwner { | |
_transferOwnership(newOwner); | |
} | |
/** | |
* @dev Transfers control of the contract to a newOwner. | |
* @param newOwner The address to transfer ownership to. | |
*/ | |
function _transferOwnership(address newOwner) internal { | |
require(newOwner != address(0)); | |
emit OwnershipTransferred(_owner, newOwner); | |
_owner = newOwner; | |
} | |
} | |
// File: patricia_tree/PatriciaTree.sol | |
/* | |
* Patricia tree implementation. | |
* | |
* More info at: https://github.com/chriseth/patricia-trie | |
*/ | |
contract PatriciaTree is PatriciaTreeFace, Ownable { | |
using Data for Data.Tree; | |
using Data for Data.Node; | |
using Data for Data.Edge; | |
using Data for Data.Label; | |
using Bits for uint; | |
Data.Tree internal tree; | |
// Get the root hash. | |
function getRootHash() external view returns (bytes32) { | |
return tree.root; | |
} | |
// Get the root edge. | |
function getRootEdge() external view returns (Data.Edge memory e) { | |
e = tree.rootEdge; | |
} | |
// Get the node with the given key. The key needs to be | |
// the keccak256 hash of the actual key. | |
function getNode(bytes32 hash) external view returns (Data.Node memory n) { | |
n = tree.nodes[hash]; | |
} | |
// Returns the Merkle-proof for the given key | |
// Proof format should be: | |
// - uint branchMask - bitmask with high bits at the positions in the key | |
// where we have branch nodes (bit in key denotes direction) | |
// - bytes32[] _siblings - hashes of sibling edges | |
function getProof(bytes calldata key) external view returns (uint branchMask, bytes32[] memory _siblings) { | |
require(tree.root != 0); | |
Data.Label memory k = Data.Label(keccak256(key), 256); | |
Data.Edge memory e = tree.rootEdge; | |
bytes32[256] memory siblings; | |
uint length; | |
uint numSiblings; | |
while (true) { | |
Data.Label memory prefix; | |
Data.Label memory suffix; | |
(prefix, suffix) = k.splitCommonPrefix(e.label); | |
assert(prefix.length == e.label.length); | |
if (suffix.length == 0) { | |
// Found it | |
break; | |
} | |
length += prefix.length; | |
branchMask |= uint(1) << 255 - length; | |
length += 1; | |
uint head; | |
Data.Label memory tail; | |
(head, tail) = suffix.chopFirstBit(); | |
siblings[numSiblings++] = tree.nodes[e.node].children[1 - head].edgeHash(); | |
e = tree.nodes[e.node].children[head]; | |
k = tail; | |
} | |
if (numSiblings > 0) { | |
_siblings = new bytes32[](numSiblings); | |
for (uint i = 0; i < numSiblings; i++) { | |
_siblings[i] = siblings[i]; | |
} | |
} | |
} | |
function verifyProof(bytes32 rootHash, bytes calldata key, bytes calldata value, uint branchMask, bytes32[] calldata siblings) external pure returns (bool) { | |
Data.Label memory k = Data.Label(keccak256(key), 256); | |
Data.Edge memory e; | |
e.node = keccak256(value); | |
for (uint i = 0; branchMask != 0; i++) { | |
uint bitSet = branchMask.lowestBitSet(); | |
branchMask &= ~(uint(1) << bitSet); | |
(k, e.label) = k.splitAt(255 - bitSet); | |
uint bit; | |
(bit, e.label) = e.label.chopFirstBit(); | |
bytes32[2] memory edgeHashes; | |
edgeHashes[bit] = e.edgeHash(); | |
edgeHashes[1 - bit] = siblings[siblings.length - i - 1]; | |
e.node = keccak256(abi.encodePacked(edgeHashes[0], edgeHashes[1])); | |
} | |
e.label = k; | |
require(rootHash == e.edgeHash()); | |
return true; | |
} | |
function insert(bytes calldata key, bytes calldata value) external onlyOwner { | |
tree.insert(key, value); | |
} | |
} | |
//This is my first time using automated testing in Solidity. | |
contract MerkleTester{ | |
PatriciaTreeFace ptf; | |
bytes32 rng; | |
constructor() public{ | |
ptf = new PatriciaTree(); | |
rng = 0x0000000000000000000000000000000000000000000000000000000000000000; | |
} | |
function nextrand() public returns (bytes memory){ | |
bytes memory temp = abi.encodePacked(rng); | |
rng = keccak256(temp); | |
return temp; | |
} | |
function test1() external{ | |
bytes memory r1 = nextrand(); | |
bytes memory r2 = nextrand(); | |
bytes memory r3 = nextrand(); | |
bytes memory r4 = nextrand(); | |
ptf.insert(r1, r2); | |
ptf.insert(r3, r4); | |
uint branchMask; | |
bytes32[] memory siblings; | |
(branchMask, siblings) = ptf.getProof(r1); | |
require(ptf.verifyProof(ptf.getRootHash(), r1, r2, branchMask, siblings)); | |
(branchMask, siblings) = ptf.getProof(r3); | |
require(ptf.verifyProof(ptf.getRootHash(), r3, r4, branchMask, siblings)); | |
} | |
} | |
//Merkle presale allows selling Ethereum EUBI tokens on MintME | |
//And generating a merkle proof that can be used to migrate tokens | |
//to the Ethereum Blockchain. | |
contract MerklePresale is Ownable{ | |
PatriciaTree public ptree; | |
mapping(address => uint256) public balanceOf; | |
constructor() public{ | |
ptree = new PatriciaTree(); | |
} | |
function() external payable{ | |
require(balanceOf[msg.sender] == 0, "To prevent a known bug, each address may only buy from the merkle presale once."); | |
if(msg.value != 0){ | |
balanceOf[msg.sender] = msg.value; | |
ptree.insert(abi.encodePacked(msg.sender), abi.encodePacked(msg.value)); | |
} | |
} | |
//Terminate presale and withdraw sale proceeds | |
function terminatePresale() external onlyOwner{ | |
renounceOwnership(); | |
//renouncing the ownership of the Patricia tree | |
//prevents it from being modified, technically | |
//freezing it | |
ptree.renounceOwnership(); | |
(bool success, ) = msg.sender.call.value(address(this).balance)(""); | |
require(success, "Can't send MintME"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment