Taquito
Integration in DApps
The Temple wallet, used in the DApps, integrates Taquito which is then used to interact with the smart contract.
The Taquito object is retrieved with a mecanism defined in the file /src/dapps.js
. All DApps use a global state managed with the constate library.
dapp.js
registers in the constate global state an accessor useTezos
, so that any module can retrieve it easily, without passing it down from root React element:
import { useTezos } from '../dapp';
const ReactComponent = (props) => {
const tezos = useTezos();
...
}
As a side note, here is the way to retrieve the account address (public key) the user has signed in with:
import { useAccountPkh } from '../dapp';
const ReactComponent = (props) => {
const account = useAccountPkh();
...
}
Note that the user account is managed by the Temple wallet, not by Taquito. The wallet internally passes the account's private key to Taquito to sign transactions.
Contract origination
Taquito originates contracts provided in the Micheline format, a json version of Michelson.
The Completium CLI command to generate Micheline from contract.arl
:
$ completium-cli generate javascript contract.arl > contract.js
The generated contract.js
file exports:
- the Micheline/Json
code
of the contract - the
getStorage
methode to build the initial storage
These two elements are passed to the Taquito's originate method:
import { code, getStorage } from 'contract.js';
try {
const operation = await tezos.wallet.originate({
code: code,
init: getStorage(...)
}).send();
console.log(`Waiting for confirmation of origination...`);
const contract = await operation.contract();
console.log(`Origination completed for ${contract.address}.`);
} catch (error) {
console.log(`Error: ${JSON.stringify(error, null, 2)}`);
}
Examples of contract origination are found is the following DApps:
DApp | Origination description |
---|---|
Online purchase | The escrow contract for payment is originated when customers decides to purchase. |
Zero-coupon-bond | The Zero-coupon bond contract is originated when contract parameters are set in the editor. |
Call contract
It is very straightforward to call contracts entry points with Taquito.
Basics
For example, the Idea Box DApp's smart contract, developed in Archetype language, defines an entry point vote
to vote for an idea:
entry vote(n : nat, weight : nat) {
require {
r2 : voter.contains(caller);
r3 : voter[caller].remaining >= weight;
r4 : state = Activated;
}
effect {
voter[caller].remaining -= weight;
idea[n].nbvotes += weight;
}
}
The entry point requires two natural integer parameters:
- the idea identifier
- the weight the user wishes to associate to the vote (max. 5)
The following code calls the vote
entry point:
const contract = await tezos.wallet.at(contractAddress);
const operation = await contract.methods.vote(id, weight).send();
console.log(`waiting for ${operation.opHash} to be confirmed`);
await operation.receipt();
Note that while the contract defines parameters as nat
(natural integers), the javascript type is simply integer
; Taquito emits an error if the conversion to Michelson type is not possible.
Typically here an error is emitted if -1
is passed as argument for example.
Transfer amount
Some entry points require to send an amount of tez for the contract to execute properly according to the business logic.
For example, the start
entry point of the Connected Object DApp requires to transfer some Tez to switch on the bulb. The amount is passed as argument of the send
method:
import { UnitValue } from '@taquito/taquito';
const contract = await tezos.wallet.at(contractAddress);
const operation = await contract.methods.start(UnitValue).send({ amount : price });
console.log(`waiting for ${operation.opHash} to be confirmed`);
await operation.receipt();
Note that UnitValue
is necessary to pass when the entry point does not have any argument.
The default amount unit is Tez. It is possible to pass Mutez (1 Tez = 10^6 Mutez) by adding mutez: true
to the send
argument.
Several Transactions
It is possible to execute several transactions in one operation.
For example in the DEX DApp, the exchange process requires calling two contracts: the FA 1.2 and the DEX. The following code illustrates how to execute that:
// FA 1.2 transaction definition
const fa12 = await tezos.wallet.at(fa12address);
const fa12params = fa12.methods.approve(UnitValue).toTransferParams();
fa12params.kind = OpKind.TRANSACTION;
// DEX transaction definition
const dex = await tezos.wallet.at(dexaddress);
const dexparams = dex.methods.exchange(UnitValue).toTransferParams();
dexparams.kind = OpKind.TRANSACTION;
// Group them in a batch operation and send
const batch = await tezos.wallet.batch([fa12params, dexparams]);
const operation = await batch.send();
await operation.receipt();
The parameters of approve
and exchange
have been simplified to UnitValue
for demo purpose.
Read contract storage
Variables
For example in the Connected Object DApp, it is necessary to read the dates of service to know whether the object is currently in use.
These variables are declared in the smart contract with the Archetype language:
variable dateofstop : date = now
variable dateofstart : date = now
variable value : int = 0tz
These values are stored in the contract storage (click here to view an instance in Better Call dev indexer).
Taquito provides the contract storage as a POJO for direct access to the contract data:
var contract = await tezos.contract.at(contractAddress);
var storage = await contract.storage();
const dateofstart = new Date(storage.dateofstart);
const dateofstop = new Date(storage.dateofstop);
const value = storage.value.toNumber();
Since Tezos can store arbitrary large number values, Taquito provides the number values as bignumber objects to be converted with toNumber
.
Collection of assets
For example in the the Idea Box DApp, the smart contract stores the idea and the votes.
The collection of ideas is declared in Archetype language the following way:
asset idea {
id : nat;
title : bytes;
desc : bytes;
nbvotes : nat = 0;
creation : date;
author : address;
}
The asset collection is compiled to a (Michelson) map from id
to a 'record' { title; desc; nbvotes; creation; author }
. It is possible to iterate over the map with the forEach operator:
var contract = await Tezos.contract.at(contractAddress);
var storage = await contract.storage();
storage.idea.forEach((i, k, _) => {
ids.push({
id: k,
title: fromHexString(i.title),
desc: fromHexString(i.desc),
author: i.author,
nbvotes: parseInt(i.nbvotes,10),
creation: (i.creation+'').substring(0,10),
winner: false
});
});
The code above stores each id in a local javascript list of records ids
. k
is the idea identifier (named id
in the Archetype contract).