Skip to main content

Tokens and multi-currency support

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

Definition

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

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

info

While custom currencies 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 currency. While non-owners can transfer different currencies between accounts, they cannot mint any currencies that they do not own.

Usage

Via the CLI

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

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

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

nil minter mint-currency OWNER_ADDRESS 50000 

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

nil minter burn-currency OWNER_ADDRESS AMOUNT 

Via the client library

To create a new currency and withdraw it:

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

const faucet = new Faucet(client);

const signer = new LocalECDSAKeySigner({
privateKey: generateRandomPrivateKey(),
});

const pubkey = signer.getPublicKey();
const wallet = new WalletV1({
pubkey: pubkey,
salt: BigInt(Math.floor(Math.random() * 10000)),
shardId: 1,
client,
signer,
});

const walletAddress = wallet.address;

const faucetHash = await faucet.withdrawToWithRetry(walletAddress, convertEthToWei(1));

await wallet.selfDeploy(true);

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

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

To burn an existing currency:

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

Example

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

Create two new wallets:

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

const faucet = new Faucet(client);

const signer = new LocalECDSAKeySigner({
privateKey: generateRandomPrivateKey(),
});

const pubkey = signer.getPublicKey();

const wallet = new WalletV1({
pubkey: pubkey,
salt: BigInt(Math.floor(Math.random() * 10000)),
shardId: 1,
client,
signer,
});

const walletAddress = wallet.address;

const faucetHash = await faucet.withdrawToWithRetry(walletAddress, convertEthToWei(1));

await waitTillCompleted(client, faucetHash);

await wallet.selfDeploy(true);

const walletTwo = new WalletV1({
pubkey: pubkey,
salt: BigInt(Math.floor(Math.random() * 10000)),
shardId: 1,
client,
signer,
});

const walletTwoAddress = walletTwo.address;

const faucetTwoHash = await faucet.withdrawToWithRetry(walletTwoAddress, convertEthToWei(1));

await walletTwo.selfDeploy(true);

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

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

Create a new currency for Wallet 1 and withdraw it:

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

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

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

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

Currency faucet service

The currency 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' currencies such as USDC and BTC.

Each currency faucet resides at a different address. To withdraw a specific currency, 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: RPC_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.