Skip to content

Commit

Permalink
fix: update ledger info and docs (#3880)
Browse files Browse the repository at this point in the history
* update ledger info and docs

* using the ledger guides
  • Loading branch information
jessiemongeon1 authored Dec 13, 2024
1 parent 4f80bf8 commit 81d0ccf
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 528 deletions.
183 changes: 103 additions & 80 deletions docs/developer-docs/defi/tokens/ledger/setup/icp_ledger_setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ import { MarkdownChipRow } from "/src/components/Chip/MarkdownChipRow";

<MarkdownChipRow labels={["Intermediate" , "Tutorial"]} />

The Internet Computer Protocol (ICP) implements management of its utility token (ticker "ICP") using a specialized canister, called the **ICP ledger canister**. It is a single ledger canister that runs alongside other canisters on a special subnet of the Internet Computer—the NNS subnet. The ICP ledger canister is a smart contract that holds **blocks**, each containing a single transaction.


The Internet Computer Protocol (ICP) implements management of its utility token (ticker "ICP") using a specialized canister, called the **ICP ledger canister**. It is a single ledger canister that runs alongside other canisters on a special subnet of the Internet Computer - the NNS subnet. The ICP ledger canister is a smart contract that holds **blocks**, each containing a single transaction.

These transactions either:
These transactions are either:

- **Mint ICP tokens** for accounts.

Expand All @@ -38,7 +36,7 @@ If you are working in a local development environment, i.e., with a local replic

An ICP ledger account (see [ICRC-1 standard](/docs/current/developer-docs/defi/tokens/token-standards#icrc-1)) belongs to and is controlled by the account owner, who must have a valid principal ID. No account can be owned by two or more principals (no "joint accounts"). However, since a principal can refer to an external user as well as to a canister, joint accounts can be implemented as canisters.

An account on the ledger is represented and stored as an `AccountIdentifier`, which is derived from the principal ID and subaccount identifier by computing a hash of the two. The subaccount is an optional bitstring that helps distinguish between the different sub-accounts of the same owner.
An account on the ledger is represented and stored as an `AccountIdentifier`, which is derived from the principal ID and subaccount identifier by computing a hash of the two. The subaccount is an optional bitstring that helps distinguish between the different subaccounts of the same owner.

In this context, you can think of principal identifiers as a rough equivalent to the hash of a user’s public key for Bitcoin or Ethereum. You use the corresponding secret key to sign messages and therefore authenticate to the ledger canister and operate on the principal’s account. Canisters can also have accounts in the ledger canister, in which case the address is derived from the canister’s principal.

Expand All @@ -47,166 +45,191 @@ In this context, you can think of principal identifiers as a rough equivalent to
The main reason for introducing accounts was to allow a principal to control multiple accounts. While this could be abstracted away for a user by the wallet software, this is not possible for canisters.
:::


## Deploying the ledger locally

There are two ways of deploying an ICP ledger locally.
- Use [dfx-nns](/docs/current/developer-docs/developer-tools/cli-tools/cli-reference/dfx-nns) to deploy the entire NNS locally. Since the ICP ledger is part of the NNS, this command will also install an ICP ledger with canister ID `ryjl3-tyaaa-aaaaa-aaaba-cai`. This solution is fast and straightforward, but also more heavyweight.
- Deploy the ICP ledger `wasm` locally. This method is discussed and demonstrated in this guide, as it gives you more control over the deployment and is lightweight.
There are two ways of deploying an ICP ledger locally:

Deploying an ICP ledger locally gives you certain advantages over the default ledger from `dfx` that is installed with `dfx nns install`. For instance, you can define the `minting account`, you have control over the initialization arguments and you have control over which `wasm` version of the ICP ledger you want to interact with.
1. Use [`dfx nns`](/docs/current/developer-docs/developer-tools/cli-tools/cli-reference/dfx-nns) to deploy the entire NNS locally. Since the ICP ledger is part of the NNS, this command will also install an ICP ledger with canister ID `ryjl3-tyaaa-aaaaa-aaaba-cai`. This solution is fast and straightforward, but also more heavyweight.

The ICP ledger only exists on the mainnet and the `wasm` that is running on the mainnet is not meant to be used for other token deployments. It needs to be backward compatible and thus contains a lot of legacy code that should not be used when deploying a new ledger.
2. Deploy the ICP ledger locally using the canister's Wasm file. This method is discussed and demonstrated in this guide, as it gives you more control over the deployment and is lightweight.

If you want to deploy your own token or build an ICRC-1 ledger, have a look at the [guide on setting up an ICRC-1 ledger](/docs/current/developer-docs/defi/tokens/ledger/setup/icrc1_ledger_setup).
Deploying an ICP ledger locally using the Wasm or `.did` files gives you certain advantages over the default ledger from `dfx` that is installed with `dfx nns install`. For instance, you can define the `minting account`, you have control over the initialization arguments, and you have control over which Wasm version of the ICP ledger you want to interact with.

Follow the steps below to deploy your copy of the ledger canister to a local replica.
:::danger
The ICP ledger is not meant to be used for other token deployments because it needs to be backwards compatible and thus contains a lot of legacy code that should not be used when deploying a new ledger.

### Step 1: Make sure you use a recent version of the [IC SDK](/docs/current/developer-docs/getting-started/install).
If you don’t have the IC SDK installed, follow the instructions on the [installing the IC SDK](/docs/current/developer-docs/getting-started/install) section to install it.
If you want to deploy your own token, read the [guide on setting up an ICRC-1 ledger](/docs/current/developer-docs/defi/tokens/ledger/setup/icrc1_ledger_setup).
:::

### Step 2: Create a new dfx project with the command:
## Using `dfx nns install`

```
dfx new icp_ledger_canister
cd icp_ledger_canister
```
The [`dfx nns install`](/docs/current/developer-docs/developer-tools/cli-tools/cli-reference/dfx-nns) command can be used to deploy an instance of the entire NNS locally. The NNS includes the ICP ledger canister with canister ID `ryjl3-tyaaa-aaaaa-aaaba-cai`.

:::caution
## Using the most recent ICP ledger Wasm file

If using `dfx` version 0.17.1 or newer, choose 'Motoko' for the backend language, and 'No frontend canister' for the frontend language.
<Tabs>
<TabItem value="prereq" label="Prerequisites" default>

:::
<input type="checkbox"/> <a href="/docs/current/developer-docs/getting-started/install">Install the IC SDK.</a>

</TabItem>
</Tabs>

### Step 3: Determine the ledger file locations.
- #### Step 1: Create a new `dfx` project or open an existing project.

Go to the [releases overview](https://dashboard.internetcomputer.org/releases) and copy the latest replica binary revision. At the time of writing, this is `aba60ffbc46acfc8990bf4d5685c1360bd7026b9`.
- #### Step 2: Obtain the latest ledger Wasm and Candid files.

The URL for the ledger Wasm module is `https://download.dfinity.systems/ic/<REVISION>/canisters/ledger-canister.wasm.gz`, so with the above revision it would be `https://download.dfinity.systems/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/canisters/ledger-canister.wasm.gz`.
Go to the [releases overview](https://dashboard.internetcomputer.org/releases) and copy the latest replica binary revision.

The URL for the ledger.did file is `https://raw.githubusercontent.com/dfinity/ic/<REVISION>/rs/ledger_suite/icp/ledger.did`, so with the above revision it would be `https://raw.githubusercontent.com/dfinity/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/rs/ledger_suite/icp/ledger.did`.
The URL for the ledger Wasm module is `https://download.dfinity.systems/ic/<REVISION>/canisters/ledger-canister.wasm.gz`.

The URL for the ledger's Candid file is `https://raw.githubusercontent.com/dfinity/ic/<REVISION>/rs/ledger_suite/icp/ledger.did`.

#### Optional
If you want to make sure you have the latest ICP ledger files, you can run the following script. Please ensure that you have [`jq`](https://jqlang.github.io/jq/) installed as the script relies on it.
If you want to make sure you have the latest ICP ledger files, you can run the following script. Please ensure that you have [`jq`](https://jqlang.github.io/jq/) installed, as the script relies on it.

``` sh
curl -o download_latest_icp_ledger.sh "https://raw.githubusercontent.com/dfinity/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/rs/rosetta-api/scripts/download_latest_icp_ledger.sh"
chmod +x download_latest_icp_ledger.sh
./download_latest_icp_ledger.sh
```

### Step 4: Create a new identity that will work as a minting account:
- #### Step 3: Create a new identity that will work as a minting account.

``` sh
dfx identity new minter
dfx identity use minter
echo $(dfx ledger account-id)
```

Record the output of these commands as your minting account ID.
Record the output of these commands as your minting account ID. Transfers from the minting account will create `Mint` transactions. Transfers to the minting account will create `Burn` transactions.

Transfers from the minting account will create `Mint` transactions. Transfers to the minting account will create `Burn` transactions.

### Step 5: Switch back to your default identity and record its ledger account identifier.
- #### Step 4: Switch back to your primary developer identity and record its ledger account identifier.

``` sh
dfx identity use default
dfx identity use MyIdentity
echo $(dfx ledger account-id)
```

Record the output of these commands as your default account ID.
Record the output of these commands as your developer account ID.

### Step 6: Configure the `dfx.json` file.
- #### Step 5: Configure the `dfx.json` file.

Open the `dfx.json` file in your project's directory. Replace the existing content with the following, updating the values of `MINTER_ACCOUNT_ID` and `DEFAULT_ACCOUNT_ID` with the values obtained in the previous steps:
Open the `dfx.json` file in your project's directory. Replace the existing content with the following, updating the values of `MINTER_ACCOUNT_ID` and `DEVELOPER_ACCOUNT_ID` with the values obtained in the previous steps:

:::info
`dfx.json` does not support referring to values through environment variables. Values must be hardcoded in plain text.
:::

``` json
{
"canisters": {
"icp_ledger_canister": {
"type": "custom",
"candid": "https://raw.githubusercontent.com/dfinity/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/rs/ledger_suite/icp/ledger.did",
"wasm": "https://download.dfinity.systems/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/canisters/ledger-canister.wasm.gz",
"remote": {
"id": {
"ic": "ryjl3-tyaaa-aaaaa-aaaba-cai"
}
},
"init_arg" : "(variant { Init = record { minting_account = \"MINTER_ACCOUNT_ID\"; initial_values = vec { record { \"DEFAULT_ACCOUNT_ID\"; record { e8s = 10_000_000_000 : nat64; }; }; }; send_whitelist = vec {}; transfer_fee = opt record { e8s = 10_000 : nat64; }; token_symbol = opt \"LICP\"; token_name = opt \"Local ICP\"; } })"
}
},
"defaults": {
"build": {
"args": "",
"packtool": ""
}
},
"output_env_file": ".env",
"version": 1
  "canisters": {
    "icp_ledger_canister": {
      "type": "custom",
      "candid": "https://raw.githubusercontent.com/dfinity/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/rs/ledger_suite/icp/ledger.did",
      "wasm": "https://download.dfinity.systems/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/canisters/ledger-canister.wasm.gz",
      "remote": {
        "id": {
          "ic": "ryjl3-tyaaa-aaaaa-aaaba-cai"
        }
      },
      "init_arg" : "(variant { Init = record { minting_account = \"MINTER_ACCOUNT_ID\"; initial_values = vec { record { \"DEFAULT_ACCOUNT_ID\"; record { e8s = 10_000_000_000 : nat64; }; }; }; send_whitelist = vec {}; transfer_fee = opt record { e8s = 10_000 : nat64; }; token_symbol = opt \"LICP\"; token_name = opt \"Local ICP\"; } })"
    }
  },
  "defaults": {
    "build": {
      "args": "",
      "packtool": ""
    }
  },
  "output_env_file": ".env",
  "version": 1
}
```

If you chose to download the ICP ledger files with the script you need to replace the Candid and Wasm file entries:
:::danger
If you chose to download the ICP ledger files with the script, you need to replace the Candid and Wasm file entries:

```json
...
"candid": icp_ledger.did,
"wasm" : icp_ledger.wasm.gz,
...
  ...
```

This `dfx.json` file also defines the init arguments for the ledger canister:
:::

This `dfx.json` file defines the init arguments for the ledger canister:

- Sets the minting account to the account identifier you saved in a previous step (`MINTER_ACCOUNT_ID`).
- Mints 100 ICP tokens to the `DEFAULT_ACCOUNT_ID` (1 ICP is equal to 10^8 e8s).
- Sets the transfer fee to 0.0001 ICP.
- Names the token `Local ICP / LICP`.

You can also pass these init args to the canister using the command line. [Learn more about init args](/docs/current/developer-docs/developer-tools/cli-tools/advanced-dfx/init-args/).
### Init arguments

You can also pass these init args to the canister [using the command line](/docs/current/developer-docs/developer-tools/cli-tools/advanced-dfx/init-args/#using-init_arg) or by [storing them in a file](/docs/current/developer-docs/developer-tools/cli-tools/advanced-dfx/init-args/#using-an-init_arg_file), then referencing that file in your `dfx.json` configuration:

```json
{
  "canisters": {
    "icp_ledger_canister": {
      "type": "custom",
      "candid": "https://raw.githubusercontent.com/dfinity/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/rs/ledger_suite/icp/ledger.did",
      "wasm": "https://download.dfinity.systems/ic/aba60ffbc46acfc8990bf4d5685c1360bd7026b9/canisters/ledger-canister.wasm.gz",
      "remote": {
        "id": {
          "ic": "ryjl3-tyaaa-aaaaa-aaaba-cai"
        }
      },
      "init_arg_file" : "init-args.did"
    }
  },
  "defaults": {
    "build": {
      "args": "",
      "packtool": ""
    }
  },
  "output_env_file": ".env",
  "version": 1
}
```

[Learn more about init args](/docs/current/developer-docs/developer-tools/cli-tools/advanced-dfx/init-args/).

### Step 7: Start a local replica.
- #### Step 6: Start a local replica.

``` sh
dfx start --clean --background
```

### Step 8: Deploy the ledger canister locally:
- #### Step 7: Deploy the ledger canister locally.

:::caution
In this workflow, you cannot deploy this canister to the playground (using flag `dfx deploy --playground`) because it does not accept gzipped Wasm files.
You cannot deploy this canister to the playground (using the flag `dfx deploy --playground`) because it does not accept gzipped Wasm files.
:::

```
dfx deploy --specified-id ryjl3-tyaaa-aaaaa-aaaba-cai icp_ledger_canister
```

Take a moment to read the details of the call made above. Not only are you deploying the ICP ledger canister, you are also deploying the canister to the same canister ID as the mainnet ledger canister. This is to make it easier to switch between local and mainnet deployments.
:::info
You are deploying the local ICP ledger canister to the same canister ID as the mainnet ledger canister. This is to facilitate switching between local and mainnet deployments.
:::

Your local ICP ledger canister is up and running. You can now deploy other canisters that need to communicate with the ledger canister.

### Step 9: Interact with the canister.
- #### Step 8: Interact with the canister.

You can interact with the canister by running CLI commands, such as:

```
dfx canister call icp_ledger_canister name
```

This command will return the token's name, such as:

```
("Local ICP")
```

Or, you can interact with it using the Candid UI by navigating to the URL provided when the canister was deployed, such as:

```
http://127.0.0.1:4943/?canisterId=bnz7o-iuaaa-aaaaa-qaaaa-cai&id=ryjl3-tyaaa-aaaaa-aaaba-cai
```

After navigating to this URL in a web browser, the Candid UI will resemble the following:

![Candid UI](../../../_attachments/CandidUI.png)

Your local ICP ledger canister is up and running. You can now deploy other canisters that need to communicate with the ledger canister.
```
Loading

0 comments on commit 81d0ccf

Please sign in to comment.