0

I've written a simple token contract for testing purposes:

pragma solidity ^0.4.18;

contract TestToken {
    uint public totalSupply;

    mapping(address => uint) public balanceOf;

    function transfer(address to, uint amount) public returns (bool) {
        require(balanceOf[msg.sender] >= amount);
        balanceOf[msg.sender] -= amount;
        balanceOf[to] += amount;
        return true;
    }

    function credit(address to, uint amount) public {
        balanceOf[to] += amount;
        totalSupply += amount;
    }

    function debit(address from, uint amount) public {
        balanceOf[from] -= amount;
        totalSupply -= amount;
    }
}

Whenever I call the credit method on the contract and pass the address of another contract as parameter, everything works as expected:

token.methods.credit(wallet._address, 500000).send({from: accounts[0], gas: "0xB3E4", gasPrice: "0x4A817C800", value: "0x"})

The status of the transaction is 0x1.

The balance is updated:

token.methods.balanceOf(wallet._address).call()
'500000'

But when I pass the address of a regular ethereum account as a parameter, the transaction gets mined, but nothing happens.

token.methods.credit(accounts[0], 500000).send({from: accounts[0], gas: "0xB3E4", gasPrice: "0x4A817C800", value: "0x"})

The status of the transaction is 0x0.

The balance doesn't change:

token.methods.balanceOf(accounts[0]).call()
'0'

Comparing the resulting signed transaction objects, the only difference other than the data field is that the signature v value is always 0 when the transaction fails and 1 when the transaction succeeds. But I'm not sure what that means.


Update:

Seems like it's not even contract vs non-contract, it's just that some addresses don't work.

For example, this works:

token.methods.credit('0xd2d0aD819B2679FBDD5C75F93fa13242bfd7E2A5', 500000000000000000).send({from: accounts[0], gas: "0xB3E4", gasPrice: "0x4A817C800", value: "0x"})

This doesn't:

token.methods.credit('0xc4beccd2ebdb32203800dfbc60ff0dd7c2762b48', 500000000000000000).send({from: accounts[0], gas: "0xB3E4", gasPrice: "0x4A817C800", value: "0x"})
2
  • 2
    One possible cause is that your gas is not enough to cover your transaction. A transaction will be cheaper is the recipient has a non-zero balance.
    – Ismael
    Commented May 1, 2018 at 18:42
  • That's exactly what the problem was, I did not account for the fact that if an account doesn't already have a balance it will cost more gas to create the balance mapping for that account. And so I was running out of gas when calling the method with new addresses.
    – Dcompoze
    Commented May 1, 2018 at 22:40

2 Answers 2

1

The problem is most probably with gas limit. How did you calculate it?

When transaction has some data attached, e.g. contract's method selector and parameters, zero bytes cost less than non-zero. So, transaction that sends tokens to 0x0011223344556677889900112233445566778899 will cost less than transaction, that send the same number of tokens to 0x112233445566778899aa112233445566778899aa. Also, changing value in storage from zero to non-zero costs more, than changing it from non-zero to non-zero. So balanceOf[to] += amount; costs less if to address already has some tokens.

0
  1. you're sending from account[0] to account[0], so the balance stays he same
  2. if the balance of (accounts[0]) is zero, as you show in your second call, then transfer call will fail because of require(balanceOf[msg.sender] >= amount)
1
  • Sorry I misstyped the question title, I was talking about the credit function which mints new tokens.
    – Dcompoze
    Commented May 1, 2018 at 12:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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