-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit f58f173
Showing
39 changed files
with
11,122 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Javascript Node CircleCI 2.0 configuration file | ||
# | ||
# Check https://circleci.com/docs/2.0/language-javascript/ for more details | ||
# | ||
version: 2 | ||
jobs: | ||
build: | ||
docker: | ||
# specify the version you desire here | ||
- image: circleci/node:10.9.0 | ||
|
||
# Specify service dependencies here if necessary | ||
# CircleCI maintains a library of pre-built images | ||
# documented at https://circleci.com/docs/2.0/circleci-images/ | ||
# - image: circleci/mongo:3.4.4 | ||
|
||
working_directory: ~/humanity | ||
|
||
steps: | ||
- checkout | ||
|
||
# Download and cache dependencies | ||
- restore_cache: | ||
key: module-cache-{{ checksum "yarn.lock" }} | ||
- run: | ||
name: Fetch Dependencies | ||
command: yarn | ||
- save_cache: | ||
key: module-cache-{{ checksum "yarn.lock" }} | ||
paths: | ||
- node_modules | ||
- run: | ||
name: Run Tests | ||
command: yarn rebuild_and_test |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
.DS_Store | ||
|
||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
/.changelog | ||
|
||
# Dependency directories | ||
node_modules/ | ||
|
||
# Optional npm cache directory | ||
.npm | ||
|
||
# Optional eslint cache | ||
.eslintcache | ||
|
||
# Output of 'npm pack' | ||
*.tgz | ||
|
||
# dotenv environment variables file | ||
.env | ||
|
||
# build directories | ||
lib/ | ||
build/ | ||
|
||
# VSCode file | ||
.vscode |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
[![CircleCI](https://circleci.com/gh/marbleprotocol/polaris/tree/master.svg?style=svg)](https://circleci.com/gh/marbleprotocol/humanity/tree/master) | ||
|
||
# Humanity | ||
|
||
Humanity is a Decentralized Autonomous Organization (DAO) that governs a registry of unique humans. | ||
|
||
## Query the Registry | ||
|
||
Create Sybil-resistant smart contract protocols by restricting permission to Ethereum addresses that are on the registry. | ||
|
||
**HumanityRegistry.sol** | ||
``` | ||
function isHuman(address who) public view returns (bool) | ||
``` | ||
|
||
See **UniversalBasicIncome.sol** for an example. | ||
|
||
## Apply to the Registry | ||
|
||
First, submit social verification in the form of a Twitter post with your Ethereum address. Then, apply to the registry with your Twitter username and a refundable proposal fee. | ||
|
||
**TwitterHumanityApplicant.sol** | ||
``` | ||
function applyWithTwitter(string memory username) public returns (uint) | ||
``` | ||
|
||
## Vote on Applicants | ||
|
||
Vote on applicants to the registry using Humanity tokens. | ||
|
||
**Governance.sol** | ||
``` | ||
function voteYes(uint proposalId) public | ||
``` | ||
|
||
``` | ||
function voteNo(uint proposalId) public | ||
``` |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
pragma solidity 0.5.7; | ||
pragma experimental ABIEncoderV2; | ||
|
||
import { IERC20 } from "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; | ||
import { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol"; | ||
|
||
/** | ||
* @title Faucet | ||
* @dev Mine Humanity tokens into Uniswap. | ||
*/ | ||
contract Faucet { | ||
using SafeMath for uint; | ||
|
||
uint public constant BLOCK_REWARD = 1e18; | ||
uint public START_BLOCK = block.number; | ||
uint public END_BLOCK = block.number + 5000000; | ||
|
||
IERC20 public humanity; | ||
address public auction; | ||
|
||
uint public lastMined = block.number; | ||
|
||
constructor(IERC20 _humanity, address _auction) public { | ||
humanity = _humanity; | ||
auction = _auction; | ||
} | ||
|
||
function mine() public { | ||
uint rewardBlock = block.number < END_BLOCK ? block.number : END_BLOCK; | ||
uint reward = rewardBlock.sub(lastMined).mul(BLOCK_REWARD); | ||
humanity.transfer(auction, reward); | ||
lastMined = block.number; | ||
} | ||
|
||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
pragma solidity 0.5.7; | ||
pragma experimental ABIEncoderV2; | ||
|
||
import { IERC20 } from "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; | ||
import { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol"; | ||
|
||
import { Void } from "./Void.sol"; | ||
|
||
/** | ||
* @title Governance | ||
* @dev Plutocratic voting system. | ||
*/ | ||
contract Governance { | ||
using SafeMath for uint; | ||
|
||
event Execute(uint indexed proposalId); | ||
event Propose(uint indexed proposalId, address indexed proposer, address indexed target, bytes data); | ||
event RemoveVote(uint indexed proposalId, address indexed voter); | ||
event Terminate(uint indexed proposalId); | ||
event Vote(uint indexed proposalId, address indexed voter, bool approve, uint weight); | ||
|
||
enum Result { Pending, Yes, No } | ||
|
||
struct Proposal { | ||
Result result; | ||
address target; | ||
bytes data; | ||
address proposer; | ||
address feeRecipient; | ||
uint fee; | ||
uint startTime; | ||
uint yesCount; | ||
uint noCount; | ||
} | ||
|
||
uint public constant OPEN_VOTE_PERIOD = 2 days; | ||
uint public constant VETO_PERIOD = 2 days; | ||
uint public constant TOTAL_VOTE_PERIOD = OPEN_VOTE_PERIOD + VETO_PERIOD; | ||
|
||
uint public proposalFee; | ||
IERC20 public token; | ||
Void public void; | ||
|
||
Proposal[] public proposals; | ||
|
||
// Proposal Id => Voter => Yes Votes | ||
mapping(uint => mapping(address => uint)) public yesVotes; | ||
|
||
// Proposal Id => Voter => No Votes | ||
mapping(uint => mapping(address => uint)) public noVotes; | ||
|
||
// Voter => Deposit | ||
mapping (address => uint) public deposits; | ||
|
||
// Voter => Withdraw timestamp | ||
mapping (address => uint) public withdrawTimes; | ||
|
||
constructor(IERC20 _token, uint _initialProposalFee) public { | ||
token = _token; | ||
proposalFee = _initialProposalFee; | ||
void = new Void(); | ||
} | ||
|
||
function deposit(uint amount) public { | ||
require(token.transferFrom(msg.sender, address(this), amount), "Governance::deposit: Transfer failed"); | ||
deposits[msg.sender] = deposits[msg.sender].add(amount); | ||
} | ||
|
||
function withdraw(uint amount) public { | ||
require(time() > withdrawTimes[msg.sender], "Governance::withdraw: Voters with an active proposal cannot withdraw"); | ||
deposits[msg.sender] = deposits[msg.sender].sub(amount); | ||
require(token.transfer(msg.sender, amount), "Governance::withdraw: Transfer failed"); | ||
} | ||
|
||
function propose(address target, bytes memory data) public returns (uint) { | ||
return proposeWithFeeRecipient(msg.sender, target, data); | ||
} | ||
|
||
function proposeWithFeeRecipient(address feeRecipient, address target, bytes memory data) public returns (uint) { | ||
require(msg.sender != address(this) && target != address(token), "Governance::proposeWithFeeRecipient: Invalid proposal"); | ||
require(token.transferFrom(msg.sender, address(this), proposalFee), "Governance::proposeWithFeeRecipient: Transfer failed"); | ||
|
||
uint proposalId = proposals.length; | ||
|
||
// Create a new proposal and vote yes | ||
Proposal memory proposal; | ||
proposal.target = target; | ||
proposal.data = data; | ||
proposal.proposer = msg.sender; | ||
proposal.feeRecipient = feeRecipient; | ||
proposal.fee = proposalFee; | ||
proposal.startTime = time(); | ||
proposal.yesCount = proposalFee; | ||
|
||
proposals.push(proposal); | ||
|
||
emit Propose(proposalId, msg.sender, target, data); | ||
|
||
return proposalId; | ||
} | ||
|
||
function voteYes(uint proposalId) public { | ||
Proposal storage proposal = proposals[proposalId]; | ||
require(time() <= proposal.startTime.add(OPEN_VOTE_PERIOD), "Governance::voteYes: Proposal is no longer accepting yes votes"); | ||
|
||
uint proposalEndTime = proposal.startTime.add(TOTAL_VOTE_PERIOD); | ||
if (proposalEndTime > withdrawTimes[msg.sender]) withdrawTimes[msg.sender] = proposalEndTime; | ||
|
||
uint weight = deposits[msg.sender].sub(yesVotes[proposalId][msg.sender]); | ||
proposal.yesCount = proposal.yesCount.add(weight); | ||
yesVotes[proposalId][msg.sender] = deposits[msg.sender]; | ||
|
||
emit Vote(proposalId, msg.sender, true, weight); | ||
} | ||
|
||
function voteNo(uint proposalId) public { | ||
Proposal storage proposal = proposals[proposalId]; | ||
require(proposal.result == Result.Pending, "Governance::voteNo: Proposal is already finalized"); | ||
|
||
uint proposalEndTime = proposal.startTime.add(TOTAL_VOTE_PERIOD); | ||
uint _time = time(); | ||
require(_time <= proposalEndTime, "Governance::voteNo: Proposal is no longer in voting period"); | ||
|
||
uint _deposit = deposits[msg.sender]; | ||
uint weight = _deposit.sub(noVotes[proposalId][msg.sender]); | ||
proposal.noCount = proposal.noCount.add(weight); | ||
noVotes[proposalId][msg.sender] = _deposit; | ||
|
||
emit Vote(proposalId, msg.sender, false, weight); | ||
|
||
// Finalize the vote and burn the proposal fee if no votes outnumber yes votes and open voting has ended | ||
if (_time > proposal.startTime.add(OPEN_VOTE_PERIOD) && proposal.noCount >= proposal.yesCount) { | ||
proposal.result = Result.No; | ||
require(token.transfer(address(void), proposal.fee), "Governance::voteNo: Transfer to void failed"); | ||
emit Terminate(proposalId); | ||
} else if (proposalEndTime > withdrawTimes[msg.sender]) { | ||
withdrawTimes[msg.sender] = proposalEndTime; | ||
} | ||
|
||
} | ||
|
||
function removeVote(uint proposalId) public { | ||
Proposal storage proposal = proposals[proposalId]; | ||
require(proposal.result == Result.Pending, "Governance::removeVote: Proposal is already finalized"); | ||
require(time() <= proposal.startTime.add(TOTAL_VOTE_PERIOD), "Governance::removeVote: Proposal is no longer in voting period"); | ||
|
||
proposal.yesCount = proposal.yesCount.sub(yesVotes[proposalId][msg.sender]); | ||
proposal.noCount = proposal.noCount.sub(noVotes[proposalId][msg.sender]); | ||
delete yesVotes[proposalId][msg.sender]; | ||
delete noVotes[proposalId][msg.sender]; | ||
|
||
emit RemoveVote(proposalId, msg.sender); | ||
} | ||
|
||
function finalize(uint proposalId) public { | ||
Proposal storage proposal = proposals[proposalId]; | ||
require(proposal.result == Result.Pending, "Governance::finalize: Proposal is already finalized"); | ||
uint _time = time(); | ||
|
||
if (proposal.yesCount > proposal.noCount) { | ||
require(_time > proposal.startTime.add(TOTAL_VOTE_PERIOD), "Governance::finalize: Proposal cannot be executed until end of veto period"); | ||
|
||
proposal.result = Result.Yes; | ||
require(token.transfer(proposal.feeRecipient, proposal.fee), "Governance::finalize: Return proposal fee failed"); | ||
proposal.target.call(proposal.data); | ||
|
||
emit Execute(proposalId); | ||
} else { | ||
require(_time > proposal.startTime.add(OPEN_VOTE_PERIOD), "Governance::finalize: Proposal cannot be terminated until end of yes vote period"); | ||
|
||
proposal.result = Result.No; | ||
require(token.transfer(address(void), proposal.fee), "Governance::finalize: Transfer to void failed"); | ||
|
||
emit Terminate(proposalId); | ||
} | ||
} | ||
|
||
function setProposalFee(uint fee) public { | ||
require(msg.sender == address(this), "Governance::setProposalFee: Proposal fee can only be set via governance"); | ||
proposalFee = fee; | ||
} | ||
|
||
function time() public view returns (uint) { | ||
return block.timestamp; | ||
} | ||
|
||
function getProposal(uint proposalId) external view returns (Proposal memory) { | ||
return proposals[proposalId]; | ||
} | ||
|
||
function getProposalsCount() external view returns (uint) { | ||
return proposals.length; | ||
} | ||
|
||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
pragma solidity 0.5.7; | ||
pragma experimental ABIEncoderV2; | ||
|
||
import { ERC20 } from "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; | ||
|
||
|
||
/** | ||
* @title Humanity | ||
* @dev ERC20 token that can be used to vote on applications to the Humanity registry. | ||
*/ | ||
contract Humanity is ERC20 { | ||
|
||
string public constant name = "Humanity"; | ||
string public constant symbol = "HUM"; | ||
uint8 public constant decimals = 18; | ||
string public version = "1.0.0"; | ||
|
||
uint public constant INITIAL_SUPPLY = 25000000e18; // 25 million | ||
uint public constant FINAL_SUPPLY = 100000000e18; // 100 million | ||
|
||
address public registry; | ||
|
||
constructor(address _registry) public { | ||
registry = _registry; | ||
_mint(msg.sender, INITIAL_SUPPLY); | ||
} | ||
|
||
function mint(address account, uint256 value) public { | ||
require(msg.sender == registry, "Humanity::mint: Only the registry can mint new tokens"); | ||
require(totalSupply().add(value) <= FINAL_SUPPLY, "Humanity::mint: Exceeds final supply"); | ||
|
||
_mint(account, value); | ||
} | ||
|
||
} |
Oops, something went wrong.