← All news

Become a Taquito Power User

Use less known features of Taquito to bring your Tezos web dev skills to the next level

Become a Taquito Power User

Taquito is an amazing JavaScript library many Tezos developers use to create web applications. It allows you to easily connect your app to a wallet and to the blockchain to read data and send transactions.

However, most developers using Taquito only scratch the surface of all the features offered by the library. While it caters to the most simple needs of the Tezos developers, like reading contract storages and forging transactions, it is also a great tool to add to your belt if you want to take your skills to the next level and build more complex dapps. It can make your dapp faster, more secure, and more efficient.

This article is better suited for JavaScript/TypeScript developers who already know/use Taquito. You will find many features of Taquito that only power users know and use. These features are present in different packages of the Taquito library and you will be only one import away from an awesome dapp on Tezos!

Although you may legitimately think twice before importing yet another package to your app, Taquito uses the @taquito/utils and @taquito/rpc packages under the hood, they are already installed, so why not using them to their fullest extent?!

Using the @taquito/taquito package

The taquito package is probably the package you are the most familiar with, all awesome Tezos web apps start with new TezosToolkit(...) 😎

Outside of its basic features, the taquito package offers many other tools you can use, whether you are dealing with bigmaps or transactions. Here are some of the most interesting ones:

Bigmap local packing

Bigmap keys need to be serialized (or packed) before being used to search a bigmap. By default, Taquito uses the PACK feature of the RPC node to do it, which creates a new HTTP request. However, you can use the MichelCodecPacker class to have Taquito pack your bigmap keys locally, which will increase the speed of your app by 50%:

_import_ { MichelCodecPacker } _from_ "@taquito/taquito";
_const_ Tezos = _new_ TezosToolkit(RPC_URL);
Tezos.setPackerProvider(_new_ MichelCodecPacker());

Bigmap multiple searches

You may have to search for different keys in the same bigmap, for example, if you are retrieving the NFTs owned by an address with their ids. Looking for the keys one by one is a tedious process, this is why you can use the getMultipleValues properties available on every BigMapAbstraction to get multiple values in one call. Here is how you can get multiple ids in a bigmap:

const contract = await Tezos.wallet.at(VALID_CONTRACT_ADDRESS);
const storage = await contract.storage();
const NFTs = 
    await storage.token_metadata.getMultipleValues([3, 5, 41, 68]);
NFTs.forEach((key, value) => {
    // key is the bigmap key
    // value is the bigmap value
});

Batching operations

There are more and more use cases in dapps that require users to send multiple operations in a predefined order and in a single transaction. For example, you have a smart contract handling users’ tokens and you want the user to approve your smart contract first. It would be a waste of time to send the first transaction to approve the contract, wait 60 seconds for the transaction to be included in a block, send the second transaction and wait another 60 seconds (or even longer).

In this case, you can batch operations together in order to send one single transaction. Include the operations in the order you want them to be run and use the Batch API to forge the transaction:

c_onst_ contract = _await_ Tezos.wallet.at(VALID_CONTRACT_ADDRESS);
_const_ batch = _await_ Tezos.wallet.batch()
    .withContractCall(contract.methods.approve(address, value))
    .withContractCall(contract.methods.transfer(...));
const batchOp = await batch.send();

Operation status

After sending a transaction to a contract, you probably want to know if everything worked as expected. During high-peak periods, it is not uncommon to see transactions fail or backtrack. By default, Taquito doesn’t warn you when it happens, but you can still use it to make sure the transaction went through. The operation returned by the contract call includes a method called status that you can use to get the status of the operation (make sure to call it after calling confirmation). It can return 6 different values: pending, unknown, applied, failed, skipped and backtracked. Needless to say, only applied is good news 😄:

try {
    c_onst_ contract = _await_ Tezos.wallet.at(VALID_CONTRACT_ADDRESS);
    const op = await contract.methods.transfer(...).send();
    await op.confirmation();
    if(await op.status() === "applied") {
        console.log("Success!");
    } else {
        throw `Transaction error: ${await op.status()}`;
    }
} catch (error) {
    console.log(error);
}

Using the @taquito/utils package

The [@taquito/utils](http://twitter.com/taquito/utils) package is an often overlooked package that offers many useful functions that are also used by the main Taquito package. These functions allow you to validate, transform and manipulate data to make your dapp more efficient and more secure. Here are a few of these functions:

Validation functions

The package exposes a few validation functions that you can use to validate different types of data used by the Tezos blockchain. For example, you can use validatePublicKey to verify that a string is a valid implicit account key, validateContractAddress to verify that an address is a valid address for a contract, validateSignature to verify whether a signature is valid, etc. These functions become even more useful when your dapp accepts addresses as inputs from users to sanitize them.

bytes2Char/char2Bytes

More and more contracts on-chain use bytes to store data, often because they allow you to store UTF-8 encoded characters, which Michelson doesn’t natively support. For example, FA2 contracts (i.e NFT and token contracts) store bytes in the token metadata.

When you have to read bytes from a contract or store bytes through an entrypoint call, it can be complicated to implement your own encoder/decoder for bytes. Fortunately, the utils package exposes two functions, bytes2Char and char2Bytes, that you can use to decode or encode bytes respectively. Now, you don’t have to search Stackoverflow for hours, looking for that kind of function!

const jsonToStore = `{"hello":"world","foo":"bar"}`;const encodedBytes = char2Bytes(jsonToStore);
// 7b2268656c6c6f223a22776f726c64222c22666f6f223a22626172227dconst decodedBytes = bytes2Char(encodedBytes);

Using the @taquito/rpc package

The @taquito/rpc package is probably the least-known of Taquito available packages but it allows you to send queries directly to the Tezos node and request data. The package is also part of the underlying cogs of theTezosToolkit class, so it is there and waiting for you!

In many cases, the rpc package can save you a request to an indexer and delegate the task of getting details from the node to your user instead of overloading an indexer API. Here is a list of the most useful methods of this package that you probably didn’t even know existed!

  • getBlock => returns the head of the chain by default or a specific block if an id is provided (useful, for instance, to get the current level):
import { RpcClient } from "@taquito/rpc";
const rpcClient = new RpcClient(RPC_URL);
const block = await rpcClient.getBlock();
  • getDelegate => returns the delegate of a contract, if any:
import { RpcClient } from "@taquito/rpc";
const rpcClient = new RpcClient(RPC_URL);
const delegate = await rpcClient.getDelegate(CONTRACT_ADDRESS);
  • getScript => returns the code of the contract:
import { RpcClient } from "@taquito/rpc";
const rpcClient = new RpcClient(RPC_URL);
const michelsonCode = await rpcClient.getCode(CONTRACT_ADDRESS);
  • packData => uses the PACK function of the node to serialize arbitrary data:
import { RpcClient } from "@taquito/rpc";
const rpcClient = new RpcClient(RPC_URL);
const data = { data: { string: "test" }, type: { prim: "string" } };
const packedData = await rpcClient.packData(data);