📔
Liberland Wiki
  • 📖Public Documents
  • 👍Primers
    • 🙋‍♀️Congress
    • 💂Executive
    • 👨‍⚖️Judiciary
    • 🤴Senate
  • 🚦Regulations
    • ✍️Drafts
      • 👮Internal Regulation of the Security Commission on the Structural and Functional Organization of the
    • 👩‍⚖️In Force
      • 🏰Orders
        • 👨Order of the President of Liberland no. 1/2021, on the Decisions of the Cabinet.
        • 👩Order of the President of Liberland no. 2/2021, on the Interim Legislature
  • ✅Policies
    • 🧑‍⚖️In Force
      • ⚖️Justice
        • 🔏Privacy policy
  • 👨‍💻Blockchain
    • 💫White Paper
    • 👨Tokenomics Primer
    • 💫Roadmap
    • 👨API
      • ⌨️Chain Explorer API
      • For CEXes
    • 🌐Ecosystem
      • 🌉How to Bridge to Ethereum
      • 🌉How to Bridge to Solana
      • How to Bridge to TRON
      • 🔁Liberland Exchange
      • How to Acquire LLD
      • How to Use Polkadot.js
      • How to use SubWallet
      • How to use Talisman
      • Known Issues
    • 🪪For Citizens and E-Residents
      • 🗳️Voting
      • Senate
      • Onboarding
      • Claiming Residency
      • Congress
      • Governance
      • Companies
    • 🖥️For Validators, Nominators & Stakers
      • Run a validator
      • Non-technical run a validator
      • Staking
      • ETH Liquidity Staking
      • SOL Liquidity Staking
      • Update node
      • Resync node
    • For Developers & Testers
      • Build, run & test using source code
      • Run in Docker
      • Manual testing guide
      • Runtime upgrade
      • Rust API docs
      • Bootstrapping new testnet
      • Chain Crash Recovery Procedure
  • Media
    • Press Kit
Powered by GitBook
On this page
  • Table of Contents
  • Overview
  • RPC Endpoints & Chain Explorers
  • Testnet
  • Mainnet
  • Common Operations
  • Get Latest Block Number
  • Create a New Address
  • Liberland Dollar (LLD)
  • Receive Wallet Balance
  • Coin Transfer
  • Monitor LLD Transfers
  • Retrieve LLD Transaction Details Using Block Hash and Index
  • Liberland Merit (LLM)
  • Receive Wallet Balance
  • Coin Transfer
  • Monitor LLM Transfers
  • Retrieve LLM Transaction Details Using Block Hash and Index
  1. Blockchain

API

PreviousRoadmapNextChain Explorer API

Last updated 12 days ago

Table of Contents

Overview

RPC Endpoints & Chain Explorers

Testnet

Type
URL
Description

RPC

wss://testchain.liberland.org

WebSocket endpoint

Explorer

Web interface for exploring the testnet

Mainnet

Type
URL
Description

RPC

wss://mainnet.liberland.org

WebSocket endpoint (operated by the Government)

RPC

wss://liberland-rpc.dwellir.com

WebSocket endpoint (operated by Dwellir)

Explorer

Web interface for exploring the mainnet (operated by the Government)

Explorer

Web interface for exploring the mainnet (operated by Dwellir)

Common Operations

Get Latest Block Number

import { ApiPromise, WsProvider } from "@polkadot/api";

const provider = new WsProvider("<WS_ENDPOINT>");
const api = await ApiPromise.create({ provider });
const bestNumber = await api.derive.chain.bestNumber();
console.log(bestNumber.toNumber());

Create a New Address

To create a new address, a minimum of 1 LLD needs to be deposited as an existential deposit.

import { ApiPromise, WsProvider, Keyring } from "@polkadot/api";

const provider = new WsProvider("<WS_ENDPOINT>");
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: "sr25519" });
const sender = keyring.addFromUri("<SENDER-ACCOUNT-PRIVATE-KEY>");
const transferExtrinsic = api.tx.balances.transfer(
  "<WALLET_ADDRESS_TO_CREATE>",
  AMOUNT, // 1_000_000_000_000 = 1 LLD
);
const txHash = await transferExtrinsic.signAndSend(sender);

Liberland Dollar (LLD)

LLD is a native token of the Liberland blockchain and all transactions, calls and queries related to LLD are identical to any other Substrate chain like Polkadot.

Receive Wallet Balance

import { ApiPromise, WsProvider, Keyring } from "@polkadot/api";

const provider = new WsProvider("<WS_ENDPOINT>");
const api = await ApiPromise.create({ provider });
const balance = await api.query.system.account("<ACCOUNT_ID>");
console.log(balance.data.free.toHuman());

Coin Transfer

For LLD transfers with transaction status monitoring, you can use the balances.transferKeepAlive method which ensures the sender's account remains active by automatically keeping the existential deposit amount. This differs from balances.transferAllowDeath which can empty the sender's account completely, potentially removing it from the blockchain state if the balance falls below the existential deposit.

import { ApiPromise, WsProvider, Keyring } from "@polkadot/api";

const provider = new WsProvider("<WS_ENDPOINT>");
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: "sr25519" });
const sender = keyring.addFromUri("<SENDER-ACCOUNT-PRIVATE-KEY>");
const transferExtrinsic = api.tx.balances.transferKeepAlive(
  "<ACCOUNT_TO>",
  AMOUNT, // 1_000_000_000_000 = 1 LLD
);

// Monitor transaction status
const unsub = await transferExtrinsic.signAndSend(
  sender,
  ({ status, events }) => {
    console.log(`Current transaction status: ${status.type}`);

    if (status.isInBlock) {
      console.log(`Transaction included in block: ${status.asInBlock.toHex()}`);
    }

    if (status.isFinalized) {
      console.log(
        `Transaction finalized in block: ${status.asFinalized.toHex()}`,
      );

      // Check if the transaction was successful
      events.forEach(({ event }) => {
        if (api.events.system.ExtrinsicSuccess.is(event)) {
          console.log("Transaction succeeded");
        } else if (api.events.system.ExtrinsicFailed.is(event)) {
          const [dispatchError] = event.data;
          let errorInfo;

          if (dispatchError.isModule) {
            const decoded = api.registry.findMetaError(dispatchError.asModule);
            errorInfo = `${decoded.section}.${decoded.name}`;
          } else {
            errorInfo = dispatchError.toString();
          }

          console.log(`Transaction failed: ${errorInfo}`);
        } else if (api.events.balances.Transfer.is(event)) {
          const [from, to, amount] = event.data;
          console.log(
            `LLD Transfer successful: ${amount} from ${from} to ${to}`,
          );
        }
      });

      unsub();
    }
  },
);

Monitor LLD Transfers

To monitor LLD transfers, subscribe to system events and filter for Balances::Transfer events.

import { ApiPromise, WsProvider } from "@polkadot/api";

async function main() {
  const provider = new WsProvider("<WS_ENDPOINT>");
  const api = await ApiPromise.create({ provider });

  // Subscribe to system events
  const unsubscribe = await api.query.system.events((events) => {
    // Filter only the Balances.Transfer events
    events.forEach(({ event, phase }) => {
      if (api.events.balances.Transfer.is(event)) {
        // LLD transferred
        const [from, to, amount] = event.data;
        console.log(
          `LLD Transfer from: ${from.toString()} to: ${to.toString()} amount: ${amount.toString()}`,
        );
      }
    });
  });

  return unsubscribe;
}

main()
  .then((unsubscribe) => {
    console.log("Subscribed to Transfer events. Press Ctrl+C to exit.");
  })
  .catch((error) => {
    console.error("Error:", error);
    process.exit(1);
  });

Retrieve LLD Transaction Details Using Block Hash and Index

Many infrastructure providers on existing blockchains, e.g. Ethereum, consider a transaction's hash as a unique identifier. In Substrate-based chains, a transaction's hash only serves as a fingerprint of the information within a transaction, and there are times when two transactions with the same hash are both valid. On a Substrate blockchain transactions (a.k.a. extrinsics) are uniquely identified by block hash and their index.

import { ApiPromise, WsProvider } from "@polkadot/api";

const txId = {
  blockHash: BLOCK_HASH,
  index: EXTRINSIC_INDEX,
};
const provider = new WsProvider("<WS_ENDPOINT>");
const api = await ApiPromise.create({ provider });
const apiAt = await api.at(txId.blockHash);
const allEvents = await apiAt.query.system.events();

const txEvents = allEvents.filter(
  ({ phase }) =>
    phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(txId.index),
);

const successEvent = txEvents.find(({ event }) =>
  api.events.system.ExtrinsicSuccess.is(event),
);
const failureEvent = txEvents.find(({ event }) =>
  api.events.system.ExtrinsicFailed.is(event),
);

if (successEvent) {
  const transferEvents = txEvents.filter(({ event }) =>
    api.events.balances.Transfer.is(event),
  );
  transferEvents.forEach(({ event }) => {
    const [fromAccount, toAccount, amount] = event.data;
    console.log(
      `Transfer of ${amount} grains of LLD from ${fromAccount} to ${toAccount}`,
    );
  });
} else {
  const [dispatchError, dispatchInfo] = failureEvent.event.data;
  let errorInfo;

  // decode the error
  if (dispatchError.isModule) {
    // for module errors, we have the section indexed, lookup
    // (For specific known errors, we can also do a check against the
    // api.errors.<module>.<ErrorName>.is(dispatchError.asModule) guard)
    const decoded = api.registry.findMetaError(dispatchError.asModule);

    errorInfo = `${decoded.section}.${decoded.name}`;
  } else {
    // Other, CannotLookup, BadOrigin, no extra info
    errorInfo = dispatchError.toString();
  }

  console.log(`ExtrinsicFailed:: ${errorInfo}`);
}

Liberland Merit (LLM)

Receive Wallet Balance

import { ApiPromise, WsProvider } from "@polkadot/api";

const provider = new WsProvider("<WS_ENDPOINT>");
const api = await ApiPromise.create({ provider });
const LLMInfo = await api.query.assets.account(
  1, // ID of LLM
  "<WALLET_ADDRESS>",
);
console.log(LLMInfo.toJSON().data?.balance ?? "0x0");

Coin Transfer

For token transfers with transaction status monitoring, you can use the assets.transfer method and subscribe to events. This allows you to track when the transaction is included in a block and finalized on the blockchain.

import { ApiPromise, WsProvider, Keyring } from "@polkadot/api";

const provider = new WsProvider("<WS_ENDPOINT>");
const api = await ApiPromise.create({ provider });
const keyring = new Keyring({ type: "sr25519" });
const sender = keyring.addFromUri("<SENDER-ACCOUNT-PRIVATE-KEY>");
// The following value 1 is the ID token of LLM.
const transferExtrinsic = api.tx.assets.transfer(
  1,
  "<WALLET_ADDRESS>",
  1_000_000_000_000,
); // 1_000_000_000_000 = 1 LLM

// Monitor transaction status
const unsub = await transferExtrinsic.signAndSend(
  sender,
  ({ status, events, dispatchError }) => {
    console.log(`Current transaction status: ${status.type}`);

    if (status.isInBlock) {
      console.log(`Transaction included in block: ${status.asInBlock.toHex()}`);
    }

    if (status.isFinalized) {
      console.log(
        `Transaction finalized in block: ${status.asFinalized.toHex()}`,
      );

      // Check if the transaction was successful
      events.forEach(({ event }) => {
        if (api.events.system.ExtrinsicSuccess.is(event)) {
          console.log("Transaction succeeded");
        } else if (api.events.system.ExtrinsicFailed.is(event)) {
          const [dispatchError] = event.data;
          let errorInfo;

          if (dispatchError.isModule) {
            const decoded = api.registry.findMetaError(dispatchError.asModule);
            errorInfo = `${decoded.section}.${decoded.name}`;
          } else {
            errorInfo = dispatchError.toString();
          }

          console.log(`Transaction failed: ${errorInfo}`);
        } else if (api.events.assets.Transferred.is(event)) {
          const [assetId, from, to, amount] = event.data;
          if (assetId.eq(1)) {
            console.log(
              `Transfer successful: ${amount} LLM from ${from} to ${to}`,
            );
          }
        }
      });

      unsub();
    }
  },
);

Monitor LLM Transfers

To monitor LLM transfers, subscribe to system events and filter for Assets::Transferred events with an ID of 1.

import { ApiPromise, WsProvider } from "@polkadot/api";

async function main() {
  const provider = new WsProvider("<WS_ENDPOINT>");
  const api = await ApiPromise.create({ provider });

  // Target asset ID to monitor
  const targetAssetId = 1;

  // Subscribe to system events
  const unsubscribe = await api.query.system.events((events) => {
    // Filter for Assets.Transferred events
    events.forEach(({ event, phase }) => {
      if (api.events.assets.Transferred.is(event)) {
        const [assetId, from, to, amount] = event.data;

        if (assetId.eq(targetAssetId)) {
          // LLM transferred
          console.log(
            `LLM Transfer from: ${from.toString()} to: ${to.toString()} amount: ${amount.toString()}`,
          );
        }
      }
    });
  });

  return unsubscribe;
}

main()
  .then((unsubscribe) => {
    console.log("Subscribed to LLM transfers. Press Ctrl+C to exit.");
  })
  .catch((error) => {
    console.error("Error:", error);
    process.exit(1);
  });

Retrieve LLM Transaction Details Using Block Hash and Index

Many infrastructure providers on existing blockchains, e.g. Ethereum, consider a transaction's hash as a unique identifier. In Substrate-based chains, a transaction's hash only serves as a fingerprint of the information within a transaction, and there are times when two transactions with the same hash are both valid. On a Substrate blockchain transactions (a.k.a. extrinsics) are uniquely identified by block hash and their index.

import { ApiPromise, WsProvider } from "@polkadot/api";

const txId = {
  blockHash: BLOCK_HASH,
  index: EXTRINSIC_INDEX,
};
const provider = new WsProvider("<WS_ENDPOINT>");
const api = await ApiPromise.create({ provider });
const apiAt = await api.at(txId.blockHash);
const allEvents = await apiAt.query.system.events();

const txEvents = allEvents.filter(
  ({ phase }) =>
    phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(txId.index),
);

const successEvent = txEvents.find(({ event }) =>
  api.events.system.ExtrinsicSuccess.is(event),
);
const failureEvent = txEvents.find(({ event }) =>
  api.events.system.ExtrinsicFailed.is(event),
);

if (successEvent) {
  const transferEvents = txEvents.filter(({ event }) =>
    api.events.assets.Transferred.is(event),
  );
  transferEvents.forEach(({ event }) => {
    const [assetId, fromAccount, toAccount, amount] = event.data;
    if (assetId == 1) {
      console.log(
        `Transfer of ${amount} grains of LLM from ${fromAccount} to ${toAccount}`,
      );
    }
  });
} else {
  const [dispatchError, dispatchInfo] = failureEvent.event.data;
  let errorInfo;

  // decode the error
  if (dispatchError.isModule) {
    // for module errors, we have the section indexed, lookup
    // (For specific known errors, we can also do a check against the
    // api.errors.<module>.<ErrorName>.is(dispatchError.asModule) guard)
    const decoded = api.registry.findMetaError(dispatchError.asModule);

    errorInfo = `${decoded.section}.${decoded.name}`;
  } else {
    // Other, CannotLookup, BadOrigin, no extra info
    errorInfo = dispatchError.toString();
  }

  console.log(`ExtrinsicFailed:: ${errorInfo}`);
}

Liberland blockchain is based on . Recommended way to interact with the chain programmatically is through library. For those interested in a glimpse of the underlying RPC interactions, see the .

LLM is an on-chain asset of the with ID of 1.

👨‍💻
👨
Polkadot SDK
@polkadot/api
Liberland CEX API: Low-Level RPC Overview
Assets pallet
Overview
RPC Endpoints & Chain Explorers
Testnet
Mainnet
Common Operations
Get Latest Block Number
Create a New Address
Liberland Dollar (LLD)
Receive Wallet Balance
Coin Transfer
Monitor LLD Transfers
Retrieve LLD Transaction Details Using Block Hash and Index
Liberland Merit (LLM)
Receive Wallet Balance
Coin Transfer
Monitor LLM Transfers
Retrieve LLM Transaction Details Using Block Hash and Index
Polkadot Apps
Polkadot Apps
Polkadot Apps