Vesting and Freemint Contract

This page breaks down a TypeScript example that demonstrates how to create and interact with a vesting contract using the Glittr SDK.

1. Setup and Configuration

import {
  Account,
  BlockTxTuple,
  GlittrSDK,
  Ratio,
  txBuilder,
} from "@glittr-sdk/sdk";

// Initialize SDK with network configuration
const NETWORK = "regtest";
const client = new GlittrSDK({
  network: NETWORK,
  glittrApi: "https://hackathon-core-api.glittr.fi",
  electrumApi: "https://hackathon-electrum.glittr.fi",
});

// Create three accounts for different roles
const account = new Account({...});         // Main account
const reserveAccount = new Account({...});  // Reserve account
const freeMintAccount = new Account({...}); // Free minting account

The code starts by setting up the SDK client and creating three different accounts that will play different roles in the vesting contract.

2. Contract Creation

The createContract() function demonstrates how to create a vesting contract with the following characteristics:

  • Total supply cap: 1000 tokens

  • Divisibility: 100 (similar to decimals in other token standards)

  • Allocation:

    • 100 tokens to receiver1

    • 200 tokens to receiver2 (reserve)

    • 700 tokens for free minting

The vesting schedule is quarterly:

const quarterlyVesting: [Ratio, number][] = [
    [[25, 100], -1], // 25% unlocked after 1 blocks
    [[25, 100], -2], // 25% unlocked after 2 blocks
    [[25, 100], -3], // 25% unlocked after 3 blocks
    [[25, 100], -4], // 25% unlocked after 4 blocks
];

Contract creation code:

async function createContract() {
  // Example: pre-allocation with free mint
  // {
  // TxType: Contract,
  // simpleAsset:{
  // 	supplyCap: 1000,
  // 	Divisibility: 100,
  // 	liveTime: 0
  // },
  // Allocation:{
  // {100:pk1}
  // {200:reservePubKey},
  // {700: freemint}
  // vestingSchedule:{
  // 		Fractions: [.25, .25, .25, .25],
  // 		Blocks: [-1, -2, -3, -4] // relative block
  // },
  // FreeMint:{
  // 		mintCap: 1,
  // },
  // },
  // }

  const receiver1PublicKey = Array.from(account.p2pkh().keypair.publicKey);
  const receiver2PublicKey = Array.from(
    reserveAccount.p2pkh().keypair.publicKey
  );

  console.log(receiver1PublicKey, receiver2PublicKey);

  const quarterlyVesting: [Ratio, number][] = [
    [[25, 100], -1], // 25% unlocked after 1 blocks
    [[25, 100], -2], // 25% unlocked after 2 blocks
    [[25, 100], -3], // 25% unlocked after 3 blocks
    [[25, 100], -4], // 25% unlocked after 4 blocks
  ];

  const tx = txBuilder.preallocatedContractInstantiate({
    simple_asset: {
      supply_cap: 1000n.toString(),
      divisibility: 100,
      live_time: 0,
    },
    preallocated: {
      allocations: {
        "100": [receiver1PublicKey],
        "200": [receiver2PublicKey],
      },
      vesting_plan: {
        scheduled: quarterlyVesting,
      },
    },
    // free mint
    free_mint: {
      supply_cap: 700n.toString(),
      amount_per_mint: 1n.toString(),
    },
  });
  console.log(JSON.stringify(tx));

  const txid = await client.createAndBroadcastTx({
    account: account.p2pkh(),
    tx,
    outputs: [{ address: account.p2pkh().address, value: 546 }],
  });

  console.log(`TX: https://hackathon-explorer.glittr.fi/tx/${txid}`);
}

3. Minting Operations

The code includes two types of minting:

Vested Minting

async function vestedMint() {
    const contract: BlockTxTuple = [101832, 1];
    // Creates a mint transaction for vested tokens
    // Only works when vesting conditions are met

    const tx = txBuilder.mint({
      contract,
      pointer: 0, // 1 is op_return, 0 is specified, last is remainder
    });
  
    const txid = await client.createAndBroadcastTx({
      account: reserveAccount.p2pkh(),
      tx,
      outputs: [{ address: reserveAccount.p2pkh().address, value: 546 }],
    });
  
    console.log(`TX: https://hackathon-explorer.glittr.fi/tx/${txid}`);
}

Free Minting

Call the following function using account that don't have vesting allocation a.k.a the freeMintAccount.

async function freeMint() {
    const contract: BlockTxTuple = [101832, 1];
    // Creates a mint transaction for free mint allocation
    // Anyone can mint from this portion
  
    const tx = txBuilder.mint({
      contract,
      pointer: 0, // 1 is op_return, 0 is specified, last is remainder
    });
  
    const txid = await client.createAndBroadcastTx({
      account: freeMintAccount.p2pkh(),
      tx,
      outputs: [{ address: freeMintAccount.p2pkh().address, value: 546 }],
    });
  
    console.log(`TX: https://hackathon-explorer.glittr.fi/tx/${txid}`);
}

4. Asset Checking

The code provides two utility functions to check the status of assets:

async function checkingAssetFreeMint() {
   const assetTxId =
    "82eda96aa5f9a0941b2b0f00b692aa389f54b210af23977f21e0006259f3282b";
  const vout = 0;
  const result = await fetch(
    `https://hackathon-core-api.glittr.fi/assets/${assetTxId}/${vout}`
  );

  console.log(await result.text());
}

Key Concepts

  1. Vesting Schedule: The contract implements a linear vesting schedule where tokens are released in 25% increments over 4 blocks.

  2. Allocation Types:

    • Direct allocation (vested)

    • Reserve allocation (vested)

    • Free mint allocation (unrestricted)

  3. Asset Verification: The code includes methods to verify the status of both vested and free-minted assets through API calls.

Usage Flow

  1. Create the contract using createContract()

  2. Wait for vesting periods to unlock

  3. Use vestedMint() to claim vested tokens

  4. Use freeMint() to mint from the free allocation

  5. Verify asset status using the checking functions

This example demonstrates a complete flow of creating and interacting with a vesting contract on the Glittr platform, including both restricted (vested) and unrestricted (free mint) token distributions.

Full Code Example

import {
  Account,
  BlockTxTuple,
  GlittrSDK,
  Ratio,
  txBuilder,
} from "@glittr-sdk/sdk";

const NETWORK = "regtest";
const client = new GlittrSDK({
  network: NETWORK,
  glittrApi: "https://hackathon-core-api.glittr.fi",
  electrumApi: "https://hackathon-electrum.glittr.fi",
});

const account = new Account({
  wif: "...",
  network: NETWORK,
});

const reserveAccount = new Account({
  wif: "...",
  network: NETWORK,
});

const freeMintAccount = new Account({
  wif: "...",
  network: NETWORK,
});

console.log(`User account ${account.p2pkh().address}`);
console.log(`Reserve account ${reserveAccount.p2pkh().address}`);
console.log(`Freemint account ${freeMintAccount.p2pkh().address}`);

async function createContract() {
  const receiver1PublicKey = Array.from(account.p2pkh().keypair.publicKey);
  const receiver2PublicKey = Array.from(
    reserveAccount.p2pkh().keypair.publicKey
  );

  const quarterlyVesting: [Ratio, number][] = [
    [[25, 100], -1],
    [[25, 100], -2],
    [[25, 100], -3],
    [[25, 100], -4],
  ];

  const tx = txBuilder.preallocatedContractInstantiate({
    simple_asset: {
      supply_cap: 1000n.toString(),
      divisibility: 100,
      live_time: 0,
    },
    preallocated: {
      allocations: {
        "100": [receiver1PublicKey],
        "200": [receiver2PublicKey],
      },
      vesting_plan: {
        scheduled: quarterlyVesting,
      },
    },
    free_mint: {
      supply_cap: 700n.toString(),
      amount_per_mint: 1n.toString(),
    },
  });

  const txid = await client.createAndBroadcastTx({
    account: account.p2pkh(),
    tx,
    outputs: [{ address: account.p2pkh().address, value: 546 }],
  });

  console.log(`TX: https://hackathon-explorer.glittr.fi/tx/${txid}`);
}

async function vestedMint() {
  const contract: BlockTxTuple = [101832, 1];
  const tx = txBuilder.mint({
    contract,
    pointer: 0,
  });

  const txid = await client.createAndBroadcastTx({
    account: reserveAccount.p2pkh(),
    tx,
    outputs: [{ address: reserveAccount.p2pkh().address, value: 546 }],
  });

  console.log(`TX: https://hackathon-explorer.glittr.fi/tx/${txid}`);
}

async function freeMint() {
  const contract: BlockTxTuple = [101832, 1];
  const tx = txBuilder.mint({
    contract,
    pointer: 0,
  });

  const txid = await client.createAndBroadcastTx({
    account: freeMintAccount.p2pkh(),
    tx,
    outputs: [{ address: freeMintAccount.p2pkh().address, value: 546 }],
  });

  console.log(`TX: https://hackathon-explorer.glittr.fi/tx/${txid}`);
}

async function checkingAssetFreeMint() {
  const assetTxId =
    "22acf70357c3adf8c3236e1c230b7c3d6796488825b963edd0d52ff13ba5a822";
  const vout = 0;
  const result = await fetch(
    `https://hackathon-core-api.glittr.fi/assets/${assetTxId}/${vout}`
  );

  console.log(await result.text());
}

async function checkingAssetVested() {
  const assetTxId =
    "82eda96aa5f9a0941b2b0f00b692aa389f54b210af23977f21e0006259f3282b";
  const vout = 0;
  const result = await fetch(
    `https://hackathon-core-api.glittr.fi/assets/${assetTxId}/${vout}`
  );

  console.log(await result.text());
}

checkingAssetVested();

Last updated