Working with Assets (tokens) using the greymass/eosio library

Last June we started on a new EOSIO library, one to fill a void we identified in our work with things like Anchor, Fuel, and the SDKs that power them. We have since integrated it into nearly all of our products and are getting close to the point where we feel it’s production ready. The library I’m specifically referring to is what we’re currently calling either “eosio-core” or just “eosio”, and can be found on github here:

I was recently closing text editor windows and came across some notes I wrote up during a conversation with another developer on Telegram. Instead of discarding the notes, I figured instead I’d write up a quick post and share this information more widely. The subject we’ll specifically cover during the course of this post is dealing with asset-type data.

The problem: painfully working with strings

If you’ve worked with balances, tokens, assets, or any other numeric value in EOSIO… you’ve probably been forced to write some code like this:

const value = parseFloat(balance.split(" ")[0]);

I’m guilty of it, there are examples of this type of code throughout the code I’ve worked on.

This is primarily because everything within the frontend space of EOSIO is dealt with as a string, and there’s nothing between your application and that string to make working with it any easier. When you ask the blockchain API for someone’s balance, on WAX for example, it’ll respond with something like:

3.00040000 WAX

Since you often want to split the value and symbol, determine the precision, style it as content, and potentially let the user interact with that number - it requires some manipulation of the string into other types of data. Unfortunately eosjs, the main library everyone uses to interact with EOSIO blockchains, isn’t designed to help you here. This is one reason (of many) we decided to set out and build a library that is essentially a replacement for eosjs.

There are better ways, and to show how, here’s one of the classes within our new library that helps make developing for EOSIO easier.

Introducing the Asset class

With @greymass/eosio added to your project:

npm install --save @greymass/eosio

OR

yarn add @greymass/eosio

You can now utilize any of the classes and methods available in this library. There are no black boxes and everything is exposed for you to write whatever custom implementations of EOSIO logic you’re interested in creating. The Asset class is here to help you deal with assets and balances:

import { Asset } from '@greymass/eosio'

You can now take the data returned from EOSIO-based APIs and pass it directly in to begin working with it. Let’s take the string example we gave in the section above, and create an instance of an Asset using it:

const balance = '3.00040000 WAX'
const asset = Asset.from(balance)

The asset variable is now an Asset object that comes with a bunch of helpful data and features to make your life as a developer easier.

// The number representation of the asset
console.log(asset.value)            
// Outputs: 3.004

// The precision of the asset
console.log(asset.symbol.precision) 
// Outputs: 8

// The name of the asset
console.log(asset.symbol.name)      
// Outputs: "WAX"

// Rendering the asset back into a string
console.log(String(asset))       
// Outputs: "3.00400000 WAX"

You can even mutate the asset and perform mathematical operations on it:

asset.value += 1.000001

console.log(asset.value)            
// Output: 4.000401

console.log(String(asset))          
// Output: "4.00040100 WAX"

In reverse, if you have a numeric value and want to convert it into an asset, instead of passing in the string to the constructor you’d instead pass in the number and the desired precision/symbol (using notation common to EOSIO):

const asset = Asset.from(3.0004, `8,WAX`)

The second parameter of 8,WAX represents a token with the symbol of WAX that has 8 places past the decimal.

Mirroring the underlying data types from EOSIO

The entire library is designed to have the underlying data of the library match that of both the blockchain itself and all of the smart contracts. Because of this, if you’re looking for more control over your data, you can access these raw data structures and work directly with the data. The Asset for example is exposed as an as Int64 which can be used to prevent dealing with floating point math in Javascript.

asset.units instanceOf Int64 // true

No matter what type of data you choose to work with, the Asset (and all the other classes in the library) will serialize to both EOSIO-style JSON as well as the EOSIO binary (ABI) format.

If you’re interested in exploring the entire Asset class in more depth before the documentation is available, I’d invite you to check out either:

  1. The Source Code: https://github.com/greymass/eosio-core/blob/master/src/chain/asset.ts
  2. The Unit Tests: https://github.com/greymass/eosio-core/blob/master/test/chain.ts#L21

Proliferating classes like Asset

We have made heavy use of the Asset class throughout our new projects and in this library. For example, if you were to use the built-in API Client within this new library, API calls can be defined to return Assets so you don’t even have to manually initialize them.

Take the API call to get an account:

/v1/chain/get_account

When called from our APIClient interface, like so:

import { APIClient } from '@greymass/eosio'

const client = new APIClient({
  url: 'https://eos.greymass.com'
})

const account = await client.v1.chain.get_account('teamgreymass')

The value of account object that is returned is fully typed. The core_liquid_balance field on the object is already an Asset class that you’ll be able to use immediately, alongside typed data for every other piece of data the response includes.

Beyond directly utilizing this library, these types are also going to be readily available in all of our other SDKs as well - like Anchor Link, our UAL plugin, and some of our yet unreleased projects. For example, in the next version of our UAL plugin (available here as the “next” version), the APIClient above will be available on the activeUser instance as client, ready to use by your app.

Closing

What started out as a tab in a text editor I was going to close, turned into this semi-rambling post about the benefits of our new library. If you want to give it a try - I’d welcome you to. I personally have been using this new library now for months and can’t speak highly enough about it. It may be sparse on documentation still - but then again, what isn’t in this space. It’s the result of everything evolving so rapidly while we all learn how best to adapt and create something meaningful.

And as a shameless plug, this type of effort how we are trying to bring value into the EOSIO ecosystem. I’d humbly as that if you want to support our work, vote for teamgreymass on your favorite EOSIO blockchains. Our rewards go both into maintaining our block production operations as well as to support our developers working full time on projects like these.

You can also expect more posts like this in the future. If you have questions, feel free to ask them here in the EOSIO Development forums!

1 Like

Looks very useful, are there any known “gotchas” with this beta library? Considering using for boid apps in the future.

The only gotcha’s I’ve experienced so far are when integrating it with old code, you’ve got to make sure to convert back to strings in situations with your old code where it’s expecting strings. Nearly everything is typed in this new library, so if you just pass the new types into eosjs or a method you’ve written that’s expecting a string, make sure you pass the String(value).

If you have something like an Account object from core and want to stringify the whole thing to make it work like eosjs, you can just stringify/parse it as well:

JSON.parse(JSON.stringify(account))

Anchor still has a bunch of eosjs code implemented within it and this has caught me a few times. It’s mostly because we’ve only partially imported core there, and you can see examples in the code like this:

1 Like