Skip to main content

Tokens support

This tutorial explains how =nil; handles tokens and multi-token operations.

Definition

=nil; supplies a basic 'default' token (NIL).

The network also has a multi-token mechanism. All accounts (smart contracts) can be paid in any number of arbitrary tokens created either by the account owner or other accounts.

info

While custom tokens can be transferred between accounts, they cannot be used for paying for essential functionalities of =nil; such as deploying contracts or sending async calls.

info

A contract can only be the owner of one token. While non-owners can transfer different tokens between accounts, they cannot mint any tokens that they do not own.

Usage

Via the CLI

To create a new token and withdraw it to the address of the owner:

nil minter create-token OWNER_ADDRESS AMOUNT NAME 
nil minter withdraw-token OWNER_ADDRESS AMOUNT OWNER_ADDRESS 

To mint an existing token (which automatically withdraws it to the owner):

nil minter mint-token OWNER_ADDRESS 50000 

To burn an existing token (the supply is automatically reduced at the address of the owner):

nil minter burn-token OWNER_ADDRESS AMOUNT 

Via the client library

To create a new token and withdraw it:

const client = new PublicClient({
transport: new HttpTransport({
endpoint: RPC_ENDPOINT,
}),
shardId: 1,
});

const wallet = await generateWallet({
shardId: 1,
rpcEndpoint: RPC_ENDPOINT,
faucetEndpoint: FAUCET_ENDPOINT,
});

{
const hashMessage = await wallet.setTokenName("MY_TOKEN");
await waitTillCompleted(client, hashMessage);
}

{
const hashMessage = await wallet.mintToken(100_000_000n);
await waitTillCompleted(client, hashMessage);
}

To burn an existing token:

{
const hashMessage = await wallet.burnToken(50_000_000n);
await waitTillCompleted(client, hashMessage);
}

Example

This example creates a wallet that stores three tokens: the default token, and two custom tokens.

Create two new wallets:

const client = new PublicClient({
transport: new HttpTransport({
endpoint: RPC_ENDPOINT,
}),
shardId: 1,
});

const wallet = await generateWallet({
shardId: 1,
rpcEndpoint: RPC_ENDPOINT,
faucetEndpoint: FAUCET_ENDPOINT,
});
const walletTwo = await generateWallet({
shardId: 1,
rpcEndpoint: RPC_ENDPOINT,
faucetEndpoint: FAUCET_ENDPOINT,
});

{
const hashMessage = await wallet.setTokenName("MY_TOKEN");
await waitTillCompleted(client, hashMessage);
}

{
const hashMessage = await walletTwo.setTokenName("ANOTHER_TOKEN");
await waitTillCompleted(client, hashMessage);
}

Create a new token for Wallet 1 and withdraw it:

{
const hashMessage = await wallet.mintToken(100_000_000n);
await waitTillCompleted(client, hashMessage);
}

{
const hashMessage = await walletTwo.mintToken(50_000_000n);
await waitTillCompleted(client, hashMessage);
}

Create a new token for Wallet 2 and send it to Wallet 1:

const transferMessage = walletTwo.sendMessage({
to: wallet.address,
value: 1_000_000n,
feeCredit: 5_000_000n,
tokens: [
{
id: walletTwo.address,
amount: 50_000_000n,
},
],
});
const tokens = await client.getTokens(wallet.address, "latest");

Token faucet service

The token faucet is a special service whose main purpose is to distribute default cluster tokens (NIL) that are used to pay for contract deployment and message execution. In addition, the faucet also distributes various pre-set 'mock' tokens such as USDC and BTC.

Each token faucet resides at a different address. To withdraw a specific token, simply call the corresponding address using the faucet_TopUpViaFaucet method.

Usage

Via JSON-RPC API

The faucet service resides at the http://api.devnet.nil.foundation/api/faucet/${USERNAME}/${TOKEN} endpoint.

To see all active faucets:

curl -X POST http://api.devnet.nil.foundation/api/faucet/${USERNAME}/${TOKEN} \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 0, "method": "faucet_getFaucets", "params": []}'

Expected response:

{
"jsonrpc":"2.0",
"id":0,
"result":{
"BTC":"0x0001111111111111111111111111111111111114",
"ETH":"0x0001111111111111111111111111111111111112",
"NIL":"0x000100000000000000000000000000000fa00ce7",
"USDT":"0x0001111111111111111111111111111111111113"}
}

To withdraw from a faucet:

curl -X POST http://api.devnet.nil.foundation/api/${USERNAME}/${TOKEN} \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 0, "method": "faucet_topUpViaFaucet", "params": ["$FAUCET_ADDRESS", "$WALLET_ADDRESS", $AMOUNT]}'

Expected output:

{
"jsonrpc":"2.0",
"id":0,
"result": HASH
}

Via the client library

tip

Refer to the Codebook for ready-made canonical examples on using the faucet service.

Nil.js offers several 'helper' wrappers designed to simplify work with the faucet service.

To create a new faucet client:

const faucetClient = new FaucetClient({
transport: new HttpTransport({
endpoint: FAUCET_ENDPOINT,
}),
});

To request a list of all faucets:

const faucets = await faucetClient.getAllFaucets();

To request tokens from a faucet:

await faucetClient.topUpAndWaitUntilCompletion({
walletAddress: WALLET_ADDRESS,
faucetAddress: FAUCET_ADDRESS,
amount: AMOUNT,
});

Via the =nil; CLI

Refer to the =nil; CLI usage guide to set up the faucet service with this tool.