Improving the Cycle Management Experience

Hi everyone!

A major pain point for developers is cycle management (“Removal of Cycles Wallet” is currently at the number-2 spot on the DX feedback board).

We’d like to pick up work on this topic soon but would like to collect some community feedback first, of course.

We currently envision the following change to dfx: A new subcommand (tentatively called) cycles would be introduced that enables you to check the cycles balance of your principal ID (dfx cycles balance). This new subcommand can also be used to transfer cycles to another principal ID or to any canister.
Naturally, it would also be possible to increase the cycles balance using ICP.

A promising approach to implement this functionality is the introduction of a cycles ledger, which would adhere to the ICRC-1 (and probably also the ICRC-2) standard.
There seems to be interest in such a ledger in general as the topic was brought up again recently on the forum.

Note that the cycles wallet will continue to exist for those who wish to use it. The cycles wallet can be used to call other canisters with cycles attached. A global cycles ledger would not have this functionality.

If you have any requests, questions, or feedback about this feature, please share them here!

16 Likes

I currently use the cycle token xtc for all my cycle needs. It would be cool if I could just keep doing that but with an ICRC token. We just need better documentations so new people know about the token.

We don’t need more dfx commands. Dfx is already complicated enough.

Maybe a redesign.

2 Likes

The process should be very similar, one of the differences being that the new ledger would be ICRC-1/2 compliant.
And yes, we will definitely try to create good/better documentation. :slight_smile:

This activity can be considered part of a redesign (rather than adding more stuff on top) to make cycle management more user-friendly.

3 Likes

A nice gui and a way to bind it all to my internet identity would be really nice. And some oauth type things so I can write cli tools that people can just plug into their dfx identity.

The ability for me to customize my own tools would be much more powerful than you guys trying to guess my needs.

3 Likes

Hey everyone!

Let me give you an update about our work on the cycles ledger:

The implementation of the ledger itself is nearly done. The ledger complies with the ICRC-1 and ICRC-2 standards. Moreover, it will also support ICRC-3, providing a standardized way to access the transaction log.

Once the implementation is ready, which should happen in the next couple of weeks, we will propose to deploy the cycles ledger on a system subnet. If the proposal is accepted and the ledger is up and running, it can then already be used to transfer cycles between principal IDs.

We are working in parallel on the required changes to use the cycles ledger from dfx with the goal of simplifying cycles management through a dedicated subcommand.
It is too early to say when this functionality will be available but the current goal is to release it in the next couple of months.

4 Likes

It’s time for another update: We had an internal security review of the cycles ledger implementation and are now in the process of fixing the issues that the security team identified.

Since we anticipate that most issues will be fixed within the next couple of weeks, we’d like to initiate the deployment process by creating a proposal to whitelist a principal ID to install the cycles ledger on the uzr34 system subnet.

Once the proposal is live, I’ll post the link here. As always, if you have any questions or concerns, please let me know!

4 Likes

Is there any preliminary documentation or API that we can work off of if we want to integrate with the cycles ledger once it launches?

Also, is this something that can first be integrated with dfx pull so we can test out the intended functionality in the meantime?

1 Like

There is no public documentation yet but I can provide the current API here. Note that there is still a chance that the API will change.

As mentioned before, the cycles ledger complies with the ICRC-1 and ICRC-2 standards. Additionally, it implements the endpoints defined in the proposed ICRC-3 standard.
Apart from the endpoints defined in these three standards, the cycles ledger only has two additional endpoints:

type Account = record { owner : principal; subaccount : opt vec nat8 };

type BlockIndex = nat;

type DepositArgs = record {
  to : Account;
  memo : opt vec nat8;
};

type DepositResult = record { balance : nat; txid : nat };

type RejectionCode = variant {
  NoError;
  CanisterError;
  SysTransient;
  DestinationInvalid;
  Unknown;
  SysFatal;
  CanisterReject;
};

type SendArgs = record {
    amount : nat;
    from_subaccount : opt vec nat8;
    to : principal;
    created_at_time : opt nat64;
};

type SendError = variant {
  GenericError : record { message : text; error_code : nat };
  TemporarilyUnavailable;
  FailedToSend : record {
    fee_block : opt nat;
    rejection_code : RejectionCode;
    rejection_reason : text;
  };
  Duplicate : record { duplicate_of : nat };
  BadFee : record { expected_fee : nat };
  InvalidReceiver : record { receiver : principal };
  CreatedInFuture : record { ledger_time : nat64 };
  TooOld;
  InsufficientFunds : record { balance : nat };
};

service : (ledger_args : LedgerArgs) -> {
  deposit : (DepositArgs) -> (DepositResult);
  [ICRC endpoints]
  send : (SendArgs) -> (variant { Ok : BlockIndex; Err : SendError });
}

The deposit endpoint makes it possible to deposit cycles in the cycles ledger: The to account in the DepositArgs is credited for the cycles attached to the call.
Conversely, the send endpoint is called to instruct the cycles ledger to send the amount (of cycles) specified in the SendArgs to the canister specified in the to field of the SendArgs.

