How do i programmatically convert ICP to cycles?

I’m trying to program my main canister to convert ICP to cycles to be consumed. How does one go about doing this? Any references to code samples would be greatly appreciated.

2 Likes

In JavaScript? If yes, I might have a code snippet somewhere…

1 Like

Yep. That would be perfect.

You should be able to reverse engineer it by reading the nns-dapp: nns-dapp/periodic_tasks_runner.rs at a05bac7533fa9bef048bc6660ccb33bac750f993 · dfinity/nns-dapp · GitHub

I suppose you’ll have to do two transactions, an ICP transfer, then a notify_top_up to the CMC (cycle minting canister); where you’d specify the canister who will receive the cycles;

Here’s also an example with XTC (Which is currently way cheaper).

And you can combine it with mint_by_icp

3 Likes

To convert ICP in cycles in JavaScript you need:

  • a function that does the conversion
  • the exchange rate that can be used in that function for the conversion

The exchange rate can be queried in the CMC canister, so you need its .did files. You can copy these from my project for example ic/ic/cycles at main · papyrs/ic · GitHub

Note: I named these files cycles.xxx but it’s a bit misleading, cmc.xxx would be more accurate, I still need to rename these.

In NodeJS you can query the exchange rate as following (source in my project here).

Note that I add the conversion to trillion ratio within that function for conveniance reason for my scripts.

import pkgAgent from '@dfinity/agent';
import fetch from 'node-fetch';
import {idlFactory as nnsIdlFactory} from '../../ic/cycles/cycles.utils.did.mjs';
import {E8S_PER_ICP, icpToE8s} from '../utils/icp.utils.mjs';

const {HttpAgent, Actor} = pkgAgent;

const icpXdrConversionRate = async () => {
  const agent = new HttpAgent({fetch, host: 'https://ic0.app'});

  const actor = Actor.createActor(nnsIdlFactory, {
    agent,
    canisterId: 'rkp4c-7iaaa-aaaaa-aaaca-cai'
  });

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

  const CYCLES_PER_XDR = BigInt(1_000_000_000_000);

  // trillionRatio
  return (xdr_permyriad_per_icp * CYCLES_PER_XDR) / BigInt(10_000);
};

Once you got the function to get the exchange rate you can for example convert icp to cycles as following:

export const icpToCycles = async (amount) => {
  const trillionRatio = await icpXdrConversionRate();

  const e8ToCycleRatio = trillionRatio / E8S_PER_ICP;
  const cyclesAmount = icpToE8s(amount) * e8ToCycleRatio;

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

  console.log(
    `${amount} ICP equals ${Number(cyclesAmount) / Number(oneTrillion)} (${cyclesAmount}) cycles`
  );

  return cyclesAmount;
};

Note that in above example the amount of cycle is a string (because I call the function from the command line). That’s why it uses a function icpToE8s that parse it to bigint. You can find its source code here.

Let me know if that helps?


Side notes:

  • this is a NodeJS example. if you need something that works in the browser let me know, we’ve got that in NNS dapp too
  • I also go cycles to ICP if you need that, let me know too
  • we actually literally discussed last week with my colleague the idea of providing such utilities in a JavaScript library too. as we do with nns-js the idea would be to provide a “cmc-js” or something. not our top priority but we think it could be cool and handy, so might happen some day
5 Likes

I have cleaned my above solution and just shared it in a brief blog post:

9 Likes

I’m finally at the part of my project where I’m ready to implement this solution. I’m reading you blog and just wanted to say, well done! on both the article and application where the article is written.

1 Like

Thanks for the flowers Jesse :pray:. Hearing that someone found one of my small blog posts useful make my day!

Since I published the article it is worth to note that we managed to take some time and create that cmc-js I mention in the opening paragraph.

Using this library should also be able to get the ICP to cycles conversion rate quite easily:

import { CMCCanister } from "@dfinity/cmc";
import { createAgent } from "@dfinity/utils";

const agent = await createAgent({
  identity,
  host: HOST,
});

const { getIcpToCyclesConversionRate } = CMCCanister.create({
  agent,
  canisterId: CYCLES_MINTING_CANISTER_ID,
});

const rate = await getIcpToCyclesConversionRate();
2 Likes

I cannot help here, never used the Plug Wallet. You might want to start a new thread as it’s not really related to this post or ask Plug directly for more visibility.

Ok. There is nothing more superfluous in this branch. It is important to me how the Identity class object is generated (from where it comes from). Right now I’m busy creating a module for converting ICP into Cycles.