How to Programmatically Convert ICP Into Cycles in NodeJS

A tutorial for using JavaScript to convert Internet Computer utility tokens into cycles to pay for computation and storage.


Long story short, to convert ICP to cycles you need two things:

  1. A function that, well, does the conversion.


To query the CMC in JavaScript easily, you need agent-js (and its peer dependencies). In addition, because following solution runs in a NodeJS context and not in a browser, node-fetch is required as well to provide previous library a way to perform XMLHttpRequest​.

npm i node-fetch @dfinity/agent @dfinity/candid @dfinity/principal


​The description of the interface of the cycles-minting canister has to be used to initialize the communication channel.

XDR conversion rate

On mainnet, ​the canister ID of the CMC is rkp4c-7iaaa-aaaaa-aaaca-caid​​. This ID should be used to instantiate the actor in order to query get_icp_xdr_conversion_rate​which returns xdr_permyriad_per_icp​​, the actual conversion rate in XDR we are looking for.

import pkgAgent from "@dfinity/agent";
import fetch from "node-fetch";
import { idlFactory } from "./cmc/cmc.utils.did.mjs";

const { HttpAgent, Actor } = pkgAgent;

const icpXdrConversionRate = async () => {
const agent = new HttpAgent({ fetch, host: "" });

const actor = Actor.createActor(idlFactory, {
canisterId: "rkp4c-7iaaa-aaaaa-aaaca-cai",

const {
data: { xdr_permyriad_per_icp },
} = await actor.get_icp_xdr_conversion_rate();

const CYCLES_PER_XDR = BigInt(1_000_000_000_000);

// Return conversion rate in trillion ratio
return (xdr_permyriad_per_icp * CYCLES_PER_XDR) / BigInt(10_000);

Conversion ICP to cycles

We aim to convert readable numbers. That is why we first need a small utility that maps number to BigInt​ (because the conversion function will process such types).

const E8S_PER_ICP = BigInt(100000000);

const toBigint = (amount) => {
const [integral, fractional] = `${amount}`.split(".");

if ((fractional ?? "0").length > 8) {
throw new Error("More than 8 decimals not supported.");

return (
BigInt(integral ?? 0) * E8S_PER_ICP +
BigInt((fractional ?? "0").padEnd(8, "0"))
*   1 -> 100000000n
* 1.2 -> 120000000n
* 34.456 -> 3445600000n
const icpToCycles = async ({icp, conversionRate}) => {
const e8ToCycleRatio = conversionRate / E8S_PER_ICP;
return toBigint(icp) * e8ToCycleRatio;


​Put together in a small demo, e.g., above functions can be chained to log the result of the conversion to the console.

const convertICPToCycles = async (icp) => {
const conversionRate = await icpXdrConversionRate();
const cycles = await icpToCycles({icp, conversionRate});

const ONE_TRILLION = BigInt(1000000) * BigInt(1000000);

`${icp} ICP equals ${
Number(cycles) / Number(ONE_TRILLION)
} (${cycles}) cycles`

await convertICPToCycles(123.56);
❯ node index.mjs
123.56 ICP equals 652.0879 (652087900000000) cycles


​I hope this small tutorial will be useful. If you have any idea of improvements, let me know!

Start building at and join the developer community at



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store