The integration with dfx deps shouldn’t be too hard. @lwshang, what do you think?

2 Likes

Hey everyone! The proposal to create the cycles ledger canister on the uzr34 subnet is now live, so please vote! :slight_smile:

The principal ID of the cycles ledger team is

b6f5g-tu3kx-cqx6r-dygkz-xevyv-fwi3i-vsqej-5ugqi-7hnsk-2scby-fae,

which should be the same as the principal ID in the proposal.

Note that, if the proposal goes through, we will first create an empty canister, which will give us the canister ID of the cycles ledger.
If all goes according to plan, the cycles ledger will then be installed in the next couple of weeks.

5 Likes

We now created two canisters on subnet uzr34:

We don’t plan to install anything to these canisters just yet, but once we do we’ll let you know here

2 Likes

What’s the ETA? Will there be a proposal soon to introduce this cycles ledger on mainnet?

I’m asking to determine if it makes sense for me to build such a feature for Juno myself or if I should wait. I will need this feature to allow developers to delete their canisters. So, ideally, I’d prefer the second option, but depending on the timeline, if it’s another feature I depend on and which takes months again, I might opt for the former. Thanks in advance for the feedback.

Thanks for reminding me to provide an update! I said a few weeks ago that the cycles ledger should be ready soon if all goes according to plan. However, other work took priority, so unfortunately progress on this feature was slower than anticipated.
The tentative goal is now to have it ready by the end of the year.

The repository should be publicly available very soon. While the code is not yet ready for production, you could use it for your own purposes if you wish. But waiting a bit longer is also an option, if that works for you. :slightly_smiling_face:

Regarding the release process, the cycles ledger team has a principal ID that is authorized to deploy the cycles ledger on a system subnet, so no proposal will be required to install the cycles ledger.

Thanks for the feedback. I’ll think about it,

Considering the ratio of developer effort to another waiting time, I’ve decided to implement my feature using deposit_cycles (PR). I’m still looking forward to the potential usefulness of the cycles ledger in the future.

2 Likes

Hey everyone!
Quick update: Unfortunately, the required resources to finish up the implementation work have not been available in the last couple of weeks, which unfortunately means that we have to postpone the release of the cycles ledger until early 2024.
The good news is that the source code is now publicly available here, so everybody can check it out.

3 Likes

Any update on when the cycle ledger would be available? This is one of the highly anticipated feature by a lot of people, and we hope the foundation can prioritize. For one, the cycle ledger would keep records of every burn (via the send function), so that we can legitimately show to people that a cycle transfer to a canister did take place.

1 Like

Good news: Work on the cycles ledger has been picked up again.
I can’t give an accurate release date yet but the plan is to release it at some point in Q1 2024.
Once we’re ready to set a release date, I’ll announce it here!

4 Likes

In the context of Scalable Messaging Model, is there a possibility of extending the cycles ledger with a batchSend() API that has the following signature:

Candid
send : (vec SendArgs) -> (vec variant { Ok : BlockIndex; Err : SendError });

Motoko

send : ([SendArgs]) -> async [{
  #Ok : BlockIndex;
  #Err : SendError;
}]

I’m not sure I understand the idea behind your proposed batchSend endpoint.
Are you trying to address the problem that the response of a send call may not tell you whether the cycles were transferred out to the target canister?
If I understand the proposal correctly, the only potential advantage of batching is that you can get a response (or not) for multiple transfers at the same time. However, the case where the response does not reveal whether the batched execution went through must still be handled.

Is that the intention or did I get it wrong?

The batched endpoint will return an array of results indicated if each send was successful or not. Providing a batch endpoint helps with the scalability of canisters that interact with the cycles ledger (or any ledger) when there are spikes in transaction requests.

As a use case, I would like to in a single request, send 100 SendArgs to the cycles ledger asking 100 different ledger accounts to transfer cycles to a specific canister. I would like to receive responses for each of the 100 transfer attempts indicating if they were successful or if they failed. In this case, I am trusting the result response from the cycles ledger that the cycles were successfully sent/transferred to a canister, and I don’t need to confirm after the fact that the cycles were actually sent.

This is not the same as a transactional update (where one would expect all messages or succeed, or would fail if one of the messages does not succeed)

Here’s my reasoning for providing a batch endpoint:

  1. Canisters have output queue limitations, so batching requests helps improve throughput to the cycles ledger. Canister Output Message Queue Limits, and IC Management Canister Throttling Limits - #2 by paulyoung
  2. Every outgoing request and outstanding call context requires a memory reservation, which is one of the reasons that the Scalable Messaging Model is being implemented. Providing a batch endpoint on a ledger reduces the number of outstanding calls at a single time (i.e. alternatively making parallel requests to the cycles ledger), which frees up this memory and increases the scalability of the subnet.