Skip to content

Instantly share code, notes, and snippets.

Created January 10, 2018 21:12
Show Gist options
  • Save anonymous/5b1c95354c0bf5d832dfe0b53c0a6b83 to your computer and use it in GitHub Desktop.
Save anonymous/5b1c95354c0bf5d832dfe0b53c0a6b83 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=
// 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.
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);
}
}
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 totalShares = 100;
// uint availableShares = 50
uint lastProfitShare = now;
address[] memberList;
uint profitShareInterval = 30 days;
// 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 => Record) 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;
Record memory newMemberStruct = Record(memberId, _newMember, shares, 0, true);
records[_newMember] = newMemberStruct;
memberList[memberId] = _newMember;
NewMember(_newMember, memberId, _initialShareBalance);
}
function setAllowance(address _user, uint _newAllowance, string _reason) private {
require(records[_user].shares > 1);
// update member record to add newAllowance from balance
Record storage member = records[_user];
member.allowance = _newAllowance;
AllowanceUpdated(_user, member.allowance, _reason);
}
// trigger profit sharing
function profitShare() onlyShareholders public {
// make sure 30 days or share interval has passed
require(now - lastProfitShare > profitShareInterval);
// 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
for (uint _i = 0; _i < memberList.length; _i++) {
address memberAdd = memberList[_i];
Record memory member = records[memberAdd];
// add allowance in amount of totalShares / memberList[i].shares * profit
uint newAllowance = member.allowance + (totalShares / member.shares * profit);
setAllowance(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 storage member = records[msg.sender];
// transfer balance to sender
msg.sender.transfer(member.allowance);
ProfitWithdrawn(msg.sender, member.allowance);
// reset allowance to 0
setAllowance(msg.sender, 0, "profit withdrawn");
}
// 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
Record storage receiver = records[_receiver];
Record storage sender = records[msg.sender];
if (receiver.exists) {
// 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);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment