I am trying to create contract which can access functions of any ERC-20 standard token contract. At first, I'd like to get balance of given address.
I run private testnet using geth, I have deployed following token contract:
pragma solidity ^0.4.16;
interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external; }
contract TokenERC20 {
string public name;
string public symbol;
uint8 public decimals = 18;
uint256 public totalSupply;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
event Transfer(address indexed from, address indexed to, uint256 value);
event Burn(address indexed from, uint256 value);
constructor(uint256 initialSupply, string tokenName, string tokenSymbol) public {
totalSupply = initialSupply;
balanceOf[msg.sender] = totalSupply;
name = tokenName;
symbol = tokenSymbol;
}
function _transfer(address _from, address _to, uint _value) internal {
require(_to != 0x0);
require(balanceOf[_from] >= _value);
require(balanceOf[_to] + _value >= balanceOf[_to]);
uint previousBalances = balanceOf[_from] + balanceOf[_to];
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
emit Transfer(_from, _to, _value);
assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
}
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_value <= allowance[_from][msg.sender]);
allowance[_from][msg.sender] -= _value;
_transfer(_from, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) public returns (bool success) {
allowance[msg.sender][_spender] = _value;
return true;
}
function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) {
tokenRecipient spender = tokenRecipient(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value, this, _extraData);
return true;
}
}
function burn(uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value);
balanceOf[msg.sender] -= _value;
totalSupply -= _value;
emit Burn(msg.sender, _value);
return true;
}
function burnFrom(address _from, uint256 _value) public returns (bool success) {
require(_value <= allowance[_from][msg.sender]);
require(balanceOf[_from] >= _value);
balanceOf[_from] -= _value;
allowance[_from][msg.sender] -= _value;
totalSupply -= _value;
emit Burn(_from, _value);
return true;
}
function () public payable {
revert();
}
}
Everything works fine, I tested it on geth successfuly.
Then I created following contract:
pragma solidity ^0.4.16;
contract ERC20 {
function totalSupply() constant returns (uint256 totalSupply);
function balanceOf(address _owner) constant returns (uint256 balance);
function transfer(address _to, uint _value);
event Transfer(address indexed _from, address indexed _to, uint _value);
}
contract TokenChecker {
address private senderAddress;
address private tokenAddress;
constructor(address _tokenAddress) public {
senderAddress = msg.sender;
tokenAddress = _tokenAddress;
}
function bal(address _address) public constant returns (uint256 balance) {
ERC20 token = ERC20(tokenAddress);
return token.balanceOf(_address);
}
function getThis() public constant returns (address thisAddress) {
return address(this);
}
function tokenAdrs() public constant returns (address adrs) {
return tokenAddress;
}
function () public payable {
revert();
}
}
This one was deployed using this JavaScript:
var tokenCheckerFactory = eth.contract(COMPILED_WITH_SOLC_ABI)
var tokenCheckerCompiled = "0xCOMPILED_WITH_SOLC_BIN"
var _tokenAddress = "DEPLOYED_TokenERC20_ADDRESS"
var tokenChecker = tokenCheckerFactory.new(_tokenAddress, {from:eth.accounts[0],data:tokenCheckerCompiled,gas:2000000}, function(e, contract){
if(e) {
console.error(e); // If something goes wrong, at least we'll know.
return;
}
if(!contract.address) {
console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined...");
} else {
console.log("Contract mined! Address: " + contract.address);
console.log(contract);
}
})
In geth, getThis()
and tokenAdrs()
are OK, but theres always 0 returned by bal()
with any argument:
// geth console
> token.balanceOf(eth.accounts[0]) // instance of TokenERC20
2.0999984e+25
> tokenChecker.bal(eth.accounts[0])
0
>
What is wrong with my code? Why can't TokenChecker interact with provided ERC-20 contract? Could it even communicate with random ERC-20 token by given its contract address like this? Thank you in advance.
Edit: When I omit constant
at bal()
, new transaction is submitted, nothing is returned to console. When i start mining, nothing special happens, only info about mining is shown. And view
returns always 0 too.
^0.4.16;
but you are using features introduced after that version. Not saying this is your solution, but noting it for reference. They keywordconstructor
was introduced in 0.4.22 (2018-04-16) github.com/ethereum/solidity/blob/develop/Changelog.mdbal()
worked and returned the proper value. I would assume the problem lies with your JS code, not Solidity. .function tokenSupply() public constant returns (uint256 totalSupply) { return token.totalSupply(); }
and it returns 0 too as if instance of ERC20 didn't exist.