1

In a Solidity contract I am using address.send() and address.transfer() to send money to a recipient. When I execute that function the balance of the contract gets deducted but the recipient address never receives the funds in their account.

What is going wrong and how I do I debug / fix? I am new to Ethereum, so baby steps please :)

Thanks

UPDATE:

I am using testrpc and it would appear that I don't see a transaction for that amount on the console output. All I am seeing on the blockchain is the transaction to call my contract function that contains address.send(). Why is this?

UPDATE: Contract as requested

pragma solidity ^0.4.11;
// We have to specify what version of compiler this code will compile with

contract Hackathon {

  struct Entry {
    bytes32 name;
    uint votes;
    address wallet;
  }

  Entry[] public entries;
  address winner;

  function AddEth () payable {}

  /* mapping field below is equivalent to an associative array or hash.
  The key of the mapping is candidate name stored as type bytes32 and value is
  an unsigned integer to store the vote count
  */

  mapping (bytes32 => uint8) public votesReceived;

  /* Solidity doesn't let you pass in an array of strings in the constructor (yet).
  We will use an array of bytes32 instead to store the list of candidates
  */

  /* This is the constructor which will be called once when you
  deploy the contract to the blockchain. When we deploy the contract,
  we will pass an array of candidates who will be contesting in the election
  */
  function Hackathon() {
  }

  // This function returns the total votes a candidate has received so far
  function totalVotesFor(bytes32 candidate) returns (uint8) {
    if (validCandidate(candidate) == false) throw;
    return votesReceived[candidate];
  }

  // This function increments the vote count for the specified candidate. This
  // is equivalent to casting a vote
  function voteForCandidate(bytes32 candidate) {
    if (validCandidate(candidate) == false) throw;
    votesReceived[candidate] += 1;
  }

  function validCandidate(bytes32 candidate) returns (bool) {
    for(uint i = 0; i < entries.length; i++) {
      if (entries[i].name == candidate) {
        return true;
      }
    }
    return false;
  }

  function getWinner() returns (bytes32, uint256, address) {

    bytes32 winnerName;
    uint winningVoteCount = 0;

    for (uint p = 0; p < entries.length; p++) {
        if (votesReceived[entries[p].name] > winningVoteCount) {
            winningVoteCount = votesReceived[entries[p].name];
            winnerName = entries[p].name;
            winner = entries[p].wallet;
        }
    }

    return (winnerName, winningVoteCount, winner);
  }

  function payWinner() returns (bool) {

    winner.transfer(23);

    return true;
  }

  function addEntry(bytes32 name, address wallet) returns (uint256) {

    Entry memory tmpEntry;
    tmpEntry.name = name;
    tmpEntry.wallet = wallet;

    return entries.push(tmpEntry);
  }

  function getEntriesCount() returns (uint256) {

    return entries.length;
  }

  function getEntry(uint index) returns (bytes32, uint, address) {

    return (entries[index].name, votesReceived[entries[index].name], entries[index].wallet);
  }
}
  • We need to see your contract to get a sense of what's happening. – Rob Hitchens - B9lab Jul 12 '17 at 15:53
  • I have updated question. I dumped it all as I wasn't sure what was important. – jim Jul 12 '17 at 16:01
1

I got pretty tangled up in there and found myself unable to pinpoint one issue that stands out. See Mapped Structs with Index over here: Are there well-solved and simple storage patterns for Solidity?

I ended up with data reorganized, events for state changes and for loops (anti-pattern) removed. You don't want those because it won't scale, so it tracks the leader as it goes now. It only awards the leader one time, only the only can do it, and there are passive read-only getters that don't change the state (the old getWinner was state changing).

it's probably not perfect but I think it's more on track and will hopefully give you ideas.

pragma solidity ^0.4.11;
// We have to specify what version of compiler this code will compile with

contract Hackathon {

  address public leader;
  uint public leaderVotes;
  bool public isOver;
  uint public prize;
  address public owner;

  struct CandidateStruct {
    bytes32 name;
    uint votes;
    uint candidatePointer;
  }

  mapping(address => CandidateStruct) public candidateStructs;
  address[] public candidateList;

  modifier onlyOwner {
      if(msg.sender != owner) throw;
      _;
  }

  event LogDeposit(address sender, uint amount);
  event LogVote(address sender, address candidate, uint votes);
  event LogVotingClosed(address sender);
  event LogWinnerPaid(address sender, address winner, uint amount);
  event LogNewCandidate(address sender, bytes32 name, address candidate, uint row);
  event LogNewLeader(address leader);

  function Hackathon() {
      owner = msg.sender;
  }

  function deposit() payable returns(bool success) {
      LogDeposit(msg.sender, msg.value);
      prize = this.balance;
      return true;
  }

  function isCandidate(address candidate) public constant returns(bool success) {
      if(candidateList.length==0) return false;
      return(candidateList[candidateStructs[candidate].candidatePointer]==candidate);
  }

  // This function increments the vote count for the specified candidate. This
  // is equivalent to casting a vote
  function voteForCandidate(address candidate) public returns(bool success) {
    if(!isCandidate(candidate)) throw;
    if(isOver) throw;
    candidateStructs[candidate].votes += 1;
    if(candidateStructs[candidate].votes > leaderVotes) {
        leader = candidate;
        leaderVotes = candidateStructs[candidate].votes;
    }
    LogVote(msg.sender, candidate, candidateStructs[candidate].votes);
    return true;
  }

  function closeVoting() onlyOwner returns(bool success) {
    if(isOver) throw;
    isOver = true;
    LogVotingClosed(msg.sender);
    return true;
  }

  function payWinner() onlyOwner returns (bool) {
    if(!isOver) throw;
    if(prize == 0) throw;
    uint amount = prize;
    prize = 0; // re-entrace
    LogWinnerPaid(msg.sender, leader, amount);
    leader.transfer(amount);
    return true;
  }

  function addCandidate(bytes32 name, address candidate) public returns(bool success) {
    if(isCandidate(candidate)) throw;
    candidateStructs[candidate].name = name;
    candidateStructs[candidate].candidatePointer = candidateList.push(candidate)-1;
    LogNewCandidate(msg.sender, name, candidate, candidateStructs[candidate].candidatePointer);
    return true;
  }

  function getCandidateCount() public constant returns (uint256) {
    return candidateList.length;
  }

  function kill() onlyOwner {
      selfdestruct(owner);
  }

}

In remix to show it working. Note the event log to see what I did.

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.