0

The Token challenge on Ethernaut - function returning Arrays in console - why?

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract Token {

  mapping(address => uint) balances;
  uint public totalSupply;

  constructor(uint _initialSupply) public {
    balances[msg.sender] = totalSupply = _initialSupply;
  }

  function transfer(address _to, uint _value) public returns (bool) {
    require(balances[msg.sender] - _value >= 0);
    balances[msg.sender] -= _value;
    balances[_to] += _value;
    return true;
  }

  function balanceOf(address _owner) public view returns (uint balance) {
    return balances[_owner];
  }
}

Before sending a transfer function to the contract in the console await contract.balanceOf("our address"), it returned this object:

o {negative: 0, words: Array(2), length: 1, red: null}
length: 1
negative: 0
red: null
words: Array(2)
0: 20
length: 2
[[Prototype]]: Array(0)

After calling await contract.transfer(instance, 21000000), the same call to that BalanceOf(our address) function await contract.balanceOf("our address") now returns an array of many more elements:

o {negative: 0, words: Array(11), length: 10, red: null}
length: 10
negative: 0
red: null
words: Array(11)
0: 46108884
1: 67108863
2: 67108863
3: 67108863
4: 67108863
5: 67108863
6: 67108863
7: 67108863
8: 67108863
9: 4194303
length: 11
[[Prototype]]: Array(0)

I was expecting to see a single number of 21000000 as per the function call, but seeing an array of numbers for some reason.

Can anyone explain why this is happening? Is the number being split across multiple entries in an array? How should one reason about this array and how to retrieve the new balance of an address?

To reproduce, just check out the contract in level 5 on https://ethernaut.openzeppelin.com/

2
  • use uint256.....
    – zmy
    Commented Aug 9, 2021 at 2:45
  • uint is an alias of uint256
    – Vlad
    Commented Aug 9, 2021 at 8:50

1 Answer 1

1

Searching the interwebs further, I discovered that the balanceOf call is actually returning a BN representation of the numbers.

So in our first case, it's returning just 20 because if we do let x = await contract.balanceOf("our address") followed by x.toString(), we'll get "20". If we do the same in the latter case, it will convert this BN array to a string: "115792089237316195423570985008687907853269984665640564039457584007913108639956" which is of course 2²⁵⁶–21000000+20 or just 115,792,089,237,316,195,423,570,985,008,687,907,853,269,984,665,640,564,039,457,584,007,913,129,639,936 - 20,999,980.

This is happening because of this line balances[msg.sender] -= _value; which makes the balance jump from negative impossible for a uint to a high positive - right to the end of the 2²⁵⁶ number scale! Hope this helps someone facing a similar question.

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.