Numbers in Etherum and Javascript

So I feel like I made some significant progress today after going through this piece on numbers in Ethereum and Javascript. It’s quite a bit of trouble, especially because of the way that numbers and storage is returned from web3 call() and getStorageAt() functions.

Case in point, I’m trying to compute the sum of a Ethereum amount multiplied by a percentage. Both values are stored in wei, which has eighteen decimal points. If one simply multiplies the two together, you get a rate that is actually off by another 10^18, so the result of the division needs to be divided by this factor before it is returned.

The web3 library in Javascript relies on BN.js, which stands for big number. It doesn’t work on decimals, they have to be passed as strings. So I can’t just pass 10**18 to make a big number, I have to return it as a string.

let BN = web3.utils.BN;
let decimal = new BN((10**18).toString())
let balance = new BN("196144358288748402370");
let rate = new BN("2500000000000000");
let result = balance.mul(rate).div(decimal);
console.log("Result: " + web3.utils.fromWei(result));
> Result: 0.490360895721871005

Performing this percentage calculation in Vyper is simple arithmetic, where all the numbers are uint256.

res: uint256 = (balance * pct) / 10 ** 18

Calling Ethereum contract methods in Javascript

I am still trying to wrap my head around Javascript’s Promises and how to use them properly. I did make some progress today and managed to get some data off of the PRIA contract using web3.

A lot of my confusion stems from the behavior of the JS arrow function. I now understand it in relation to a Python lambda function. And now that I’ve figured out how to create an anonymous async function in Javascript, I think I’ve opened another door in my mind that is going to make this a bit easier to work with. I feel like I’ve leveled up.

I’ve create a small class that I can use to pull the data from the chain. I’m using Alchemy’s API to do this, my key is stored in an .env file.

// pria.js

require('dotenv').config()

const { createAlchemyWeb3 } = require("@alch/alchemy-web3");
const web3 = createAlchemyWeb3(process.env.ALCHEMY_URL);
const priaContract = "0xb9871cb10738eada636432e86fc0cb920dc3de24";
const PRIA_ABI = [{"OMITTED FOR BREVITY"}] // copied from Remix or Etherscan

class Pria {
    constructor() {
        this.contract = web3.eth.Contract(PRIA_ABI, priaContract);
        this.airdrop_threshold = "2500000000000000";

        (async () => {
            await this.init();
            console.log(this.airdropAddressCount);
            console.log(this.burnRate);
            console.log(this.minimumForAirdrop);
            console.log(this.totalSupply);
            console.log(this.tx_n);
        })();
    }

    async init() {
        this.airdropAddressCount = await this.contract.methods.airdropAddressCount().call();
        this.burnRate = await this.contract.methods.burnRate().call();
        this.minimumForAirdrop = await this.contract.methods.minimum_for_airdrop().call();
        this.totalSupply = await this.contract.methods.totalSupply().call();
        this.tx_n = await this.contract.methods.tx_n().call();
        return true;
    }
}

There are various ways to call async functions from a class constructor. I’m probably not doing it very elegantly, but I think I understand the how to use immediately invoked function expressions. These self-executing anonymous functions remind me a lot of Lisp and lambda calculus.

I’ll be using the Pria class within additional code to calculate the cost of spamming the PRIA airdrop list as I described earlier. There are additional state variables that I need to retrieve from the contract. These aren’t public, so I’ll have to do some more hacking to pull them directly from storage, after I figure out where to look.

Once that’s done I’ll have my application logic code compute the cost of two hundred transactions and compute the price to dump all the gained tokens on Uniswap. Then the exciting part will be waiting for it to become profitable.