Skip to main content

Mint Firelight Vault Shares

Overview

This guide demonstrates how to mint vault shares in a Firelight vault by depositing assets. The Firelight vault implements the ERC-4626 standard, which allows users to deposit assets (e.g., FXRP) and receive vault shares in return.

Minting shares is the process of depositing assets into the vault and receiving vault shares, which represent your proportional ownership of the vault's assets.

Prerequisites

Firelight Vault Mint Script

The following script demonstrates how to mint vault shares by depositing assets into the Firelight vault:

scripts/firelight/mint.ts
/**
* FirelightVault Mint Script
*
* This script mints vault shares (ERC-4626) by depositing assets into the FirelightVault.
* It checks max mint capacity, calculates required assets, approves tokens, and mints shares.
*/

import { ethers } from "hardhat";
import { bnToBigInt } from "../utils/core";
import type { IFirelightVaultInstance } from "../../typechain-types/contracts/firelight/IFirelightVault";
import type { ERC20Instance } from "../../typechain-types/@openzeppelin/contracts/token/ERC20/ERC20";

export const FIRELIGHT_VAULT_ADDRESS =
"0x91Bfe6A68aB035DFebb6A770FFfB748C03C0E40B";

const sharesToMint = 1; // Number of shares to mint

// @ts-expect-error - Type definitions issue, but works at runtime
const IERC20 = artifacts.require(
"@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20",
);

const FirelightVault = artifacts.require("IFirelightVault");

async function getAccount() {
const [signer] = await ethers.getSigners();
return { signer, account: signer.address };
}

async function getVaultAndAsset() {
const vault = (await FirelightVault.at(
FIRELIGHT_VAULT_ADDRESS,
)) as IFirelightVaultInstance;
const assetAddress = await vault.asset();
const assetToken = (await IERC20.at(assetAddress)) as ERC20Instance;
return { vault, assetAddress, assetToken };
}

async function getAssetInfo(assetToken: ERC20Instance) {
const symbol = await assetToken.symbol();
const assetDecimals = (await assetToken.decimals()).toNumber();
return { symbol, assetDecimals };
}

function logMintInfo(
account: string,
assetAddress: string,
symbol: string,
assetDecimals: number,
sharesAmount: bigint,
) {
console.log("=== Mint vault shares (ERC-4626) ===");
console.log("Sender:", account);
console.log("Vault:", FIRELIGHT_VAULT_ADDRESS);
console.log("Asset:", assetAddress, `(${symbol}, decimals=${assetDecimals})`);
console.log(
"Shares to mint:",
sharesAmount.toString(),
`(= ${sharesToMint} share${sharesToMint > 1 ? "s" : ""})`,
);
}

async function validateMint(
vault: IFirelightVaultInstance,
account: string,
sharesAmount: bigint,
) {
const maxMint = bnToBigInt(await vault.maxMint(account));
console.log("Max mint:", maxMint.toString());
if (sharesAmount > maxMint) {
console.error(
`Cannot mint ${sharesAmount.toString()} shares. Max allowed: ${maxMint.toString()}`,
);
process.exit(1);
}
}

async function calculateAssetsNeeded(
vault: IFirelightVaultInstance,
sharesAmount: bigint,
) {
const assetsNeeded = await vault.previewMint(sharesAmount.toString());
console.log("Assets needed (from previewMint):", assetsNeeded.toString());
return assetsNeeded;
}

async function approveTokens(
assetToken: ERC20Instance,
vault: IFirelightVaultInstance,
amount: bigint,
account: string,
) {
const approveTx = await assetToken.approve(vault.address, amount.toString(), {
from: account,
});
console.log("Approve tx:", approveTx.tx);
}

async function executeMint(
vault: IFirelightVaultInstance,
sharesAmount: bigint,
account: string,
) {
const mintTx = await vault.mint(sharesAmount.toString(), account, {
from: account,
});
console.log("Mint tx:", mintTx.tx);
}

async function main() {
// 1. Get the account
const { account } = await getAccount();

// 2. Get the vault and asset token
const { vault, assetAddress, assetToken } = await getVaultAndAsset();

// 3. Get asset info (symbol, decimals)
const { symbol, assetDecimals } = await getAssetInfo(assetToken);

// 4. Calculate the shares amount to mint
const sharesAmount = BigInt(sharesToMint * 10 ** assetDecimals);

// 5. Log mint info
logMintInfo(account, assetAddress, symbol, assetDecimals, sharesAmount);

// 6. Validate the mint (check max mint)
await validateMint(vault, account, sharesAmount);

// 7. Calculate assets needed using previewMint
const assetsNeeded = await calculateAssetsNeeded(vault, sharesAmount);

// 8. Approve tokens for transfer
await approveTokens(assetToken, vault, bnToBigInt(assetsNeeded), account);

// 9. Execute the mint
await executeMint(vault, sharesAmount, account);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});

Script Breakdown

The main() function executes the following steps:

  1. Get the account: Retrieves the signer account from the Hardhat environment.
  2. Get the vault and asset token: Connects to the vault contract and retrieves the underlying asset token.
  3. Get asset info: Fetches the asset token's symbol and decimals.
  4. Calculate the shares amount to mint: Converts the desired shares into the correct units based on decimals.
  5. Log mint info: Displays the mint details, including sender, vault, and shares.
  6. Validate the mint: Checks if the amount exceeds the maximum allowed.
  7. Calculate assets needed: Uses previewMint() to determine the required assets.
  8. Approve tokens for transfer: Approves the vault to spend the required assets.
  9. Execute the mint: Calls mint() to transfer assets and mint shares.

Running the Script

To run the Firelight vault mint script:

  1. Ensure you have the Flare Hardhat Starter Kit set up.
  2. Update the FIRELIGHT_VAULT_ADDRESS constant with the correct vault address for your network.
  3. Adjust the SHARES_TO_MINT constant to the desired number of shares.
  4. Ensure your account has sufficient asset balance (e.g., FXRP) to cover the minting cost.
  5. Run the script using Hardhat:
npx hardhat run scripts/firelight/mint.ts --network coston2

Output

The script outputs the following information:

=== Mint vault shares (ERC-4626) ===
Sender: 0x0d09ff7630588E05E2449aBD3dDD1D8d146bc5c2
Vault: 0x91Bfe6A68aB035DFebb6A770FFfB748C03C0E40B
Asset: 0x0b6A3645c240605887a5532109323A3E12273dc7 (FTestXRP, decimals=6)
Shares to mint: 1000000 (= 1 share)
Max mint: 115792089237316195423570985008687907853269984665640564039457584007913129639935
Assets needed (from previewMint): 1000000
Approve tx: 0xfe5683b82a4997df7d7b7c22c8c4dc416cdec8d1380dceeb996279c64c525460
Mint tx: 0x14d1c7ffe4f3b6a9fa04315eb8592ff9c64f2ae80c7e6e3a6e1b9cf9478106c3

Difference Between Mint and Deposit

The Firelight vault provides two ways to add assets:

  • mint: You specify the number of shares you want, and the vault calculates how many assets you need to deposit.
  • deposit: You specify the amount of assets to deposit, and the vault calculates how many shares you'll receive based on the current exchange rate.

Both functions follow the ERC-4626 standard and result in the same outcome: you deposit assets and receive vault shares.

Summary

In this guide, you learned how to mint vault shares in a Firelight vault by specifying the number of shares you want.

What's next

To continue your Firelight development journey, you can: