From 6699a7b0845eeb4e1e6a0aa9a4c3d7e9f8b01d0e Mon Sep 17 00:00:00 2001 From: lsgunnlsgunn Date: Thu, 24 Sep 2020 13:04:49 -0700 Subject: [PATCH 1/2] Start on wallet tutorial --- .../pages/tutorials/wallet-app.adoc | 484 ++++++++++++++++++ 1 file changed, 484 insertions(+) create mode 100644 modules/developers-guide/pages/tutorials/wallet-app.adoc diff --git a/modules/developers-guide/pages/tutorials/wallet-app.adoc b/modules/developers-guide/pages/tutorials/wallet-app.adoc new file mode 100644 index 000000000..94b828641 --- /dev/null +++ b/modules/developers-guide/pages/tutorials/wallet-app.adoc @@ -0,0 +1,484 @@ += Transferring cycles +ifdef::env-github,env-browser[:outfilesuffix:.adoc] +:toc: +:toc: right +:toc-title: TUTORIAL - CYCLES +:toclevels: 3 +:proglang: Motoko +:platform: Internet Computer platform +:IC: Internet Computer +:company-id: DFINITY +:sdk-short-name: DFINITY Canister SDK +:sdk-long-name: DFINITY Canister Software Development Kit (SDK) + +As discussed in link:introduction-key-concepts{outfilesuffix}#resource-intro[Canisters and resource usage], applications that run on the {IC} pay for the resources they consume. + +To illustrate how to transfer cycles between canisters owned by different user identities, this tutorial creates a simple program with **wallet canisters** that can be used to hold, send, and receive cycles that can then be used to pay for the storage and computation resources required to run applications. + +In this example, there are two canister owners—`+bob+` and `+alice+`—each with a unique identity represented by a unique principal. +Each identity has a wallet canister—the `+bob_wallet+` and the `+alice_wallet+`—that they use to hold their cycle balance and to transfer cycles to other canisters. + +For this tutorial, the sample program is written in the Rust programming language and uses features and interfaces provided by the link:https://github.com/dfinity/rust-cdk[Rust Canister Development Kit]. +The sample program includes the following functions to illustrate some common operations you would expect a wallet canister to provide: + +* An `+init+` function to declare some initial variables and types. +* A `+custodians+` function to list all of the currently-trusted custodians. +* An `+authorize+` function to authorize a specific principal as a trusted custodian. +* A `+deauthorize+` to remove authorization from a currently-trusted custodian principal. +* A `+cycle_balance+` function to return the current cycle balance for a specified canister. +* A `+send_cycles+` function to send cycles to a specified canister. +* A `+receive_cycles+` function to receive cycles from a specified canister. +* A `+call_external+` function to forward a call that transfers cycles as payload to another canister. + +The sample program also includes a `+record+` function to record a simple audit trail of certain types of cycle transfer events and an `+events+` to return a simple audit trail of recent events that have been recorded by a canister. + +== Before you begin + +Before starting the tutorial, verify the following: + +* You have downloaded and installed the {sdk-short-name} package as described in link:../../quickstart/quickstart{outfilesuffix}#download-and-install[Download and install]. + +* + +* You have stopped any {IC} network processes running on the local +computer. + +== Create a new project + +To create a new project for transferring cycles between wallet canisters: + +[arabic] +. Open a terminal shell on your local computer, if you don’t already have one open. +. Change to the folder you are using for your {IC} sample projects. +. Create a new project by running the following command: ++ +[source,bash] +---- +dfx new rust_wallet_app +---- +. Change to your project directory by running the following command: ++ +[source,bash] +---- +cd rust_wallet_app +---- + +== Modify the default program + +For this tutorial, you are going to replace the template source code file with a program that has functions for assigning and retrieving roles. + +To modify the default program: + +. Open the `+src/access_hello/main.mo+` file in a text editor and delete the existing content. +. Copy and paste the following sample code into the file: ++ +[source,motoko] +---- +include::example$access-hello/main.mo[] +---- ++ +Let's take a look at a few key elements of this program: ++ +-- +* You might notice that the `+greet+` function is a variation on the `+greet+` function you have seen in previous tutorials. ++ +In this program, however, the `+greet+` function uses a message caller to determine the permissions that should be applied and, based on the permissions associated with the caller, which greeting to display. +* The program defines two custom types—one for `+Roles+` and one for `+Permissions+`. +* The `+assign_roles+` function enables the message aller to assign a role to the principal associated with an identity. +* The `+callerPrincipal+` function enables you to return the principal associated with an identity. +* The `+my_role+` function enables you to return the role that is associated with an identity. +-- +. Save your changes and close the `+main.mo+` file to continue. + +== Start the local network + +Before you can build the `+access_hello+` project, you need to connect to the {IC} network either running locally in your development environment or running remotely on a sub-network that you can access. + +To start the network locally: + +[arabic] +. Open a new terminal window or tab on your local computer and navigate to your project directory. ++ +For example, you can do either of the following if running Terminal on macOS: ++ +-- +* Click *Shell*, then select *New Tab* to open a new terminal in your current working directory. + +* Click *Shell* and select *New Window*, then run `+cd ~/ic-projects/access_hello+` in the new terminal if your `+access_hello+` project is in the `+ic-projects+` working folder. +-- ++ +You should now have two terminals open with your project directory as your current working directory. +. Start the {IC} network on your local computer by running the following command: ++ +[source,bash] +---- +dfx start +---- ++ +After you start the local network, the terminal displays messages about network operations. +. Leave the terminal that displays network operations open and switch your focus to your original terminal where you created your project. + +== Register canister identifiers + +After you connect to the {IC} network running locally in your development environment, you can register with the network to generate unique canister identifiers for your project. + +To register canister identifiers for the local network: + +. Check that you are still in your project directory, if needed. +. Register a unique canister identifier for the project by running the following command: ++ +[source,bash] +---- +dfx canister create access_hello +---- ++ +The first time you run this command, it creates a `+default+` user identity in the `+$HOME/.config/dfx/identity/+` directory. ++ +.... +Creating the "default" identity. + - migrating key from /Users/lisagunn/.dfinity/identity/creds.pem to /Users/lisagunn/.config/dfx/identity/default/identity.pem +Created the "default" identity. +Creating canister "access_hello"... +"access_hello" canister created with canister id: "75hes-oqbaa-aaaaa-aaaaa-aaaaa-aaaaa-aaaaa-q" +.... ++ +After creating the `+identity.pem+` key file for the `+default+` user identity, the command displays the network-specific canister identifier for the `+access_hello+` main program. + +== Build and deploy the program + +You are now ready to compile the program into a WebAssembly module and deploy it on your local network. + +Because this tutorial illustrates running the {IC} locally, the canister identifier is only valid on the local network. +To deploy canisters on a remote network, you must connect to that network using the `+--network+` command-line option and a specific network name or address to register identifiers on that network. + +To build and deploy the program: + +[arabic] +. Check that you are still in your project directory, if needed. +. Build the executable WebAssembly module by running the following command: ++ +[source,bash] +---- +dfx build access_hello +---- ++ +The command displays output similar to the following: ++ +.... +Building canisters... +.... +. Deploy your `+access_hello+` project on the local network by running the following command: ++ +[source,bash] +---- +dfx canister install access_hello +---- ++ +The command output displays output similar to the following: ++ +.... +Installing code for canister access_hello, with canister_id 75hes-oqbaa-aaaaa-aaaaa-aaaaa-aaaaa-aaaaa-q +.... +. Check the principal for the `+default+` user identity by running the following command: ++ +[source,bash] +---- +dfx canister call access_hello callerPrincipal +---- ++ +The command displays output similar to the following: ++ +.... +(principal "nnuac-d26ja-o4tcm-mcr4i-qxgon-fkuqx-tshde-74bb4-6fead-hdnd6-5ae") +.... +. Check the role associated with the `+default+` user identity by running the following command: ++ +[source,bash] +---- +dfx canister call access_hello my_role +---- ++ +The command displays output similar to the following: ++ +.... +(opt variant { owner }) +.... + +== Create a new user identity + +To begin testing the access controls in our program, you need to create some new user identities and assign those users to different roles. + +To create a new user identity: + +. Check that you are still in your project directory, if needed. +. Create a new administrative user identity by running the following command: ++ +[source,bash] +---- +dfx identity new ic_admin +---- ++ +The command displays output similar to the following: ++ +.... +Creating identity: "ic_admin". +Created identity: "ic_admin". +.... +. Call the `+my_role+` function to see that your new user identity has not been assigned to any role. ++ +[source,bash] +---- +dfx --identity ic_admin canister call access_hello my_role +---- ++ +The command displays output similar to the following: ++ +.... +(null) +.... +. Get the principal for the new `+ic_admin+` user identity by running the following command: ++ +[source,bash] +---- +dfx --identity ic_admin canister call access_hello callerPrincipal +---- ++ +The command displays output similar to the following: ++ +.... +(principal "kenjo-txsrk-ctozi-gnls4-v4sf4-ndupc-wmrji-nuemy-7hp2y-kwkre-tae") +.... +. Assign this principal the `+admin+` role by running a command similar to the following using Candid syntax: ++ +.... +dfx canister call access_hello assign_role '((principal "kenjo-txsrk-ctozi-gnls4-v4sf4-ndupc-wmrji-nuemy-7hp2y-kwkre-tae"),opt variant{admin})' +.... ++ + +NOTE: Be sure to replace the `+principal+` hash with the one returned by the `+dfx identity callerPrincipal+` command. + ++ +Optionally, you can rerun the command to call the `+my_role+` function to verify the role assignment. ++ +[source,bash] +---- +dfx --identity ic_admin canister call access_hello my_role +---- +The command displays output similar to the following: ++ +.... +(opt variant { admin }) +.... +. Call the `+greet+` function using the `+ic_admin+` user identity that you just assigned the `+admin+` role by running the following command: ++ +[source,bash] +---- +dfx --identity ic_admin canister call access_hello greet "Internet Computer Admin" +---- ++ +The command displays output similar to the following: ++ +.... +( + "Hello, Internet Computer Admin. You have a role with administrative privileges.", +) +.... + +== Add an authorized user identity + +At this point, you have a `+default+` user identity with the `+owner+` role and an `+ic_admin+` user identity with the `+admin+` role. +Let's add another user identity and assign it to the `+authorized+` role. +For this example, however, we'll use an environment variable to store the user's principal. + +To add a new authorized user identity: + +. Check that you are still in your project directory, if needed. +. Create a new authorized user identity by running the following command: ++ +[source,bash] +---- +dfx identity new alice_auth +---- ++ +The command displays output similar to the following: ++ +.... +Creating identity: "alice_auth". +Created identity: "alice_auth". +.... +. Store the principal for the new user in an environment variable by running the following command: ++ +[source,bash] +---- +ALICE_ID=$(dfx --identity alice_auth canister call access_hello callerPrincipal | sed 's/[\\(\\)]//g') +---- ++ +You can verify the principal stored by running the following command: ++ +[source,bash] +---- +echo $ALICE_ID +---- ++ +The command displays output similar to the following: ++ +.... +principal "ixskg-luu4i-jxn6i-ie5v4-ynykj-6d2sz-l6ctg-r6524-yxoeb-taimb-rqe" +.... ++ +Optionally, you can call the `+my_role+` function to verify that the principal role assignment is `+null+`. +. Use the `+ic_admin+` identity to assign the `+authorized+` role to `+alice_auth+` by running the following command: ++ +[source,bash] +---- +dfx --identity ic_admin canister call access_hello assign_role "($ALICE_ID, opt variant{authorized})" +---- +. Call the `+my_role+` function to verify the role assignment. ++ +[source,bash] +---- +dfx --identity alice_auth canister call access_hello my_role +---- +The command displays output similar to the following: ++ +.... +(opt variant { authorized }) +.... +. Call the `+greet+` function using the `+alice_auth+` user identity that you just assigned the `+authorized+` role by running the following command: ++ +[source,bash] +---- +dfx --identity alice_auth canister call access_hello greet "Alice" +---- ++ +The command displays output similar to the following: ++ +.... +( + "Welcome, Alice. You have an authorized account. Would you like to play a game?", +) +.... + +== Add an unauthorized user identity + +You have now seen a simple example of creating users with specific roles and permissions. +The next step is to create a user identity that is not assigned to a role or given any special permissions. + +To add an unauthorized user identity: + +. Check that you are still in your project directory, if needed. +. Create a new user identity by running the following command: ++ +[source,bash] +---- +dfx identity new bob_standard +---- ++ +The command displays output similar to the following: ++ +.... +Creating identity: "bob_standard". +Created identity: "bob_standard". +.... +. Call the `+my_role+` function to see that your new user identity has not been assigned to any role. ++ +[source,bash] +---- +dfx --identity bob_standard canister call access_hello my_role +---- ++ +The command displays output similar to the following: ++ +.... +(null) +.... +. Store the principal for the new user in an environment variable by running the following command: ++ +[source,bash] +---- +BOB_ID=$(dfx --identity bob_standard canister call access_hello callerPrincipal | sed 's/[\\(\\)]//g') +---- +. Attempt to use the `+bob_standard+` identity to assign a role. ++ +[source,bash] +---- +dfx --identity bob_standard canister call access_hello assign_role "($BOB_ID, opt variant{authorized})" +---- ++ +This command returns an `+unauthorized+` error. +. Attempt to use the `+default+` user identity to assign `+bob_standard+` the `+owner+` role by running the following command: ++ +[source,bash] +---- +dfx canister call access_hello assign_role "($BOB_ID, opt variant{owner})" +---- ++ +This command fails because users cannot be assigned the `+owner+` role. +. Call the `+greet+` function using the `+bob_standard+` user identity by running the following command: ++ +[source,bash] +---- +dfx --identity bob_standard canister call access_hello greet "Bob" +---- ++ +The command displays output similar to the following: ++ +.... +("Greetings, Bob. Nice to meet you!") +.... + +== Set the user identity for multiple commands + +So far, you have seen how to create and switch between user identities for individual commands. +You can also specify a user identity you want to use, then run multiple commands in the context of that user identity. + +To run multiple commands under one user identity: + +. Check that you are still in your project directory, if needed. +. List the user identities currently available by running the following command: ++ +[source,bash] +---- +dfx identity list +---- ++ +The command displays output similar to the following with an asterisk indicating the currently active user identity. ++ +.... +alice_auth +bob_standard +default * +ic_admin +.... ++ +In this example, the `+default+` user identity is used unless you explicitly select a different identity. +. Select a new user identity from the list and make it the active user context by running a command similar to the following: ++ +[source,bash] +---- +dfx identity use ic_admin +---- ++ The command displays output similar to the following: ++ +.... +Using identity: "ic_admin". +.... ++ +If you rerun the `+dfx identity list+` command, the `+ic_admin+` user identity displays an asterisk to indicate it is the currently active user context. ++ +You can now run commands using the selected user identity without specifying `+--identity+` on the command-line. + +== Stop the local network + +After you finish experimenting with the program and using identities, you can stop the local Internet Computer network so that it doesn’t continue running in the background. + +To stop the local network: + +. In the terminal that displays network operations, press Control-C to interrupt the local network process. + +. Stop the {IC} network by running the following command: ++ +[source,bash] +---- +dfx stop +---- From e6e5aaa97b3b9bd2ee9be733cbcb6c139db3950d Mon Sep 17 00:00:00 2001 From: lsgunnlsgunn Date: Thu, 24 Sep 2020 14:26:55 -0700 Subject: [PATCH 2/2] draft wallet tutorial WIP --- .../pages/tutorials/wallet-app.adoc | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/modules/developers-guide/pages/tutorials/wallet-app.adoc b/modules/developers-guide/pages/tutorials/wallet-app.adoc index 94b828641..e8084254d 100644 --- a/modules/developers-guide/pages/tutorials/wallet-app.adoc +++ b/modules/developers-guide/pages/tutorials/wallet-app.adoc @@ -36,9 +36,13 @@ The sample program also includes a `+record+` function to record a simple audit Before starting the tutorial, verify the following: +* You have downloaded and installed the Rust programming language and Cargo as described in the link:https://doc.rust-lang.org/book/ch01-01-installation.html[Rust installation instructions] for your operating system. + * You have downloaded and installed the {sdk-short-name} package as described in link:../../quickstart/quickstart{outfilesuffix}#download-and-install[Download and install]. -* +* You have downloaded the latest version of the {cdk-long-name} from the link:https://crates.io/[Rust community’s crate registry] or from the link:https://github.com/dfinity/rust-cdk[Rust CDK] repository. ++ +For this tutorial, you should note the location you use for the local version of the `+rust-cdk+` repository or copy the directory to the folder you are using for your {IC} sample projects. * You have stopped any {IC} network processes running on the local computer. @@ -63,6 +67,22 @@ dfx new rust_wallet_app cd rust_wallet_app ---- +== Modify the default canister settings + +Creating a new project adds a default `+dfx.json+` configuration file to your project directory. +Because the sample program for this tutorial is written in the Rust programming language, we need to modify the default canister settings. + +For this sample program, we'll create the following canisters: + +* The `+alice_account+` canister is the wallet canister that's owned by the `+alice+` identity. +* The `+bob_account+` is the wallet canister that's owned by the `+bob+` identity. +* The `+wallet_app+` is a wallet canister that's owned by the default user for initialization purposes. + +To modify the default `+dfx.json+` configuration file for the `+wallet_app+` Rust project: + +. Open the `+dfx.json+` configuration file in a text editor and delete the existing content. +. Replace the `+canisters.rust_counter+` settings with settings for building a canister using the `+cargo build+` command. + == Modify the default program For this tutorial, you are going to replace the template source code file with a program that has functions for assigning and retrieving roles.