Cycles are the only native token on the Internet Computer, so it feels strange that they don’t seem to have all the first-class support they deserve. For example, there is no “standard” or “convention” to do just cycles transfer. Ever wonder how you could collect remaining cycles before uninstalling a canister that you no longer use? You are not alone!
It is time for us developers to come together and establish a common interface for cycles transfer!
To that end, I’ve started a Cycles Common Initiative on github to analyze the problems that developers are current facing, and to find solutions to address them. Your participation will benefit the entire dev community!
I’ve made a first proposal trying to tackle the cycles transfer interface in the form of a pull request. I need your reviews, comments, and suggestions!
The gist of the proposal can be summarized as a single function that enables both send and receive, and much more:
type Response =
variant {
rejected: text;
transferred: nat64;
unauthorized;
};
type Request =
record {
amount: opt nat64;
receiver: opt principal;
sender: opt principal;
};
type CyclesTransfer =
service {
cycles_transfer: (Request) -> (Response);
};
Early implementation and example can be found in the cycles-motoko repository. I plan to work on a Rust implementation in the coming days, if no one beats me to it.
Such an interface will not take off without community adoption, because sending/receiving cycles between canisters and services requires coordination! Hopefully this kick start will boost such an effort and we’ll all benefit from it. Thank you!
Thanks for starting this! Good common interfaces will be crucial for the success of the platform.
Did you look at the interface of the cycle wallet? It defines an interface for receiving cycles, via wallet_receive. It seems your interface is for instructing a canister to send cycles somewhere else, so it should probably send them in a wallet-compatible way?
Also, I am confused why your Request contains a sender. What does that mean? Wouldn’t a call to cycle_transfer not always tell the canister to send some of its cycles to some receiver?
Thanks for commenting! The purpose of this proposal is to establish a general cycles transfer interface that can enable many use cases based on different implementations.
Specifically for the “sender” field, it can be null in most cases when caller_id can be assumed to be the “sender”. However, this only works in the case of “direct” cycles transfer. If cycles have to go through intermediaries, the original sender would not be the “caller” of the final deposit.
Why use intermediaries? For one, direct transfer from “ordinary” application subnet to “verified” application subnet is not possible at the moment. Seeing that IC probably will develop many subnet “flavors”, developers will likely have to live with this kind of restrictions for a long time to come. We can imagine that someone to offer a “cycles bridge” service to help funnel cycles between different subnet flavors.
Another reason is for user to build redirection services, where the receiving canister can be chosen from a set maintained by the redirection service, not by the actual cycles sender.
I am aware of the existing cycles wallet interface, but my hope is that if this proposal makes more sense, maybe the cycles wallet can change to follow this interface instead?
We went down the route of just wrapping cycles (https://wtctoken.com/) and providing endpoints which allow these wrapped cycles to be converted to traditional cycles instantly. This has the following benefits:
Users (as in self-authenticating principals) can’t hold a balance of cycles directly. WTC allows this to occur so any principal can hold a balance of WTC and no proxy is required
WTC as a token allows for better interoperability with dapps/wallets as it can use the same standard as other tokens. This will also allow WTC to be tradable on exchanges
EXT as a token standard has some cool features, like transferAndCall, so a receiving canister can access data like the sender’s principal, and even have the ability to reject a transfer as well.
I’d say WTC addresses a different problem. It naturally becomes a central place where cycles can be exchanged conveniently. But this proposal here tries to address how cycles can be freely transferred between canisters without restriction. Involving a central bank-like canister should be a choice, not a requirement.
The proposed interface here is trying to encourage more interoperability between canisters. It’ll be great if your WTC canister can implement this interface too! For example, transfer-in can be seen as converting cycles to WTC, and transfer-out can be seen as converting WTC to cycles. Happy to discuss further if you think the proposed interface can be adjusted to better accommodate WTC’s use case. Thanks!
I don’t really have an opinion to be honest, there are already ways to send and receive cycles without having any special interface, e.g. using the ic system deposit_cycles call which I think does this.
I think a standard interface could be good, but not sure how it should look like at this stage.