This library makes it easy to interact with tokens and operate with token quantities.
The library needs @permaweb/aoconnect
as a peer dependency.
npm i ao-tokens @permaweb/aoconnect
yarn add ao-tokens @permaweb/aoconnect
The Token
class provides basic methods to query token data. It first needs to be loaded:
// load CRED
const aoCredToken = await Token(
// id of the token
"Sa0iBLPNyJQrwpTTG-tWLQU-1QeUAJA73DdxGGiKoJc"
);
You can also provide custom configuration for this:
const aoCredToken = await Token(
// id of the token
"Sa0iBLPNyJQrwpTTG-tWLQU-1QeUAJA73DdxGGiKoJc",
// custom signer (default is window.arweaveWallet)
createDataItemSigner(wallet),
// custom aoconnect instance
connect({ ... })
);
Information about the token, such as Name
, Ticker
, Denomination
, etc. is preloaded:
const tokenID = aoCredToken.id;
const tokenName = aoCredToken.info.Name;
const symbol = aoCredToken.info.Ticker;
const denomination = aoCredToken.info.Denomination;
const logo = aoCredToken.info.Logo;
You can easily manage quantities as special, bigint
based floating point numbers that keep precision, using the token.Quantity
field. This field provides a Quantity
instance every time it's called, with a pre-configured denomination matching the token's denomination. Read more about quantities here.
// initialise a quantity from a token
const amountToSend = aoCredToken.Quantity.fromString("752.34");
You can query the token balance for an address. This will return a Quantity
instance.
const balance = await aoCredToken.getBalance(
// wallet address
"HjvCPN31XCLxkBo9FUeB7vAK0VCfSeY52-CS-6Iho8l"
);
// prints something like: "1,345.87"
console.log("Your balance is:", balance.existingBal.toLocaleString());
Querying all balances will return the balances object stored in the token's memory. Each holder's address is associated with a Quantity
instance.
const balances = await aoCredToken.getBalances();
for (const addr in balances) {
console.log(`${addr} owns ${balances[addr].toLocaleString()} CRED`);
}
The transfer functions allows you to send a message to the token process that initiates the transfer of the provided quantity to a recipient.
// this will transfer 1000 CRED to the provided address
const id = await aoCredToken.transfer(
aoCredToken.Quantity.fromString("1000"),
"XjvCPN31XCLPFBo9FUeB7vAK0VC6TwY52MCS-6Iho8h"
);
console.log("The transfer ID is", id);
The Quantity
class is an implementation of floating point numbers with extreme precision. It works by storing a bigint
instance as the raw value for token quantities. This is the same value the token process works with, so it makes operations and calculations extremely easy. It helps implementing logic for tokens on the front-end by abstracting calculations with the token denomination away from the developer, executing these within the library.
A quantity first needs to be initialised with the raw quantity provided by the token process (or 0
) and the token denomination:
// init 0 quantity for a specific denomination
const quantity = new Quantity(0n, token.info.Denomination);
If you already have a Token
instance in scope, you can also use the shortcut mentioned above to initialise a new quantity that belongs to the token process.
This is one of the most important fields of the Quantity
class. It is a raw bigint
value that must be used when communicating with a token process, as this is in the same format that token processes use internally for managing balances. For example, if you want to use @permaweb/aoconnect
to transfer tokens, instead of the built in transfer function, you need to provide the raw value to the message:
// 751.34 CRED tokens
const quantity = aoCredToken.Quantity.fromString("752.34");
// send these tokens to someone
await message({
// token process ID
process: "Sa0iBLPNyJQrwpTTG-tWLQU-1QeUAJA73DdxGGiKoJc",
// browser wallet signer
signer: createDataItemSigner(window.arweaveWallet),
tags: [
{ name: "Action", value: "Transfer" },
{ name: "Recipient", value: "XjvCPN31XCLPFBo9FUeB7vAK0VC6TwY52MCS-6Iho8h" },
//
// notice how we use the raw value
{ name: "Quantity", value: quantity.raw.toString() }
//
]
});
These getters are also accessible from a Quantity
instance.
integer
: Get the integer/whole part of the quantity (for e.g. for115.67
this will return115n
)fractional
: Get the fractional part of the quantity in integer (for e.g. for115.67
this will return67n
)denomination
: The token denomination this instance uses for calculations
Get if a provided value is a valid Quantity
instance:
// will return false
Quantity.isQuantity(15);
// wil return true
Quantity.isQuantity(new Quantity(15n, 4n));
Get if a provided value is a valid Quantity
of a Token
instance. This will compare the denomination used in the provided Quantity
instance:
// CRED has a denomination of 3
// this will return false
Quantity.isQuantityOf(new Quantity(345n, 12n), aoCredToken);
// this will return true
Quantity.isQuantityOf(new Quantity(9456n, 3n), aoCredToken);
Parse a quantity from a string:
aoCredToken.Quantity.fromString("256.8");
Parse a quantity from a JS number:
aoCredToken.Quantity.fromNumber(256.8);
Get the stringified quantity:
const qty = aoCredToken.Quantity.fromNumber(74.089);
// prints "74.089"
console.log(qty.toString());
Print formatted string according to the provided/default locale:
const qty = aoCredToken.Quantity.fromNumber(1474.089);
// prints "1,474.089"
console.log(qty.toString());
Get JS native floating point value held in a quantity. This can cause precision loss:
qty.toNumber();
Clone the Quantity
instance. This will keep the same value and denomination:
// 1.2 with 1 as the denomination
const qty = new Quantity(12n, 1n);
const qty2 = qty.clone();
qty2.fromNumber(4);
// prints "1.2"
console.log("qty is", qty.toString());
// prints "4"
console.log("qty2 is", qty2.toString());
These functions have both static and non-static implementations. Static implementations will always start with two "_
" and create new Quantity
instances. Non-static implementations start with one "_
" and modify themselves (the instances they are associated with). Calling static functions with tokens of different denominations will cause the result to have the higher denomination by default. Non-static functions (that are modified in-place) keep their denominations, but might lose precision in doing so.
eq()
: Check if two quantities are equallt()
: Check if the first quantity is less than the secondle()
: Check if the first quantity is less or equal than the second_add()
and__add
: Add together two quantities_sub()
and__sub
: Subtract one quantity from another_mul()
and__mul()
: Multiply two quantities_div()
and__div()
: Divide one quantity by another_pow()
and__pow()
: Raise one quantity to the power of an integer_mod()
and__mod()
: Get the remainder of the division of one quantity by another_neg()
and__neg()
: Get the negation of a quantity_abs()
and__abs()
: Get the absolute value of a quantity_trunc()
and__trunc()
: Truncate a quantity_floor()
and__floor()
: Round down a quantity_ceil()
and__ceil()
: Round up a quantity
_one()
and__one()
: Shortcut to "1" according to the denomination_convert()
and__convert()
: Convert to a different denominationsameDenomination()
: Ensure that the provided quantities all have the same denomination. Returns an array of quantities converted to the largest denomination from the provided quantities.min()
: Get the minimum of a list of quantitiesmax()
: Get the maximum of a list of quantities