diff --git a/README.md b/README.md index 9262ad06..85c52d18 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ More examples are available [here](canister/scripts/examples.sh). #### Prerequisites: -* Add the `sol_rpc_client` library as a dependency in your `Cargo.toml`. +* Add the `sol_rpc_client` and `sol_rpc_types` libraries as dependencies in your `Cargo.toml`. * Follow the steps outlined [here](libs/client/README.md#build-requirements) to ensure your code compiles. * If you are running the example locally, follow the instructions [here](README.md#deployment) to deploy a local instance of the SOL RPC canister. diff --git a/examples/basic_solana/README.md b/examples/basic_solana/README.md index 6f2b2c05..f077ef4d 100644 --- a/examples/basic_solana/README.md +++ b/examples/basic_solana/README.md @@ -30,7 +30,8 @@ the [chain fusion overview](https://internetcomputer.org/docs/building-apps/chai * [ ] Confirm the IC SDK has been installed with the correct version with `dfx --version`. * [ ] On **macOS**, an `llvm` version that supports the `wasm32-unknown-unknown` target is required. This is because the `zstd` crate (used, for example, to decode `base64+zstd`-encoded responses from Solana's [`getAccountInfo`](https://solana.com/de/docs/rpc/http/getaccountinfo)) depends on LLVM during compilation. The default LLVM bundled with Xcode does not support `wasm32-unknown-unknown`. To fix this, install the [Homebrew version](https://formulae.brew.sh/formula/llvm), using `brew install llvm`. -> ⚠️ **NOTE:** If you wish to use this example as a starting point for your own project, make sure your follow the instructions in the [build requirements](https://github.com/dfinity/sol-rpc-canister/blob/main/libs/client/README.md#build-requirements) for the `sol_rpc_client` crate to ensure that your code compiles. +> [!NOTE] +> If you wish to use this example as a starting point for your own project, make sure your follow the instructions in the [build requirements](https://github.com/dfinity/sol-rpc-canister/blob/main/libs/client/README.md#build-requirements) for the `sol_rpc_client` crate to ensure that your code compiles. ## Step 1: Building and deploying sample code @@ -41,7 +42,6 @@ To clone and build the smart contract in **Rust**: ```bash git clone https://github.com/dfinity/sol-rpc-canister cd examples/basic_solana -git submodule update --init --recursive ``` **If you are using macOS, you'll need to install Homebrew and run `brew install llvm` to be able to @@ -64,7 +64,7 @@ the following command: dfx deploy --ic ``` -This deploys a wallet canister to the ICP Mainnet which is configured to interact with the Solana Devnet via the SOL RPC +This deploys a Solana wallet canister to the ICP Mainnet which is configured to interact with the **Solana Devnet** via the SOL RPC canister at [`tghme-zyaaa-aaaar-qarca-cai`](https://dashboard.internetcomputer.org/canister/tghme-zyaaa-aaaar-qarca-cai). Note that you will need to pay for your requests with cycles. If you do not have cycles available for testing, consider running this example locally as described in the next section. @@ -81,14 +81,15 @@ dfx deploy What this does: - `dfx start --clean --background` starts a local instance of the ICP blockchain. -- `dfx deploy` deploys a wallet canister as well as a SOL RPC canister, both locally. The wallet canister interacts with +- `dfx deploy` deploys a Solana wallet canister as well as a SOL RPC canister, both locally. The Solana wallet canister interacts with the Solana Devnet via the local SOL RPC canister. -**NOTE:** If running this example locally, you will need to skip the `--ic` flag in all subsequent `dfx` commands. +> [!TIP] +> To target Solana Mainnet, you will need to change the `init_arg` for the `basic_solana` canister in the `dfx.json` file. To learn more about the initialization arguments, see the `InitArg` type in [`basic_solana.did`](basic_solana.did). ### Getting the canister ID -If the canister deployment is successful (whether on Mainnet of locally), you should see an output that looks like this: +If the canister deployment is successful (whether on Mainnet or locally), you should see an output that looks like this: ```bash Deploying: basic_solana @@ -107,6 +108,9 @@ In the output above, to see the Candid Web UI for your Solana canister, you woul `https://bd3sg-teaaa-aaaaa-qaaba-cai.raw.icp0.io/?id=`. You should see the methods specified in the Candid file `basic_solana.did`. +> [!IMPORTANT] +> If running this example locally, you will need to skip the `--ic` flag in all subsequent `dfx` commands. + ## Step 2: Generating a Solana account A Solana account can be derived from an EdDSA public key. To derive a user's specific account, identified on the IC by a @@ -134,7 +138,7 @@ This will return a different Solana address as the one above, such as ## Step 3: Receiving SOL -Now that you have your Solana account, let us send some (Devnet) SOL to it: +Now that you have your Solana account, let us send some Devnet SOL to it: 1. Get some Devnet SOL if you don't have any. You can for example use [this faucet](https://faucet.solana.com/). 2. Send some Devnet SOL to the address you obtained in the previous step. You can use any Solana wallet to do so. @@ -148,6 +152,9 @@ You can send SOL using the `send_sol` endpoint on your canister, specifying a So in the smallest unit (Lamport). For example, to send 1 Lamport to `8HNiduWaBanrBv8c2pgGXZWnpKBdEYuQNHnspqto4yyq`, run the following command: +> [!NOTE] +> If no principal is provided, the caller's principal is used. In this `basic_solana` example, you could replace `null` with another principal to send SOL on their behalf. This is behaviour you would typically not want in production, as it allows anyone to send SOL from any account to any other account. In production, you would typically want to restrict the `send_sol` endpoint to only allow sending SOL from the caller's account. + ```shell dfx canister --ic call basic_solana send_sol '(null, "8HNiduWaBanrBv8c2pgGXZWnpKBdEYuQNHnspqto4yyq", 1)' ``` @@ -191,6 +198,9 @@ dfx canister --ic call basic_solana get_nonce To send some SOL using a durable nonce, you can run the following command: +> [!NOTE] +> If no principal is provided, the caller's principal is used. In this `basic_solana` example, you could replace `null` with another principal to send SOL on their behalf. This is behaviour you would typically not want in production, as it allows anyone to send SOL from any account to any other account. In production, you would typically want to restrict the `send_sol_with_durable_nonce` endpoint to only allow sending SOL from the caller's account. + ```shell dfx canister --ic call basic_solana send_sol_with_durable_nonce '(null, "8HNiduWaBanrBv8c2pgGXZWnpKBdEYuQNHnspqto4yyq", 1)' ``` @@ -223,21 +233,28 @@ example use the USDC token whose mint account on Devnet is `4zMMC9srt5Ri5X14GAgX You first need to create [Associated Token Accounts (ATA)](https://spl.solana.com/associated-token-account) for the sender and recipient accounts if they do not exist yet. An ATA is a [Program Derived Address (PDA)](https://solana.com/docs/core/pda) derived from a Solana account using the token mint -account. An ATA is needed for each type of SPL token held by a Solana account. To create the ATAs for the sender and -recipient, you can run the following commands: +account. An ATA is needed for each type of SPL token held by a Solana account. + +We create two new identities, one for the sender and one for the recipient. You can do this by running the following commands: ```bash -dfx identity use sender -dfx canister call basic_solana create_associated_token_account '(null, "")' -dfx identity use recipient -dfx canister call basic_solana create_associated_token_account '(null, "")' +dfx identity new sender +dfx identity new recipient ``` -or +We have to make sure the Solana accounts belonging to the new identities created above actually hold SOL to pay for transaction fees. For this, follow the instructions outlined in [Step 2](#step-2-generating-a-solana-account) and [Step 3](#step-3-receiving-sol) for each identity. You can switch between identities using the `dfx identity use ` command or specify the identity to use by adding the `--identity ` flag to the `dfx` commands. + +To create the ATAs for the sender and +recipient, you can run the following commands: + +> [!NOTE] +> If no principal is provided as the first argument, the caller's principal is used. ```bash -dfx canister call basic_solana create_associated_token_account '(opt principal "", "")' -dfx canister call basic_solana create_associated_token_account '(opt principal "", "")' +dfx identity use sender +dfx canister --ic call basic_solana create_associated_token_account '(null, "")' +dfx identity use recipient +dfx canister --ic call basic_solana create_associated_token_account '(null, "")' ``` This works by sending transactions that instruct the @@ -249,16 +266,23 @@ To send some tokens from the sender to the receiver, you will need to obtain som e.g. [this faucet](https://faucet.circle.com/) for USDC). To do this, you will need the ATA address of the sender. You can for example get it by running the following command: +> [!NOTE] +> If no principal is provided as the first argument, the caller's principal is used. + ```bash dfx identity use sender -dfx canister call basic_solana associated_token_account '(null, "")' +dfx canister --ic call basic_solana associated_token_account '(null, "")' ``` To transfer some tokens from the sender to the recipient, you can run the following command: +> [!NOTE] +> If no principal is provided as the first argument, the caller's principal is used. +> Make sure to use the `RECIPIENT SOLANA ADDRESS`, not their ATA. + ```bash dfx identity use sender -dfx canister call basic_solana send_spl_token '(null, "", "", )' +dfx canister --ic call basic_solana send_spl_token '(null, "", "", )' ``` The `send_spl_token` endpoint works similarly to the `send_sol` endpoint, but creates a transaction with the sender and @@ -266,9 +290,12 @@ recipient ATAs instead of their account addresses. You can also inspect the resu and verify that the associated token balances were updated accordingly. You can also check the updated token balances by running the following commands: +> [!NOTE] +> If no ATA is provided, it is derived from the caller's principal. + ```bash -dfx canister call basic_solana get_spl_token_balance '(opt principal "", "")' -dfx canister call basic_solana get_spl_token_balance '(opt principal "", "")' +dfx canister --ic call basic_solana get_spl_token_balance '(opt "", "")' +dfx canister --ic call basic_solana get_spl_token_balance '(opt "", "")' ``` ## Conclusion diff --git a/examples/basic_solana/local/canister_ids.json b/examples/basic_solana/local/canister_ids.json index 21f147bf..fb5c9eb8 100644 --- a/examples/basic_solana/local/canister_ids.json +++ b/examples/basic_solana/local/canister_ids.json @@ -1,5 +1,5 @@ { "sol_rpc": { - "local": "lxzze-o7777-77777-aaaaa-cai" + "local": "tghme-zyaaa-aaaar-qarca-cai" } } \ No newline at end of file diff --git a/examples/basic_solana/local/dfx.json b/examples/basic_solana/local/dfx.json index c5a13c99..42a898f2 100644 --- a/examples/basic_solana/local/dfx.json +++ b/examples/basic_solana/local/dfx.json @@ -1,7 +1,7 @@ { "canisters": { "sol_rpc": { - "specified_id": "lxzze-o7777-77777-aaaaa-cai", + "specified_id": "tghme-zyaaa-aaaar-qarca-cai", "candid": "../../../canister/sol_rpc_canister.did", "package": "sol_rpc_canister", "type": "custom", @@ -12,7 +12,12 @@ "name": "candid:service" } ], - "init_arg": "( record { manageApiKeys = null; overrideProvider = null; logFilter = opt variant { ShowAll }; numSubnetNodes = null; mode = opt variant { Demo }; } )" + "init_arg": "( record { manageApiKeys = null; overrideProvider = null; logFilter = opt variant { ShowAll }; numSubnetNodes = null; mode = opt variant { Demo }; } )", + "remote": { + "id": { + "ic": "tghme-zyaaa-aaaar-qarca-cai" + } + } }, "basic_solana": { "candid": "../basic_solana.did", @@ -25,7 +30,7 @@ "name": "candid:service" } ], - "init_arg": "( record { solana_network = opt variant { Custom = record { url = \"https://api.devnet.solana.com\"; headers = null } }; ed25519_key_name = opt variant { LocalDevelopment }; sol_rpc_canister_id = opt principal \"lxzze-o7777-77777-aaaaa-cai\" } )" + "init_arg": "( record { solana_network = opt variant { Custom = record { url = \"https://api.devnet.solana.com\"; headers = null } }; ed25519_key_name = opt variant { LocalDevelopment }; sol_rpc_canister_id = opt principal \"tghme-zyaaa-aaaar-qarca-cai\" } )" } }, "version": 1