Giter Club home page Giter Club logo

cycles-ledger's Introduction

Cycles Ledger

The cycles ledger is a global ledger canister that enables principal IDs to hold cycles.

The cycles ledger complies with the ICRC-2 and ICRC-1 token standards. Additionally, it implements the endpoints defined in the proposed ICRC-3 standard.

The cycles ledger further provides endpoints to deposit and withdraw cycles, and also to create canisters using cycles. These custom endpoints are introduced in the following.

Cycles Ledger Canister

Principal

um5iw-rqaaa-aaaaq-qaaba-cai

View on Internet Computer Dashboard

Depositing Cycles

The cycles ledger has the following endpoint for other canisters to deposit cycles.

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

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

deposit : (DepositArgs) -> (DepositResult);

When invoked with a particular account (and, optionally, a memo), the balance of the account is incremented by the number of cycles attached to the call. There is no fee when depositing cycles; however, the number of cycles must be at least the transfer fee of 100M cycles.

NOTE: The deposit is rejected if fewer than 100M cycles are attached to the call.

Withdrawing Cycles

The cycles ledger has the following endpoint to withdraw cycles to other canisters.

type BlockIndex = nat;

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

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

type WithdrawError = variant {
  GenericError : record { message : text; error_code : nat };
  TemporarilyUnavailable;
  FailedToWithdraw : 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 };
};

withdraw : (WithdrawArgs) -> (variant { Ok : BlockIndex; Err : WithdrawError });

The two required parameters are the amount to be sent and the principal ID of the targeted canister ID. Optionally, the subaccount from which cycles are deducted and the time at which the transaction is created can be set as well.

There is a fee of 100M cycles for withdrawing cycles to another canister.

NOTE: The function returns an error when the parameter to is not a valid canister ID.

Creating Canisters Using Cycles

The canister creation process via cycles can be triggered from the cycles ledger using the endpoint create_canister.

type CreateCanisterArgs = record {
  from_subaccount : opt vec nat8;
  created_at_time : opt nat64;
  amount : nat;
  creation_args : opt CmcCreateCanisterArgs;
};

type CmcCreateCanisterArgs = record {
  settings : opt CanisterSettings;
  subnet_selection : opt SubnetSelection;
};

type CanisterSettings = record {
  controllers : opt vec principal;
  compute_allocation : opt nat;
  memory_allocation : opt nat;
  freezing_threshold : opt nat;
};

type SubnetFilter = record {
  subnet_type : opt text;
};

type SubnetSelection = variant {
  /// Choose a specific subnet
  Subnet : record {
    subnet : principal;
  };
  Filter : SubnetFilter;
};

type CreateCanisterError = variant {
  InsufficientFunds : record { balance : nat };
  TooOld;
  CreatedInFuture : record { ledger_time : nat64 };
  TemporarilyUnavailable;
  Duplicate : record { duplicate_of : nat };
  FailedToCreate : record {
    fee_block : opt BlockIndex;
    refund_block : opt BlockIndex;
    error : text;
  };
  GenericError : record { message : text; error_code : nat };
};

create_canister : (CreateCanisterArgs) -> (variant { Ok : CreateCanisterSuccess; Err : CreateCanisterError });

The only parameter that must be provided is the number of cycles that should be used for the canister creation. The cycles ledger fee of 100M cycles is deducted from the user's account together with the specified amount. The cycles ledger then sends the request to create a canister to the cycles minting canister, attaching amount cycles to the call. The cost for the canister creation itself can be found here.

NOTE: The canister is created on a random subnet unless specified otherwise. SubnetSelection can be used to specify a particular subnet or subnet type.

Build the cycles-ledger

The cycles-ledger should be built using the script ./scripts/docker-build. The script will put the cycles-ledger.wasm.gz in the directory where it was run.

Make a new Release

The CI job release-with-github.yml is responsible to create a new release. The release job uses cargo-release. This project follows Semantic Versioning 2.0.0 (aka semver).

The release job can be triggered by using gh or directly from github:

gh workflow run --repo dfinity/cycles-ledger "release-with-github.yml" -f semverBump=(major|minor|patch)

The job will then bump the version based on the strategy passed via semverBump, make the release and make a PR with the version changes and the release linked to the PR. See this for valid semverBump values and their effect.

cycles-ledger's People

Contributors

dfx-json avatar ericswanson-dfinity avatar eust-dfinity avatar github-actions[bot] avatar lwshang avatar maciejdfinity avatar mariodfinity avatar nikolashai avatar sesi200 avatar thlo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cycles-ledger's Issues

feature request: alternative withdrawal method by making arbitrary canister call

It would be similar to wallet_call that is offered by cycle wallet at the moment.

type WalletResultCall = variant {
  Ok : record { return: blob };
  Err : text;
};

//Call Forwarding
  wallet_call: (record {
    canister: principal;
    method_name: text;
    args: blob;
    cycles: nat64;
  }) -> (WalletResultCall);
  wallet_call128: (record {
    canister: principal;
    method_name: text;
    args: blob;
    cycles: nat;
  }) -> (WalletResultCall);

This would enable users to make calls that require cycles. For example, an ICRC token canister may want its fees paid in cycles.

I know that there is a security concern of outstanding call contexts that could prevent ledger from being upgraded. But I still think this is worth discussing.

Transfer_from Duplicate request errors when transfering from different accounts

In local testing, I'm currently batching multiple transfer_from calls from a canister to the cycles ledger.

In this simple case, I set up 16 cycle ledger developer "user" accounts, and then make calls in parallel to transfer the exact same amount of cycles from each user to an account owned by a canister (the receiver account is the same for all 16 calls).

Even though the "sender" of cycles in each case is different, I'm receiving duplication errors.

When I stringify the resulting errors (in Motoko) I see one successful transfer, and the rest recognized as duplicates.

[{"ok":"720"},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}},{"err":{"Duplicate":{"duplicate_of":"720"}}}]

Following these deduplication instructions and adding unique memo content for each request solves this problem (no deduplication errors), but it feels like if the sender and receiver are different, the payload is structurally different and this deduplication error shouldn't occur (it shouldn't require me adding a unique memo).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.