---
id: dev-keys-zrc2-wallet-support
title: ZRC-2 Wallet Support
keywords:
  - key management
  - zrc2
  - wallet
  - support
  - token
  - fungible
  - zilliqa
description: Integrating ZRC-2 Fungible Tokens Support into Wallets and dApps
---

---

This guide is meant for wallet developers looking to add support for [ZRC-2 tokens](https://github.com/Zilliqa/ZRC/blob/master/zrcs/zrc-2.md) in their wallet.
Since most of the wallet front-ends are built using a JavaScript framework, most developers would find the code found in the `js` tab to be relevant to them. We have included code snippets for some other languages as well in case you want to handle these functionalities
at the backend.

:::note
It is assumed that you have already installed language-specific Zilliqa SDKs, e.g., zilliqa-js, laksaj, pyzil, gozilliqa.
:::

## Introduction to ZRC-2

[ZRC-2](https://github.com/Zilliqa/ZRC/blob/master/zrcs/zrc-2.md) is the formal standard for Fungible Token in Zilliqa. It is an open standard for creating currencies on the Zilliqa blockchain.

The ZRC-2 standard allows for functionalities like

- Minting/burning tokens
- Transferring tokens from one account to another
- Querying account token balance
- Querying total token balances
- Approving third party to spend a certain amount of tokens
- Etc.

## Examples of ZRC-2

- [$XSGD](https://www.xfers.com/) - the first Singapore dollar-pegged stablecoin built by [Xfers](https://www.xfers.com/)
- [$gZIL](https://github.com/Zilliqa/ZIP/blob/master/zips/zip-11.md#governance-tokens-aka-gzil) - Governance ZIL token earned through Zilliqa Seed Node Staking Program

## Getting Testnet ZRC-2 Tokens

- [$XSGD faucet](https://faucet.xfers.com/) by Xfers
- [Stake testnet $ZIL and earn testnet $gZIL](https://testnet-stake.zilliqa.com/)

## ZRC-2 Specification

ZRC-2 fungible tokens contract consists of the following components in smart contracts as per the [specification](https://github.com/Zilliqa/ZRC/blob/master/zrcs/zrc-2.md#iv-specification).

### Error Codes

| Name                        | Type    | Code | Mandatory?                            |
| --------------------------- | ------- | ---- | ------------------------------------- |
| `CodeIsSender`              | `Int32` | `-1` | <center> :heavy_check_mark: </center> |
| `CodeInsufficientFunds`     | `Int32` | `-2` | <center> :heavy_check_mark: </center> |
| `CodeInsufficientAllowance` | `Int32` | `-3` | <center> :heavy_check_mark: </center> |
| `CodeNotOwner`              | `Int32` | `-4` | <center> :x: </center>                |
| `CodeNotApprovedOperator`   | `Int32` | `-5` | <center> :x: </center>                |

### Immutable Variables

| Name                | Type           | Mandatory?                            |
| ------------------- | -------------- | ------------------------------------- |
| `contract_owner`    | `ByStr20`      | <center> :heavy_check_mark: </center> |
| `name`              | `String`       | <center> :heavy_check_mark: </center> |
| `symbol`            | `String`       | <center> :heavy_check_mark: </center> |
| `decimals`          | `Uint32`       | <center> :heavy_check_mark: </center> |
| `init_supply`       | `Uint128`      | <center> :heavy_check_mark: </center> |
| `default_operators` | `List ByStr20` | <center> :x: </center>                |

### Mutable Variables

| Name                        | Type                                | Mandatory?                            |
| --------------------------- | ----------------------------------- | ------------------------------------- |
| `total_supply`              | `Uint128`                           | <center> :heavy_check_mark: </center> |
| `balances`                  | `Map ByStr20 Uint128`               | <center> :heavy_check_mark: </center> |
| `allowances`                | `Map ByStr20 (Map ByStr20 Uint128)` | <center> :heavy_check_mark: </center> |
| `operators`                 | `Map ByStr20 (Map ByStr20 Unit)`    | <center> :x: </center>                |
| `revoked_default_operators` | `Map ByStr20 (Map ByStr20 Unit)`    | <center> :x: </center>                |

### Transitions and Events

| Name                  | Events                              | Mandatory?                            |
| --------------------- | ----------------------------------- | ------------------------------------- |
| `IsOperatorFor()`     |                                     | <center> :x: </center>                |
| `Mint()`              | `Minted`, `Error`                   | <center> :x: </center>                |
| `Burn()`              | `Burnt`, `Error`                    | <center> :x: </center>                |
| `AuthorizeOperator()` | `AuthorizeOperatorSuccess`, `Error` | <center> :x: </center>                |
| `RevokeOperator()`    | `RevokeOperatorSuccess`, `Error`    | <center> :x: </center>                |
| `IncreaseAllowance()` | `IncreasedAllowance`, `Error`       | <center> :heavy_check_mark: </center> |
| `DecreaseAllowance()` | `DecreasedAllowance`, `Error`       | <center> :heavy_check_mark: </center> |
| `Transfer()`          | `TransferSuccess`, `Error`          | <center> :heavy_check_mark: </center> |
| `TransferFrom()`      | `TransferFromSuccess`, `Error`      | <center> :heavy_check_mark: </center> |
| `OperatorSend()`      | `OperatorSendSuccess`, `Error`      | <center> :x: </center>                |

## Checking if Contract is Compliant with ZRC-2 Standard

In order to check if the address entered by the user is a ZRC-2 compliant contract, we need to look at the contract code and check if it has the required properties.

### Check Immutable Variables

For immutable variables, we'll use the `GetSmartContractInit` method of the Zilliqa API to get the immutable variables of the contract.
The address of the ZRC-2 contract referred below is `0x173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5`.

#### Example Request

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

<Tabs
  defaultValue="cURL"
  values={[
    { label: 'cURL', value: 'cURL', },
    { label: 'js', value: 'js', },
    { label: 'java', value: 'java', },
    { label: 'python', value: 'python', },
    { label: 'go', value: 'go', },
  ]
}>

<TabItem value="cURL">

```shell
curl -d '{
    "id": "1",
    "jsonrpc": "2.0",
    "method": "GetSmartContractInit",
    "params": ["173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5"]
}' -H "Content-Type: application/json" -X POST "https://api.zilliqa.com/"
```

</TabItem>
<TabItem value="js">

```js
const smartContractInit = await zilliqa.blockchain.getSmartContractInit(
  "173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5"
);
console.log(smartContractInit.result);
```

</TabItem>
<TabItem value="java">

```java
public class App {
    public static void main(String[] args) throws IOException {
        HttpProvider client = new HttpProvider("https://api.zilliqa.com");
        Rep<List<Contract.State>> smartContractInit = client.getSmartContractInit("173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5");
        System.out.println(new Gson().toJson(smartContractInit));
    }
}
```

</TabItem>

<TabItem value="python">

```python
from pyzil.zilliqa import chain
chain.set_active_chain(chain.MainNet)
print(chain.active_chain.api.GetSmartContractInit("173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5"))
```

</TabItem>

<TabItem value="go">

```go
func GetSmartContractInit() {
	provider := NewProvider("https://api.zilliqa.com/")
	response := provider.GetSmartContractInit("173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5")
	result, _ := json.Marshal(response)
	fmt.Println(string(result))
}
```

</TabItem>
</Tabs>

#### Example Response

```json
{
  "id": "1",
  "jsonrpc": "2.0",
  "result": [
    {
      "type": "Uint32",
      "value": "0",
      "vname": "_scilla_version"
    },
    {
      "type": "ByStr20",
      "value": "0x0f8167a0CBFfb8AB1d1919E31f83DC26C863D0F9",
      "vname": "contract_owner"
    },
    {
      "type": "String",
      "value": "XSGD",
      "vname": "name"
    },
    {
      "type": "String",
      "value": "XSGD",
      "vname": "symbol"
    },
    {
      "type": "Uint32",
      "value": "6",
      "vname": "decimals"
    },
    {
      "type": "Uint128",
      "value": "0",
      "vname": "init_supply"
    },
    {
      "type": "ByStr20",
      "value": "0x0f8167a0CBFfb8AB1d1919E31f83DC26C863D0F9",
      "vname": "init_implementation"
    },
    {
      "type": "ByStr20",
      "value": "0x0f8167a0CBFfb8AB1d1919E31f83DC26C863D0F9",
      "vname": "init_admin"
    },
    {
      "type": "BNum",
      "value": "732529",
      "vname": "_creation_block"
    },
    {
      "type": "ByStr20",
      "value": "0x173ca6770aa56eb00511dac8e6e13b3d7f16a5a5",
      "vname": "_this_address"
    }
  ]
}
```

The response received consists of the `type`, `value`, and `vname` for each immutable variable.

To check whether a contract is compliant with the ZRC-2 standard's immutable variables requirement, see if the contract implements the [mandatory immutable variables](#immutable-variables).

:::note
This code snippet is in JavaScript but the same logic can be applied in other languages.
:::

```js
let vNameArray = []; //Array to store immutable variable names
for (let i = 0; i < smartContractInit.result.length; i++) {
  vNameArray[i] = smartContractInit.result[i].vname;
}
//check if the immutable variables: name, symbol, decimals & init_supply exist in the vName array.
let isZRC2 =
  vNameArray.includes("name") &&
  vNameArray.includes("symbol") &&
  vNameArray.includes("decimals") &&
  vNameArray.includes("init_supply");

console.log(isZRC2);
```

### Check Mutable Variables

For mutable variables, we'll use the `GetSmartContractState` method of the Zilliqa API to get the mutable variables of the contract.
The address of the ZRC2 contract referred below is `0x173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5`.

#### Example Request

<Tabs
  defaultValue="cURL"
  values={[
    { label: 'cURL', value: 'cURL', },
    { label: 'js', value: 'js', },
    { label: 'java', value: 'java', },
    { label: 'python', value: 'python', },
    { label: 'go', value: 'go', },
  ]
}>

<TabItem value="cURL">

```shell
curl -d '{
    "id": "1",
    "jsonrpc": "2.0",
    "method": "GetSmartContractState",
    "params": ["173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5"]
}' -H "Content-Type: application/json" -X POST "https://api.zilliqa.com/"
```

</TabItem>
<TabItem value="js">

```js
const smartContractState = await zilliqa.blockchain.getSmartContractState(
  "173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5"
);
console.log(smartContractState.result);
```

</TabItem>
<TabItem value="java">

```java
public class App {
    public static void main(String[] args) throws IOException {
        HttpProvider client = new HttpProvider("https://api.zilliqa.com");
        String smartContractState = client.getSmartContractState("173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5");
        System.out.println(smartContractState);
    }
}
```

</TabItem>

<TabItem value="python">

```python
from pyzil.zilliqa import chain
chain.set_active_chain(chain.MainNet)
print(chain.active_chain.api.GetSmartContractState("173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5"))
```

</TabItem>

<TabItem value="go">

```go
func GetSmartContractState() {
	provider := NewProvider("https://api.zilliqa.com/")
	response := provider.GetSmartContractState("173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5")
	result, _ := json.Marshal(response)
	fmt.Println(string(result))
}
```

</TabItem>
</Tabs>

#### Example Response

```json
{
  "id": "1",
  "jsonrpc": "2.0",
  "result": {
    "_balance": "0",
    "admin": "0x2f604cbd408e2c8b7442b1b629a1288c44945130",
    "allowances": {},
    "balances": {
      "0x05d087623bc636108d450e0550ddbfc03da99fa9": "10000000",
      "0x0f8167a0cbffb8ab1d1919e31f83dc26c863d0f9": "24250000",
      "0x18c241a5f0d6cf380f721618880f2c2b7aa5ea97": "9975750000",
      "0x5abf71d798ca594b7317b04f52ad5a31fae62170": "10000000",
      "0x8c3de413a9d8d602a1757210ab539853103e08d8": "250000000000",
      "0x93eb1d0cb7ba3962fcc86cd28aa45b241c888277": "20000",
      "0xab61c57a9a4b2742a4a325ecd9e77b5da67f663a": "980000",
      "0xabe1e844c776e97beb619f3ca64faa2b3edc2840": "400000",
      "0xc48565c853fe4ffa5d7eac33e255141134640ceb": "600000",
      "0xf5f9e1ad8ea6439f625e12b8ef57e1e99ac2d383": "7000000"
    },
    "implementation": "0x3bd9ad6fee7bfdf5b5875828b555e4f702e427cd",
    "total_supply": "260029000000"
  }
}
```

The response received above consists of the mutable variables `total_supply`, `balances`, and `allowances`.

To check whether a contract is compliant with the ZRC-2 standard's mutable variables requirement, see if the contract implements the [mandatory mutable variables](#mutable-variables).

:::note
This code snippet is in JavaScript but the same logic can be applied in other languages.
:::

```js
let vNameArray = []; //Array to store mutable variable names
for (let i = 0; i < smartContractState.result.length; i++) {
  vNameArray[i] = smartContractState.result[i].vname;
}
//check if the mutable variables: total_supply, balances & allowances exist in the vName array.
let isZRC2 =
  vNameArray.includes("total_supply") &&
  vNameArray.includes("balances") &&
  vNameArray.includes("allowances");

console.log(isZRC2);
```

### Check Transitions, Events, and Error Codes

Currently, you need to look at the smart contract code manually and check for transitions, events, and error codes in a contract. To check whether a contract is compliant with the ZRC-2 standard's error codes - as well transitions and events - requirement, see if the contract implements the [mandatory error codes](#error-codes) and [mandatory transitions and events](#transitions-and-events).

## Integrating with ZRC-2 Fungible Tokens Contract

### Fetch Token Supply

In a ZRC-2 fungible tokens contract, the mutable field `total_supply` stores the value of the current total supply.
We'll use the `GetSmartContractState` method of the Zilliqa API to get the mutable variables of the contract.
The address of the ZRC-2 contract referred below is `0x173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5`.

#### Example Request

<Tabs
  defaultValue="cURL"
  values={[
    { label: 'cURL', value: 'cURL', },
    { label: 'js', value: 'js', },
    { label: 'java', value: 'java', },
    { label: 'python', value: 'python', },
    { label: 'go', value: 'go', },
  ]
}>

<TabItem value="cURL">

```shell
curl -d '{
    "id": "1",
    "jsonrpc": "2.0",
    "method": "GetSmartContractState",
    "params": ["173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5"]
}' -H "Content-Type: application/json" -X POST "https://api.zilliqa.com/"
```

</TabItem>
<TabItem value="js">

```js
const smartContractState = await zilliqa.blockchain.getSmartContractState(
  "173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5"
);
console.log(smartContractState.result);
```

</TabItem>
<TabItem value="java">

```java
public class App {
    public static void main(String[] args) throws IOException {
        HttpProvider client = new HttpProvider("https://api.zilliqa.com");
        String smartContractState = client.getSmartContractState("173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5");
        System.out.println(smartContractState);
    }
}
```

</TabItem>

<TabItem value="python">

```python
from pyzil.zilliqa import chain
chain.set_active_chain(chain.MainNet)
print(chain.active_chain.api.GetSmartContractState("173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5"))
```

</TabItem>

<TabItem value="go">

```go
func GetSmartContractState() {
	provider := NewProvider("https://api.zilliqa.com/")
	response := provider.GetSmartContractState("173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5")
	result, _ := json.Marshal(response)
	fmt.Println(string(result))
}
```

</TabItem>
</Tabs>

#### Example Response

```json
{
  "id": "1",
  "jsonrpc": "2.0",
  "result": {
    "balances": {
      "0x00034c431f642dfca0129694061263d72049a909": "1033606"
    }
  }
}
```

If the response json received above is stored in the variable `smartContractState`, total supply would then be:

```js
let smartContractState = await zilliqa.blockchain.getSmartContractState(
  contractAddress
);
let totalSupply = smartContractState.result.total_supply; // Total Supply
```

### Fetch Token Balance

In a ZRC-2 fungible tokens contract, the mutable field `balances` (with data type `Map`) stores the mapping between addresses and their
corresponding token balances. We'll use the `GetSmartContractState` method of the Zilliqa API to get the mutable variables of the contract.
The address of the ZRC-2 contract referred below is `0x173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5`.

#### Example Request

<Tabs
  defaultValue="cURL"
  values={[
    { label: 'cURL', value: 'cURL', },
    { label: 'js', value: 'js', },
    { label: 'java', value: 'java', },
    { label: 'python', value: 'python', },
    { label: 'go', value: 'go', },
  ]
}>

<TabItem value="cURL">

```shell
curl -d '{
    "id": "1",
    "jsonrpc": "2.0",
    "method": "GetSmartContractState",
    "params": ["173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5"]
}' -H "Content-Type: application/json" -X POST "https://api.zilliqa.com/"
```

</TabItem>
<TabItem value="js">

```js
const smartContractState = await zilliqa.blockchain.getSmartContractState(
  "173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5"
);
console.log(smartContractState.result);
```

</TabItem>
<TabItem value="java">

```java
public class App {
    public static void main(String[] args) throws IOException {
        HttpProvider client = new HttpProvider("https://api.zilliqa.com");
        String smartContractState = client.getSmartContractState("173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5");
        System.out.println(smartContractState);
    }
}
```

</TabItem>

<TabItem value="python">

```python
from pyzil.zilliqa import chain
chain.set_active_chain(chain.MainNet)
print(chain.active_chain.api.GetSmartContractState("173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5"))
```

</TabItem>

<TabItem value="go">

```go
func GetSmartContractState() {
	provider := NewProvider("https://api.zilliqa.com/")
	response := provider.GetSmartContractState("173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5")
	result, _ := json.Marshal(response)
	fmt.Println(string(result))
}
```

</TabItem>
</Tabs>

#### Example Response

```json
{
  "id": "1",
  "jsonrpc": "2.0",
  "result": {
    "_balance": "0",
    "admin": "0x2f604cbd408e2c8b7442b1b629a1288c44945130",
    "allowances": {},
    "balances": {
      "0x05d087623bc636108d450e0550ddbfc03da99fa9": "10000000",
      "0x0f8167a0cbffb8ab1d1919e31f83dc26c863d0f9": "24250000",
      "0x18c241a5f0d6cf380f721618880f2c2b7aa5ea97": "9975750000",
      "0x5abf71d798ca594b7317b04f52ad5a31fae62170": "10000000",
      "0x8c3de413a9d8d602a1757210ab539853103e08d8": "250000000000",
      "0x93eb1d0cb7ba3962fcc86cd28aa45b241c888277": "20000",
      "0xab61c57a9a4b2742a4a325ecd9e77b5da67f663a": "980000",
      "0xabe1e844c776e97beb619f3ca64faa2b3edc2840": "400000",
      "0xc48565c853fe4ffa5d7eac33e255141134640ceb": "600000",
      "0xf5f9e1ad8ea6439f625e12b8ef57e1e99ac2d383": "7000000"
    },
    "implementation": "0x3bd9ad6fee7bfdf5b5875828b555e4f702e427cd",
    "total_supply": "260029000000"
  }
}
```

### Fetch Token Balance For A Single Key

If the need to fetch a single token value from the `balances` map arises. Instead of requesting the whole map state over the network, using `getSmartContractSubState` is the most efficent method to use when you don't need to fetch the whole map. It returns one value per key, instead of the entire map. Allowing for quicker response times when only certain key values are required to be fetched.

#### Example Request

<Tabs
  defaultValue="cURL"
  values={[
    { label: 'cURL', value: 'cURL', },
    { label: 'js', value: 'js', },
  ]
}>

<TabItem value="cURL">

```shell
curl -d '{
    "id": "1",
    "jsonrpc": "2.0",
    "method": "GetSmartContractSubState",
    "params": ["173ca6770aa56eb00511dac8e6e13b3d7f16a5a5", "balances", ["0x00034c431f642dfca0129694061263d72049a909, ..."] ]
}' -H "Content-Type: application/json" -X POST "https://api.zilliqa.com/"
```

</TabItem>
<TabItem value="js">

```js
const smartContractState = await zilliqa.blockchain.getSmartContractSubState(
  "173Ca6770Aa56EB00511Dac8e6E13B3D7f16a5a5",
  "balances",
  ["0x8c3de413a9d8d602a1757210ab539853103e08d8, ..."]
);
console.log(smartContractState.result);
```

</TabItem>

</Tabs>

#### Example Response

```json
{
  "id": "1",
  "jsonrpc": "2.0",
  "result": {
      "0x8c3de413a9d8d602a1757210ab539853103e08d8": "250000000000",
      ...
  }
}
```

### Transfer Token

ZRC-2 contracts have the `transfer` transition that allows users to transfer tokens to another address by specifying the receiving address and amount.

The code snippet below illustrates how one can transfer ZRC-2 tokens to another address.

<Tabs
  defaultValue="js"
  values={[
    { label: 'js', value: 'js', },
    { label: 'java', value: 'java', },
    { label: 'go', value: 'go', },
  ]
}>

<TabItem value="js">

```js
//zilliqa, privateKey, bytes, units, recipientAddress, sendingAmount are defined in the codebase before

zilliqa.wallet.addByPrivateKey(privateKey);
const CHAIN_ID = 1;
const MSG_VERSION = 1;
const VERSION = bytes.pack(CHAIN_ID, MSG_VERSION);
const myGasPrice = units.toQa("1000", units.Units.Li); // Gas Price that will be used by all transactions
try {
  const contract = zilliqa.contracts.at(contractAddress);
  const callTx = await contract.call(
    "Transfer",
    [
      {
        vname: "to",
        type: "ByStr20",
        value: recipientAddress,
      },
      {
        vname: "amount",
        type: "Uint128",
        value: sendingAmount,
      },
    ],
    {
      // amount, gasPrice and gasLimit must be explicitly provided
      version: VERSION,
      amount: new BN(0),
      gasPrice: myGasPrice,
      gasLimit: Long.fromNumber(10000),
    }
  );
  console.log(JSON.stringify(callTx.TranID));
} catch (err) {
  console.log(err);
}
```

</TabItem>
<TabItem value="java">

```java
List<Value> init = Arrays.asList();
Wallet wallet = new Wallet();
wallet.addByPrivateKey(privateKey);
ContractFactory factory = ContractFactory.builder().provider(new HttpProvider("https://api.zilliqa.com/")).signer(wallet).build();
Contract contract = factory.atContract(contractAddress, "", (Value[]) init.toArray(), "");
Integer nonce = Integer.valueOf(factory.getProvider().getBalance(address).getResult().getNonce());
CallParams params = CallParams.builder().nonce(String.valueOf(nonce + 1)).version(String.valueOf(pack(333, 1))).gasPrice("1000000000").gasLimit("1000").senderPubKey(publicKey).amount("0").build();
List<Value> values = Arrays.asList(Value.builder().vname("to").type("ByStr20").value(recipientAddress).build(), Value.builder().vname("amount").type("Uint128").value("10").build());
contract.call("Transfer", (Value[]) values.toArray(), params, 3000, 3);

```

</TabItem>

<TabItem value="go">

```go
wallet := account.NewWallet()
	wallet.AddByPrivateKey(privateKey)
	publickKey := keytools.GetPublicKeyFromPrivateKey(util.DecodeHex(privateKey), true)
	address := keytools.GetAddressFromPublic(publickKey)
	fmt.Println(address)

	contract := Contract{
		Address: "contractAddress",
		Signer:  wallet,
	}

	args := []core.ContractValue{
		{
			"to",
			"ByStr20",
			"0x" + address,
		},
		{
			"amount",
			"Uint128",
			"10",
		},
	}

	tx, err2 := contract.CallFor("Transfer", args, true, "0", TestNet)
	assert.Nil(t, err2, err2)
	tx.Confirm(tx.ID, 1000, 3, contract.Provider)
	assert.True(t, tx.Status == core.Confirmed)


```

</TabItem>
</Tabs>

### Adding Token Allowance

The Zilliqa blockchain allows transactions with smart contracts and those smart contracts can be facilitated by third parties like a DEX or a protocol relayer – permissions have to be granted to the third party by token owners before those smart contracts can execute.
Token allowance permission gives the dApp contract the right to transfer the user's ZRC-2 token if the current approved allowance is equal to or more than `amount` requested to being transferred. The approval is done by calling `IncreaseAllowance` transition.

In the example below, the allowance amount is the same as the entire token supply. This is done so that the approval needs to only be done once per token contract, reducing the number of approval transactions required for users conducting multiple swaps.

However, you can make this value to be specific as well. Non-custodial control of the token should be ensured by the dApp contract itself, which does not allow for the transfer of tokens unless explicitly invoked by the sender.

<Tabs
  defaultValue="js"
  values={[
    { label: 'js', value: 'js', }
  ]
}>

<TabItem value="js">

```js
let increaseAllowance = async function (contractAddress, spenderAddress) {
  //contractAddress is the address of ZRC2 contract
  //spenderAddress is the address of which you want to increase the allowance, eg: your dApp contract
  const CHAIN_ID = 333;
  const MSG_VERSION = 1;
  const VERSION = bytes.pack(CHAIN_ID, MSG_VERSION);
  const myGasPrice = units.toQa("2000", units.Units.Li);

  let smartContractState = await zilliqa.blockchain.getSmartContractState(
    contractAddress
  );
  let totalSupply = smartContractState.result.total_supply;

  try {
    const contract = zilliqa.contracts.at(contractAddress);
    const callTx = await contract.call(
      "IncreaseAllowance",
      [
        {
          vname: "spender",
          type: "ByStr20",
          value: spenderAddress,
        },
        {
          vname: "amount",
          type: "Uint128",
          value: totalSupply,
        },
      ],
      {
        // amount, gasPrice and gasLimit must be explicitly provided
        version: VERSION,
        amount: new BN(0),
        gasPrice: myGasPrice,
        gasLimit: Long.fromNumber(10000),
      }
    );
    console.log(JSON.stringify(callTx.TranID));
  } catch (err) {
    console.log(err);
  }
};
```

</TabItem>

</Tabs>

### Calling TransferFrom

`TransferFrom` transition moves a given amount of tokens from one address to another using the allowance mechanism.
The caller must be an `approved_spender`, refer the section on [Adding Token Allowance](dev-keys-zrc2-wallet-support#adding-token-allowance)
if you want to add an address to become an approved_sender.
Balance of recipient will increase and the balance of `token_owner` will decrease.

<Tabs
  defaultValue="js"
  values={[
    { label: 'js', value: 'js', }
  ]
}>

<TabItem value="js">

```js
let transferFrom = async function (
  contractAddress,
  userAddress,
  receiverAddress
) {
  const CHAIN_ID = 333;
  const MSG_VERSION = 1;
  const VERSION = bytes.pack(CHAIN_ID, MSG_VERSION);
  const myGasPrice = units.toQa("2000", units.Units.Li);

  try {
    const contract = zilliqa.contracts.at(contractAddress);
    const callTx = await contract.call(
      "TransferFrom",
      [
        {
          vname: "from",
          type: "ByStr20",
          value: userAddress,
        },
        {
          vname: "to",
          type: "ByStr20",
          value: receiverAddress,
        },
        {
          vname: "amount",
          type: "Uint128",
          value: "1000",
        },
      ],
      {
        // amount, gasPrice and gasLimit must be explicitly provided
        version: VERSION,
        amount: new BN(0),
        gasPrice: myGasPrice,
        gasLimit: Long.fromNumber(10000),
      }
    );
    console.log(JSON.stringify(callTx.TranID));
  } catch (err) {
    console.log(err);
  }
};
```

</TabItem>

</Tabs>

## Tracking Incoming ZRC-2 Deposit

Please check the [Tracking Incoming ZRC-2 Deposit](../exchanges/exchange-managing-zrc2-tokens#tracking-incoming-zrc-2-deposit) subsection
under exchanges section to track any new incoming deposit of a specific ZRC-2 token.

## Getting your Token Listed

You can get your token listed on various Zilliqa ecosystem products to allow for easier recognition by your community.

### Listing on [Zilswap](https://zilswap.io/)

To add your token to the token listed on Zilswap, please refer the README.md file on this [repository](https://github.com/Switcheo/zilswap-token-list).

[Zilpay wallet](https://zilpay.xyz/) also refers to the listed tokens list on Zilswap when deciding which tokens to add to their default list.

### Listing on [Viewblock](https://viewblock.io/zilliqa)

To add your token to [Viewblock tokens listing page](https://viewblock.io/zilliqa/tokens), please refer to the README.md file on this [repository](https://github.com/Ashlar/cryptometa.git). Viewblock will assign a score to your token based on the stated token listing criteria.

## Other References

- [Sample codes for various ZRC-2 operations](https://github.com/Zilliqa/ZRC/tree/master/example/zrc2)
