From 67a3bf512d983dfe263073d92663bc2097ac074f Mon Sep 17 00:00:00 2001 From: Philipp Date: Wed, 24 Aug 2022 17:43:07 +0200 Subject: [PATCH] Extend and refactor Stardust examples (#981) * Commit example for testing/debugging * Working alias-controls-alias example * Impl `StardustDID` -> `AliasId` conversion * Add more (unfinished) examples * Fix native assets example * Remove adding Sender Feature by default * Polish alias-controls-alias example * Use latest draft PR commit * Use `AliasId::from` instead of `AliasId::try_from` * Use `iota-client` crates version * Add token issue example * Add nft owns did example * Rename examples * Refactor examples into separate project * Polish examples * Rename examples stardust directory * Update CI examples instructions * Remove `./` * Remove unknown clippy lint * Polish examples * Polish utils * Remove unused manifest key in examples * Polish examples more * Revert "Remove unknown clippy lint" This reverts commit 7dd77e949ee60195f7eb58593323289e1408b5b0. * Remove dedicated stardust build step in CI * Integrated stardust crates into root workspace * Bump bee-block version to match iota-client * Impl `From` for re-exported `AliasId` * Inline NFT example creation * Use Stronghold secret manager * Use double-digits in example names * Improve examples with suggestions * Remove unnecessary CI steps * Rename package to `examples` * Add examples README * Number sub-folders * Improve variable names in DPP example * Use single-digit within folders after all * Rename old examples to examples_legacy * Add key exchange example * Rename example stronghold file * Use network bech 32 in utils * Use Shimmer Testnet * Use "basic" instead of "crud" folder name * Fix links to examples in Wiki * Use new banner * Fix example paths in CI * Use Shimmer Testnet in Wasm examples * Clarify issuer feature in example * Use explicit digit regex * Remove stronghold file in CI * Revert "Remove stronghold file in CI" This reverts commit e7ee19956d99a02a4e907a5a1cd8e387ae7ad9eb. * Improve examples README * Revert "Revert "Remove stronghold file in CI"" This reverts commit ef80751c774b83b7a03b35512ecd6fcf5dc140a0. * Enable `fs` tokio feature * Remove stronghold removal for CI * Use random stronghold paths --- .github/workflows/build-and-test.yml | 57 +----- .github/workflows/clippy.yml | 7 - .github/workflows/format.yml | 6 - .meta/identity_banner.png | Bin 138128 -> 0 bytes Cargo.toml | 2 + README.md | 2 +- bindings/wasm/examples-account/README.md | 2 +- bindings/wasm/examples-stardust/README.md | 2 +- .../examples-stardust/src/ex0_create_did.ts | 5 +- bindings/wasm/examples/README.md | 2 +- .../decentralized_identifiers/create.mdx | 4 +- .../private_tangle.mdx | 4 +- .../decentralized_identifiers/resolve.mdx | 8 +- .../decentralized_identifiers/update.mdx | 6 +- .../verifiable_credentials/create.mdx | 4 +- .../verifiable_credentials/revocation.mdx | 4 +- .../verifiable_presentations.mdx | 4 +- .../getting_started/create_and_publish.mdx | 4 +- examples/0_basic/0_create_did.rs | 64 ++++++ .../0_basic/1_update_did.rs | 33 ++- .../0_basic/2_resolve_did.rs | 27 ++- .../0_basic/3_deactivate_did.rs | 29 ++- .../0_basic/4_delete_did.rs | 26 ++- examples/1_advanced/0_did_controls_did.rs | 143 +++++++++++++ examples/1_advanced/1_did_issues_nft.rs | 147 ++++++++++++++ examples/1_advanced/2_nft_owns_did.rs | 146 ++++++++++++++ examples/1_advanced/3_did_issues_tokens.rs | 190 ++++++++++++++++++ examples/1_advanced/4_key_exchange.rs | 133 ++++++++++++ examples/Cargo.toml | 88 +++----- examples/README.md | 62 +++--- .../utils/utils.rs | 120 ++++++----- examples_legacy/Cargo.toml | 84 ++++++++ examples_legacy/README.md | 47 +++++ .../account/config.rs | 0 .../account/create_did.rs | 0 .../account/create_vc.rs | 0 .../account/create_vp.rs | 0 .../account/encryption.rs | 0 {examples => examples_legacy}/account/lazy.rs | 0 .../account/manipulate_did.rs | 0 .../account/multiple_identities.rs | 0 .../account/revoke_vc.rs | 0 .../account/signing.rs | 0 .../account/unchecked.rs | 0 .../getting_started.rs | 0 .../low-level-api/common.rs | 0 .../low-level-api/create_did.rs | 0 .../low-level-api/key_exchange.rs | 0 .../low-level-api/manipulate_did.rs | 0 .../low-level-api/private_tangle.rs | 0 .../low-level-api/resolve_did.rs | 0 .../low-level-api/resolve_history.rs | 0 identity_iota/README.md | 2 +- identity_stardust/Cargo.toml | 11 +- .../src/client/identity_client.rs | 20 +- identity_stardust/src/client/iota_client.rs | 2 +- identity_stardust/src/did/stardust_did.rs | 15 ++ 57 files changed, 1218 insertions(+), 294 deletions(-) delete mode 100644 .meta/identity_banner.png create mode 100644 examples/0_basic/0_create_did.rs rename identity_stardust/examples/ex1_update_did.rs => examples/0_basic/1_update_did.rs (69%) rename identity_stardust/examples/ex2_resolve_did.rs => examples/0_basic/2_resolve_did.rs (50%) rename identity_stardust/examples/ex3_deactivate_did.rs => examples/0_basic/3_deactivate_did.rs (78%) rename identity_stardust/examples/ex4_delete_did.rs => examples/0_basic/4_delete_did.rs (62%) create mode 100644 examples/1_advanced/0_did_controls_did.rs create mode 100644 examples/1_advanced/1_did_issues_nft.rs create mode 100644 examples/1_advanced/2_nft_owns_did.rs create mode 100644 examples/1_advanced/3_did_issues_tokens.rs create mode 100644 examples/1_advanced/4_key_exchange.rs rename identity_stardust/examples/ex0_create_did.rs => examples/utils/utils.rs (50%) create mode 100644 examples_legacy/Cargo.toml create mode 100644 examples_legacy/README.md rename {examples => examples_legacy}/account/config.rs (100%) rename {examples => examples_legacy}/account/create_did.rs (100%) rename {examples => examples_legacy}/account/create_vc.rs (100%) rename {examples => examples_legacy}/account/create_vp.rs (100%) rename {examples => examples_legacy}/account/encryption.rs (100%) rename {examples => examples_legacy}/account/lazy.rs (100%) rename {examples => examples_legacy}/account/manipulate_did.rs (100%) rename {examples => examples_legacy}/account/multiple_identities.rs (100%) rename {examples => examples_legacy}/account/revoke_vc.rs (100%) rename {examples => examples_legacy}/account/signing.rs (100%) rename {examples => examples_legacy}/account/unchecked.rs (100%) rename {examples => examples_legacy}/getting_started.rs (100%) rename {examples => examples_legacy}/low-level-api/common.rs (100%) rename {examples => examples_legacy}/low-level-api/create_did.rs (100%) rename {examples => examples_legacy}/low-level-api/key_exchange.rs (100%) rename {examples => examples_legacy}/low-level-api/manipulate_did.rs (100%) rename {examples => examples_legacy}/low-level-api/private_tangle.rs (100%) rename {examples => examples_legacy}/low-level-api/resolve_did.rs (100%) rename {examples => examples_legacy}/low-level-api/resolve_history.rs (100%) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index a9ccc1352a..e884a280ae 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -114,67 +114,18 @@ jobs: # run examples only on ubuntu for now if: matrix.os == 'ubuntu-latest' run: | - cargo read-manifest --manifest-path ./examples/Cargo.toml | \ + cargo read-manifest --manifest-path ./examples_legacy/Cargo.toml | \ jq -r '.targets[].name' | \ parallel -k -j 4 --retries 3 cargo run --example {} --all-features --release - - name: Stop sccache - uses: './.github/actions/rust/sccache/stop-sccache' - with: - os: ${{matrix.os}} - - build-and-test-stardust: - needs: [ check-for-run-condition, check-for-modification ] - if: ${{ needs.check-for-run-condition.outputs.should-run == 'true' && needs.check-for-modification.outputs.core-modified == 'true' }} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - os: [ ubuntu-latest ] - include: - - os: ubuntu-latest - sccache-path: /home/runner/.cache/sccache - env: - SCCACHE_DIR: ${{ matrix.sccache-path }} - RUSTC_WRAPPER: sccache - - steps: - - uses: actions/checkout@v2 - - - name: Setup Rust and cache - uses: './.github/actions/rust/rust-setup' - with: - os: ${{ runner.os }} - job: ${{ github.job }} - target-cache-enabled: false - sccache-enabled: true - sccache-path: ${{ matrix.sccache-path }} - - - name: Setup sccache - uses: './.github/actions/rust/sccache/setup-sccache' - with: - os: ${{matrix.os}} - - - name: Build Stardust - uses: actions-rs/cargo@v1 - with: - command: build - args: --manifest-path ./identity_stardust/Cargo.toml --workspace --tests --examples --all-features --release - - - name: Run Stardust tests - uses: actions-rs/cargo@v1 - with: - command: test - args: --manifest-path ./identity_stardust/Cargo.toml --workspace --all-features --release - - name: Run Stardust Rust examples # run examples only on ubuntu for now if: matrix.os == 'ubuntu-latest' run: | - cargo read-manifest --manifest-path ./identity_stardust/Cargo.toml | \ + cargo read-manifest --manifest-path ./examples/Cargo.toml | \ jq -r '.targets[].name' | \ - awk '$1 ~ /ex.*/' | \ - parallel -k -j 4 --retries 3 cargo run --manifest-path ./identity_stardust/Cargo.toml --example {} --all-features --release + awk '$1 ~ /[0-9].*/' | \ + parallel -k -j 4 --retries 3 cargo run --manifest-path ./examples/Cargo.toml --example {} --all-features --release - name: Stop sccache uses: './.github/actions/rust/sccache/stop-sccache' diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index ce08221e1a..3005724418 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -43,13 +43,6 @@ jobs: args: --all-targets --all-features -- -D warnings name: core - - name: Stardust clippy check - uses: actions-rs/clippy-check@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --manifest-path ./identity_stardust/Cargo.toml --all-targets --all-features -- -D warnings - name: stardust - - name: Wasm clippy check uses: actions-rs/clippy-check@v1 with: diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index ae910b33a3..9e8894b595 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -41,12 +41,6 @@ jobs: command: fmt args: --all -- --check - - name: Stardust fmt check - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --manifest-path ./identity_stardust/Cargo.toml --all -- --check - - name: wasm fmt check uses: actions-rs/cargo@v1 with: diff --git a/.meta/identity_banner.png b/.meta/identity_banner.png deleted file mode 100644 index c78a32862622152d61ecabdb8e77d0388f601d65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 138128 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 F{{b|D`E~#R diff --git a/Cargo.toml b/Cargo.toml index e564cfa7e4..b4342ed792 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,9 @@ members = [ "identity_iota", "identity_iota_client", "identity_iota_core", + "identity_stardust", + "examples_legacy", "examples", ] diff --git a/README.md b/README.md index d8f7db8ce6..135b9856b6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![banner](https://github.com/iotaledger/identity.rs/raw/HEAD/.meta/identity_banner.png) +![banner](https://github.com/iotaledger/identity.rs/raw/HEAD/documentation/static/img/Banner/banner_identity.svg)

StackExchange diff --git a/bindings/wasm/examples-account/README.md b/bindings/wasm/examples-account/README.md index 64f137e3b0..d8f4c4e416 100644 --- a/bindings/wasm/examples-account/README.md +++ b/bindings/wasm/examples-account/README.md @@ -1,4 +1,4 @@ -![banner](./../../../.meta/identity_banner.png) +![banner](./../../../documentation/static/img/Banner/banner_identity.svg) ## IOTA Identity Account Examples diff --git a/bindings/wasm/examples-stardust/README.md b/bindings/wasm/examples-stardust/README.md index ecce863248..6594c6597e 100644 --- a/bindings/wasm/examples-stardust/README.md +++ b/bindings/wasm/examples-stardust/README.md @@ -1,4 +1,4 @@ -![banner](./../../../.meta/identity_banner.png) +![banner](./../../../documentation/static/img/Banner/banner_identity.svg) ## IOTA Identity UTXO Examples diff --git a/bindings/wasm/examples-stardust/src/ex0_create_did.ts b/bindings/wasm/examples-stardust/src/ex0_create_did.ts index ca690a9f05..e1fe698b31 100644 --- a/bindings/wasm/examples-stardust/src/ex0_create_did.ts +++ b/bindings/wasm/examples-stardust/src/ex0_create_did.ts @@ -15,9 +15,8 @@ import {Bip39} from "@iota/crypto.js"; import fetch from "node-fetch"; import {Client, MnemonicSecretManager, SecretManager} from "@cycraig/iota-client-wasm/node"; -const EXPLORER = "https://explorer.alphanet.iotaledger.net/alphanet"; -const API_ENDPOINT = "https://api.alphanet.iotaledger.net/"; -const FAUCET = "https://faucet.alphanet.iotaledger.net/api/enqueue"; +const API_ENDPOINT = "https://api.testnet.shimmer.network/"; +const FAUCET = "https://faucet.testnet.shimmer.network/api/enqueue"; /** Demonstrate how to create a DID Document and publish it in a new Alias Output. */ export async function createIdentity(): Promise<{ diff --git a/bindings/wasm/examples/README.md b/bindings/wasm/examples/README.md index bb500f3526..09d6771208 100644 --- a/bindings/wasm/examples/README.md +++ b/bindings/wasm/examples/README.md @@ -1,4 +1,4 @@ -![banner](./../../../.meta/identity_banner.png) +![banner](./../../../documentation/static/img/Banner/banner_identity.svg) ## IOTA Identity Examples diff --git a/documentation/docs/concepts/decentralized_identifiers/create.mdx b/documentation/docs/concepts/decentralized_identifiers/create.mdx index 1039d269aa..a9cd6d66bd 100644 --- a/documentation/docs/concepts/decentralized_identifiers/create.mdx +++ b/documentation/docs/concepts/decentralized_identifiers/create.mdx @@ -11,7 +11,7 @@ keywords: - Publish --- import CodeSnippet from '../../../src/components/CodeSnippetComponent' -import createDidRustExample from '!!raw-loader!../../../../examples/account/create_did.rs'; +import createDidRustExample from '!!raw-loader!../../../../examples_legacy/account/create_did.rs'; When someone or something wants to benefit from Self-Sovereign Identity, they must first create a Decentralized Identity. This identity consists of many parts that have different functions. This page will cover both the basics and the details about identity creation, storage, and publishing to the Tangle. @@ -29,7 +29,7 @@ Select your programming language of choice and press the green play button to ex nodeReplitLink="https://repl.it/@IOTAFoundation/create-did?lite=true" rustContent={createDidRustExample} nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/create_did.ts" - rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/account/create_did.rs" + rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/create_did.rs" /> The first step in this example is the creation of an account. This acts as a stateful object that manages one or more identities. The account provides an interface to execute high-level operations on identities, such as creating, updating, and storing them. diff --git a/documentation/docs/concepts/decentralized_identifiers/private_tangle.mdx b/documentation/docs/concepts/decentralized_identifiers/private_tangle.mdx index 6b02aa5832..8a26f834d8 100644 --- a/documentation/docs/concepts/decentralized_identifiers/private_tangle.mdx +++ b/documentation/docs/concepts/decentralized_identifiers/private_tangle.mdx @@ -11,8 +11,8 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; import private_tangle_js from '!!raw-loader!../../../../bindings/wasm/examples/src/private_tangle.js'; -import private_tangle_rs from '!!raw-loader!../../../../examples/low-level-api/private_tangle.rs'; -import account_private_tangle_rs from '!!raw-loader!../../../../examples/account/config.rs'; +import private_tangle_rs from '!!raw-loader!../../../../examples_legacy/low-level-api/private_tangle.rs'; +import account_private_tangle_rs from '!!raw-loader!../../../../examples_legacy/account/config.rs'; ## Example diff --git a/documentation/docs/concepts/decentralized_identifiers/resolve.mdx b/documentation/docs/concepts/decentralized_identifiers/resolve.mdx index b636bbb5fb..78405873b6 100644 --- a/documentation/docs/concepts/decentralized_identifiers/resolve.mdx +++ b/documentation/docs/concepts/decentralized_identifiers/resolve.mdx @@ -6,8 +6,8 @@ image: /img/Identity_icon.png keywords: - Resolve --- -import resolve_did_rs from '!!raw-loader!../../../../examples/low-level-api/resolve_did.rs'; -import resolve_history_rs from '!!raw-loader!../../../../examples/low-level-api/resolve_history.rs'; +import resolve_did_rs from '!!raw-loader!../../../../examples_legacy/low-level-api/resolve_did.rs'; +import resolve_history_rs from '!!raw-loader!../../../../examples_legacy/low-level-api/resolve_history.rs'; import resolve_did_js from '!!raw-loader!../../../../bindings/wasm/examples/src/resolve_did.js'; import resolve_history_js from '!!raw-loader!../../../../bindings/wasm/examples/src/resolve_history.js'; import CodeSnippet from '../../../src/components/CodeSnippetComponent' @@ -61,7 +61,7 @@ What happens in this example can be explained on a high level as follows: The Re ## Resolving from a private tangle Resolving a DID from a private tangle is similar to resolving a DID from the main net. The only difference is that -the resolver needs to be configured to have a client capable of operating on said private tangle. Building a `Client` configured for a specified Tangle is explained in [this example in Rust](https://github.com/iotaledger/identity.rs/blob/dev/examples/low-level-api/private_tangle.rs) and [this example in Javascript](https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples/src/private_tangle.js). +the resolver needs to be configured to have a client capable of operating on said private tangle. Building a `Client` configured for a specified Tangle is explained in [this example in Rust](https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/low-level-api/private_tangle.rs) and [this example in Javascript](https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples/src/private_tangle.js). The following example demonstrates how one can setup a `Resolver` with a given `client` and then attempt resolving a specified `did` which may be on any Tangle (public or private). @@ -168,7 +168,7 @@ This section shows complete examples from the Iota Identity Framework code base. nodeReplitLink="https://repl.it/@IOTAFoundation/resolve-did?lite=true" rustContent={resolve_did_rs} nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples/src/resolve_did.js" - rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/low-level-api/resolve_did.rs" + rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/low-level-api/resolve_did.rs" /> diff --git a/documentation/docs/concepts/decentralized_identifiers/update.mdx b/documentation/docs/concepts/decentralized_identifiers/update.mdx index ae95b5e834..91bd8e2d48 100644 --- a/documentation/docs/concepts/decentralized_identifiers/update.mdx +++ b/documentation/docs/concepts/decentralized_identifiers/update.mdx @@ -10,7 +10,7 @@ keywords: - Update - Publish --- -import account_manipulate_did_rs from '!!raw-loader!../../../../examples/account/manipulate_did.rs'; +import account_manipulate_did_rs from '!!raw-loader!../../../../examples_legacy/account/manipulate_did.rs'; import CodeSnippet from '../../../src/components/CodeSnippetComponent' import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -72,7 +72,7 @@ The following example demonstrates adding verification methods and services to a nodeReplitLink="https://repl.it/@IOTAFoundation/manipulate-did?lite=true" rustContent={account_manipulate_did_rs} nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/manipulate_did.ts" - rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/account/manipulate_did.rs" + rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/manipulate_did.rs" /> ### Creating Identity @@ -404,5 +404,5 @@ Furthermore and similar to deleting verification methods, services can be delete :::tip In this example, a message is published to the tangle every time the document is updated. These messages can be unnecessary. Instead, one message can be published that contains all the updates to the DID Document. -See the [lazy example for Rust](https://github.com/iotaledger/identity.rs/blob/dev/examples/account/lazy.rs) and [lazy example for JS](https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/lazy.ts) to learn more about lazy publishing. +See the [lazy example for Rust](https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/lazy.rs) and [lazy example for JS](https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/lazy.ts) to learn more about lazy publishing. ::: diff --git a/documentation/docs/concepts/verifiable_credentials/create.mdx b/documentation/docs/concepts/verifiable_credentials/create.mdx index d4577dec46..dba0368c3f 100644 --- a/documentation/docs/concepts/verifiable_credentials/create.mdx +++ b/documentation/docs/concepts/verifiable_credentials/create.mdx @@ -9,7 +9,7 @@ keywords: - Create - sign --- -import create_vc_rs from '!!raw-loader!../../../../examples/account/create_vc.rs'; +import create_vc_rs from '!!raw-loader!../../../../examples_legacy/account/create_vc.rs'; import CodeSnippet from '../../../src/components/CodeSnippetComponent' A [verifiable credential (VC)](./overview.md) can represent all information that a physical credential represents, such as a passport or university degree. However, by allowing other parties to cryptographically verify the authorship and integrity of the claims, verifiable credentials can be seen as more tamper-evident and more trustworthy than their physical counterparts. @@ -82,5 +82,5 @@ This Verifiable Credential can be [verified by anyone](./verifiable_presentation nodeReplitLink="https://repl.it/@IOTAFoundation/create-vc?lite=true" rustContent={create_vc_rs} nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/create_vc.ts" - rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/account/create_vc.rs" + rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/create_vc.rs" /> \ No newline at end of file diff --git a/documentation/docs/concepts/verifiable_credentials/revocation.mdx b/documentation/docs/concepts/verifiable_credentials/revocation.mdx index 70bab99914..0ec43bb7de 100644 --- a/documentation/docs/concepts/verifiable_credentials/revocation.mdx +++ b/documentation/docs/concepts/verifiable_credentials/revocation.mdx @@ -10,7 +10,7 @@ keywords: - revocation --- -import revoke_vc_rs from "!!raw-loader!../../../../examples/account/revoke_vc.rs"; +import revoke_vc_rs from "!!raw-loader!../../../../examples_legacy/account/revoke_vc.rs"; import CodeSnippet from "../../../src/components/CodeSnippetComponent"; ## Overview @@ -58,5 +58,5 @@ The following code exemplifies how you can revoke a [Verifiable Credential (VC)] nodeReplitLink="https://replit.com/@IOTAFoundation/revoke-vc-06?lite=true" rustContent={revoke_vc_rs} nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/revoke_vc.ts" - rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/account/revoke_vc.rs" + rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/revoke_vc.rs" /> diff --git a/documentation/docs/concepts/verifiable_credentials/verifiable_presentations.mdx b/documentation/docs/concepts/verifiable_credentials/verifiable_presentations.mdx index 4c1c9e4c5c..d2a1c3fbe7 100644 --- a/documentation/docs/concepts/verifiable_credentials/verifiable_presentations.mdx +++ b/documentation/docs/concepts/verifiable_credentials/verifiable_presentations.mdx @@ -7,7 +7,7 @@ keywords: - verifiable - presentations --- -import create_vp_rs from '!!raw-loader!../../../../examples/account/create_vp.rs'; +import create_vp_rs from '!!raw-loader!../../../../examples_legacy/account/create_vp.rs'; import CodeSnippet from '../../../src/components/CodeSnippetComponent' A verifiable presentation is the recommended data format for sharing one or more [verifiable credentials](./overview.md). @@ -169,5 +169,5 @@ serialize it to JSON for transmission, deserialize it on the receiving side as a nodeReplitLink="https://repl.it/@IOTAFoundation/create-vp?lite=true" rustContent={create_vp_rs} nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/create_vp.ts" - rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/account/create_vp.rs" + rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/create_vp.rs" /> diff --git a/documentation/docs/getting_started/create_and_publish.mdx b/documentation/docs/getting_started/create_and_publish.mdx index 3c3ec1601b..a8a3b8281b 100644 --- a/documentation/docs/getting_started/create_and_publish.mdx +++ b/documentation/docs/getting_started/create_and_publish.mdx @@ -11,7 +11,7 @@ keywords: - Publish --- import CodeSnippet from '../../src/components/CodeSnippetComponent' -import createDidRustExample from '!!raw-loader!../../../examples/account/create_did.rs'; +import createDidRustExample from '!!raw-loader!../../../examples_legacy/account/create_did.rs'; If you want to benefit from Self-Sovereign Identity, you need to create a [Decentralized Identity](../concepts/decentralized_identifiers/overview). This identity consists of many parts that have different functions. This page will cover the basics about identity creation and publishing to the Tangle. @@ -33,7 +33,7 @@ Select your programming language of choice and press the green play button to ex nodeReplitLink="https://repl.it/@IOTAFoundation/create-did?lite=true" rustContent={createDidRustExample} nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/create_did.ts" - rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/account/create_did.rs" + rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/create_did.rs" /> The first step in this example is the creation of an account. The account is a stateful object that manages one or more identities. The account provides an interface to execute high-level operations on identities, such as [creating](../concepts/decentralized_identifiers/create) and [updating](../concepts/decentralized_identifiers/update)) them. diff --git a/examples/0_basic/0_create_did.rs b/examples/0_basic/0_create_did.rs new file mode 100644 index 0000000000..7ecb79740a --- /dev/null +++ b/examples/0_basic/0_create_did.rs @@ -0,0 +1,64 @@ +// Copyright 2020-2022 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::Context; +use examples::get_address_with_funds; +use examples::random_stronghold_path; +use examples::NETWORK_ENDPOINT; +use identity_core::convert::ToJson; +use identity_core::crypto::KeyPair; +use identity_core::crypto::KeyType; +use identity_did::verification::MethodScope; +use identity_stardust::NetworkName; +use identity_stardust::StardustClientExt; +use identity_stardust::StardustDocument; +use identity_stardust::StardustIdentityClientExt; +use identity_stardust::StardustVerificationMethod; +use iota_client::block::address::Address; +use iota_client::block::output::AliasOutput; +use iota_client::secret::stronghold::StrongholdSecretManager; +use iota_client::secret::SecretManager; +use iota_client::Client; + +/// Demonstrates how to create a DID Document and publish it in a new Alias Output. +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // Create a new client to interact with the IOTA ledger. + let client: Client = Client::builder().with_primary_node(NETWORK_ENDPOINT, None)?.finish()?; + + // Create a new secret manager backed by a Stronghold. + let mut secret_manager: SecretManager = SecretManager::Stronghold( + StrongholdSecretManager::builder() + .password("secure_password") + .try_build(random_stronghold_path())?, + ); + + // Get an address and with funds for testing. + let address: Address = get_address_with_funds(&client, &mut secret_manager) + .await + .context("failed to get address with funds")?; + + // Get the Bech32 human-readable part (HRP) of the network. + let network_name: NetworkName = client.network_name().await?; + + // Create a new DID document with a placeholder DID. + // The DID will be derived from the Alias Id of the Alias Output after publishing. + let mut document: StardustDocument = StardustDocument::new(&network_name); + + // Insert a new Ed25519 verification method in the DID document. + let keypair: KeyPair = KeyPair::new(KeyType::Ed25519)?; + let method: StardustVerificationMethod = + StardustVerificationMethod::new(document.id().clone(), keypair.type_(), keypair.public(), "#key-1")?; + document.insert_method(method, MethodScope::VerificationMethod)?; + + // Construct an Alias Output containing the DID document, with the wallet address + // set as both the state controller and governor. + let alias_output: AliasOutput = client.new_did_output(address, document, None).await?; + println!("Alias Output: {}", alias_output.to_json()?); + + // Publish the Alias Output and get the published DID document. + let document: StardustDocument = client.publish_did_output(&secret_manager, alias_output).await?; + println!("Published DID document: {:#}", document); + + Ok(()) +} diff --git a/identity_stardust/examples/ex1_update_did.rs b/examples/0_basic/1_update_did.rs similarity index 69% rename from identity_stardust/examples/ex1_update_did.rs rename to examples/0_basic/1_update_did.rs index 77e44c6a05..d3253107f5 100644 --- a/identity_stardust/examples/ex1_update_did.rs +++ b/examples/0_basic/1_update_did.rs @@ -1,30 +1,43 @@ // Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use examples::create_did; +use examples::random_stronghold_path; +use examples::NETWORK_ENDPOINT; use identity_core::common::Timestamp; use identity_core::convert::FromJson; use identity_core::json; use identity_did::did::DID; use identity_did::service::Service; use identity_did::verification::MethodRelationship; -use iota_client::block::output::AliasOutput; -use iota_client::block::output::AliasOutputBuilder; -use iota_client::secret::SecretManager; -use iota_client::Client; - +use identity_stardust::block::address::Address; +use identity_stardust::block::output::RentStructure; use identity_stardust::StardustClientExt; use identity_stardust::StardustDID; use identity_stardust::StardustDocument; use identity_stardust::StardustIdentityClientExt; use identity_stardust::StardustService; - -mod ex0_create_did; +use iota_client::block::output::AliasOutput; +use iota_client::block::output::AliasOutputBuilder; +use iota_client::secret::stronghold::StrongholdSecretManager; +use iota_client::secret::SecretManager; +use iota_client::Client; /// Demonstrates how to update a DID document in an existing Alias Output. #[tokio::main] async fn main() -> anyhow::Result<()> { + // Create a new client to interact with the IOTA ledger. + let client: Client = Client::builder().with_primary_node(NETWORK_ENDPOINT, None)?.finish()?; + + // Create a new secret manager backed by a Stronghold. + let mut secret_manager: SecretManager = SecretManager::Stronghold( + StrongholdSecretManager::builder() + .password("secure_password") + .try_build(random_stronghold_path())?, + ); + // Create a new DID in an Alias Output for us to modify. - let (client, _, secret_manager, did): (Client, _, SecretManager, StardustDID) = ex0_create_did::run().await?; + let (_, did): (Address, StardustDID) = create_did(&client, &mut secret_manager).await?; // Resolve the latest state of the document. let mut document: StardustDocument = client.resolve_did(&did).await?; @@ -49,8 +62,8 @@ async fn main() -> anyhow::Result<()> { // Because the size of the DID document increased, we have to increase the allocated storage deposit. // This increases the deposit amount to the new minimum. - let rent_structure = client.get_rent_structure().await?; - let alias_output = AliasOutputBuilder::from(&alias_output) + let rent_structure: RentStructure = client.get_rent_structure().await?; + let alias_output: AliasOutput = AliasOutputBuilder::from(&alias_output) .with_minimum_storage_deposit(rent_structure) .finish()?; diff --git a/identity_stardust/examples/ex2_resolve_did.rs b/examples/0_basic/2_resolve_did.rs similarity index 50% rename from identity_stardust/examples/ex2_resolve_did.rs rename to examples/0_basic/2_resolve_did.rs index fdfedfdb73..e3b9cca41d 100644 --- a/identity_stardust/examples/ex2_resolve_did.rs +++ b/examples/0_basic/2_resolve_did.rs @@ -1,19 +1,33 @@ // Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use iota_client::block::output::AliasOutput; -use iota_client::Client; - +use examples::create_did; +use examples::random_stronghold_path; +use examples::NETWORK_ENDPOINT; +use identity_stardust::block::address::Address; use identity_stardust::StardustDID; use identity_stardust::StardustDocument; use identity_stardust::StardustIdentityClientExt; - -mod ex0_create_did; +use iota_client::block::output::AliasOutput; +use iota_client::secret::stronghold::StrongholdSecretManager; +use iota_client::secret::SecretManager; +use iota_client::Client; /// Demonstrates how to resolve an existing DID in an Alias Output. #[tokio::main] async fn main() -> anyhow::Result<()> { - let (client, _, _, did): (Client, _, _, StardustDID) = ex0_create_did::run().await?; + // Create a new client to interact with the IOTA ledger. + let client: Client = Client::builder().with_primary_node(NETWORK_ENDPOINT, None)?.finish()?; + + // Create a new secret manager backed by a Stronghold. + let mut secret_manager: SecretManager = SecretManager::Stronghold( + StrongholdSecretManager::builder() + .password("secure_password") + .try_build(random_stronghold_path())?, + ); + + // Create a new DID in an Alias Output for us to modify. + let (_, did): (Address, StardustDID) = create_did(&client, &mut secret_manager).await?; // Resolve the associated Alias Output and extract the DID document from it. let resolved: StardustDocument = client.resolve_did(&did).await?; @@ -21,6 +35,7 @@ async fn main() -> anyhow::Result<()> { // We can also resolve the Alias Output directly. let alias_output: AliasOutput = client.resolve_did_output(&did).await?; + println!("The Alias Output holds {} tokens", alias_output.amount()); Ok(()) diff --git a/identity_stardust/examples/ex3_deactivate_did.rs b/examples/0_basic/3_deactivate_did.rs similarity index 78% rename from identity_stardust/examples/ex3_deactivate_did.rs rename to examples/0_basic/3_deactivate_did.rs index c9634804f5..b3b1ae2a8d 100644 --- a/identity_stardust/examples/ex3_deactivate_did.rs +++ b/examples/0_basic/3_deactivate_did.rs @@ -1,24 +1,35 @@ // Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use iota_client::block::address::Address; -use iota_client::block::output::AliasOutput; -use iota_client::block::output::AliasOutputBuilder; -use iota_client::secret::SecretManager; -use iota_client::Client; - +use examples::create_did; +use examples::random_stronghold_path; +use examples::NETWORK_ENDPOINT; +use identity_stardust::block::address::Address; use identity_stardust::StardustClientExt; use identity_stardust::StardustDID; use identity_stardust::StardustDocument; use identity_stardust::StardustIdentityClientExt; - -mod ex0_create_did; +use iota_client::block::output::AliasOutput; +use iota_client::block::output::AliasOutputBuilder; +use iota_client::secret::stronghold::StrongholdSecretManager; +use iota_client::secret::SecretManager; +use iota_client::Client; /// Demonstrates how to deactivate a DID in an Alias Output. #[tokio::main] async fn main() -> anyhow::Result<()> { + // Create a new client to interact with the IOTA ledger. + let client: Client = Client::builder().with_primary_node(NETWORK_ENDPOINT, None)?.finish()?; + + // Create a new secret manager backed by a Stronghold. + let mut secret_manager: SecretManager = SecretManager::Stronghold( + StrongholdSecretManager::builder() + .password("secure_password") + .try_build(random_stronghold_path())?, + ); + // Create a new DID in an Alias Output for us to modify. - let (client, _, secret_manager, did): (Client, Address, SecretManager, StardustDID) = ex0_create_did::run().await?; + let (_, did): (Address, StardustDID) = create_did(&client, &mut secret_manager).await?; // Resolve the latest state of the DID document, so we can reactivate it later. let document: StardustDocument = client.resolve_did(&did).await?; diff --git a/identity_stardust/examples/ex4_delete_did.rs b/examples/0_basic/4_delete_did.rs similarity index 62% rename from identity_stardust/examples/ex4_delete_did.rs rename to examples/0_basic/4_delete_did.rs index 458de0b995..4312c4943c 100644 --- a/identity_stardust/examples/ex4_delete_did.rs +++ b/examples/0_basic/4_delete_did.rs @@ -1,23 +1,33 @@ // Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use iota_client::block::address::Address; -use iota_client::secret::SecretManager; -use iota_client::Client; - +use examples::create_did; +use examples::random_stronghold_path; +use examples::NETWORK_ENDPOINT; use identity_stardust::Error; use identity_stardust::StardustClientExt; use identity_stardust::StardustDID; use identity_stardust::StardustIdentityClientExt; - -mod ex0_create_did; +use iota_client::block::address::Address; +use iota_client::secret::stronghold::StrongholdSecretManager; +use iota_client::secret::SecretManager; +use iota_client::Client; /// Demonstrates how to delete a DID in an Alias Output, reclaiming the storage deposit. #[tokio::main] async fn main() -> anyhow::Result<()> { + // Create a new client to interact with the IOTA ledger. + let client: Client = Client::builder().with_primary_node(NETWORK_ENDPOINT, None)?.finish()?; + + // Create a new secret manager backed by a Stronghold. + let mut secret_manager: SecretManager = SecretManager::Stronghold( + StrongholdSecretManager::builder() + .password("secure_password") + .try_build(random_stronghold_path())?, + ); + // Create a new DID in an Alias Output for us to modify. - let (client, address, secret_manager, did): (Client, Address, SecretManager, StardustDID) = - ex0_create_did::run().await?; + let (address, did): (Address, StardustDID) = create_did(&client, &mut secret_manager).await?; // Deletes the Alias Output and its contained DID Document, rendering the DID permanently destroyed. // This operation is *not* reversible. diff --git a/examples/1_advanced/0_did_controls_did.rs b/examples/1_advanced/0_did_controls_did.rs new file mode 100644 index 0000000000..948341c21d --- /dev/null +++ b/examples/1_advanced/0_did_controls_did.rs @@ -0,0 +1,143 @@ +// Copyright 2020-2022 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::ops::Deref; + +use examples::create_did; +use examples::random_stronghold_path; +use examples::NETWORK_ENDPOINT; +use identity_core::crypto::KeyPair; +use identity_core::crypto::KeyType; +use identity_did::verification::MethodScope; +use identity_stardust::block::output::AliasId; +use identity_stardust::block::output::UnlockCondition; +use identity_stardust::NetworkName; +use identity_stardust::StardustClientExt; +use identity_stardust::StardustDID; +use identity_stardust::StardustDocument; +use identity_stardust::StardustIdentityClientExt; +use identity_stardust::StardustVerificationMethod; +use iota_client::block::address::Address; +use iota_client::block::address::AliasAddress; +use iota_client::block::output::feature::IssuerFeature; +use iota_client::block::output::AliasOutput; +use iota_client::block::output::AliasOutputBuilder; +use iota_client::block::output::RentStructure; +use iota_client::secret::stronghold::StrongholdSecretManager; +use iota_client::secret::SecretManager; +use iota_client::Client; + +/// Demonstrates how an identity can control another identity. +/// +/// For this example, we consider the case where a parent company's DID controls the DID of a subsidiary. +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // ======================================================== + // Create the company's and subsidiary's Alias Output DIDs. + // ======================================================== + + // Create a new client to interact with the IOTA ledger. + let client: Client = Client::builder().with_primary_node(NETWORK_ENDPOINT, None)?.finish()?; + + // Create a new secret manager backed by a Stronghold. + let mut secret_manager: SecretManager = SecretManager::Stronghold( + StrongholdSecretManager::builder() + .password("secure_password") + .try_build(random_stronghold_path())?, + ); + + // Create a new DID for the company. + let (_, company_did): (Address, StardustDID) = create_did(&client, &mut secret_manager).await?; + + // Get the current byte costs and network name. + let rent_structure: RentStructure = client.get_rent_structure().await?; + let network_name: NetworkName = client.network_name().await?; + + // Construct a new DID document for the subsidiary. + let subsidiary_document: StardustDocument = StardustDocument::new(&network_name); + + // Create a DID for the subsidiary that is controlled by the parent company's DID. + // This means the subsidiary's Alias Output can only be updated or destroyed by + // the state controller or governor of the company's Alias Output respectively. + let subsidiary_alias: AliasOutput = client + .new_did_output( + Address::Alias(AliasAddress::new(AliasId::from(&company_did))), + subsidiary_document, + Some(rent_structure.clone()), + ) + .await?; + + let subsidiary_alias: AliasOutput = AliasOutputBuilder::from(&subsidiary_alias) + // Optionally, we can mark the company as the issuer of the subsidiary DID. + // This allows to verify trust relationships between DIDs, as a resolver can + // verify that the subsidiary DID was created by the parent company. + .add_immutable_feature(IssuerFeature::new(AliasAddress::new(AliasId::from(&company_did)).into()).into()) + // Adding the issuer feature means we have to recalculate the required storage deposit. + .with_minimum_storage_deposit(rent_structure.clone()) + .finish()?; + + // Publish the subsidiary's DID. + let mut subsidiary_document: StardustDocument = client.publish_did_output(&secret_manager, subsidiary_alias).await?; + + // ===================================== + // Update the subsidiary's Alias Output. + // ===================================== + + // Add a verification method to the subsidiary. + // This only serves as an example for updating the subsidiary DID. + let keypair: KeyPair = KeyPair::new(KeyType::Ed25519)?; + let method: StardustVerificationMethod = StardustVerificationMethod::new( + subsidiary_document.id().clone(), + keypair.type_(), + keypair.public(), + "#key-2", + )?; + subsidiary_document.insert_method(method, MethodScope::VerificationMethod)?; + + // Update the subsidiary's Alias Output with the updated document + // and increase the storage deposit. + let subsidiary_alias: AliasOutput = client.update_did_output(subsidiary_document).await?; + let subsidiary_alias: AliasOutput = AliasOutputBuilder::from(&subsidiary_alias) + .with_minimum_storage_deposit(rent_structure.clone()) + .finish()?; + + // Publish the updated subsidiary's DID. + // + // This works because `secret_manager` can unlock the company's Alias Output, + // which is required in order to update the subsidiary's Alias Output. + let subsidiary_document: StardustDocument = client.publish_did_output(&secret_manager, subsidiary_alias).await?; + + // =================================================================== + // Determine the controlling company's DID given the subsidiary's DID. + // =================================================================== + + // Resolve the subsidiary's Alias Output. + let subsidiary_output: AliasOutput = client.resolve_did_output(subsidiary_document.id()).await?; + + // Extract the company's Alias Id from the state controller unlock condition. + // + // If instead we wanted to determine the original creator of the DID, + // we could inspect the issuer feature. This feature needs to be set when creating the DID. + let company_alias_id: AliasId = if let Some(UnlockCondition::StateControllerAddress(address)) = + subsidiary_output.unlock_conditions().iter().next() + { + if let Address::Alias(alias) = *address.address() { + *alias.alias_id() + } else { + anyhow::bail!("expected an alias address as the state controller"); + } + } else { + anyhow::bail!("expected two unlock conditions"); + }; + + // Reconstruct the company's DID from the Alias Id and the network. + let company_did = StardustDID::new(company_alias_id.deref(), &network_name); + + // Resolve the company's DID document. + let company_document: StardustDocument = client.resolve_did(&company_did).await?; + + println!("Company: {company_document:#}"); + println!("Subsidiary: {subsidiary_document:#}"); + + Ok(()) +} diff --git a/examples/1_advanced/1_did_issues_nft.rs b/examples/1_advanced/1_did_issues_nft.rs new file mode 100644 index 0000000000..b06b6991c7 --- /dev/null +++ b/examples/1_advanced/1_did_issues_nft.rs @@ -0,0 +1,147 @@ +// Copyright 2020-2022 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use examples::create_did; +use examples::random_stronghold_path; +use examples::NETWORK_ENDPOINT; +use identity_stardust::block::output::feature::MetadataFeature; +use identity_stardust::NetworkName; +use identity_stardust::StardustDID; +use identity_stardust::StardustDocument; +use identity_stardust::StardustIdentityClientExt; +use iota_client::api_types::responses::OutputResponse; +use iota_client::block::address::Address; +use iota_client::block::address::AliasAddress; +use iota_client::block::output::feature::IssuerFeature; +use iota_client::block::output::unlock_condition::AddressUnlockCondition; +use iota_client::block::output::AliasId; +use iota_client::block::output::Feature; +use iota_client::block::output::NftId; +use iota_client::block::output::NftOutput; +use iota_client::block::output::NftOutputBuilder; +use iota_client::block::output::Output; +use iota_client::block::output::OutputId; +use iota_client::block::output::RentStructure; +use iota_client::block::output::UnlockCondition; +use iota_client::block::payload::transaction::TransactionEssence; +use iota_client::block::payload::Payload; +use iota_client::block::Block; +use iota_client::secret::stronghold::StrongholdSecretManager; +use iota_client::secret::SecretManager; +use iota_client::Client; + +/// Demonstrates how an identity can issue and own NFTs, +/// and how observers can verify the issuer of the NFT. +/// +/// For this example, we consider the case where a manufacturer issues +/// a digital product passport (DPP) as an NFT. +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // ============================================== + // Create the manufacturer's DID and the DPP NFT. + // ============================================== + + // Create a new client to interact with the IOTA ledger. + let client: Client = Client::builder().with_primary_node(NETWORK_ENDPOINT, None)?.finish()?; + + // Create a new secret manager backed by a Stronghold. + let mut secret_manager: SecretManager = SecretManager::Stronghold( + StrongholdSecretManager::builder() + .password("secure_password") + .try_build(random_stronghold_path())?, + ); + + // Create a new DID for the manufacturer. + let (_, manufacturer_did): (Address, StardustDID) = create_did(&client, &mut secret_manager).await?; + + // Get the current byte cost. + let rent_structure: RentStructure = client.get_rent_structure().await?; + + // Create a Digital Product Passport NFT issued by the manufacturer. + let product_passport_nft: NftOutput = + NftOutputBuilder::new_with_minimum_storage_deposit(rent_structure, NftId::null())? + // The NFT will initially be owned by the manufacturer. + .add_unlock_condition(UnlockCondition::Address(AddressUnlockCondition::new(Address::Alias( + AliasAddress::new(AliasId::from(&manufacturer_did)), + )))) + // Set the manufacturer as the immutable issuer. + .add_immutable_feature(Feature::Issuer(IssuerFeature::new(Address::Alias(AliasAddress::new( + AliasId::from(&manufacturer_did), + ))))) + // A proper DPP would hold its metadata here. + .add_immutable_feature(Feature::Metadata(MetadataFeature::new( + b"Digital Product Passport Metadata".to_vec(), + )?)) + .finish()?; + + // Publish the NFT. + let block: Block = client + .block() + .with_secret_manager(&secret_manager) + .with_outputs(vec![product_passport_nft.into()])? + .finish() + .await?; + let _ = client.retry_until_included(&block.id(), None, None).await?; + + // ======================================================== + // Resolve the Digital Product Passport NFT and its issuer. + // ======================================================== + + // Extract the identifier of the NFT from the published block. + let nft_id: NftId = NftId::from(get_nft_output_id( + block + .payload() + .ok_or_else(|| anyhow::anyhow!("expected block to contain a payload"))?, + )?); + + // Fetch the NFT Output. + let nft_output_id: OutputId = client.nft_output_id(nft_id).await?; + let output_response: OutputResponse = client.get_output(&nft_output_id).await?; + let output: Output = Output::try_from(&output_response.output)?; + + // Extract the issuer of the NFT. + let nft_output: NftOutput = if let Output::Nft(nft_output) = output { + nft_output + } else { + anyhow::bail!("expected NFT output") + }; + + let issuer_address: Address = if let Some(Feature::Issuer(issuer)) = nft_output.immutable_features().iter().next() { + *issuer.address() + } else { + anyhow::bail!("expected an issuer feature") + }; + + let manufacturer_alias_id: AliasId = if let Address::Alias(alias_address) = issuer_address { + *alias_address.alias_id() + } else { + anyhow::bail!("expected an Alias Address") + }; + + // Reconstruct the manufacturer's DID from the Alias Id. + let network: NetworkName = client.network_name().await?; + let manufacturer_did: StardustDID = StardustDID::new(&*manufacturer_alias_id, &network); + + // Resolve the issuer of the NFT. + let manufacturer_document: StardustDocument = client.resolve_did(&manufacturer_did).await?; + + println!("The issuer of the Digital Product Passport NFT is: {manufacturer_document:#}"); + + Ok(()) +} + +// Helper function to get the output id for the first NFT output in a Block. +fn get_nft_output_id(payload: &Payload) -> anyhow::Result { + match payload { + Payload::Transaction(tx_payload) => { + let TransactionEssence::Regular(regular) = tx_payload.essence(); + for (index, output) in regular.outputs().iter().enumerate() { + if let Output::Nft(_nft_output) = output { + return Ok(OutputId::new(tx_payload.id(), index.try_into().unwrap())?); + } + } + anyhow::bail!("no NFT output in transaction essence") + } + _ => anyhow::bail!("No transaction payload"), + } +} diff --git a/examples/1_advanced/2_nft_owns_did.rs b/examples/1_advanced/2_nft_owns_did.rs new file mode 100644 index 0000000000..d90f25f6fd --- /dev/null +++ b/examples/1_advanced/2_nft_owns_did.rs @@ -0,0 +1,146 @@ +// Copyright 2020-2022 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use examples::create_did_document; +use examples::get_address_with_funds; +use examples::random_stronghold_path; +use examples::NETWORK_ENDPOINT; +use identity_stardust::block::address::NftAddress; +use identity_stardust::block::output::AliasOutput; +use identity_stardust::NetworkName; +use identity_stardust::StardustClientExt; +use identity_stardust::StardustDocument; +use identity_stardust::StardustIdentityClientExt; +use iota_client::api_types::responses::OutputResponse; +use iota_client::block::address::Address; +use iota_client::block::output::unlock_condition::AddressUnlockCondition; +use iota_client::block::output::NftId; +use iota_client::block::output::NftOutput; +use iota_client::block::output::NftOutputBuilder; +use iota_client::block::output::Output; +use iota_client::block::output::OutputId; +use iota_client::block::output::RentStructure; +use iota_client::block::output::UnlockCondition; +use iota_client::block::payload::transaction::TransactionEssence; +use iota_client::block::payload::Payload; +use iota_client::block::Block; +use iota_client::secret::stronghold::StrongholdSecretManager; +use iota_client::secret::SecretManager; +use iota_client::Client; + +/// Demonstrates how an identity can be owned by NFTs, +/// and how observers can verify that relationship. +/// +/// For this example, we consider the case where a car's NFT owns +/// the DID of the car, so that transferring the NFT also transfers DID ownership. +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // ============================= + // Create the car's NFT and DID. + // ============================= + + // Create a new client to interact with the IOTA ledger. + let client: Client = Client::builder().with_primary_node(NETWORK_ENDPOINT, None)?.finish()?; + + // Create a new secret manager backed by a Stronghold. + let mut secret_manager: SecretManager = SecretManager::Stronghold( + StrongholdSecretManager::builder() + .password("secure_password") + .try_build(random_stronghold_path())?, + ); + + // Get an address with funds for testing. + let address: Address = get_address_with_funds(&client, &mut secret_manager).await?; + + // Get the current byte cost. + let rent_structure: RentStructure = client.get_rent_structure().await?; + + // Create the car NFT with an Ed25519 address as the unlock condition. + let car_nft: NftOutput = NftOutputBuilder::new_with_minimum_storage_deposit(rent_structure.clone(), NftId::null())? + .add_unlock_condition(UnlockCondition::Address(AddressUnlockCondition::new(address))) + .finish()?; + + // Publish the NFT output. + let block: Block = client + .block() + .with_secret_manager(&secret_manager) + .with_outputs(vec![car_nft.into()])? + .finish() + .await?; + let _ = client.retry_until_included(&block.id(), None, None).await?; + + let car_nft_id: NftId = NftId::from(get_nft_output_id( + block + .payload() + .ok_or_else(|| anyhow::anyhow!("expected the block to contain a payload"))?, + )?); + + let network: NetworkName = client.network_name().await?; + + // Construct a DID document for the subsidiary. + let document: StardustDocument = create_did_document(&network)?; + + // Create a new DID for the car that is owned by the car NFT. + let car_did_output: AliasOutput = client + .new_did_output(Address::Nft(car_nft_id.into()), document, Some(rent_structure)) + .await?; + + let car_document: StardustDocument = client.publish_did_output(&secret_manager, car_did_output).await?; + + // ============================================ + // Determine the car's NFT given the car's DID. + // ============================================ + + let output: AliasOutput = client.resolve_did_output(car_document.id()).await?; + + // Extract the NFT address from the state controller unlock condition. + let unlock_condition: &UnlockCondition = output + .unlock_conditions() + .iter() + .next() + .ok_or_else(|| anyhow::anyhow!("expected at least one unlock condition"))?; + + let car_nft_address: NftAddress = + if let UnlockCondition::StateControllerAddress(state_controller_unlock_condition) = unlock_condition { + if let Address::Nft(nft_address) = state_controller_unlock_condition.address() { + *nft_address + } else { + anyhow::bail!("expected an NFT address as the unlock condition"); + } + } else { + anyhow::bail!("expected an Address as the unlock condition"); + }; + + // Retrieve the NFT Output of the car. + let car_nft_id: &NftId = car_nft_address.nft_id(); + let output_id: OutputId = client.nft_output_id(*car_nft_id).await?; + let output_response: OutputResponse = client.get_output(&output_id).await?; + let output: Output = Output::try_from(&output_response.output)?; + + let car_nft: NftOutput = if let Output::Nft(nft_output) = output { + nft_output + } else { + anyhow::bail!("expected an NFT output"); + }; + + println!("The car's DID is: {car_document:#}"); + println!("The car's NFT is: {car_nft:#?}"); + + Ok(()) +} + +// Helper function to get the output id for the first NFT output in a Block. +fn get_nft_output_id(payload: &Payload) -> anyhow::Result { + match payload { + Payload::Transaction(tx_payload) => { + let TransactionEssence::Regular(regular) = tx_payload.essence(); + for (index, output) in regular.outputs().iter().enumerate() { + if let Output::Nft(_nft_output) = output { + return Ok(OutputId::new(tx_payload.id(), index.try_into().unwrap())?); + } + } + anyhow::bail!("no NFT output in transaction essence") + } + _ => anyhow::bail!("No transaction payload"), + } +} diff --git a/examples/1_advanced/3_did_issues_tokens.rs b/examples/1_advanced/3_did_issues_tokens.rs new file mode 100644 index 0000000000..7a91ef2427 --- /dev/null +++ b/examples/1_advanced/3_did_issues_tokens.rs @@ -0,0 +1,190 @@ +// Copyright 2020-2022 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::ops::Deref; + +use examples::create_did; +use examples::get_address; +use examples::random_stronghold_path; +use examples::NETWORK_ENDPOINT; +use identity_core::common::Duration; +use identity_core::common::Timestamp; +use identity_stardust::block::output::unlock_condition::AddressUnlockCondition; +use identity_stardust::block::output::unlock_condition::ExpirationUnlockCondition; +use identity_stardust::block::output::BasicOutput; +use identity_stardust::block::output::BasicOutputBuilder; +use identity_stardust::block::output::Output; +use identity_stardust::block::output::OutputId; +use identity_stardust::NetworkName; +use identity_stardust::StardustDID; +use identity_stardust::StardustDocument; +use identity_stardust::StardustIdentityClientExt; +use iota_client::api_types::responses::OutputResponse; +use iota_client::block::address::Address; +use iota_client::block::address::AliasAddress; +use iota_client::block::output::unlock_condition::ImmutableAliasAddressUnlockCondition; +use iota_client::block::output::AliasId; +use iota_client::block::output::AliasOutput; +use iota_client::block::output::AliasOutputBuilder; +use iota_client::block::output::FoundryId; +use iota_client::block::output::FoundryOutput; +use iota_client::block::output::FoundryOutputBuilder; +use iota_client::block::output::NativeToken; +use iota_client::block::output::RentStructure; +use iota_client::block::output::SimpleTokenScheme; +use iota_client::block::output::TokenId; +use iota_client::block::output::TokenScheme; +use iota_client::block::output::UnlockCondition; +use iota_client::block::Block; +use iota_client::secret::stronghold::StrongholdSecretManager; +use iota_client::secret::SecretManager; +use iota_client::Client; +use primitive_types::U256; + +/// Demonstrates how an identity can issue and control native assets +/// such as Token Foundries and NFTs. +/// +/// For this example, we consider the case where an authority issues +/// carbon credits that can be used to pay for carbon emissions or traded on a marketplace. +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // =========================================== + // Create the authority's DID and the foundry. + // =========================================== + + // Create a new client to interact with the IOTA ledger. + let client: Client = Client::builder().with_primary_node(NETWORK_ENDPOINT, None)?.finish()?; + + // Create a new secret manager backed by a Stronghold. + let mut secret_manager: SecretManager = SecretManager::Stronghold( + StrongholdSecretManager::builder() + .password("secure_password") + .try_build(random_stronghold_path())?, + ); + + // Create a new DID for the authority. + + let (_, authority_did): (Address, StardustDID) = create_did(&client, &mut secret_manager).await?; + + let rent_structure: RentStructure = client.get_rent_structure().await?; + + // We want to update the foundry counter of the authority's Alias Output, so we create an + // updated version of the output. We pass in the previous document, + // because we don't want to modify it in this update. + let authority_document: StardustDocument = client.resolve_did(&authority_did).await?; + let authority_alias_output: AliasOutput = client.update_did_output(authority_document).await?; + + // We will add one foundry to this Alias Output. + let authority_alias_output = AliasOutputBuilder::from(&authority_alias_output) + .with_foundry_counter(1) + .finish()?; + + // Create a token foundry that represents carbon credits. + let token_scheme = TokenScheme::Simple(SimpleTokenScheme::new( + U256::from(500_000u32), + U256::from(0u8), + U256::from(1_000_000u32), + )?); + + // Create the identifier of the foundry, which is partially derived from the Alias Address. + let foundry_id = FoundryId::build( + &AliasAddress::new(AliasId::from(&authority_did)), + 1, + token_scheme.kind(), + ); + + // Create the Foundry Output. + let carbon_credits_foundry: FoundryOutput = + FoundryOutputBuilder::new_with_minimum_storage_deposit(rent_structure.clone(), 1, token_scheme)? + // Initially, all carbon credits are owned by the foundry. + .add_native_token(NativeToken::new(TokenId::from(foundry_id), U256::from(500_000u32))?) + // The authority is set as the immutable owner. + .add_unlock_condition(UnlockCondition::ImmutableAliasAddress( + ImmutableAliasAddressUnlockCondition::new(AliasAddress::new(AliasId::from(&authority_did))), + )) + .finish()?; + + let carbon_credits_foundry_id: FoundryId = carbon_credits_foundry.id(); + + // Publish all outputs. + let block: Block = client + .block() + .with_secret_manager(&secret_manager) + .with_outputs(vec![authority_alias_output.into(), carbon_credits_foundry.into()])? + .finish() + .await?; + let _ = client.retry_until_included(&block.id(), None, None).await?; + + // =================================== + // Resolve Foundry and its issuer DID. + // =================================== + + // Get the latest output that contains the foundry. + let foundry_output_id: OutputId = client.foundry_output_id(carbon_credits_foundry_id).await?; + let carbon_credits_foundry: OutputResponse = client.get_output(&foundry_output_id).await?; + let carbon_credits_foundry: Output = Output::try_from(&carbon_credits_foundry.output)?; + + let carbon_credits_foundry: FoundryOutput = if let Output::Foundry(foundry_output) = carbon_credits_foundry { + foundry_output + } else { + anyhow::bail!("expected foundry output") + }; + + // Get the Alias Id of the authority that issued the carbon credits foundry. + let authority_alias_id: &AliasId = carbon_credits_foundry.alias_address().alias_id(); + + // Reconstruct the DID of the authority. + let network: NetworkName = client.network_name().await?; + let authority_did: StardustDID = StardustDID::new(authority_alias_id.deref(), &network); + + // Resolve the authority's DID document. + let authority_document: StardustDocument = client.resolve_did(&authority_did).await?; + + println!("The authority's DID is: {authority_document:#}"); + + // ========================================================= + // Transfer 1000 carbon credits to the address of a company. + // ========================================================= + + // Create a new address that represents the company. + let company_address = get_address(&client, &mut secret_manager).await?; + + // Create the timestamp at which the basic output will expire. + let tomorrow: u32 = Timestamp::now_utc() + .checked_add(Duration::seconds(60 * 60 * 24)) + .ok_or_else(|| anyhow::anyhow!("timestamp overflow"))? + .to_unix() + .try_into() + .map_err(|err| anyhow::anyhow!("cannot fit timestamp into u32: {err}"))?; + + // Create a basic output containing our carbon credits that we'll send to the company's address. + let basic_output: BasicOutput = BasicOutputBuilder::new_with_minimum_storage_deposit(rent_structure)? + .add_unlock_condition(UnlockCondition::Address(AddressUnlockCondition::new(company_address))) + .add_native_token(NativeToken::new(carbon_credits_foundry.token_id(), U256::from(1000))?) + .add_unlock_condition(UnlockCondition::Expiration(ExpirationUnlockCondition::new( + Address::Alias(AliasAddress::new(*authority_alias_id)), + tomorrow, + )?)) + .finish()?; + + // Reduce the carbon credits in the foundry by the amount that is sent to the company. + let carbon_credits_foundry = FoundryOutputBuilder::from(&carbon_credits_foundry) + .with_native_tokens(vec![NativeToken::new( + carbon_credits_foundry.token_id(), + U256::from(499_000u32), + )?]) + .finish()?; + + // Publish the output, transferring the carbon credits. + let block: Block = client + .block() + .with_secret_manager(&secret_manager) + .with_outputs(vec![basic_output.into(), carbon_credits_foundry.into()])? + .finish() + .await?; + let _ = client.retry_until_included(&block.id(), None, None).await?; + + println!("Sent carbon credits to {}", company_address.to_bech32(network.as_ref())); + + Ok(()) +} diff --git a/examples/1_advanced/4_key_exchange.rs b/examples/1_advanced/4_key_exchange.rs new file mode 100644 index 0000000000..a3126a6ef5 --- /dev/null +++ b/examples/1_advanced/4_key_exchange.rs @@ -0,0 +1,133 @@ +// Copyright 2020-2022 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::Context; +use examples::get_address_with_funds; +use examples::random_stronghold_path; +use examples::NETWORK_ENDPOINT; +use identity_core::crypto::KeyPair; +use identity_core::crypto::KeyType; +use identity_core::crypto::X25519; +use identity_did::verification::MethodScope; +use identity_stardust::block::address::Address; +use identity_stardust::block::output::AliasOutput; +use identity_stardust::block::output::RentStructure; +use identity_stardust::NetworkName; +use identity_stardust::StardustClientExt; +use identity_stardust::StardustDID; +use identity_stardust::StardustDocument; +use identity_stardust::StardustIdentityClientExt; +use identity_stardust::StardustVerificationMethod; +use iota_client::secret::stronghold::StrongholdSecretManager; +use iota_client::secret::SecretManager; +use iota_client::Client; + +/// Demonstrates Elliptic-curve Diffie-Hellman (ECDH) cryptographic key exchange with DID Documents. +/// +/// Alice and Bob want to communicate securely by encrypting their messages so only they +/// can read them. They both publish DID Documents with X25519 public keys and use them +/// to derive a shared secret key for encryption. +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // ============================== + // Create DIDs for Alice and Bob. + // ============================== + + // Create a new client to interact with the IOTA ledger. + let client: Client = Client::builder().with_primary_node(NETWORK_ENDPOINT, None)?.finish()?; + + // Create a new secret manager backed by a Stronghold. + let mut secret_manager: SecretManager = SecretManager::Stronghold( + StrongholdSecretManager::builder() + .password("secure_password") + .try_build(random_stronghold_path())?, + ); + + // Get an address and with funds for testing. + let address: Address = get_address_with_funds(&client, &mut secret_manager) + .await + .context("failed to get address with funds")?; + + let network: NetworkName = client.network_name().await?; + let rent_structure: RentStructure = client.get_rent_structure().await?; + + // Alice creates and publishes their DID Document. + let (alice_did, alice_x25519): (StardustDID, KeyPair) = { + // Create a DID Document. + let mut alice_document: StardustDocument = StardustDocument::new(&network); + + // Insert a new X25519 KeyAgreement verification method. + let x25519: KeyPair = KeyPair::new(KeyType::X25519)?; + let method: StardustVerificationMethod = + StardustVerificationMethod::new(alice_document.id().clone(), KeyType::X25519, x25519.public(), "kex-0")?; + alice_document.insert_method(method, MethodScope::key_agreement())?; + + // Publish the DID. + let alice_output: AliasOutput = client + .new_did_output(address, alice_document, Some(rent_structure.clone())) + .await?; + let alice_document: StardustDocument = client.publish_did_output(&secret_manager, alice_output).await?; + + (alice_document.id().clone(), x25519) + }; + + // Bob creates and publishes their DID Document. + let (bob_did, bob_x25519): (StardustDID, KeyPair) = { + // Create a DID Document. + let mut bob_document: StardustDocument = StardustDocument::new(&network); + + // Insert a new X25519 KeyAgreement verification method. + let x25519: KeyPair = KeyPair::new(KeyType::X25519)?; + let method: StardustVerificationMethod = + StardustVerificationMethod::new(bob_document.id().clone(), KeyType::X25519, x25519.public(), "kex-0")?; + bob_document.insert_method(method, MethodScope::key_agreement())?; + + // Publish the DID. + let bob_output: AliasOutput = client + .new_did_output(address, bob_document, Some(rent_structure)) + .await?; + let bob_document: StardustDocument = client.publish_did_output(&secret_manager, bob_output).await?; + + (bob_document.id().clone(), x25519) + }; + + // ====================================================================== + // Alice and Bob tell each other their DIDs. They each resolve the + // DID Document of the other to obtain their X25519 public key. + // Note that in practice, they would run this code completely separately. + // ====================================================================== + + let alice_shared_secret_key: [u8; 32] = { + // Alice: resolves Bob's DID Document and extracts their public key. + let bob_document: StardustDocument = client.resolve_did(&bob_did).await?; + let bob_method: &StardustVerificationMethod = bob_document + .core_document() + .resolve_method("kex-0", Some(MethodScope::key_agreement())) + .unwrap(); + let bob_public_key: Vec = bob_method.data().try_decode()?; + + // Compute the shared secret. + X25519::key_exchange(alice_x25519.private(), &bob_public_key)? + }; + + let bob_shared_secret_key: [u8; 32] = { + // Bob: resolves Alice's DID Document and extracts their public key. + let alice_document: StardustDocument = client.resolve_did(&alice_did).await?; + let alice_method: &StardustVerificationMethod = alice_document + .core_document() + .resolve_method("kex-0", Some(MethodScope::key_agreement())) + .unwrap(); + let alice_public_key: Vec = alice_method.data().try_decode()?; + + // Compute the shared secret. + X25519::key_exchange(bob_x25519.private(), &alice_public_key)? + }; + + // Both shared secret keys computed separately by Alice and Bob will match + // and can then be used to establish encrypted communications. + assert_eq!(alice_shared_secret_key, bob_shared_secret_key); + + println!("Diffie-Hellman key exchange successful!"); + + Ok(()) +} diff --git a/examples/Cargo.toml b/examples/Cargo.toml index a1a2050f0d..26f3642972 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -1,85 +1,59 @@ [package] name = "examples" version = "0.6.0" +authors = ["IOTA Stiftung"] edition = "2021" publish = false -release = false [dependencies] -identity_iota = { path = "../identity_iota" } -pretty_env_logger = { version = "0.4" } -rand = { version = "0.8" } -tokio = { version = "1.17.0", features = ["full"] } +anyhow = "1.0.62" +identity_core = { path = "../identity_core" } +identity_did = { path = "../identity_did" } +identity_stardust = { path = "../identity_stardust" } +iota-client = { version = "2.0.0-beta.2", default-features = false, features = ["tls", "stronghold"] } +primitive-types = "0.11.1" +rand = "0.8.5" +tokio = { version = "1.20.1", default-features = false, features = ["rt"] } -[[example]] -name = "getting_started" -path = "getting_started.rs" - -[[example]] -name = "account_create" -path = "account/create_did.rs" - -[[example]] -name = "account_config" -path = "account/config.rs" - -[[example]] -name = "account_manipulate" -path = "account/manipulate_did.rs" - -[[example]] -name = "account_lazy" -path = "account/lazy.rs" - -[[example]] -name = "account_signing" -path = "account/signing.rs" - -# TODO: Temporarily disabled until iotaledger/stronghold.rs#353 is fixed. -# [[example]] -# name = "account_multiple" -# path = "account/multiple_identities.rs" - -[[example]] -name = "account_unchecked" -path = "account/unchecked.rs" +[lib] +path = "utils/utils.rs" [[example]] -name = "account_encryption" -path = "account/encryption.rs" +path = "0_basic/0_create_did.rs" +name = "0_create_did" [[example]] -name = "create_did" -path = "low-level-api/create_did.rs" +path = "0_basic/1_update_did.rs" +name = "1_update_did" [[example]] -name = "account_create_vc" -path = "account/create_vc.rs" +path = "0_basic/2_resolve_did.rs" +name = "2_resolve_did" [[example]] -name = "account_create_vp" -path = "account/create_vp.rs" +path = "0_basic/3_deactivate_did.rs" +name = "3_deactivate_did" [[example]] -name = "resolve_history" -path = "low-level-api/resolve_history.rs" +path = "0_basic/4_delete_did.rs" +name = "4_delete_did" [[example]] -name = "manipulate_did" -path = "low-level-api/manipulate_did.rs" +path = "1_advanced/0_did_controls_did.rs" +name = "0_did_controls_did" [[example]] -name = "key_exchange" -path = "low-level-api/key_exchange.rs" +path = "1_advanced/1_did_issues_nft.rs" +name = "1_did_issues_nft" [[example]] -name = "resolve_did" -path = "low-level-api/resolve_did.rs" +path = "1_advanced/2_nft_owns_did.rs" +name = "2_nft_owns_did" [[example]] -name = "private_tangle" -path = "low-level-api/private_tangle.rs" +path = "1_advanced/3_did_issues_tokens.rs" +name = "3_did_issues_tokens" [[example]] -name = "account_revoke_vc" -path = "account/revoke_vc.rs" +path = "1_advanced/4_key_exchange.rs" +name = "4_key_exchange" diff --git a/examples/README.md b/examples/README.md index 209c028188..8ed43604d1 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,10 +1,8 @@ -![banner](./../.meta/identity_banner.png) +![banner](./../documentation/static/img/Banner/banner_identity.svg) +# IOTA Identity Examples - -## IOTA Identity Examples - -This folder provides code examples for you to learn how IOTA Identity can be used. +This folder provides code examples to learn how IOTA Identity can be used. You can run each example using @@ -12,36 +10,32 @@ You can run each example using cargo run --example ``` -For Instance, to run the example `getting_started`, use +For instance, to run the example `0_create_did`, use: ```rust -cargo run --example getting_started +cargo run --example 0_create_did ``` -The following examples are available for using the basic account (A high-level API): - -| # | Name | Information | -| :--: | :----------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------- | -| 1 | [getting_started](./getting_started.rs) | Introductory example for you to test whether the library is set up / working properly and compiles. | -| 2 | [account_create](./account/create_did.rs) | A basic example that generates and publishes a DID Document, the fundamental building block for decentralized identity. | -| 3 | [account_config](./account/config.rs) | How to configure the account to work with different networks and other settings. | -| 4 | [account_manipulate](./account/manipulate_did.rs) | How to manipulate a DID Document by adding/removing Verification Methods and Services. | -| 5 | [account_lazy](./account/lazy.rs) | How to take control over publishing DID updates manually, instead of the default automated behavior. | -| 6 | [account_signing](./account/signing.rs) | Using a DID to sign arbitrary statements and validating them. | -| 7 | [account_create_vc](account/create_vc.rs) | Generates and publishes subject and issuer DID Documents, then creates a Verifiable Credential (VC) specifying claims about the subject, and retrieves information through the CredentialValidator API. | -| 8 | [account_create_vp](account/create_vp.rs) | This example explains how to create a Verifiable Presentation from a set of credentials and sign it. | -| 9 | [account_revoke_vc](account/revoke_vc.rs) | Removes a verification method from the Issuers DID Document, making the Verifiable Credential it signed unable to verify, effectively revoking the VC. | -| 10 | [account_multiple](./account/multiple_identities.rs) | How to create multiple identities from a builder and how to load existing identities into an account. | -| 11 | [account_unchecked](./account/unchecked.rs) | How to update the custom properties of a DID document directly by using the account's unchecked methods. | -| 12 | [account_encryption](./account/encryption.rs) | Demonstrates Elliptic-curve Diffie-Hellman (ECDH) cryptographic key exchange by encrypting and decrypting data with a shared key. | - -The following examples are available for using the low-level APIs, which provides more flexibility at the cost of complexity: - -| # | Name | Information | -| :--: | :----------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------- | -| 1 | [create_did](./low-level-api/create_did.rs) | A basic example that generates and publishes a DID Document, the fundamental building block for decentralized identity. | -| 2 | [manipulate_did](low-level-api/manipulate_did.rs) | This example demonstrates how to perform a basic update to the integration chain of a DID Document. | -| 3 | [resolve_history](low-level-api/resolve_history.rs) | Advanced example that performs multiple updates and demonstrates how to resolve the DID Document history to view them. | -| 4 | [resolve_did](./low-level-api/resolve_did.rs) | A basic example that shows how to retrieve information through DID Document resolution/dereferencing. | -| 5 | [key_exchange](./low-level-api/key_exchange.rs) | Demonstrates Elliptic-curve Diffie-Hellman (ECDH) cryptographic key exchange with DID Documents. | -| 6 | [private_tangle](./low-level-api/private_tangle.rs) | Showcases the same procedure as `create_did`, but on a private tangle - a locally running hornet node. | +## Basic Examples + +The following basic CRUD (Create, Read, Update, Delete) examples are available: + +| Name | Information | +| :------------------------------------------------ | :----------------------------------------------------------------------------------- | +| [0_create_did](./0_basic/0_create_did.rs) | Demonstrates how to create a DID Document and publish it in a new Alias Output. | +| [1_update_did](./0_basic/1_update_did.rs) | Demonstrates how to update a DID document in an existing Alias Output. | +| [2_resolve_did](./0_basic/2_resolve_did.rs) | Demonstrates how to resolve an existing DID in an Alias Output. | +| [3_deactivate_did](./0_basic/3_deactivate_did.rs) | Demonstrates how to deactivate a DID in an Alias Output. | +| [4_delete_did](./0_basic/4_delete_did.rs) | Demonstrates how to delete a DID in an Alias Output, reclaiming the storage deposit. | + +## Advanced Examples + +The following advanced examples are available: + +| Name | Information | +| :--------------------------------------------------------- | :------------------------------------------------------------------------------------------------------- | +| [0_did_controls_did](./1_advanced/0_did_controls_did.rs) | Demonstrates how an identity can control another identity. | +| [1_did_issues_nft](./1_advanced/1_did_issues_nft.rs) | Demonstrates how an identity can issue and own NFTs, and how observers can verify the issuer of the NFT. | +| [2_nft_owns_did](./1_advanced/2_nft_owns_did.rs) | Demonstrates how an identity can be owned by NFTs, and how observers can verify that relationship. | +| [3_did_issues_tokens](./1_advanced/3_did_issues_tokens.rs) | Demonstrates how an identity can issue and control native assets such as Token Foundries and NFTs. | +| [4_key_exchange](./1_advanced/4_key_exchange.rs) | Demonstrates Elliptic-curve Diffie-Hellman (ECDH) cryptographic key exchange with DID Documents. | diff --git a/identity_stardust/examples/ex0_create_did.rs b/examples/utils/utils.rs similarity index 50% rename from identity_stardust/examples/ex0_create_did.rs rename to examples/utils/utils.rs index 5495cc5e90..932a8b56bd 100644 --- a/identity_stardust/examples/ex0_create_did.rs +++ b/examples/utils/utils.rs @@ -1,80 +1,98 @@ -// Copyright 2020-2022 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 +use std::path::PathBuf; use anyhow::Context; -use identity_core::convert::ToJson; + use identity_core::crypto::KeyPair; use identity_core::crypto::KeyType; use identity_did::verification::MethodScope; +use identity_stardust::NetworkName; +use identity_stardust::StardustClientExt; +use identity_stardust::StardustDID; +use identity_stardust::StardustDocument; +use identity_stardust::StardustIdentityClientExt; +use identity_stardust::StardustVerificationMethod; + use iota_client::block::address::Address; use iota_client::block::output::AliasOutput; use iota_client::block::output::Output; use iota_client::crypto::keys::bip39; use iota_client::node_api::indexer::query_parameters::QueryParameter; -use iota_client::secret::mnemonic::MnemonicSecretManager; use iota_client::secret::SecretManager; use iota_client::Client; +use rand::distributions::DistString; -use identity_stardust::NetworkName; -use identity_stardust::StardustClientExt; -use identity_stardust::StardustDID; -use identity_stardust::StardustDocument; -use identity_stardust::StardustIdentityClient; -use identity_stardust::StardustIdentityClientExt; -use identity_stardust::StardustVerificationMethod; - -static ENDPOINT: &str = "https://api.testnet.shimmer.network/"; -static FAUCET_URL: &str = "https://faucet.testnet.shimmer.network/api/enqueue"; +pub static NETWORK_ENDPOINT: &str = "https://api.testnet.shimmer.network/"; +pub static FAUCET_URL: &str = "https://faucet.testnet.shimmer.network/api/enqueue"; -/// Demonstrates how to create a DID Document and publish it in a new Alias Output. -pub async fn run() -> anyhow::Result<(Client, Address, SecretManager, StardustDID)> { - // Create a client and a wallet address with funds from the testnet faucet. - let client: Client = Client::builder().with_primary_node(ENDPOINT, None)?.finish()?; - let (address, secret_manager): (Address, SecretManager) = get_address_with_funds(&client) +/// Creates a DID Document and publishes it in a new Alias Output. +/// +/// Its functionality is equivalent to the "create DID" example +/// and exists for convenient calling from the other examples. +pub async fn create_did(client: &Client, secret_manager: &mut SecretManager) -> anyhow::Result<(Address, StardustDID)> { + let address: Address = get_address_with_funds(client, secret_manager) .await .context("failed to get address with funds")?; - // Get the Bech32 human-readable part (HRP) of the network. let network_name: NetworkName = client.network_name().await?; - // Create a new DID document with a placeholder DID. - // The DID will be derived from the Alias Id of the Alias Output after publishing. - let mut document: StardustDocument = StardustDocument::new(&network_name); + let document: StardustDocument = create_did_document(&network_name)?; + + let alias_output: AliasOutput = client.new_did_output(address, document, None).await?; + + let document: StardustDocument = client.publish_did_output(secret_manager, alias_output).await?; + + Ok((address, document.id().clone())) +} + +/// Creates an example DID document with the given `network_name`. +/// +/// Its functionality is equivalent to the "create DID" example +/// and exists for convenient calling from the other examples. +pub fn create_did_document(network_name: &NetworkName) -> anyhow::Result { + let mut document: StardustDocument = StardustDocument::new(network_name); - // Insert a new Ed25519 verification method in the DID document. let keypair: KeyPair = KeyPair::new(KeyType::Ed25519)?; + let method: StardustVerificationMethod = StardustVerificationMethod::new(document.id().clone(), keypair.type_(), keypair.public(), "#key-1")?; + document.insert_method(method, MethodScope::VerificationMethod)?; - // Construct an Alias Output containing the DID document, with the wallet address - // set as both the state controller and governor. - let alias_output: AliasOutput = client.new_did_output(address, document, None).await?; - println!("Alias Output: {}", alias_output.to_json()?); + Ok(document) +} - // Publish the Alias Output and get the published DID document. - let document: StardustDocument = client.publish_did_output(&secret_manager, alias_output).await?; - println!("Published DID document: {:#}", document); +/// Generates an address from the given [`SecretManager`] and adds funds from the testnet faucet. +pub async fn get_address_with_funds(client: &Client, stronghold: &mut SecretManager) -> anyhow::Result

{ + let address: Address = get_address(client, stronghold).await?; - Ok((client, address, secret_manager, document.id().clone())) + request_faucet_funds(client, address, client.get_bech32_hrp().await?.as_str()) + .await + .context("failed to request faucet funds")?; + + Ok(address) } -/// Creates a new address and SecretManager with funds from the testnet faucet. -async fn get_address_with_funds(client: &Client) -> anyhow::Result<(Address, SecretManager)> { +/// Initializes the [`SecretManager`] with a new mnemonic, if necessary, +/// and generates an address from the given [`SecretManager`]. +pub async fn get_address(client: &Client, secret_manager: &mut SecretManager) -> anyhow::Result
{ let keypair = identity_core::crypto::KeyPair::new(KeyType::Ed25519)?; let mnemonic = iota_client::crypto::keys::bip39::wordlist::encode(keypair.private().as_ref(), &bip39::wordlist::ENGLISH) .map_err(|err| anyhow::anyhow!(format!("{err:?}")))?; - let secret_manager = SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic(&mnemonic)?); + if let SecretManager::Stronghold(ref mut stronghold) = secret_manager { + match stronghold.store_mnemonic(mnemonic).await { + Ok(()) => (), + Err(iota_client::Error::StrongholdMnemonicAlreadyStored) => (), + Err(err) => anyhow::bail!(err), + } + } else { + anyhow::bail!("expected a `StrongholdSecretManager`"); + } - let address = client.get_addresses(&secret_manager).with_range(0..1).get_raw().await?[0]; - let network_hrp = client.get_network_hrp().await?; - request_faucet_funds(client, address, &network_hrp) - .await - .context("failed to request faucet funds")?; + let address = client.get_addresses(secret_manager).with_range(0..1).get_raw().await?[0]; - Ok((address, secret_manager)) + Ok(address) } /// Requests funds from the testnet faucet for the given `address`. @@ -107,9 +125,9 @@ async fn get_address_balance(client: &Client, address: &str) -> anyhow::Result anyhow::Result anyhow::Result<()> { - run().await.map(|_| ()).map_err(|err| { - eprintln!("ex0_create_did error: {:#}", err); - err - }) +/// Creates a random stronghold path in the temporary directory, whose exact location is OS-dependent. +pub fn random_stronghold_path() -> PathBuf { + let mut file = std::env::temp_dir(); + file.push("test_strongholds"); + file.push(rand::distributions::Alphanumeric.sample_string(&mut rand::thread_rng(), 32)); + file.set_extension("stronghold"); + file.to_owned() } diff --git a/examples_legacy/Cargo.toml b/examples_legacy/Cargo.toml new file mode 100644 index 0000000000..07e7ab1acd --- /dev/null +++ b/examples_legacy/Cargo.toml @@ -0,0 +1,84 @@ +[package] +name = "examples_legacy" +version = "0.6.0" +edition = "2021" +publish = false + +[dependencies] +identity_iota = { path = "../identity_iota" } +pretty_env_logger = { version = "0.4" } +rand = { version = "0.8" } +tokio = { version = "1.17.0", features = ["full"] } + +[[example]] +name = "getting_started" +path = "getting_started.rs" + +[[example]] +name = "account_create" +path = "account/create_did.rs" + +[[example]] +name = "account_config" +path = "account/config.rs" + +[[example]] +name = "account_manipulate" +path = "account/manipulate_did.rs" + +[[example]] +name = "account_lazy" +path = "account/lazy.rs" + +[[example]] +name = "account_signing" +path = "account/signing.rs" + +# TODO: Temporarily disabled until iotaledger/stronghold.rs#353 is fixed. +# [[example]] +# name = "account_multiple" +# path = "account/multiple_identities.rs" + +[[example]] +name = "account_unchecked" +path = "account/unchecked.rs" + +[[example]] +name = "account_encryption" +path = "account/encryption.rs" + +[[example]] +name = "create_did" +path = "low-level-api/create_did.rs" + +[[example]] +name = "account_create_vc" +path = "account/create_vc.rs" + +[[example]] +name = "account_create_vp" +path = "account/create_vp.rs" + +[[example]] +name = "resolve_history" +path = "low-level-api/resolve_history.rs" + +[[example]] +name = "manipulate_did" +path = "low-level-api/manipulate_did.rs" + +[[example]] +name = "key_exchange" +path = "low-level-api/key_exchange.rs" + +[[example]] +name = "resolve_did" +path = "low-level-api/resolve_did.rs" + +[[example]] +name = "private_tangle" +path = "low-level-api/private_tangle.rs" + +[[example]] +name = "account_revoke_vc" +path = "account/revoke_vc.rs" diff --git a/examples_legacy/README.md b/examples_legacy/README.md new file mode 100644 index 0000000000..c0bd008e9c --- /dev/null +++ b/examples_legacy/README.md @@ -0,0 +1,47 @@ +![banner](./../documentation/static/img/Banner/banner_identity.svg) + + + +## IOTA Identity Examples + +This folder provides code examples for you to learn how IOTA Identity can be used. + +You can run each example using + +```rust +cargo run --example +``` + +For Instance, to run the example `getting_started`, use + +```rust +cargo run --example getting_started +``` + +The following examples are available for using the basic account (A high-level API): + +| # | Name | Information | +| :--: | :----------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------- | +| 1 | [getting_started](./getting_started.rs) | Introductory example for you to test whether the library is set up / working properly and compiles. | +| 2 | [account_create](./account/create_did.rs) | A basic example that generates and publishes a DID Document, the fundamental building block for decentralized identity. | +| 3 | [account_config](./account/config.rs) | How to configure the account to work with different networks and other settings. | +| 4 | [account_manipulate](./account/manipulate_did.rs) | How to manipulate a DID Document by adding/removing Verification Methods and Services. | +| 5 | [account_lazy](./account/lazy.rs) | How to take control over publishing DID updates manually, instead of the default automated behavior. | +| 6 | [account_signing](./account/signing.rs) | Using a DID to sign arbitrary statements and validating them. | +| 7 | [account_create_vc](account/create_vc.rs) | Generates and publishes subject and issuer DID Documents, then creates a Verifiable Credential (VC) specifying claims about the subject, and retrieves information through the CredentialValidator API. | +| 8 | [account_create_vp](account/create_vp.rs) | This example explains how to create a Verifiable Presentation from a set of credentials and sign it. | +| 9 | [account_revoke_vc](account/revoke_vc.rs) | Removes a verification method from the Issuers DID Document, making the Verifiable Credential it signed unable to verify, effectively revoking the VC. | +| 10 | [account_multiple](./account/multiple_identities.rs) | How to create multiple identities from a builder and how to load existing identities into an account. | +| 11 | [account_unchecked](./account/unchecked.rs) | How to update the custom properties of a DID document directly by using the account's unchecked methods. | +| 12 | [account_encryption](./account/encryption.rs) | Demonstrates Elliptic-curve Diffie-Hellman (ECDH) cryptographic key exchange by encrypting and decrypting data with a shared key. | + +The following examples are available for using the low-level APIs, which provides more flexibility at the cost of complexity: + +| # | Name | Information | +| :--: | :----------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------- | +| 1 | [create_did](./low-level-api/create_did.rs) | A basic example that generates and publishes a DID Document, the fundamental building block for decentralized identity. | +| 2 | [manipulate_did](low-level-api/manipulate_did.rs) | This example demonstrates how to perform a basic update to the integration chain of a DID Document. | +| 3 | [resolve_history](low-level-api/resolve_history.rs) | Advanced example that performs multiple updates and demonstrates how to resolve the DID Document history to view them. | +| 4 | [resolve_did](./low-level-api/resolve_did.rs) | A basic example that shows how to retrieve information through DID Document resolution/dereferencing. | +| 5 | [key_exchange](./low-level-api/key_exchange.rs) | Demonstrates Elliptic-curve Diffie-Hellman (ECDH) cryptographic key exchange with DID Documents. | +| 6 | [private_tangle](./low-level-api/private_tangle.rs) | Showcases the same procedure as `create_did`, but on a private tangle - a locally running hornet node. | diff --git a/examples/account/config.rs b/examples_legacy/account/config.rs similarity index 100% rename from examples/account/config.rs rename to examples_legacy/account/config.rs diff --git a/examples/account/create_did.rs b/examples_legacy/account/create_did.rs similarity index 100% rename from examples/account/create_did.rs rename to examples_legacy/account/create_did.rs diff --git a/examples/account/create_vc.rs b/examples_legacy/account/create_vc.rs similarity index 100% rename from examples/account/create_vc.rs rename to examples_legacy/account/create_vc.rs diff --git a/examples/account/create_vp.rs b/examples_legacy/account/create_vp.rs similarity index 100% rename from examples/account/create_vp.rs rename to examples_legacy/account/create_vp.rs diff --git a/examples/account/encryption.rs b/examples_legacy/account/encryption.rs similarity index 100% rename from examples/account/encryption.rs rename to examples_legacy/account/encryption.rs diff --git a/examples/account/lazy.rs b/examples_legacy/account/lazy.rs similarity index 100% rename from examples/account/lazy.rs rename to examples_legacy/account/lazy.rs diff --git a/examples/account/manipulate_did.rs b/examples_legacy/account/manipulate_did.rs similarity index 100% rename from examples/account/manipulate_did.rs rename to examples_legacy/account/manipulate_did.rs diff --git a/examples/account/multiple_identities.rs b/examples_legacy/account/multiple_identities.rs similarity index 100% rename from examples/account/multiple_identities.rs rename to examples_legacy/account/multiple_identities.rs diff --git a/examples/account/revoke_vc.rs b/examples_legacy/account/revoke_vc.rs similarity index 100% rename from examples/account/revoke_vc.rs rename to examples_legacy/account/revoke_vc.rs diff --git a/examples/account/signing.rs b/examples_legacy/account/signing.rs similarity index 100% rename from examples/account/signing.rs rename to examples_legacy/account/signing.rs diff --git a/examples/account/unchecked.rs b/examples_legacy/account/unchecked.rs similarity index 100% rename from examples/account/unchecked.rs rename to examples_legacy/account/unchecked.rs diff --git a/examples/getting_started.rs b/examples_legacy/getting_started.rs similarity index 100% rename from examples/getting_started.rs rename to examples_legacy/getting_started.rs diff --git a/examples/low-level-api/common.rs b/examples_legacy/low-level-api/common.rs similarity index 100% rename from examples/low-level-api/common.rs rename to examples_legacy/low-level-api/common.rs diff --git a/examples/low-level-api/create_did.rs b/examples_legacy/low-level-api/create_did.rs similarity index 100% rename from examples/low-level-api/create_did.rs rename to examples_legacy/low-level-api/create_did.rs diff --git a/examples/low-level-api/key_exchange.rs b/examples_legacy/low-level-api/key_exchange.rs similarity index 100% rename from examples/low-level-api/key_exchange.rs rename to examples_legacy/low-level-api/key_exchange.rs diff --git a/examples/low-level-api/manipulate_did.rs b/examples_legacy/low-level-api/manipulate_did.rs similarity index 100% rename from examples/low-level-api/manipulate_did.rs rename to examples_legacy/low-level-api/manipulate_did.rs diff --git a/examples/low-level-api/private_tangle.rs b/examples_legacy/low-level-api/private_tangle.rs similarity index 100% rename from examples/low-level-api/private_tangle.rs rename to examples_legacy/low-level-api/private_tangle.rs diff --git a/examples/low-level-api/resolve_did.rs b/examples_legacy/low-level-api/resolve_did.rs similarity index 100% rename from examples/low-level-api/resolve_did.rs rename to examples_legacy/low-level-api/resolve_did.rs diff --git a/examples/low-level-api/resolve_history.rs b/examples_legacy/low-level-api/resolve_history.rs similarity index 100% rename from examples/low-level-api/resolve_history.rs rename to examples_legacy/low-level-api/resolve_history.rs diff --git a/identity_iota/README.md b/identity_iota/README.md index 4fd9e6422d..00ad3729f3 100644 --- a/identity_iota/README.md +++ b/identity_iota/README.md @@ -1,4 +1,4 @@ -![banner](https://github.com/iotaledger/identity.rs/raw/HEAD/.meta/identity_banner.png) +![banner](https://github.com/iotaledger/identity.rs/raw/HEAD/documentation/static/img/Banner/banner_identity.svg)

