Skip to main content

Asset operations and queries

In this lesson, we will implement the core operations for the pool account and manage FT4 assets, including minting, burning, transferring, and locking assets.

Initializing the dapp

Let’s implement the initialization operation that creates our pool account:

src/main.rell
operation initialize_dapp() {
admin.require_admin();
create_pool_account();
}

function create_pool_account() = accounts.create_account_without_auth(get_pool_account_id(), account_type);

function get_pool_account_id() = (account_type + chain_context.blockchain_rid).hash();

function get_pool_account() = accounts.account_by_id(get_pool_account_id());

Key points:

  • Creates a pool account with admin privileges
  • Generates a unique account ID

Minting assets

Minting creates new assets and adds them to the pool account:

src/main.rell
operation mint() {
admin.require_admin();
Unsafe.mint(get_pool_account(), dapp_meta.asset, asset_amount_to_mint);
}

Key points:

  • Only admins can mint new assets
  • Assets are minted to the pool account
  • The amount is specified in the smallest unit (considering decimals)

Burning assets

Burning permanently removes assets from circulation:

src/main.rell
operation burn() {
admin.require_admin();
val pool_account = get_pool_account();
Unsafe.burn(pool_account, Asset(get_asset_id()), asset_amount_to_burn);
}

Key points:

  • Only admins can burn assets
  • Assets must reside in the pool account
  • Burning reduces the total supply of assets

Faucet implementation

Creating a faucet for testing purposes:

src/main.rell
@extend(auth.auth_handler)
function () = auth.add_auth_handler(
flags = ["T"]
);

We require users to have the "T" flag, ensuring that only transfer-capable accounts can access the faucet. This guarantees they can effectively use the assets they receive.

src/main.rell
operation faucet() {
val receiver = auth.authenticate();
val pool_account = get_pool_account();
Unsafe.transfer(pool_account, receiver, Asset(get_asset_id()), asset_amount_to_faucet);
}

Key points:

  • Users must authenticate
  • There is a fixed amount per request
  • Transfers are conducted from the pool account

Transferring assets

Implementing asset transfers between accounts:

src/main.rell
operation transfer(receiver: byte_array, amount: big_integer) {
val sender = auth.authenticate();
Unsafe.transfer(sender, accounts.Account(receiver), Asset(get_asset_id()), amount);
}

Key points:

  • The sender must be authenticated
  • The amount must be positive

Asset locking

Implementing asset locking for temporary restrictions:

src/main.rell
operation lock_asset(type: text, account_id: byte_array, amount: big_integer) {
admin.require_admin();
locking.lock_asset(type, accounts.Account(account_id), Asset(get_asset_id()), amount);
}

operation unlock_asset(type: text, account_id: byte_array, amount: big_integer) {
admin.require_admin();
locking.unlock_asset(type, accounts.Account(account_id), Asset(get_asset_id()), amount);
}

Key points:

  • Only admins can lock or unlock assets
  • Assets remain in the account but cannot be transferred
  • Different lock types can be specified

Queries

Implementing queries to check balances and account statuses:

src/main.rell
query get_pool_account_balance() =  get_asset_balance(get_pool_account(), Asset(get_asset_id()));

query get_user_account_balance(
pubkey
) = get_asset_balance(accounts.account_by_id(pubkey.hash()), Asset(get_asset_id()));

query get_user_lock_account_balance(
pubkey
) = locking.get_locked_asset_balance(
accounts.account_by_id(pubkey.hash()),
Asset(get_asset_id()),
["FT4_LOCK"],
5,
null
);

function create_pool_account() = accounts.create_account_without_auth(get_pool_account_id(), account_type);

function get_pool_account_id() = (account_type + chain_context.blockchain_rid).hash();

function get_pool_account() = accounts.account_by_id(get_pool_account_id());

function get_asset_id() = (asset_name, chain_context.blockchain_rid).hash();