A note on numbers in Ethereum and Javascript

4,332 reads

Being at ConsenSys, I get to work with some of the best developers in the space. I recently published this article as a “Getting Started” guide for new developers who have stumbled into this magical Ethereum ecosystem and don’t want to leave. It was not long until Joseph Chow raised issue with my neglecting to mention BigNumber s and not longer after that until Jim Berry dropped a wonderful description of the danger at hand. So props to both of them and also thanks to Aakil Fernandes for explaining how BigNumber works to me.

It turns out I’ve been doing things the wrong way. I updated my previous article and felt compelled to write this one so that I could A) unburden my soul and B) show how you may currently be mathing wrong between Javascript and Ethereum.

This is important because if you math wrong in Ethereum, you can lose money.

Numbers in Ethereum

Much to the pain and suffering of many developers, Ethereum does not support floating point numbers at all. We are forced like barbarians to settle for int s and uint s (I suggest you use the latter unless you have a very good reason to use the former) instead. There are probably valid technical reasons (I don’t know what they are) for this, but it’s fine because we can represent everything as integers and just keep track of decimals (recall that 1 ether = 10**18 wei).

Numbers in Javascript

Javascript is weird. Because it’s a dynamically typed language, you can run into all sorts of interesting interpretation scenarios. The relevant problem here is that default division behavior in JS is floating point division (more specifically, double floating point division). This is incompatible with Ethereum, which (obviously) uses integer division.

How to lose money

Have you spotted the problem yet? Oh yes, Javascript’s [double] floating point numbers only go up to 16 decimals, but 1 ether = 10**18 wei. And all ether values in transactions must be denominated in wei.

To see the problem in action, consider this:

var my_money = 10*Math.pow(10, 18);

my_money/3

> 3333333333333333500

Uh… whoops. You just gave me 167 wei.

You may be saying “I don’t care about 167 wei.” And that’s a perfectly reasonable reaction. I don’t care about 167 wei either. But what happens when every one of the 1B daily state pushes that your swarm of IoT devices makes to Raiden is off by 167 wei? Your problems start adding up fast.

BigNumber — A [really annoying] solution

Contrary to popular belief, the built in toPrecision() function does absolutely nothing for you. So we need to parse our number using some abstracted layer (I recommend bignumber.js, mostly because that’s what web3.js returns you anyway) and then operate on that.

So now our math looks like this:

var my_money = 10*Math.pow(10, 18);

var my_safe_money = new BigNumber(my_money);

// Still wrong

my_safe_money/3

> 3333333333333333500

// This is how you do it

var less_money = my_safe_money.div(3);

So what do you do with this weird BigNumber thing?

{

[String: '3333333333333333333.333333333333333333']

s: 1,

e: 18,

c: [ 33333, 33333333333333, 33333333333333, 33330000000000 ]

}

Well, you have to pass it around and keep operating on it with div() or times() or whatever. Look here for the full list of functions. Unfortunately, if you ever pull out the value:

var free_at_last = less_money.toNumber();

You will be sad about the result:

free_at_last

> 3333333333333333500

So yeah… you have to keep doing BigNumber operations. If you want a glimpse of what the number is, you can do this:

less_money.toString()

> '3333333333333333333.333333333333333333'

Also remember that if you’re forming transactions yourself, you have to provide Ethereum with hex numbers, so you would need to do the following before putting it in a transaction:

less_money.floor().toString(16)

> '2e426101834d5555'

Of course if you’re abstracting that logic into web3, that will convert your numbers for you.

Always Be Careful

It’s hard out there for an Ethereum application developer (although not nearly as hard as it is for a Bitcoin application developer — I think those still exist?). We need to watch out for each other and be careful with what we’re doing. Always remember that there is (probably) money being moved by your application and take the necessary precautions.

And, of course, if you find out about a pro tip or catch some dangerous behavior, report it!

—

If you like my articles, follow me on twitter or check out my company, ConsenSys, because we do awesome stuff.

And, as always, there is an open invitation to join the Ethereum community and help us conquer the world.

Tags