mikewlange
2/23/2018 - 10:35 AM

Smart Contract for Donations

Smart Contract for Donations

pragma solidity ^0.4.4;

// TestRPC HD wallet
// warrior minimum breeze raven garden express solar flavor obvious twenty alpha actress

contract Donation {

  // Instantiate a variable to hold the account address of the contract administrator
  address public owner;

  // Create a data structure to reperesent each of the participants.
  struct Payee {
    // If the payee can administer their account.
    bool status;
    // The amount relative to aggregate weight that a payee will receive.
    uint weight;
    // A record of the amount held for the payee.
    uint balance;
  }

  // Create an associative arrays with account address as key and payee data sturcture as value.
  mapping(address => Payee) public payees;
  // Create an array like mapping to behave as an index of addreesses
  mapping (int8 => address) public payeesIndex;
  // Keep note of total number of participants in the system so we can iterate over index.
  int8 public payeesIndexSize;

  // Declare events for actions we may want to watch
  event NewDonation(address indexed donator, uint amt);
  event Transfer(address indexed from, address indexed to, uint amt);
  event PayeeAction(address indexed payee, bytes32 action);
  event Withdrawal(address indexed payee, uint amt);
  event OwnerChanged(address indexed owner, address indexed newOwner);
  event ContractDestroyed(address indexed contractAddress);

  // Constructor
  function Donation() {
    // Set the address of the contract deployer to be owner.
    owner = msg.sender;
    payees[owner].status = true;
    payees[owner].weight = 10;
    payeesIndex[0] = owner;
    payeesIndexSize = 1;
  }

  // Check if current account calling methods is the owner.
  modifier isOwner() {
    if (msg.sender != owner) throw;
    _;
  }

  // Check if current account calling methods is a valid payee of the contract.
  modifier isPayee() {
    if (payees[msg.sender].status != true) throw;
    _;
  }

  // Aggregate all payee weights.
  function getTotalWeight() private returns (uint) {

    int8 i;
    uint totalWeight = 0;

    for (i=0;i<payeesIndexSize;i++) {
       if (payees[payeesIndex[i]].status == true) {
         totalWeight += payees[payeesIndex[i]].weight;
       }
    }

    return totalWeight;
  }

  // Function which will accept donations.
  function deposit() payable {

  if (msg.value == 0) throw;
    int8 i;
    uint totalWeight = 0;

    totalWeight = getTotalWeight();
    // Update account balances for all payees.
    for (i=0;i<payeesIndexSize;i++) {
       if (payees[payeesIndex[i]].status == true) {
         uint divisor = (totalWeight / payees[payeesIndex[i]].weight);
         payees[payeesIndex[i]].balance = msg.value / divisor;
       }
    }

    NewDonation(msg.sender, msg.value);
  }

  // Add a new payee to the contract.
  function addPayee(address _payee, uint _weight) isOwner returns (bool) {

    payees[_payee].weight = _weight;
    payees[_payee].status = true;
    payeesIndex[payeesIndexSize] = _payee;
    payeesIndexSize++;

    PayeeAction(_payee, 'added');
  }

  // Amend payee weight.
  function updatePayeeWeight(address _payee, uint _weight) isOwner {
    payees[_payee].weight = _weight;
  }

  // Disallow an account address from acting on contract.
  function disablePayee(address _payee) isOwner returns (bool) {
    if (_payee == owner) throw; // Don't lock out the main account
    payees[_payee].status = false;
    PayeeAction(_payee, 'disabled');
  }

  // Allow an account address from acting on contract.
  function enablePayee(address _address) isOwner {
    payees[_address].status = true;
    PayeeAction(_address, 'enabled');
  }

  // Allows payee to withdraw eth to their Ethereum account address.
  function withdraw(uint amount) payable isPayee {
    if (payees[msg.sender].status != true || amount > payees[msg.sender].balance) throw;
    if (!msg.sender.send(amount)) throw;
        Withdrawal(msg.sender, amount);
        payees[msg.sender].balance -= amount;
  }

  // Transfer some Ether available to withdraw to another account.
  function transferBalance(address _from, address _to, uint amount) isOwner {
    if (payees[_from].balance < amount) throw;
    payees[_from].balance -= amount;
    payees[_to].balance += amount;
    Transfer(_from, _to, amount);
  }


  function getBalance(address _address) isPayee returns (uint) {
    return payees[_address].balance;
  }


  function getWeight(address _address) isPayee returns(uint) {
    return payees[_address].weight;
  }


  function getStatus(address _address) returns(bool) {
    return payees[_address].status;
  }


  // Change ownership of the contract.
  function transferOwner(address newOwner) isOwner returns (bool) {
    if (!payees[newOwner].status == true) throw;
    OwnerChanged(owner, newOwner);
    owner = newOwner;
  }

  // Destroy the contract and pay out all enabled members.
  // Any outstanding value will be transferred to owner.
  function kill() payable isOwner {
    int8 i;
    address payee;

    for (i=0;i<payeesIndexSize;i++) {
      payee = payeesIndex[i];
      if (payees[payee].balance > 0 ) {
        if (payee.send(payees[payee].balance)) {
          Withdrawal(payee, payees[payee].balance);
        }
      }
    }

    ContractDestroyed(this);
    selfdestruct(owner);
  }
}