Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port advanced Stardust examples to Wasm #1018

Merged
merged 36 commits into from Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
3291bb0
Refactor basic examples
PhilippGackstatter Sep 12, 2022
e6b2abf
Merge remote-tracking branch 'origin/dev' into chore/wasm-examples-re…
PhilippGackstatter Sep 13, 2022
80ab3c4
Port 0_did_controls_did to Wasm
PhilippGackstatter Sep 13, 2022
7478049
Expose `to_alias_id` method in Wasm
PhilippGackstatter Sep 13, 2022
1dfe855
Remove unnecessary console logs
PhilippGackstatter Sep 13, 2022
8dc3626
Remove unused imports
PhilippGackstatter Sep 13, 2022
6c26baa
Partially impl 1_did_issues_nft
PhilippGackstatter Sep 13, 2022
e31bd58
Remove unused imports; don't slice alias id
PhilippGackstatter Sep 14, 2022
ac51a4a
Finish porting 1_did_issues_nft
PhilippGackstatter Sep 14, 2022
7a53ea2
Improve variable name
PhilippGackstatter Sep 14, 2022
94008e5
Impl 2_nft_owns_did
PhilippGackstatter Sep 14, 2022
556b861
Improve 2_nft_owns_did Rust example comments
PhilippGackstatter Sep 14, 2022
01932b5
Use convenience functions
PhilippGackstatter Sep 14, 2022
f73e1e5
Merge remote-tracking branch 'origin/dev' into chore/wasm-examples-re…
PhilippGackstatter Sep 14, 2022
48d27a4
Generate a new address
PhilippGackstatter Sep 15, 2022
7844750
Impl 3_did_issues_tokens
PhilippGackstatter Sep 15, 2022
78f1493
Add `big-integer` dependency
PhilippGackstatter Sep 15, 2022
f8b8afc
Merge remote-tracking branch 'origin/dev' into chore/wasm-examples-re…
PhilippGackstatter Sep 15, 2022
a789b9a
Use iota-scoped package for new examples
PhilippGackstatter Sep 15, 2022
f020a2e
Port 4_key_exchange
PhilippGackstatter Sep 15, 2022
6a70ad2
Create directory structure
PhilippGackstatter Sep 15, 2022
3dbe676
Remove `ex` prefix from example names
PhilippGackstatter Sep 15, 2022
aef0e5e
Add comment
PhilippGackstatter Sep 15, 2022
20dac2b
Remove unused imports
PhilippGackstatter Sep 15, 2022
9cf6e91
Fix wiki links to examples
PhilippGackstatter Sep 15, 2022
e24fdd5
Add advanced examples to Readme
PhilippGackstatter Sep 15, 2022
da182a7
Add new examples as tests
PhilippGackstatter Sep 15, 2022
5d2c7c7
Update package-lock.json
PhilippGackstatter Sep 15, 2022
336d9b5
Update api-reference.md
PhilippGackstatter Sep 15, 2022
4e4e023
Document `create_did` utility function
PhilippGackstatter Sep 15, 2022
c4bb2ea
Apply suggestions from code review
PhilippGackstatter Sep 16, 2022
9cc15f9
Remove `webpack` & `webpack-cli`
PhilippGackstatter Sep 16, 2022
0859df9
Use package-lock.json from dev
PhilippGackstatter Sep 19, 2022
cee2ffc
Merge remote-tracking branch 'origin/dev' into chore/wasm-examples-re…
PhilippGackstatter Sep 19, 2022
d0d72f8
Merge remote-tracking branch 'origin/dev' into chore/wasm-examples-re…
PhilippGackstatter Sep 19, 2022
8d85bc3
Update package-lock.json
PhilippGackstatter Sep 19, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions bindings/wasm/docs/api-reference.md
Expand Up @@ -1624,6 +1624,7 @@ A DID conforming to the IOTA DID method specification.
* [.methodId()](#IotaDID+methodId) ⇒ <code>string</code>
* [.join(segment)](#IotaDID+join) ⇒ [<code>IotaDIDUrl</code>](#IotaDIDUrl)
* [.toUrl()](#IotaDID+toUrl) ⇒ [<code>IotaDIDUrl</code>](#IotaDIDUrl)
* [.toAliasId()](#IotaDID+toAliasId) ⇒ <code>string</code>
* [.intoUrl()](#IotaDID+intoUrl) ⇒ [<code>IotaDIDUrl</code>](#IotaDIDUrl)
* [.toString()](#IotaDID+toString) ⇒ <code>string</code>
* [.toJSON()](#IotaDID+toJSON) ⇒ <code>any</code>
Expand Down Expand Up @@ -1717,6 +1718,12 @@ Construct a new `DIDUrl` by joining with a relative DID Url string.
### did.toUrl() ⇒ [<code>IotaDIDUrl</code>](#IotaDIDUrl)
Clones the `DID` into a `DIDUrl`.

**Kind**: instance method of [<code>IotaDID</code>](#IotaDID)
<a name="IotaDID+toAliasId"></a>

### did.toAliasId() ⇒ <code>string</code>
Creates an AliasId from the DID tag.

**Kind**: instance method of [<code>IotaDID</code>](#IotaDID)
<a name="IotaDID+intoUrl"></a>

Expand Down
34 changes: 25 additions & 9 deletions bindings/wasm/examples/README.md
Expand Up @@ -26,19 +26,35 @@ Then, run an example using:
npm run example:node -- <example-name>
```

For instance, to run the `ex0_create_did` example execute:
For instance, to run the `0_create_did` example execute:

```bash
npm run example:node -- ex0_create_did
npm run example:node -- 0_create_did
```

| # | Name | Details |
|-----|-------------------------------------------------|------------------------------------------------------------------|
| 0 | [ex0_create_did](src/ex0_create_did.ts) | Create a DID Document and publish it in a new Alias Output. |
| 1 | [ex1_update_did](src/ex1_update_did.ts) | Update a DID document in an existing Alias Output. |
| 2 | [ex2_resolve_did](src/ex2_resolve_did.ts) | Resolve an existing DID in an Alias Output. |
| 3 | [ex3_deactivate_did](src/ex3_deactivate_did.ts) | Deactivate a DID in an Alias Output. |
| 4 | [ex4_delete_did](src/ex4_delete_did.ts) | Delete a DID in an Alias Output, reclaiming the storage deposit. |
## Basic Examples

The following basic CRUD (Create, Read, Update, Delete) examples are available:

| Name | Information |
| :-------------------------------------------------- | :----------------------------------------------------------------------------------- |
| [0_create_did](src/0_basic/0_create_did.ts) | Demonstrates how to create a DID Document and publish it in a new Alias Output. |
| [1_update_did](src/0_basic/1_update_did.ts) | Demonstrates how to update a DID document in an existing Alias Output. |
| [2_resolve_did](src/0_basic/2_resolve_did.ts) | Demonstrates how to resolve an existing DID in an Alias Output. |
| [3_deactivate_did](src/0_basic/3_deactivate_did.ts) | Demonstrates how to deactivate a DID in an Alias Output. |
| [4_delete_did](src/0_basic/4_delete_did.ts) | 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](src/1_advanced/0_did_controls_did.ts) | Demonstrates how an identity can control another identity. |
| [1_did_issues_nft](src/1_advanced/1_did_issues_nft.ts) | Demonstrates how an identity can issue and own NFTs, and how observers can verify the issuer of the NFT. |
| [2_nft_owns_did](src/1_advanced/2_nft_owns_did.ts) | Demonstrates how an identity can be owned by NFTs, and how observers can verify that relationship. |
| [3_did_issues_tokens](src/1_advanced/3_did_issues_tokens.ts) | Demonstrates how an identity can issue and control a Token Foundry and its tokens. |
| [4_key_exchange](src/1_advanced/4_key_exchange.ts) | Demonstrates Elliptic-curve Diffie-Hellman (ECDH) cryptographic key exchange with DID Documents. |

## Browser

Expand Down
Expand Up @@ -9,14 +9,11 @@ import {
IotaDocument,
IotaIdentityClient,
IotaVerificationMethod
} from '../../node';
} from '../../../node';
import { Bech32Helper, IAliasOutput } from '@iota/iota.js';
import { Bip39 } from "@iota/crypto.js";
import fetch from "node-fetch";
import { Client, MnemonicSecretManager, SecretManager } from "@iota/iota-client-wasm/node";

const API_ENDPOINT = "https://api.testnet.shimmer.network/";
const FAUCET = "https://faucet.testnet.shimmer.network/api/enqueue";
import { API_ENDPOINT, ensureAddressHasFunds } from '../util';

/** Demonstrate how to create a DID Document and publish it in a new Alias Output. */
export async function createIdentity(): Promise<{
Expand Down Expand Up @@ -75,73 +72,3 @@ export async function createIdentity(): Promise<{
did: published.id()
};
}

/** Request funds from the testnet faucet API, if needed, and wait for them to show in the wallet. */
async function ensureAddressHasFunds(client: Client, addressBech32: string) {
let balance = await getAddressBalance(client, addressBech32);
if (balance > 0) {
return;
}

await requestFundsFromFaucet(addressBech32);

for (let i = 0; i < 9; i++) {
// Wait for the funds to reflect.
await new Promise(f => setTimeout(f, 5000));

let balance = await getAddressBalance(client, addressBech32);
if (balance > 0) {
break;
}
}
}

/** Returns the balance of the given Bech32-encoded address. */
async function getAddressBalance(client: Client, addressBech32: string): Promise<number> {
// TODO: use the `addresses/ed25519/<addressHex>` API to get the balance?
const outputIds = await client.basicOutputIds([
{ address: addressBech32 },
{ hasExpiration: false },
{ hasTimelock: false },
{ hasStorageDepositReturn: false }
]);
const outputs = await client.getOutputs(outputIds);

let totalAmount = 0;
for (const output of outputs) {
totalAmount += Number(output.output.amount);
}

return totalAmount;
}

/** Request tokens from the testnet faucet API. */
async function requestFundsFromFaucet(addressBech32: string) {
const requestObj = JSON.stringify({ address: addressBech32 });
let errorMessage, data;
try {
const response = await fetch(FAUCET, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: requestObj,
});
if (response.status === 202) {
errorMessage = "OK";
} else if (response.status === 429) {
errorMessage = "too many requests, please try again later.";
} else {
data = await response.json();
// @ts-ignore
errorMessage = data.error.message;
}
} catch (error) {
errorMessage = error;
}

if (errorMessage != "OK") {
throw new Error(`failed to get funds from faucet: ${errorMessage}`);
}
}
@@ -1,15 +1,27 @@
// Copyright 2020-2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { MethodRelationship, IotaDocument, IotaService, Timestamp, IotaVerificationMethod, KeyPair, KeyType, MethodScope } from '../../node';
import { MethodRelationship, IotaDocument, IotaService, Timestamp, IotaVerificationMethod, KeyPair, KeyType, MethodScope, IotaIdentityClient } from '../../../node';
import { IAliasOutput, IRent, TransactionHelper } from '@iota/iota.js';

import { createIdentity } from "./ex0_create_did";
import { API_ENDPOINT, createDid } from '../util';
import { Client, MnemonicSecretManager } from '@iota/iota-client-wasm/node';
import { Bip39 } from '@iota/crypto.js';

/** Demonstrates how to update a DID document in an existing Alias Output. */
export async function updateIdentity() {
// Creates a new wallet and identity (see "ex0_create_did" example).
const { didClient, secretManager, did } = await createIdentity();
const client = new Client({
primaryNode: API_ENDPOINT,
localPow: true,
});
const didClient = new IotaIdentityClient(client);

// Generate a random mnemonic for our wallet.
const secretManager: MnemonicSecretManager = {
Mnemonic: Bip39.randomMnemonic()
};

// Creates a new wallet and identity (see "0_create_did" example).
const { did } = await createDid(client, secretManager);

// Resolve the latest state of the document.
// Technically this is equivalent to the document above.
Expand Down
@@ -1,15 +1,27 @@
// Copyright 2020-2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import type { IotaDocument } from '../../node';
import { IotaDocument, IotaIdentityClient } from '../../../node';
import type { IAliasOutput } from '@iota/iota.js';

import { createIdentity } from "./ex0_create_did";
import { API_ENDPOINT, createDid } from '../util';
import { Bip39 } from '@iota/crypto.js';
import { Client, MnemonicSecretManager } from '@iota/iota-client-wasm/node';

/** Demonstrates how to resolve an existing DID in an Alias Output. */
export async function resolveIdentity() {
// Creates a new wallet and identity (see "ex0_create_did" example).
const { didClient, did } = await createIdentity();
const client = new Client({
primaryNode: API_ENDPOINT,
localPow: true,
});
const didClient = new IotaIdentityClient(client);

// Generate a random mnemonic for our wallet.
const secretManager: MnemonicSecretManager = {
Mnemonic: Bip39.randomMnemonic()
};

// Creates a new wallet and identity (see "0_create_did" example).
const { did } = await createDid(client, secretManager);

// Resolve the associated Alias Output and extract the DID document from it.
const resolved: IotaDocument = await didClient.resolveDid(did);
Expand Down
@@ -1,15 +1,27 @@
// Copyright 2020-2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import type { IotaDocument } from '../../node';
import { IotaDocument, IotaIdentityClient } from '../../../node';
import { IAliasOutput, IRent, TransactionHelper } from '@iota/iota.js';

import { createIdentity } from "./ex0_create_did";
import { API_ENDPOINT, createDid } from '../util';
import { Bip39 } from '@iota/crypto.js';
import { Client, MnemonicSecretManager } from '@iota/iota-client-wasm/node';

/** Demonstrates how to deactivate a DID in an Alias Output. */
export async function deactivateIdentity() {
// Creates a new wallet and identity (see "ex0_create_did" example).
const { didClient, secretManager, did } = await createIdentity();
const client = new Client({
primaryNode: API_ENDPOINT,
localPow: true,
});
const didClient = new IotaIdentityClient(client);

// Generate a random mnemonic for our wallet.
const secretManager: MnemonicSecretManager = {
Mnemonic: Bip39.randomMnemonic()
};

// Creates a new wallet and identity (see "0_create_did" example).
const { did } = await createDid(client, secretManager);

// Resolve the latest state of the DID document, so we can reactivate it later.
let document: IotaDocument = await didClient.resolveDid(did);
Expand Down
@@ -1,18 +1,31 @@
// Copyright 2020-2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import {createIdentity} from "./ex0_create_did";
import {Bech32Helper} from "@iota/iota.js";
import { Client, MnemonicSecretManager } from "@iota/iota-client-wasm/node";
import { IotaIdentityClient } from "../../../node";
import { API_ENDPOINT, createDid } from "../util";
import { Bip39 } from "@iota/crypto.js";

/** Demonstrates how to delete a DID in an Alias Output, reclaiming the storage deposit. */
export async function deleteIdentity() {
// Creates a new wallet and identity (see "ex0_create_did" example).
const {didClient, secretManager, walletAddressBech32, did} = await createIdentity();
const client = new Client({
primaryNode: API_ENDPOINT,
localPow: true,
});
const didClient = new IotaIdentityClient(client);

// Generate a random mnemonic for our wallet.
const secretManager: MnemonicSecretManager = {
Mnemonic: Bip39.randomMnemonic()
};

// Creates a new wallet and identity (see "0_create_did" example).
const { address, did } = await createDid(client, secretManager);

// Deletes the Alias Output and its contained DID Document, rendering the DID permanently destroyed.
// This operation is *not* reversible.
// Deletion can only be done by the governor of the Alias Output.
const destinationAddress = Bech32Helper.addressFromBech32(walletAddressBech32, await didClient.getNetworkHrp());
const destinationAddress = address;
await didClient.deleteDidOutput(secretManager, destinationAddress, did);

// Attempting to resolve a deleted DID results in a `NotFound` error.
Expand Down