# Programmatically mint cycles in rust

**URL:** https://forum.dfinity.org/t/programmatically-mint-cycles-in-rust/32271
**Category:** Rust
**Created:** [June 21, 2024, 9:54pm UTC](https://forum.dfinity.org/t/programmatically-mint-cycles-in-rust/32271 "2024-06-21T21:54:53Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![amschel99](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/amschel99/32/18280_2.png) [@amschel99](https://forum.dfinity.org/u/amschel99)
#### Post date: [June 21, 2024, 9:54pm UTC](https://forum.dfinity.org/t/programmatically-mint-cycles-in-rust/32271/1 "2024-06-21T21:54:53Z")

</div>

I realized there is no Rust library for converting ICP tokens into cycles. The normal way would be to use DFX. In a situation where, for example, you want to deploy canisters for your users programmatically, you need cycles for those canisters, and having a way to mint them programmatically would be useful. I was trying to implement this functionality myself and there were no tools existed to do this but I found this project ,[multisig\_index/src at master · Catalyze-Software/multisig\_index · GitHub](https://github.com/Catalyze-Software/multisig_index/tree/master/src), was implementing this and pieced their code together into this library, [https://github.com/amschel99/mint-cycles](https://github.com/amschel99/mint-cycles)

All credits to them

---

<div class="post-metadata">

### Author: ![Ray04](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/ray04/32/24164_2.png) [@Ray04](https://forum.dfinity.org/u/Ray04)
#### Post date: [September 26, 2024, 6:03am UTC](https://forum.dfinity.org/t/programmatically-mint-cycles-in-rust/32271/2 "2024-09-26T06:03:58Z")

</div>

Hello there @amschel99  
I wanted to integrate this rust library that you made in my project and when I went through the source code, I see that in the function: transfer\_icp, you’ve used this function: transfer  
calling the icp ledger, ofcourse. What my question is, if I’d like to take ICP from the user, and then use that to convert to cycles for a new canister creation or top up. We usually use, approve and transfer\_from functions of icrc2 in icp ledger, So, my question is in order to use your library in my project, will I have to alter the transfer function or just proceed with this one? Please let me know, thanks.

---

<div class="post-metadata">

### Author: ![amschel99](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/amschel99/32/18280_2.png) [@amschel99](https://forum.dfinity.org/u/amschel99)
#### Post date: [November 1, 2024, 7:28am UTC](https://forum.dfinity.org/t/programmatically-mint-cycles-in-rust/32271/3 "2024-11-01T07:28:03Z")

</div>

It’s been a while since I logged in here. Hope you got the help you wanted. In my setup, what I was doing is make the user send some icp to the backend canister that I want to mint cycles for using Plug wallet. They have logic for this which uses icrc2 approve. When the canister has ICP i now use this library to mint cycles. You can also write the function to spend on behalf of the user too using icrc2 approve.

---

<div class="post-metadata">

### Author: ![rem.codes](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/rem.codes/32/40260_2.png) [@rem.codes](https://forum.dfinity.org/u/rem.codes)
#### Post date: [November 3, 2024, 6:24pm UTC](https://forum.dfinity.org/t/programmatically-mint-cycles-in-rust/32271/4 "2024-11-03T18:24:08Z")

</div>

Nice to see that the code I’ve written is being used, a [reference](https://github.com/Catalyze-Software/multisig_index/tree/master/src) to it would have been nice tho.

---

<div class="post-metadata">

### Author: ![amschel99](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/amschel99/32/18280_2.png) [@amschel99](https://forum.dfinity.org/u/amschel99)
#### Post date: [November 5, 2024, 6:48am UTC](https://forum.dfinity.org/t/programmatically-mint-cycles-in-rust/32271/5 "2024-11-05T06:48:35Z")

</div>

All credits to you. Powerful code

---

<div class="post-metadata">

### Author: ![Ray04](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/ray04/32/24164_2.png) [@Ray04](https://forum.dfinity.org/u/Ray04)
#### Post date: [November 6, 2024, 6:37am UTC](https://forum.dfinity.org/t/programmatically-mint-cycles-in-rust/32271/6 "2024-11-06T06:37:20Z")

</div>

@rem.codes @amschel99  
That’s exactly what I want to do as well.  
I want to take ICP from user and have it send to my backend canister, but we always need their approval before the transfer right? icrc2\_approve → icrc2\_transfer\_from.  
My question was, in order to do exactly this does the function need any alteration?  
It’ll be great help, if any of you can help me with this. Thank you!

---

<div class="post-metadata">

### Author: ![rem.codes](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/rem.codes/32/40260_2.png) [@rem.codes](https://forum.dfinity.org/u/rem.codes)
#### Post date: [November 7, 2024, 10:46am UTC](https://forum.dfinity.org/t/programmatically-mint-cycles-in-rust/32271/7 "2024-11-07T10:46:06Z")

</div>

There are a couple of flows you can follow, the main approach i usually take is adding cycles to the “parent” canister and use that to spin up a “child” canister which is the flow explained below.

You can also spin up a canister directly from the CMC canister by using the right memo and skip a call, but i was running into issues with pocket-ic that it tried to create the new canister on the NNS subnet.

You should send `ICP` to the “parent canister” and then following the flow below, optionally using a subaccount (left it out to make it easier to follow)

–  
**Ledger**  
Structs used are coming from the following package

```auto
ic-ledger-types = "0.13"

```

```rs
pub static MEMO_TOP_UP_CANISTER: Memo = Memo(1347768404);
pub static MEMO_CREATE_CANISTER: Memo = Memo(1095062083);

pub async fn topup_self(
    icp_amount_e8s: u64,
    canister: Principal,
) -> CanisterResult<Nat> {
    let amount = Tokens::from_e8s(icp_amount_e8s) - ICP_TRANSACTION_FEE;

    let args = TransferArgs {
        memo: MEMO_TOP_UP_CANISTER, // important
        amount,
        fee: ICP_TRANSACTION_FEE,
        from_subaccount: None,
        to: AccountIdentifier::new(
            &MAINNET_CYCLES_MINTING_CANISTER_ID, // imported from ic-ledger-types
            &Subaccount::from(canister), // important
        ),
        created_at_time: None
    };

    match transfer(MAINNET_LEDGER_CANISTER_ID, args).await {
        Ok(result) => match result {
            Ok(block_index) => notify_top_up_cycles(block_index).await,
            Err(err) => todo!("handle error"),
        },
        Err(err) => todo!("handle error"),
    }
}

```

–  
**CMC**  
The [CyclesMintingService](https://dashboard.internetcomputer.org/canister/rkp4c-7iaaa-aaaaa-aaaca-cai) can be pulled from the rust declarations on the bottom of the linked dashboard page, this holds the methods and structs needed for the method below.

```rs
pub async fn notify_top_up_cycles(block_index: u64) -> CanisterResult<Nat> {
    match CyclesMintingService(MAINNET_CYCLES_MINTING_CANISTER_ID)
        .notify_top_up(NotifyTopUpArg {
            block_index, // block index of the transaction
            canister_id: id(), // principal set in the transfer.to subaccount
        })
        .await
    {
        Ok((result,)) => match result {
            NotifyTopUpResult::Ok(cycles) => Ok(cycles),
            NotifyTopUpResult::Err(err) => todo!("handle error"),
        },
        Err((_, err)) => todo!("handle error"),
    }
}

```

–  
**Create canister**  
Finally creating the canister

```auto
ic-cdk = "0.16"

```

```rs
pub async fn deploy_canister(
    cycles: u64,
    controllers: Vec<Principal>,
) -> CanisterResult<Principal> {
    let args = CreateCanisterArgument { 
        settings: Some(CanisterSettings {
            controllers: Some(controllers),
            compute_allocation: None,
            memory_allocation: None,
            freezing_threshold: None,
            reserved_cycles_limit: None,
            wasm_memory_limit: None,
            log_visibility: None,
        }),
    };

    create_canister(args, cycles as u128)
        .await
        .map(|(result,)| result.canister_id)
        .map_err(|(_, err)| todo!("handle error"))
}

```

also some helper functions that are used for converting the cycles to the right format.

```auto
pub fn nat_to_f64(n: &Nat) -> f64 {
    let n_str = n.0.to_string();
    n_str.parse::<f64>().unwrap()
}

pub fn f64_to_u64(f: f64) -> u64 {
    f.round() as u64
}

pub fn nat_to_u64(n: &Nat) -> u64 {
    f64_to_u64(nat_to_f64(n))
}

```

so in the end it would look something like

```rs
let cycles = topup_self(icp_e8s, id()).await?;
let new_canister = deploy_canister(nat_to_u64(&cycles), vec![id()]).await?;

```
