Instantly share code, notes, and snippets.
Forked from anonymous/ShareholderOrg.sol
Created
January 16, 2018 04:38
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save jonchurch/23f75920f794692de51d97573dd49021 to your computer and use it in GitHub Desktop.
Created using browser-solidity: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://ethereum.github.io/browser-solidity/#version=soljson-v0.4.19+commit.c4cbbb05.js&optimize=false&gist=
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
// 1 - Accept profits sent as ETH to the contract. | |
// 2 - Allow shareholders to withdraw their fair portion of the profits based on the % they own at the time of the profits' sharing. | |
// 3 - Allow a shareholder to transfer his or her stake in the contract to someone else. | |
// 4 - Allow all shareholders to hold a vote: | |
// - if passing 51% agreement, allows them to dilute all of their own shares and issue a % of new equity at a valuation that is equal to 100 multiplied by the profits accrued during the previous month | |
// 5 - Allow new users to buy the new equity at the offered price following a successful vote, to become shareholders themselves. | |
// 6 - Allow all interaction with the smart contracts to occur via the browser, including letting shareholders check their balance of profits to be paid. |
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
pragma solidity ^0.4.19; | |
contract owned { | |
address public owner; | |
function owned() { | |
owner = msg.sender; | |
} | |
modifier onlyOwner { | |
require(msg.sender == owner); | |
_; | |
} | |
function transferOwnership(address newOwner) onlyOwner { | |
owner = newOwner; | |
} | |
} | |
contract tokenRecipient { | |
uint256 public balance; | |
event receivedEther(address sender, uint amount); | |
// event receivedTokens(address _from, uint256 _value, address _token, bytes _extraData); | |
// function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData){ | |
// // Token t = Token(_token); | |
// require(t.transferFrom(_from, this, _value)); | |
// // receivedTokens(_from, _value, _token, _extraData); | |
// } | |
function () payable { | |
receivedEther(msg.sender, msg.value); | |
balance += msg.value; | |
} | |
} | |
// contract Token { | |
// mapping (address => uint256) public balanceOf; | |
// function transferFrom(address _from, address _to, uint256 _value) returns (bool success); | |
// } | |
/** | |
* The shareholder association contract itself | |
*/ | |
contract ShareholderOrg is owned, tokenRecipient { | |
uint public minimumQuorum; | |
uint public debatingPeriodInMinutes; | |
Proposal[] public proposals; | |
uint public numProposals; | |
// Token public sharesTokenAddress; | |
event ProposalAdded(uint proposalID, address recipient, uint amount, string description); | |
event Voted(uint proposalID, bool position, address voter); | |
event ProposalTallied(uint proposalID, uint result, uint quorum, bool active); | |
event ChangeOfRules(uint newMinimumQuorum, uint newDebatingPeriodInMinutes, address newSharesTokenAddress); | |
struct Proposal { | |
address recipient; | |
uint amount; | |
string description; | |
uint votingDeadline; | |
bool executed; | |
bool proposalPassed; | |
uint numberOfVotes; | |
bytes32 proposalHash; | |
Vote[] votes; | |
mapping (address => bool) voted; | |
} | |
struct Vote { | |
bool inSupport; | |
address voter; | |
} | |
// Modifier that allows only shareholders to vote and create new proposals | |
modifier onlyShareholders { | |
require(sharesTokenAddress.balanceOf(msg.sender) > 0); | |
_; | |
} | |
function withdrawProfit() onlyShareholders returns (bool success) { | |
} | |
/** | |
* Constructor function | |
* | |
* First time setup | |
*/ | |
function ShareholderOrg(Token sharesAddress, uint minimumSharesToPassAVote, uint minutesForDebate) payable { | |
changeVotingRules(sharesAddress, minimumSharesToPassAVote, minutesForDebate); | |
} | |
/** | |
* Change voting rules | |
* | |
* Make so that proposals need tobe discussed for at least `minutesForDebate/60` hours | |
* and all voters combined must own more than `minimumSharesToPassAVote` shares of token `sharesAddress` to be executed | |
* | |
* @param sharesAddress token address | |
* @param minimumSharesToPassAVote proposal can vote only if the sum of shares held by all voters exceed this number | |
* @param minutesForDebate the minimum amount of delay between when a proposal is made and when it can be executed | |
*/ | |
function changeVotingRules(Token sharesAddress, uint minimumSharesToPassAVote, uint minutesForDebate) onlyOwner { | |
sharesTokenAddress = Token(sharesAddress); | |
if (minimumSharesToPassAVote == 0 ) minimumSharesToPassAVote = 1; | |
minimumQuorum = minimumSharesToPassAVote; | |
debatingPeriodInMinutes = minutesForDebate; | |
ChangeOfRules(minimumQuorum, debatingPeriodInMinutes, sharesTokenAddress); | |
} | |
} |
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
pragma solidity ^0.4.19; | |
contract owned { | |
address public owner; | |
function owned() public { | |
owner = msg.sender; | |
} | |
modifier onlyOwner { | |
require(msg.sender == owner); | |
_; | |
} | |
function transferOwnership(address newOwner) onlyOwner public{ | |
owner = newOwner; | |
} | |
} | |
contract tokenRecipient { | |
uint256 public profit; | |
event receivedEther(address sender, uint amount); | |
event balanceUpdated(address sender, uint amount, uint balance); | |
function () payable public { | |
receivedEther(msg.sender, msg.value); | |
profit += msg.value; | |
// balanceUpdated(msg.sender, msg.value, profit); | |
} | |
} | |
contract Shareholders is owned, tokenRecipient { | |
// Track total shares in existence | |
uint public totalShares = 100; | |
// uint availableShares = 50 | |
uint public lastProfitShare = now; | |
address[] public memberList; | |
uint public profitShareInterval = 30 seconds;//30 days; | |
uint public minimumShares = 1; | |
uint balance = this.balance; | |
// I need to keep track of who owns how many stakes in the contract | |
struct Record { | |
uint id; | |
address holder; | |
uint shares; | |
uint allowance; | |
// check if record exists, open to a better way to do this | |
bool exists; | |
} | |
// mapping (address => uint) public allowances; | |
mapping (address => Record) public records; | |
// Record[] records; | |
// I want to eventually loop through all Shareholders | |
// and create an allowance for them to withdraw | |
event ProfitWithdrawn(address user, uint amount); | |
event AllowanceUpdated(address user, uint totalAllowance, string reason); | |
event TransferShares(address sender, address receiver, uint sharesSent); | |
event NewMember(address user, uint memberId, uint shareBalance); | |
modifier onlyShareholders { | |
require(records[msg.sender].shares > 1); | |
_; | |
} | |
function createNewMember(address _newMember, uint _initialShareBalance) private { | |
// create a struct for member with _initialShareBalance or 0 shares | |
// persist struct | |
uint memberId = memberList.length; | |
uint shares = _initialShareBalance > 1 ? _initialShareBalance : 0; | |
var newMemberStruct = Record(memberId, _newMember, shares, 0, true); | |
memberList.push(_newMember); | |
records[_newMember] = newMemberStruct; | |
NewMember(_newMember, memberId, shares); | |
} | |
// trigger profit sharing | |
function profitShare() onlyShareholders public { | |
// make sure 30 days or share interval has passed | |
require(now - lastProfitShare > profitShareInterval); | |
require(profit > 0); | |
// Create an allowance for each user based on their current stake | |
// loop through all members and dish out their allowance based on last period's profit | |
// period profit = profit | |
uint d = 1000; | |
for (uint _i = 0; _i < memberList.length; _i += 1) { | |
address memberAdd = memberList[_i]; | |
var member = records[memberAdd]; | |
// add allowance in amount of totalShares / memberList[i].shares * profit | |
// I'm getting an error tryna multiply a decimal like 0.5 by a uint... THE FUCK? | |
// everyone says to just use an integer, but how do I get an int from my decimal? | |
uint p = (d * member.shares / totalShares); | |
uint newAllowance = (profit * p)/d; | |
member.allowance = newAllowance; | |
AllowanceUpdated(memberAdd, newAllowance, "profit share"); | |
} | |
// reset our running tab of profit for the period | |
profit = 0; | |
// set current time as most recent profit sharing | |
lastProfitShare = now; | |
} | |
function withdrawProfits() onlyShareholders public { | |
require(records[msg.sender].allowance > 0); | |
// if user has an allowance, send it to them and set allowance to 0 | |
// Record memory member = records[msg.sender]; | |
// uint amount = allowances[msg.sender]; | |
// transfer balance to sender | |
msg.sender.transfer(records[msg.sender].allowance); | |
// ProfitWithdrawn(msg.sender, records[msg.sender].allowance); | |
// reset allowance to 0 | |
// setAllowance(msg.sender, 0, "profit withdrawn"); | |
records[msg.sender].allowance = 0; | |
// allowances[msg.sender] = 0; | |
// return false; | |
} | |
// stakeholder can send their shares to another user | |
function sendShares(address _receiver, uint _sharesToSend) onlyShareholders public { | |
// sender must have enough balance to cover shares they are sending | |
require(records[msg.sender].shares >= _sharesToSend); | |
// make sure user cant send shares to oblivion | |
require(_receiver != 0x0); | |
// grab modifiable versions of sender and receiver from storage | |
var receiver = records[_receiver]; | |
var sender = records[msg.sender]; | |
if (receiver.id != 0x0) { | |
// update existing member share total | |
receiver.shares += _sharesToSend; | |
} else { | |
// create new member with share balance | |
createNewMember(_receiver, _sharesToSend); | |
} | |
sender.shares -= _sharesToSend; | |
TransferShares(msg.sender, _receiver, _sharesToSend); | |
} | |
function Shareholders() public { | |
// make owner a member and give them all the shares | |
createNewMember(owner, totalShares / 2); | |
createNewMember(0x6CBAD7cDDF6Dd425f220d107cA0625eE9D243723, totalShares / 2); | |
} | |
function kill() onlyOwner public { | |
selfdestruct(owner); | |
} | |
function getBalance() view public returns (uint256) { | |
return this.balance; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment