Glittr Transactions

In Glittr, transactions are embedded within Bitcoin transactions, meaning each transaction contains both components. Glittr operates as a UTXO-based system, so all functionality is directly encoded in the transaction.

There are three types of transactions: Contract Creation, Contract Call, and Transfer.

Contract Creation

These transactions create new contracts. The Bitcoin piece of this transaction is basically just dust and fees, or can arbitrarily be anything at all. The contract itself will not have an address or keys, so the other outputs don’t matter.

Specification

{
  contract_creation: {
    contract_type: {
      asset: { // This contract is Asset contract, there will be more non-asset contracts (e.g. AMM)
        asset: {
          "divisibility": 18, // asset could be divided to smaller units, 10**18
          "live_time": 0, // Indicates when the contract is live (in bitcoin block height)
          "supply_cap": "2000" // Total supply
        },
        distribution_schemes: {
          free_mint: {
            amount_per_mint: 10; // amount per mint, cannot exceeds supply cap
          },
          preallocated: {}, // details on the contracts page
          purchase: {} // details on contracts page
        }
      }
    }
  }
}

Code Example

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

async function main() {
  const NETWORK = "regtest";

  const client = new GlittrSDK({
    network: NETWORK,
    electrumApi: "https://devnet-electrum.glittr.fi",
    glittrApi: "https://devnet-core-api.glittr.fi",
  });
  const account = new Account({
    wif: "cW84FgWG9U1MpKvdzZMv4JZKLSU7iFAzMmXjkGvGUvh5WvhrEASj",
    network: NETWORK,
  });

  const c = txBuilder.freeMintContractInstantiate({
    simple_asset: {
      supply_cap: 2000n.toString(),
      divisibility: 18,
      live_time: 0,
    },
    amount_per_mint: 2n.toString(),
  });

  const txid = await client.createAndBroadcastTx({
    account: account.p2pkh(),
    tx: c,
    outputs: []
  });
  console.log("TXID : ", txid);
}

main();

Contract Call

Any transaction that interacts with a contract that already exists. The bitcoin piece of this type of transaction depends on the asset contract, e.g. for free mint contract, pointer indicates which output in the bitcoin tx will have the glittr asset. Another example would be during oracle mint, the contract call must includes the signature and the message that was being signed by the oracle.

Specification

{
  contract: [123456, 0], // block, tx position
  call_type: {
    mint: {
      pointer: 1,       // Index position for minting
      oracle_message?: {     // Optional oracle verification
        signature: [23, 4, ...] , // Cryptographic signature
        message: {
          input_outpoint: {  // Reference to UTXO
            txid: "1a2b3c...",    // Transaction ID
            vout: 1     // Output index
          },
          min_in_value: "1",    // Minimum input value (U128)
          out_value: "100",       // Oracle valuation (U128), 1 BTC(input) equals to 100 wUSD
          asset_id?: "wbtc",       // Optional asset identifier
          block_height: 870000     // Block height at signing
        }
      }
    },
    burn: {},
    swap: {},
  }
}

Code Example Contract Call

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

async function main() {
  const NETWORK = "regtest";

  const client = new GlittrSDK({
    network: NETWORK,
    electrumApi: "https://devnet-electrum.glittr.fi",
    glittrApi: "https://devnet-core-api.glittr.fi",
  });
  const creatorAccount = new Account({
    wif: "cW84FgWG9U1MpKvdzZMv4JZKLSU7iFAzMmXjkGvGUvh5WvhrEASj",
    network: NETWORK,
  });
  const minterAccount = new Account({
    wif: "cMqUkLHLtHJ4gSBdxAVtgFjMnHkUi5ZXkrsoBcpECGrE2tcJiNDh",
    network: NETWORK,
  });

  /**
   * Create Contract
   */
  const creatorBitcoinAddress = creatorAccount.p2pkh().address;
  const contractTx = txBuilder.purchaseBurnSwapContractInstantiate({
    simple_asset: {
      supply_cap: 21000000n.toString(),
      divisibility: 8,
      live_time: 0,
    },
    purchase_burn_swap: {
      input_asset: "raw_btc",
      transfer_scheme: { purchase: creatorBitcoinAddress },
      transfer_ratio_type: { fixed: { ratio: [1, 1] } }, // 1:1 ratio
    },
  });
  await client.createAndBroadcastTx({
    account: creatorAccount.p2pkh(),
    tx: contractTx,
    outputs: [{ address: creatorAccount.p2pkh().address, value: 546 }],
  });


  /**
   * Mint 
   */
  const contract: BlockTxTuple = [101869, 1]; // [block, vout]
  const tx = txBuilder.mint({
    contract,
    pointer: 0,
  });
  const txid = await client.createAndBroadcastTx({
    account: minterAccount.p2pkh(),
    tx: tx,
    outputs: [
      { address: minterAccount.p2pkh().address, value: 546 },
      { address: creatorAccount.p2pkh().address, value: 1000 },
    ],
  });
  console.log("TXID : ", txid);
}

main();

Transfer

These transactions take assets from one UTXO and move them to another. The actual signature pieces of this are handled in the Bitcoin script piece of the transaction. A transfer can be complete or can UTXO split, but any assets not explicitly assigned to outputs are forfeit - this is necessary to avoid recursion.

The transfer transaction restates things that can be inferred, again to prevent recursive validation. The Glittr node will check whether the OP_RETURN message *and* the inputs are correct (the bitcoin inputs have the specified assets).

Specification

{
  transfers: [
      {
        asset: [876011, 1], // block and tx position for the asset
        output: 0, // utxo in which the asset will be transferred
        amount: "500000" // amount, cannot exceed the assets in bitcoin inputs
      },
      {
        asset: [500000, 2],
        output: 1,
        amount: "300000"
      },
      ...
    ]
{

Code Example Transfer

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

async function main() {
  const NETWORK = "regtest";

  const client = new GlittrSDK({
    network: NETWORK,
    electrumApi: "https://hackathon-electrum.glittr.fi",
    glittrApi: "https://hackathon-core-api.glittr.fi",
  });
  const creatorAccount = new Account({
    wif: "cW84FgWG9U1MpKvdzZMv4JZKLSU7iFAzMmXjkGvGUvh5WvhrEASj",
    network: NETWORK,
  });
  const minterAccount = new Account({
    wif: "cMqUkLHLtHJ4gSBdxAVtgFjMnHkUi5ZXkrsoBcpECGrE2tcJiNDh",
    network: NETWORK,
  });

  const contract: BlockTxTuple = [101869, 1];
  const tx = txBuilder.transfer({
    transfers: [
      {
        amount: "100",
        asset: contract,
        output: 1,
      },
    ],
  });
  const txid = await client.createAndBroadcastTx({
    account: minterAccount.p2pkh(),
    tx: tx,
    outputs: [{ address: creatorAccount.p2pkh().address, value: 1000 }],
  });
  console.log("TXID : ", txid);
}

main();

Last updated