This document serves as a walkthrough to deploy a canister on the mainnet.
Get your Internet Identities via Internet Identity. I recommend having a Bitwarden account and the Bitwarden Chrome extension installed for passkey activation.
Login to NNS via NNS Dapp.
Top up some 2.0 ICP tokens to your NNS-II address. This can be done on the panel Tokens > Internet Computer
.
Install DFX CLI on your system using this guide: Installing tools | Internet Computer.
Create a new identity locally using dfx
:
dfx identity new custodian_name
This will generate a passphrase that you should save somewhere secure. Ensure you have selected the right identity
via this command:
dfx identity whoami
# To see a list of identities on this machine
dfx identity list
# To switch identity
dfx identity use some_idname
Get the principal address
of the currently active identity:
dfx identity get-principal
# This will print e.g., pztcx-5wpjw-ko6rv-3cjff-466eb-4ywbn-a5jww-rs6yy-ypk4a-ceqfb-nqe
Export this to an environment variable CUSTODIAN_PRINCIPAL
:
export CUSTODIAN_PRINCIPAL=$(dfx identity get-principal)
We will use this to deploy our canister later.
Add cycles:
Add the controller using the custodian_principal
that we obtained locally:
Make sure you already have Git and Rust installed:
git clone [email protected]:garudaidr/icp-subaccount-indexer-prototype.git
Within your project’s root directory, add or adjust the following file canister_ids.json
:
{
"icp_prototype_backend": {
"ic": "upy4y-myaaa-aaaal-qjbxa-cai"
}
}
Replace the canister_id
that can be retrieved from the canister panel on the NNS dashboard. For example, upy4y-myaaa-aaaal-qjbxa-cai
.
Sync the local wallet to the mainnet:
dfx identity --network ic deploy-wallet <canister_id>
Convert ICP to cycles:
dfx cycles convert 0.3 --network ic
Ensure the currently active identity is the correct custodian
identity linked as the controller on NNS from previous steps. Don’t forget to export the value for CUSTODIAN_PRINCIPAL
using the sub-step from step 5.
dfx deploy icp_prototype_backend --network ic --no-wallet --argument "(variant { Mainnet }, 15 : nat64, 10 : nat32, \"ryjl3-tyaaa-aaaaa-aaaba-cai\", \"$(echo $CUSTODIAN_PRINCIPAL)\")"
Some roadblocks you may encounter:
- The
wasm32-unknown-unknown
target may not be installed:
rustup target add wasm32-unknown-unknown
Upon success, it will generate a URL, e.g., https://a4gq6-oaaaa-aaaab-qaa4q-cai.raw.icp0.io/?id=uiz2m-baaaa-aaaal-qjbxq-cai
. Sometimes, due to network issues, you may encounter a stuck process that needs to be canceled and re-run.
Export the Canister ID to a shell environment variable:
export CANISTER_ID=<canister_id>
# e.g.
# export CANISTER_ID=g5nrt-myaaa-aaaap-qhluq-cai
The poller needs to be jumpstarted
by setting the poller interval:
dfx canister --network ic call $(echo $CANISTER_ID) set_interval '(1)'
Set next_block
to avoid querying from 0. The most recent block number can be checked here: ICP Transactions.
dfx canister --network ic call $(echo $CANISTER_ID) set_next_block '(12110174)'
To check the ongoing next_block
:
dfx canister --network ic call $(echo $CANISTER_ID) get_next_block '()'
This part of the operation is to be done by [email protected]. To test methods on your canister, use the format: dfx canister --network ic call <canister_id> <method_name> '<argument>'
.
dfx canister --network ic call $(echo $CANISTER_ID) canister_status '()'
To sweep:
dfx canister --network ic call $(echo $CANISTER_ID) sweep '()'
To check the balance:
dfx ledger --network ic balance
To transfer out (make sure to deduct 0.0001
for the fee, otherwise it will fail):
dfx ledger transfer --network ic --amount <amount-fee> --memo <any_number> <withdraw_address>
If the previous balance was 0.5099, the amount to withdraw should be 0.5098:
dfx ledger transfer --network ic --amount 0.5098 --memo 0 5c8aea1a5c6b871125c5b876688f2c28483a37314717750f2175156742fd08d8
![Step 12 Image 4](https://slabstatic.com/prod/uploads/nq0f6x9q/posts/images/preload/vbcfmy7VMLGZCsH9
ffOWYgO5.png)
Upon successful transfer, you will get the response: "Transfer sent at block height 12110251".
There may be a need to export the identity from the deployer to an operator.
dfx identity export <identity_name>
Example:
dfx identity export user
Copy the printed text into <some_file.pem>
.
dfx identity import <identity_name> <pem_file>
Example:
dfx identity import user2 user2.pem
You can check if the identities are already listed:
dfx identity list
Don’t forget to switch identity as needed via the command:
dfx identity use <some_id>
Example:
dfx identity use user2
Hardcode the principal ID if the initial deployment doesn't properly set it:
let custodian_principal = "".to_string(); // fill this ""
let custodian_principal =
Principal::from_text(&custodian_principal).expect("Invalid custodian principal");
CUSTODIAN_PRINCIPAL.with(|principal_ref| {
let stored_principal = StoredPrincipal::new(custodian_principal);
let _ = principal_ref.borrow_mut().set(stored_principal);
});
Put the above code in the async fn post_upgrade()
function.
Set the ledger ID if it is not set in the initial deployment:
let ledger_principal = "ryjl3-tyaaa-aaaaa-aaaba-cai".to_string();
let principal = Principal::from_text(&ledger_principal).expect("Invalid ledger principal");
PRINCIPAL.with(|principal_ref| {
let stored_principal = StoredPrincipal::new(principal);
let _ = principal_ref.borrow_mut().set(stored_principal);
});
ic_cdk::println!("running post_upgrade...");
reconstruct_subaccounts();
reconstruct_network();
Put the above code in the async fn post_upgrade()
function.