StackExchange diff --git a/identity_stardust/Cargo.toml b/identity_stardust/Cargo.toml index 371a11f59c..b94ff8faf9 100644 --- a/identity_stardust/Cargo.toml +++ b/identity_stardust/Cargo.toml @@ -10,16 +10,16 @@ readme = "../README.md" repository = "https://github.com/iotaledger/identity.rs" rust-version = "1.62" description = "An IOTA Ledger integration for the identity.rs library." -[workspace] [dependencies] # Ensure bee-block always matches the version used by iota-client. -bee-block = { version = "1.0.0-beta.5", default-features = false, features = ["std"], optional = true } +bee-block = { version = "1.0.0-beta.6", default-features = false, features = ["std"], optional = true } identity_core = { version = "=0.6.0", path = "../identity_core", default-features = false } identity_credential = { version = "=0.6.0", path = "../identity_credential", default-features = false } identity_did = { version = "=0.6.0", path = "../identity_did", default-features = false } async-trait = { version = "0.1.56", default-features = false, optional = true } +iota-client = { version = "2.0.0-beta.2", default-features = false, features = ["tls"], optional = true } num-derive = { version = "0.3", default-features = false } num-traits = { version = "0.2", default-features = false, features = ["std"] } once_cell = { version = "1", default-features = false, features = ["std"] } @@ -28,13 +28,6 @@ serde = { version = "1.0", default-features = false, features = ["std", "derive" strum = { version = "0.21", features = ["derive"] } thiserror = { version = "1.0", default-features = false } -[dependencies.iota-client] -git = "https://github.com/iotaledger/iota.rs" -rev = "a582bfa882793fe21db2055c4f7878ebc531877a" # develop branch, 2022-07-27 -features = ["tls"] -default-features = false -optional = true - [dev-dependencies] anyhow = { version = "1.0.57" } iota-crypto = { version = "0.12.1", default-features = false, features = ["bip39", "bip39-en"] } diff --git a/identity_stardust/src/client/identity_client.rs b/identity_stardust/src/client/identity_client.rs index eea778cccb..cbed527097 100644 --- a/identity_stardust/src/client/identity_client.rs +++ b/identity_stardust/src/client/identity_client.rs @@ -1,8 +1,6 @@ // Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use identity_did::did::DIDError; - use crate::block::address::Address; use crate::block::output::feature::SenderFeature; use crate::block::output::unlock_condition::GovernorAddressUnlockCondition; @@ -20,16 +18,6 @@ use crate::Result; use crate::StardustDID; use crate::StardustDocument; -impl TryFrom<&StardustDID> for AliasId { - type Error = Error; - - fn try_from(did: &StardustDID) -> std::result::Result { - let tag_bytes: [u8; StardustDID::TAG_BYTES_LEN] = - prefix_hex::decode(did.tag()).map_err(|_| DIDError::InvalidMethodId)?; - Ok(AliasId::new(tag_bytes)) - } -} - /// Helper functions necessary for the [`StardustIdentityClientExt`] trait. #[async_trait::async_trait(? Send)] pub trait StardustIdentityClient { @@ -103,7 +91,7 @@ pub trait StardustIdentityClientExt: StardustIdentityClient { /// /// Returns `Err` when failing to resolve the DID contained in `document`. async fn update_did_output(&self, document: StardustDocument) -> Result { - let id: AliasId = AliasId::try_from(document.id())?; + let id: AliasId = AliasId::from(document.id()); let (_, alias_output) = self.get_alias_output(id).await?; let mut alias_output_builder: AliasOutputBuilder = AliasOutputBuilder::from(&alias_output) @@ -130,7 +118,7 @@ pub trait StardustIdentityClientExt: StardustIdentityClient { /// /// Returns `Err` when failing to resolve the `did`. async fn deactivate_did_output(&self, did: &StardustDID) -> Result { - let alias_id: AliasId = AliasId::try_from(did)?; + let alias_id: AliasId = AliasId::from(did); let (_, alias_output) = self.get_alias_output(alias_id).await?; let mut alias_output_builder: AliasOutputBuilder = AliasOutputBuilder::from(&alias_output) @@ -154,7 +142,7 @@ pub trait StardustIdentityClientExt: StardustIdentityClient { async fn resolve_did(&self, did: &StardustDID) -> Result { validate_network(self, did).await?; - let id: AliasId = AliasId::try_from(did)?; + let id: AliasId = AliasId::from(did); let (_, alias_output) = self.get_alias_output(id).await?; let document: &[u8] = alias_output.state_metadata(); @@ -170,7 +158,7 @@ pub trait StardustIdentityClientExt: StardustIdentityClient { async fn resolve_did_output(&self, did: &StardustDID) -> Result { validate_network(self, did).await?; - let id: AliasId = AliasId::try_from(did)?; + let id: AliasId = AliasId::from(did); self.get_alias_output(id).await.map(|(_, alias_output)| alias_output) } diff --git a/identity_stardust/src/client/iota_client.rs b/identity_stardust/src/client/iota_client.rs index fb76512f6b..d3c6dcd80d 100644 --- a/identity_stardust/src/client/iota_client.rs +++ b/identity_stardust/src/client/iota_client.rs @@ -79,7 +79,7 @@ impl StardustClientExt for Client { async fn delete_did_output(&self, secret_manager: &SecretManager, address: Address, did: &StardustDID) -> Result<()> { validate_network(self, did).await?; - let alias_id: AliasId = AliasId::try_from(did)?; + let alias_id: AliasId = AliasId::from(did); let (output_id, alias_output) = self.get_alias_output(alias_id).await?; let basic_output = BasicOutputBuilder::new_with_amount(alias_output.amount()) diff --git a/identity_stardust/src/did/stardust_did.rs b/identity_stardust/src/did/stardust_did.rs index b18429ead5..61bc819ac3 100644 --- a/identity_stardust/src/did/stardust_did.rs +++ b/identity_stardust/src/did/stardust_did.rs @@ -343,6 +343,21 @@ impl KeyComparable for StardustDID { } } +#[cfg(feature = "client")] +mod __stardust_did_iota_client { + use crate::block::output::AliasId; + use crate::StardustDID; + + impl From<&StardustDID> for AliasId { + /// Creates an [`AliasId`] from the DID tag. + fn from(did: &StardustDID) -> Self { + let tag_bytes: [u8; StardustDID::TAG_BYTES_LEN] = prefix_hex::decode(did.tag()) + .expect("being able to successfully decode the tag should be checked during DID creation"); + AliasId::new(tag_bytes) + } + } +} + #[cfg(test)] mod tests { use once_cell::sync::Lazy;