diff --git a/bindings/wasm/Cargo.toml b/bindings/wasm/Cargo.toml index 778d30944d..e2bb3c250c 100644 --- a/bindings/wasm/Cargo.toml +++ b/bindings/wasm/Cargo.toml @@ -19,8 +19,7 @@ crate-type = ["cdylib", "rlib"] async-trait = { version = "0.1", default-features = false } console_error_panic_hook = { version = "0.1" } futures = { version = "0.3" } -# Pin until iota-client v2.0.1-rc.4 is released -iota-types = { version = "=1.0.0-rc.1", default-features = false, features = ["block", "api", "dto", "std"] } +iota-types = { version = "1.0.0-rc.3", default-features = false, features = ["block", "api", "dto", "std"] } js-sys = { version = "0.3.60" } proc_typescript = { version = "0.1.0", path = "./proc_typescript" } serde = { version = "1.0", features = ["derive"] } diff --git a/bindings/wasm/README.md b/bindings/wasm/README.md index 72bbbd792b..e1f1bb6968 100644 --- a/bindings/wasm/README.md +++ b/bindings/wasm/README.md @@ -78,7 +78,7 @@ const API_ENDPOINT = "http://127.0.0.1:14265"; /** Demonstrate how to create a DID Document. */ async function main() { // Create a new client with the given network endpoint. - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md index 06e2ba3a0b..f3888ea8fa 100644 --- a/bindings/wasm/docs/api-reference.md +++ b/bindings/wasm/docs/api-reference.md @@ -102,6 +102,8 @@ See IVerifierOptions.

## Members
+
StateMetadataEncoding
+
StatusCheck

Controls validation behaviour when checking whether or not a credential has been revoked by its credentialStatus.

@@ -148,8 +150,6 @@ This variant is the default used if no other variant is specified when construct
MethodRelationship
-
StateMetadataEncoding
-
## Functions @@ -510,13 +510,13 @@ A method-agnostic DID Document. * [.properties()](#CoreDocument+properties) ⇒ Map.<string, any> * [.setPropertyUnchecked(key, value)](#CoreDocument+setPropertyUnchecked) * [.service()](#CoreDocument+service) ⇒ [Array.<CoreService>](#CoreService) - * [.insertService(service)](#CoreDocument+insertService) ⇒ boolean - * [.removeService(didUrl)](#CoreDocument+removeService) ⇒ boolean + * [.insertService(service)](#CoreDocument+insertService) + * [.removeService(didUrl)](#CoreDocument+removeService) ⇒ [CoreService](#CoreService) \| undefined * [.resolveService(query)](#CoreDocument+resolveService) ⇒ [CoreService](#CoreService) \| undefined * [.methods(scope)](#CoreDocument+methods) ⇒ [Array.<CoreVerificationMethod>](#CoreVerificationMethod) * [.verificationRelationships()](#CoreDocument+verificationRelationships) ⇒ Array.<(CoreDIDUrl\|CoreVerificationMethod)> * [.insertMethod(method, scope)](#CoreDocument+insertMethod) - * [.removeMethod(did)](#CoreDocument+removeMethod) + * [.removeMethod(did)](#CoreDocument+removeMethod) ⇒ [CoreVerificationMethod](#CoreVerificationMethod) \| undefined * [.resolveMethod(query, scope)](#CoreDocument+resolveMethod) ⇒ [CoreVerificationMethod](#CoreVerificationMethod) \| undefined * [.attachMethodRelationship(didUrl, relationship)](#CoreDocument+attachMethodRelationship) ⇒ boolean * [.detachMethodRelationship(didUrl, relationship)](#CoreDocument+detachMethodRelationship) ⇒ boolean @@ -550,6 +550,12 @@ Returns a copy of the DID Document `id`. ### coreDocument.setId(id) Sets the DID of the document. +### Warning + +Changing the identifier can drastically alter the results of +[`Self::resolve_method`](CoreDocument::resolve_method()), +[`Self::resolve_service`](CoreDocument::resolve_service()) and the related [DID URL dereferencing](https://w3c-ccg.github.io/did-resolution/#dereferencing) algorithm. + **Kind**: instance method of [CoreDocument](#CoreDocument) | Param | Type | @@ -642,6 +648,7 @@ Sets a custom property in the DID Document. If the value is set to `null`, the custom property will be removed. ### WARNING + This method can overwrite existing properties like `id` and result in an invalid document. **Kind**: instance method of [CoreDocument](#CoreDocument) @@ -659,10 +666,10 @@ Returns a set of all [CoreService](#CoreService) in the document. **Kind**: instance method of [CoreDocument](#CoreDocument) -### coreDocument.insertService(service) ⇒ boolean +### coreDocument.insertService(service) Add a new [CoreService](#CoreService) to the document. -Returns `true` if the service was added. +Errors if there already exists a service or verification method with the same id. **Kind**: instance method of [CoreDocument](#CoreDocument) @@ -672,7 +679,7 @@ Returns `true` if the service was added. -### coreDocument.removeService(didUrl) ⇒ boolean +### coreDocument.removeService(didUrl) ⇒ [CoreService](#CoreService) \| undefined Remoce a [CoreService](#CoreService) identified by the given [CoreDIDUrl](#CoreDIDUrl) from the document. Returns `true` if the service was removed. @@ -729,7 +736,7 @@ Adds a new `method` to the document in the given `scope`. -### coreDocument.removeMethod(did) +### coreDocument.removeMethod(did) ⇒ [CoreVerificationMethod](#CoreVerificationMethod) \| undefined Removes all references to the specified Verification Method. **Kind**: instance method of [CoreDocument](#CoreDocument) @@ -1980,12 +1987,12 @@ Deserializes an instance from a JSON object. * [.properties()](#IotaDocument+properties) ⇒ Map.<string, any> * [.setPropertyUnchecked(key, value)](#IotaDocument+setPropertyUnchecked) * [.service()](#IotaDocument+service) ⇒ [Array.<IotaService>](#IotaService) - * [.insertService(service)](#IotaDocument+insertService) ⇒ boolean - * [.removeService(did)](#IotaDocument+removeService) ⇒ boolean + * [.insertService(service)](#IotaDocument+insertService) + * [.removeService(did)](#IotaDocument+removeService) ⇒ [IotaService](#IotaService) \| undefined * [.resolveService(query)](#IotaDocument+resolveService) ⇒ [IotaService](#IotaService) \| undefined * [.methods(scope)](#IotaDocument+methods) ⇒ [Array.<IotaVerificationMethod>](#IotaVerificationMethod) * [.insertMethod(method, scope)](#IotaDocument+insertMethod) - * [.removeMethod(did)](#IotaDocument+removeMethod) + * [.removeMethod(did)](#IotaDocument+removeMethod) ⇒ [IotaVerificationMethod](#IotaVerificationMethod) \| undefined * [.resolveMethod(query, scope)](#IotaDocument+resolveMethod) ⇒ [IotaVerificationMethod](#IotaVerificationMethod) \| undefined * [.attachMethodRelationship(didUrl, relationship)](#IotaDocument+attachMethodRelationship) ⇒ boolean * [.detachMethodRelationship(didUrl, relationship)](#IotaDocument+detachMethodRelationship) ⇒ boolean @@ -2012,7 +2019,7 @@ Deserializes an instance from a JSON object. * _static_ * [.newWithId(id)](#IotaDocument.newWithId) ⇒ [IotaDocument](#IotaDocument) * [.unpackFromOutput(did, aliasOutput, allowEmpty, tokenSupply)](#IotaDocument.unpackFromOutput) ⇒ [IotaDocument](#IotaDocument) - * [.unpackFromBlock(network, block, protocolResponseJson)](#IotaDocument.unpackFromBlock) ⇒ [Array.<IotaDocument>](#IotaDocument) + * [.unpackFromBlock(network, block, protocol_parameters)](#IotaDocument.unpackFromBlock) ⇒ [Array.<IotaDocument>](#IotaDocument) * [.fromJSON(json)](#IotaDocument.fromJSON) ⇒ [IotaDocument](#IotaDocument) @@ -2071,6 +2078,7 @@ Sets a custom property in the DID Document. If the value is set to `null`, the custom property will be removed. ### WARNING + This method can overwrite existing properties like `id` and result in an invalid document. **Kind**: instance method of [IotaDocument](#IotaDocument) @@ -2088,7 +2096,7 @@ Return a set of all [IotaService](#IotaService) in the document. **Kind**: instance method of [IotaDocument](#IotaDocument) -### iotaDocument.insertService(service) ⇒ boolean +### iotaDocument.insertService(service) Add a new [IotaService](#IotaService) to the document. Returns `true` if the service was added. @@ -2101,7 +2109,7 @@ Returns `true` if the service was added. -### iotaDocument.removeService(did) ⇒ boolean +### iotaDocument.removeService(did) ⇒ [IotaService](#IotaService) \| undefined Remove a [IotaService](#IotaService) identified by the given [IotaDIDUrl](#IotaDIDUrl) from the document. Returns `true` if a service was removed. @@ -2152,7 +2160,7 @@ Adds a new `method` to the document in the given `scope`. -### iotaDocument.removeMethod(did) +### iotaDocument.removeMethod(did) ⇒ [IotaVerificationMethod](#IotaVerificationMethod) \| undefined Removes all references to the specified Verification Method. **Kind**: instance method of [IotaDocument](#IotaDocument) @@ -2438,7 +2446,7 @@ encoded in the `AliasId` alone. -### IotaDocument.unpackFromBlock(network, block, protocolResponseJson) ⇒ [Array.<IotaDocument>](#IotaDocument) +### IotaDocument.unpackFromBlock(network, block, protocol_parameters) ⇒ [Array.<IotaDocument>](#IotaDocument) Returns all DID documents of the Alias Outputs contained in the block's transaction payload outputs, if any. @@ -2452,7 +2460,7 @@ Errors if any Alias Output does not contain a valid or empty DID Document. | --- | --- | | network | string | | block | IBlock | -| protocolResponseJson | string | +| protocol_parameters | INodeInfoProtocol | @@ -4055,6 +4063,10 @@ This is possible because Ed25519 is birationally equivalent to Curve25519 used b | --- | --- | | publicKey | Uint8Array | + + +## StateMetadataEncoding +**Kind**: global variable ## StatusCheck @@ -4141,10 +4153,6 @@ Return after the first error occurs. ## MethodRelationship **Kind**: global variable - - -## StateMetadataEncoding -**Kind**: global variable ## start() diff --git a/bindings/wasm/examples/src/0_basic/0_create_did.ts b/bindings/wasm/examples/src/0_basic/0_create_did.ts index 7c3b6dab57..4a352abc12 100644 --- a/bindings/wasm/examples/src/0_basic/0_create_did.ts +++ b/bindings/wasm/examples/src/0_basic/0_create_did.ts @@ -22,7 +22,7 @@ export async function createIdentity(): Promise<{ walletAddressBech32: string; did: IotaDID; }> { - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/examples/src/0_basic/1_update_did.ts b/bindings/wasm/examples/src/0_basic/1_update_did.ts index 6611bf10c3..f18d364d60 100644 --- a/bindings/wasm/examples/src/0_basic/1_update_did.ts +++ b/bindings/wasm/examples/src/0_basic/1_update_did.ts @@ -19,7 +19,7 @@ import { API_ENDPOINT, createDid } from "../util"; /** Demonstrates how to update a DID document in an existing Alias Output. */ export async function updateIdentity() { - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/examples/src/0_basic/2_resolve_did.ts b/bindings/wasm/examples/src/0_basic/2_resolve_did.ts index e66526d24e..33173eb272 100644 --- a/bindings/wasm/examples/src/0_basic/2_resolve_did.ts +++ b/bindings/wasm/examples/src/0_basic/2_resolve_did.ts @@ -9,7 +9,7 @@ import { API_ENDPOINT, createDid } from "../util"; /** Demonstrates how to resolve an existing DID in an Alias Output. */ export async function resolveIdentity() { - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/examples/src/0_basic/3_deactivate_did.ts b/bindings/wasm/examples/src/0_basic/3_deactivate_did.ts index 535514874b..d39aacdaa8 100644 --- a/bindings/wasm/examples/src/0_basic/3_deactivate_did.ts +++ b/bindings/wasm/examples/src/0_basic/3_deactivate_did.ts @@ -9,7 +9,7 @@ import { API_ENDPOINT, createDid } from "../util"; /** Demonstrates how to deactivate a DID in an Alias Output. */ export async function deactivateIdentity() { - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/examples/src/0_basic/4_delete_did.ts b/bindings/wasm/examples/src/0_basic/4_delete_did.ts index 54795b9806..7451a5b487 100644 --- a/bindings/wasm/examples/src/0_basic/4_delete_did.ts +++ b/bindings/wasm/examples/src/0_basic/4_delete_did.ts @@ -8,7 +8,7 @@ import { API_ENDPOINT, createDid } from "../util"; /** Demonstrates how to delete a DID in an Alias Output, reclaiming the storage deposit. */ export async function deleteIdentity() { - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/examples/src/0_basic/5_create_vc.ts b/bindings/wasm/examples/src/0_basic/5_create_vc.ts index 50dadb177b..677ac7bcc8 100644 --- a/bindings/wasm/examples/src/0_basic/5_create_vc.ts +++ b/bindings/wasm/examples/src/0_basic/5_create_vc.ts @@ -19,7 +19,7 @@ import { API_ENDPOINT, createDid } from "../util"; * This Verifiable Credential can be verified by anyone, allowing Alice to take control of it and share it with whomever they please. */ export async function createVC() { - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/examples/src/0_basic/6_create_vp.ts b/bindings/wasm/examples/src/0_basic/6_create_vp.ts index 9a04933aeb..e7dde79e70 100644 --- a/bindings/wasm/examples/src/0_basic/6_create_vp.ts +++ b/bindings/wasm/examples/src/0_basic/6_create_vp.ts @@ -29,7 +29,7 @@ export async function createVP() { // Step 1: Create identities for the issuer and the holder. // =========================================================================== - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts b/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts index 0d9dadf775..e24cc3b144 100644 --- a/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts +++ b/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts @@ -32,7 +32,7 @@ export async function revokeVC() { // Create a Verifiable Credential. // =========================================================================== - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/examples/src/1_advanced/0_did_controls_did.ts b/bindings/wasm/examples/src/1_advanced/0_did_controls_did.ts index 65c0d1fd6b..4394deca3d 100644 --- a/bindings/wasm/examples/src/1_advanced/0_did_controls_did.ts +++ b/bindings/wasm/examples/src/1_advanced/0_did_controls_did.ts @@ -35,7 +35,7 @@ export async function didControlsDid() { // ======================================================== // Create a new Client to interact with the IOTA ledger. - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/examples/src/1_advanced/1_did_issues_nft.ts b/bindings/wasm/examples/src/1_advanced/1_did_issues_nft.ts index be89c2a6c7..5444c5c57c 100644 --- a/bindings/wasm/examples/src/1_advanced/1_did_issues_nft.ts +++ b/bindings/wasm/examples/src/1_advanced/1_did_issues_nft.ts @@ -36,7 +36,7 @@ export async function didIssuesNft() { // ============================================== // Create a new Client to interact with the IOTA ledger. - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/examples/src/1_advanced/2_nft_owns_did.ts b/bindings/wasm/examples/src/1_advanced/2_nft_owns_did.ts index c6cd352093..ee31c8c414 100644 --- a/bindings/wasm/examples/src/1_advanced/2_nft_owns_did.ts +++ b/bindings/wasm/examples/src/1_advanced/2_nft_owns_did.ts @@ -37,7 +37,7 @@ export async function nftOwnsDid() { // ============================= // Create a new Client to interact with the IOTA ledger. - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/examples/src/1_advanced/3_did_issues_tokens.ts b/bindings/wasm/examples/src/1_advanced/3_did_issues_tokens.ts index e313afb3a8..abc7c502d1 100644 --- a/bindings/wasm/examples/src/1_advanced/3_did_issues_tokens.ts +++ b/bindings/wasm/examples/src/1_advanced/3_did_issues_tokens.ts @@ -37,7 +37,7 @@ export async function didIssuesTokens() { // =========================================== // Create a new Client to interact with the IOTA ledger. - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/examples/src/1_advanced/4_key_exchange.ts b/bindings/wasm/examples/src/1_advanced/4_key_exchange.ts index d32baa4b07..6d883f3608 100644 --- a/bindings/wasm/examples/src/1_advanced/4_key_exchange.ts +++ b/bindings/wasm/examples/src/1_advanced/4_key_exchange.ts @@ -26,7 +26,7 @@ export async function keyExchange() { // ============================== // Create a new Client to interact with the IOTA ledger. - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/examples/src/1_advanced/5_custom_resolution.ts b/bindings/wasm/examples/src/1_advanced/5_custom_resolution.ts index 80e177ddfb..675fe9eb9b 100644 --- a/bindings/wasm/examples/src/1_advanced/5_custom_resolution.ts +++ b/bindings/wasm/examples/src/1_advanced/5_custom_resolution.ts @@ -19,7 +19,7 @@ export async function customResolution() { }; // Create a new Client to interact with the IOTA ledger. - const client = await Client.new({ + const client = new Client({ primaryNode: API_ENDPOINT, localPow: true, }); diff --git a/bindings/wasm/lib/iota_identity_client.ts b/bindings/wasm/lib/iota_identity_client.ts index 174426454f..4a46bf9150 100644 --- a/bindings/wasm/lib/iota_identity_client.ts +++ b/bindings/wasm/lib/iota_identity_client.ts @@ -13,6 +13,7 @@ import { IUTXOInput, TransactionHelper, } from "@iota/iota.js"; +import type { INodeInfoProtocol } from "@iota/types"; import type { Client, INodeInfoWrapper, SecretManager } from "~iota-client-wasm"; /** Provides operations for IOTA DID Documents with Alias Outputs. */ @@ -47,14 +48,22 @@ export class IotaIdentityClient implements IIotaIdentityClient { return info.nodeInfo.protocol.rentStructure; } - async getTokenSupply(): Promise { + async getTokenSupply(): Promise { return await this.client.getTokenSupply(); } + /* async getProtocolResponse(): Promise { return await this.client.getProtocolResponse(); } + */ + + async getProtocolParameters(): Promise { + const protocolParameters: INodeInfoProtocol = await this.client.getProtocolParameters(); + return protocolParameters; + } + /** Create a DID with a new Alias Output containing the given `document`. * * The `address` will be set as the state controller and governor unlock conditions. @@ -114,15 +123,13 @@ export class IotaIdentityClient implements IIotaIdentityClient { */ async publishDidOutput(secretManager: SecretManager, aliasOutput: IAliasOutput): Promise { const networkHrp = await this.getNetworkHrp(); - // Publish block. const [blockId, block] = await this.client.buildAndPostBlock(secretManager, { outputs: [aliasOutput], }); await this.client.retryUntilIncluded(blockId); - const protocolParams = await this.client.getProtocolResponse(); - + const protocolParams = await this.client.getProtocolParameters(); // Extract document with computed AliasId. const documents = IotaDocument.unpackFromBlock(networkHrp, block, protocolParams); if (documents.length < 1) { diff --git a/bindings/wasm/package-lock.json b/bindings/wasm/package-lock.json index 5c212fb432..3123115a8d 100644 --- a/bindings/wasm/package-lock.json +++ b/bindings/wasm/package-lock.json @@ -39,7 +39,7 @@ "node": ">=16" }, "peerDependencies": { - "@iota/iota-client-wasm": "^0.5.0-alpha.5", + "@iota/iota-client-wasm": "^0.5.0-alpha.6", "@iota/iota.js": "^1.9.0-stardust.25" } }, @@ -191,9 +191,9 @@ } }, "node_modules/@iota/iota-client-wasm": { - "version": "0.5.0-alpha.5", - "resolved": "https://registry.npmjs.org/@iota/iota-client-wasm/-/iota-client-wasm-0.5.0-alpha.5.tgz", - "integrity": "sha512-FzyHMxBtwcPcCqLYk4um5pLk8KqCIWiSdE3c1bX4iTv0IH7EdM9G9js/GILFc2KlzWKYZK2L08xG0ogcrCPIHA==", + "version": "0.5.0-alpha.6", + "resolved": "https://registry.npmjs.org/@iota/iota-client-wasm/-/iota-client-wasm-0.5.0-alpha.6.tgz", + "integrity": "sha512-/bG8oQKa3j+XMgkZcA2nmHzVCgHQs8bDKyurKIk8OfDUdE02BEon4YQ2GAjfQEDVgW11IsgYOFZZ5SB09LKlgg==", "peer": true, "dependencies": { "@iota/types": "^1.0.0-beta.11", @@ -6890,9 +6890,9 @@ } }, "@iota/iota-client-wasm": { - "version": "0.5.0-alpha.5", - "resolved": "https://registry.npmjs.org/@iota/iota-client-wasm/-/iota-client-wasm-0.5.0-alpha.5.tgz", - "integrity": "sha512-FzyHMxBtwcPcCqLYk4um5pLk8KqCIWiSdE3c1bX4iTv0IH7EdM9G9js/GILFc2KlzWKYZK2L08xG0ogcrCPIHA==", + "version": "0.5.0-alpha.6", + "resolved": "https://registry.npmjs.org/@iota/iota-client-wasm/-/iota-client-wasm-0.5.0-alpha.6.tgz", + "integrity": "sha512-/bG8oQKa3j+XMgkZcA2nmHzVCgHQs8bDKyurKIk8OfDUdE02BEon4YQ2GAjfQEDVgW11IsgYOFZZ5SB09LKlgg==", "peer": true, "requires": { "@iota/types": "^1.0.0-beta.11", diff --git a/bindings/wasm/package.json b/bindings/wasm/package.json index 6191df097c..7bafacd1de 100644 --- a/bindings/wasm/package.json +++ b/bindings/wasm/package.json @@ -79,8 +79,8 @@ "node-fetch": "^2.6.7" }, "peerDependencies": { - "@iota/iota-client-wasm": "^0.5.0-alpha.5", - "@iota/iota.js": "^1.9.0-stardust.25" + "@iota/iota.js": "^1.9.0-stardust.25", + "@iota/iota-client-wasm": "^0.5.0-alpha.6" }, "engines": { "node": ">=16" diff --git a/bindings/wasm/src/iota/identity_client.rs b/bindings/wasm/src/iota/identity_client.rs index d39dca3a5a..44b787ec12 100644 --- a/bindings/wasm/src/iota/identity_client.rs +++ b/bindings/wasm/src/iota/identity_client.rs @@ -8,9 +8,10 @@ use identity_iota::iota::block::output::dto::AliasOutputDto; use identity_iota::iota::block::output::AliasId; use identity_iota::iota::block::output::AliasOutput; use identity_iota::iota::block::output::OutputId; -use identity_iota::iota::block::output::RentStructure; -use identity_iota::iota::block::output::RentStructureBuilder; use identity_iota::iota::IotaIdentityClient; +use identity_iota::iota::IotaIdentityClientExt; +use iota_types::block::protocol::dto::ProtocolParametersDto; +use iota_types::block::protocol::ProtocolParameters; use js_sys::Promise; use wasm_bindgen::prelude::*; use wasm_bindgen_futures::JsFuture; @@ -22,21 +23,12 @@ extern "C" { #[wasm_bindgen(typescript_type = "IIotaIdentityClient")] pub type WasmIotaIdentityClient; - #[wasm_bindgen(method, js_name = getNetworkHrp)] - pub fn get_network_hrp(this: &WasmIotaIdentityClient) -> JsValue; - #[allow(non_snake_case)] #[wasm_bindgen(method, js_name = getAliasOutput)] pub fn get_alias_output(this: &WasmIotaIdentityClient, aliasId: String) -> JsValue; - #[wasm_bindgen(method, js_name = getRentStructure)] - pub fn get_rent_structure(this: &WasmIotaIdentityClient) -> JsValue; - - #[wasm_bindgen(method, js_name = getTokenSupply)] - pub fn get_token_supply(this: &WasmIotaIdentityClient) -> JsValue; - - #[wasm_bindgen(method, js_name = getProtocolResponse)] - pub fn get_protocol_response(this: &WasmIotaIdentityClient) -> JsValue; + #[wasm_bindgen(method, js_name = getProtocolParameters)] + pub fn get_protocol_parameters(this: &WasmIotaIdentityClient) -> JsValue; } impl Debug for WasmIotaIdentityClient { @@ -47,19 +39,6 @@ impl Debug for WasmIotaIdentityClient { #[async_trait::async_trait(?Send)] impl IotaIdentityClient for WasmIotaIdentityClient { - async fn get_network_hrp(&self) -> Result { - let promise: Promise = Promise::resolve(&WasmIotaIdentityClient::get_network_hrp(self)); - let result: JsValueResult = JsFuture::from(promise).await.into(); - let js: JsValue = result.to_iota_core_error()?; - let network_hrp = match js.as_string() { - Some(hrp) => hrp, - None => js.into_serde().map_err(|err| { - identity_iota::iota::Error::JsError(format!("get_network_hrp failed to deserialize String: {}", err)) - })?, - }; - Ok(network_hrp) - } - async fn get_alias_output(&self, id: AliasId) -> Result<(OutputId, AliasOutput), identity_iota::iota::Error> { let promise: Promise = Promise::resolve(&WasmIotaIdentityClient::get_alias_output(self, id.to_string())); let result: JsValueResult = JsFuture::from(promise).await.into(); @@ -85,49 +64,26 @@ impl IotaIdentityClient for WasmIotaIdentityClient { )) })?; - let token_supply_promise: Promise = Promise::resolve(&WasmIotaIdentityClient::get_token_supply(self)); - let token_supply: u64 = JsValueResult::from(JsFuture::from(token_supply_promise).await) - .to_iota_core_error() - .and_then(|value| { - if let Some(big_int) = value.as_f64() { - Ok(big_int as u64) - } else { - Err(identity_iota::iota::Error::JsError( - "could not retrieve a token supply of the required type".into(), - )) - } - })?; - - let alias_output = AliasOutput::try_from_dto(&alias_dto, token_supply).map_err(|err| { + let alias_output = AliasOutput::try_from_dto( + &alias_dto, + ::get_token_supply(self).await?, + ) + .map_err(|err| { identity_iota::iota::Error::JsError(format!("get_alias_output failed to convert AliasOutputDto: {}", err)) })?; Ok((output_id, alias_output)) } - async fn get_rent_structure(&self) -> Result { - let promise: Promise = Promise::resolve(&WasmIotaIdentityClient::get_rent_structure(self)); + async fn get_protocol_parameters(&self) -> Result { + let promise: Promise = Promise::resolve(&WasmIotaIdentityClient::get_protocol_parameters(self)); let result: JsValueResult = JsFuture::from(promise).await.into(); - let rent_structure: RentStructureBuilder = result.to_iota_core_error()?.into_serde().map_err(|err| { - identity_iota::iota::Error::JsError(format!("get_rent_structure failed to deserialize: {}", err)) + let protocol_parameters: ProtocolParametersDto = result.to_iota_core_error().and_then(|parameters| { + parameters + .into_serde() + .map_err(|err| identity_iota::iota::Error::JsError(format!("could not obtain protocol parameters: {}", err))) })?; - Ok(rent_structure.finish()) - } - - async fn get_token_supply(&self) -> Result { - let promise: Promise = Promise::resolve(&WasmIotaIdentityClient::get_token_supply(self)); - Ok( - JsValueResult::from(JsFuture::from(promise).await) - .to_iota_core_error() - .and_then(|value| { - if let Some(big_int) = value.as_f64() { - Ok(big_int as u64) - } else { - Err(identity_iota::iota::Error::JsError( - "could not retrieve a token supply of the required type".into(), - )) - } - })?, - ) + ProtocolParameters::try_from(protocol_parameters) + .map_err(|err| identity_iota::iota::Error::JsError(format!("could not obtain protocol parameters: {}", err))) } } @@ -136,22 +92,10 @@ const I_IOTA_IDENTITY_CLIENT: &'static str = r#" import type { IAliasOutput, IRent } from '@iota/types'; /** Helper interface necessary for `IotaIdentityClientExt`. */ interface IIotaIdentityClient { - /** - * Return the Bech32 human-readable part (HRP) of the network. - * - * E.g. "iota", "atoi", "smr", "rms". - */ - getNetworkHrp(): Promise; /** Resolve an Alias identifier, returning its latest `OutputId` and `AliasOutput`. */ getAliasOutput(aliasId: string): Promise<[string, IAliasOutput]>; - /** Return the rent structure of the network, indicating the byte costs for outputs. */ - getRentStructure(): Promise; - - /** Gets the token supply of the node we're connecting to. */ - getTokenSupply(): Promise; - - /** Returns the protocol response as a JSON string. */ - getProtocolResponse(): Promise; + /** Returns the protocol parameters. */ + getProtocolParameters(): Promise; }"#; diff --git a/bindings/wasm/src/iota/iota_document.rs b/bindings/wasm/src/iota/iota_document.rs index fd7de74660..9b3a994694 100644 --- a/bindings/wasm/src/iota/iota_document.rs +++ b/bindings/wasm/src/iota/iota_document.rs @@ -1,7 +1,6 @@ // Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use identity_iota::core::FromJson; use identity_iota::core::OneOrMany; use identity_iota::core::OrderedSet; use identity_iota::core::Timestamp; @@ -20,7 +19,7 @@ use identity_iota::iota::IotaDocument; use identity_iota::iota::IotaVerificationMethod; use identity_iota::iota::NetworkName; use identity_iota::iota::StateMetadataEncoding; -use iota_types::api::response::ProtocolResponse; +use iota_types::block::protocol::dto::ProtocolParametersDto; use iota_types::block::protocol::ProtocolParameters; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; @@ -430,7 +429,11 @@ impl WasmIotaDocument { /// `protocolResponseJson` can be obtained from a `Client`. #[allow(non_snake_case)] #[wasm_bindgen(js_name = unpackFromBlock)] - pub fn unpack_from_block(network: String, block: &IBlock, protocolResponseJson: String) -> Result { + pub fn unpack_from_block( + network: String, + block: &IBlock, + protocol_parameters: &INodeInfoProtocol, + ) -> Result { let network_name: NetworkName = NetworkName::try_from(network).wasm_result()?; let block_dto: iota_types::block::BlockDto = block .into_serde() @@ -439,8 +442,15 @@ impl WasmIotaDocument { }) .wasm_result()?; - let protocol_response: ProtocolResponse = ProtocolResponse::from_json(&protocolResponseJson).wasm_result()?; - let protocol_parameters: ProtocolParameters = ProtocolParameters::try_from(protocol_response).wasm_result()?; + let protocol_parameters_dto: ProtocolParametersDto = protocol_parameters + .into_serde() + .map_err(|err| identity_iota::iota::Error::JsError(format!("could not obtain protocolParameters: {}", err))) + .wasm_result()?; + + let protocol_parameters: ProtocolParameters = ProtocolParameters::try_from(protocol_parameters_dto) + .map_err(|err| identity_iota::iota::Error::JsError(format!("could not obtain protocolParameters: {}", err))) + .wasm_result()?; + let block: iota_types::block::Block = iota_types::block::Block::try_from_dto(&block_dto, &protocol_parameters) .map_err(|err| { identity_iota::iota::Error::JsError(format!("unpackFromBlock failed to convert BlockDto: {}", err)) @@ -601,7 +611,11 @@ extern "C" { // External interface from `@iota/types`, must be deserialized via BlockDto. #[wasm_bindgen(typescript_type = "IBlock")] pub type IBlock; + + // External interface from `@iota/types`, must be deserialized via ProtocolParameters. + #[wasm_bindgen(typescript_type = "INodeInfoProtocol")] + pub type INodeInfoProtocol; } #[wasm_bindgen(typescript_custom_section)] -const TYPESCRIPT_IMPORTS: &'static str = r#"import type { IBlock } from '@iota/types';"#; +const TYPESCRIPT_IMPORTS: &'static str = r#"import type { IBlock, INodeInfoProtocol } from '@iota/types';"#; diff --git a/bindings/wasm/src/lib.rs b/bindings/wasm/src/lib.rs index 9abcf69fb1..757ec99d83 100644 --- a/bindings/wasm/src/lib.rs +++ b/bindings/wasm/src/lib.rs @@ -34,6 +34,5 @@ pub mod resolver; #[wasm_bindgen(start)] pub fn start() -> Result<(), JsValue> { console_error_panic_hook::set_once(); - Ok(()) } diff --git a/examples/0_basic/1_update_did.rs b/examples/0_basic/1_update_did.rs index a7dd70508d..8b24a4266b 100644 --- a/examples/0_basic/1_update_did.rs +++ b/examples/0_basic/1_update_did.rs @@ -79,10 +79,10 @@ 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: RentStructure = client.get_rent_structure()?; + let rent_structure: RentStructure = client.get_rent_structure().await?; let alias_output: AliasOutput = AliasOutputBuilder::from(&alias_output) .with_minimum_storage_deposit(rent_structure) - .finish(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; // Publish the updated Alias Output. let updated: IotaDocument = client.publish_did_output(&secret_manager, alias_output).await?; diff --git a/examples/0_basic/3_deactivate_did.rs b/examples/0_basic/3_deactivate_did.rs index bf4de45e74..75fdf4dd6d 100644 --- a/examples/0_basic/3_deactivate_did.rs +++ b/examples/0_basic/3_deactivate_did.rs @@ -42,10 +42,10 @@ async fn main() -> anyhow::Result<()> { let deactivated_output: AliasOutput = client.deactivate_did_output(&did).await?; // Optional: reduce and reclaim the storage deposit, sending the tokens to the state controller. - let rent_structure = client.get_rent_structure()?; + let rent_structure = client.get_rent_structure().await?; let deactivated_output = AliasOutputBuilder::from(&deactivated_output) .with_minimum_storage_deposit(rent_structure) - .finish(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; // Publish the deactivated DID document. let _ = client.publish_did_output(&secret_manager, deactivated_output).await?; @@ -60,10 +60,10 @@ async fn main() -> anyhow::Result<()> { let reactivated_output: AliasOutput = client.update_did_output(document.clone()).await?; // Increase the storage deposit to the minimum again, if it was reclaimed during deactivation. - let rent_structure = client.get_rent_structure()?; + let rent_structure = client.get_rent_structure().await?; let reactivated_output = AliasOutputBuilder::from(&reactivated_output) .with_minimum_storage_deposit(rent_structure) - .finish(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; client.publish_did_output(&secret_manager, reactivated_output).await?; // Resolve the reactivated DID document. diff --git a/examples/0_basic/7_revoke_vc.rs b/examples/0_basic/7_revoke_vc.rs index 874af3b0c0..257235a55c 100644 --- a/examples/0_basic/7_revoke_vc.rs +++ b/examples/0_basic/7_revoke_vc.rs @@ -88,10 +88,10 @@ 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: RentStructure = client.get_rent_structure()?; + let rent_structure: RentStructure = client.get_rent_structure().await?; let alias_output: AliasOutput = AliasOutputBuilder::from(&alias_output) .with_minimum_storage_deposit(rent_structure) - .finish(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; // Publish the updated Alias Output. issuer_document = client.publish_did_output(&secret_manager_issuer, alias_output).await?; @@ -145,10 +145,10 @@ async fn main() -> anyhow::Result<()> { // Publish the changes. let alias_output: AliasOutput = client.update_did_output(issuer_document.clone()).await?; - let rent_structure: RentStructure = client.get_rent_structure()?; + let rent_structure: RentStructure = client.get_rent_structure().await?; let alias_output: AliasOutput = AliasOutputBuilder::from(&alias_output) .with_minimum_storage_deposit(rent_structure) - .finish(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; issuer_document = client.publish_did_output(&secret_manager_issuer, alias_output).await?; let validation_result = CredentialValidator::validate( @@ -175,7 +175,7 @@ async fn main() -> anyhow::Result<()> { // Publish the changes. let alias_output: AliasOutput = client.update_did_output(issuer_document.clone()).await?; - let alias_output: AliasOutput = AliasOutputBuilder::from(&alias_output).finish(client.get_token_supply()?)?; + let alias_output: AliasOutput = AliasOutputBuilder::from(&alias_output).finish(client.get_token_supply().await?)?; client.publish_did_output(&secret_manager_issuer, alias_output).await?; // We expect the verifiable credential to be revoked. diff --git a/examples/1_advanced/0_did_controls_did.rs b/examples/1_advanced/0_did_controls_did.rs index 3e5257b71b..35050f902d 100644 --- a/examples/1_advanced/0_did_controls_did.rs +++ b/examples/1_advanced/0_did_controls_did.rs @@ -51,7 +51,7 @@ async fn main() -> anyhow::Result<()> { let company_did = company_document.id().clone(); // Get the current byte costs and network name. - let rent_structure: RentStructure = client.get_rent_structure()?; + 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. @@ -75,7 +75,7 @@ async fn main() -> anyhow::Result<()> { .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(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; // Publish the subsidiary's DID. let mut subsidiary_document: IotaDocument = client.publish_did_output(&secret_manager, subsidiary_alias).await?; @@ -100,7 +100,7 @@ async fn main() -> anyhow::Result<()> { 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(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; // Publish the updated subsidiary's DID. // diff --git a/examples/1_advanced/1_did_issues_nft.rs b/examples/1_advanced/1_did_issues_nft.rs index 28cbbe577e..a402a27b4a 100644 --- a/examples/1_advanced/1_did_issues_nft.rs +++ b/examples/1_advanced/1_did_issues_nft.rs @@ -10,9 +10,9 @@ use identity_iota::iota::IotaDID; use identity_iota::iota::IotaDocument; use identity_iota::iota::IotaIdentityClientExt; use identity_iota::iota::NetworkName; -use iota_client::api_types::response::OutputResponse; use iota_client::block::address::Address; use iota_client::block::address::AliasAddress; +use iota_client::block::output::dto::OutputDto; use iota_client::block::output::feature::IssuerFeature; use iota_client::block::output::unlock_condition::AddressUnlockCondition; use iota_client::block::output::AliasId; @@ -58,7 +58,7 @@ async fn main() -> anyhow::Result<()> { let manufacturer_did = manufacturer_document.id().clone(); // Get the current byte cost. - let rent_structure: RentStructure = client.get_rent_structure()?; + let rent_structure: RentStructure = client.get_rent_structure().await?; // Create a Digital Product Passport NFT issued by the manufacturer. let product_passport_nft: NftOutput = @@ -75,7 +75,7 @@ async fn main() -> anyhow::Result<()> { .add_immutable_feature(Feature::Metadata(MetadataFeature::new( b"Digital Product Passport Metadata".to_vec(), )?)) - .finish(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; // Publish the NFT. let block: Block = client @@ -91,7 +91,7 @@ async fn main() -> anyhow::Result<()> { // ======================================================== // Extract the identifier of the NFT from the published block. - let nft_id: NftId = NftId::from(get_nft_output_id( + let nft_id: NftId = NftId::from(&get_nft_output_id( block .payload() .ok_or_else(|| anyhow::anyhow!("expected block to contain a payload"))?, @@ -99,8 +99,11 @@ async fn main() -> anyhow::Result<()> { // 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_dto(&output_response.output, client.get_token_supply()?)?; + let output_dto: OutputDto = client + .get_output(&nft_output_id) + .await + .map(|response| response.output)?; + let output: Output = Output::try_from_dto(&output_dto, client.get_token_supply().await?)?; // Extract the issuer of the NFT. let nft_output: NftOutput = if let Output::Nft(nft_output) = output { diff --git a/examples/1_advanced/2_nft_owns_did.rs b/examples/1_advanced/2_nft_owns_did.rs index da29cb3c18..8d656feb86 100644 --- a/examples/1_advanced/2_nft_owns_did.rs +++ b/examples/1_advanced/2_nft_owns_did.rs @@ -12,8 +12,8 @@ use identity_iota::iota::IotaClientExt; use identity_iota::iota::IotaDocument; use identity_iota::iota::IotaIdentityClientExt; use identity_iota::iota::NetworkName; -use iota_client::api_types::response::OutputResponse; use iota_client::block::address::Address; +use iota_client::block::output::dto::OutputDto; use iota_client::block::output::unlock_condition::AddressUnlockCondition; use iota_client::block::output::NftId; use iota_client::block::output::NftOutput; @@ -54,12 +54,12 @@ async fn main() -> anyhow::Result<()> { let address: Address = get_address_with_funds(&client, &mut secret_manager, FAUCET_ENDPOINT).await?; // Get the current byte cost. - let rent_structure: RentStructure = client.get_rent_structure()?; + 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(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; // Publish the NFT output. let block: Block = client @@ -70,7 +70,7 @@ async fn main() -> anyhow::Result<()> { .await?; let _ = client.retry_until_included(&block.id(), None, None).await?; - let car_nft_id: NftId = NftId::from(get_nft_output_id( + 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"))?, @@ -117,8 +117,8 @@ async fn main() -> anyhow::Result<()> { // 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_dto(&output_response.output, client.get_token_supply()?)?; + let output_dto: OutputDto = client.get_output(&output_id).await.map(|response| response.output)?; + let output: Output = Output::try_from_dto(&output_dto, client.get_token_supply().await?)?; let car_nft: NftOutput = if let Output::Nft(nft_output) = output { nft_output diff --git a/examples/1_advanced/3_did_issues_tokens.rs b/examples/1_advanced/3_did_issues_tokens.rs index b72161d931..2a08923961 100644 --- a/examples/1_advanced/3_did_issues_tokens.rs +++ b/examples/1_advanced/3_did_issues_tokens.rs @@ -19,9 +19,9 @@ use identity_iota::iota::IotaDID; use identity_iota::iota::IotaDocument; use identity_iota::iota::IotaIdentityClientExt; use identity_iota::iota::NetworkName; -use iota_client::api_types::response::OutputResponse; use iota_client::block::address::Address; use iota_client::block::address::AliasAddress; +use iota_client::block::output::dto::OutputDto; use iota_client::block::output::unlock_condition::ImmutableAliasAddressUnlockCondition; use iota_client::block::output::AliasId; use iota_client::block::output::AliasOutput; @@ -66,7 +66,7 @@ async fn main() -> anyhow::Result<()> { let (_, authority_document, _): (Address, IotaDocument, KeyPair) = create_did(&client, &mut secret_manager).await?; let authority_did = authority_document.id().clone(); - let rent_structure: RentStructure = client.get_rent_structure()?; + 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, @@ -77,7 +77,7 @@ async fn main() -> anyhow::Result<()> { // We will add one foundry to this Alias Output. let authority_alias_output = AliasOutputBuilder::from(&authority_alias_output) .with_foundry_counter(1) - .finish(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; // Create a token foundry that represents carbon credits. let token_scheme = TokenScheme::Simple(SimpleTokenScheme::new( @@ -102,7 +102,7 @@ async fn main() -> anyhow::Result<()> { .add_unlock_condition(UnlockCondition::ImmutableAliasAddress( ImmutableAliasAddressUnlockCondition::new(AliasAddress::new(AliasId::from(&authority_did))), )) - .finish(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; let carbon_credits_foundry_id: FoundryId = carbon_credits_foundry.id(); @@ -121,9 +121,11 @@ async fn main() -> anyhow::Result<()> { // 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_dto(&carbon_credits_foundry.output, client.get_token_supply()?)?; + let carbon_credits_foundry: OutputDto = client + .get_output(&foundry_output_id) + .await + .map(|response| response.output)?; + let carbon_credits_foundry: Output = Output::try_from_dto(&carbon_credits_foundry, client.get_token_supply().await?)?; let carbon_credits_foundry: FoundryOutput = if let Output::Foundry(foundry_output) = carbon_credits_foundry { foundry_output @@ -167,7 +169,7 @@ async fn main() -> anyhow::Result<()> { Address::Alias(AliasAddress::new(*authority_alias_id)), tomorrow, )?)) - .finish(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; // 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) @@ -175,7 +177,7 @@ async fn main() -> anyhow::Result<()> { carbon_credits_foundry.token_id(), U256::from(499_000u32), )?]) - .finish(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; // Publish the output, transferring the carbon credits. let block: Block = client diff --git a/examples/1_advanced/4_key_exchange.rs b/examples/1_advanced/4_key_exchange.rs index 7ccae50be1..0062c64ad4 100644 --- a/examples/1_advanced/4_key_exchange.rs +++ b/examples/1_advanced/4_key_exchange.rs @@ -50,7 +50,7 @@ async fn main() -> anyhow::Result<()> { .context("failed to get address with funds")?; let network: NetworkName = client.network_name().await?; - let rent_structure: RentStructure = client.get_rent_structure()?; + let rent_structure: RentStructure = client.get_rent_structure().await?; // Alice creates and publishes their DID Document. let (alice_did, alice_x25519): (IotaDID, KeyPair) = { diff --git a/examples/1_advanced/5_alias_output_history.rs b/examples/1_advanced/5_alias_output_history.rs index 6ce6321a78..49c576ae02 100644 --- a/examples/1_advanced/5_alias_output_history.rs +++ b/examples/1_advanced/5_alias_output_history.rs @@ -75,10 +75,10 @@ async fn main() -> anyhow::Result<()> { // Increase the storage deposit and publish the update. let alias_output: AliasOutput = client.update_did_output(document.clone()).await?; - let rent_structure: RentStructure = client.get_rent_structure()?; + let rent_structure: RentStructure = client.get_rent_structure().await?; let alias_output: AliasOutput = AliasOutputBuilder::from(&alias_output) .with_minimum_storage_deposit(rent_structure) - .finish(client.get_token_supply()?)?; + .finish(client.get_token_supply().await?)?; client.publish_did_output(&secret_manager, alias_output).await?; } @@ -149,7 +149,7 @@ fn block_alias_output(block: &Block, alias_id: &AliasId) -> anyhow::Result { if &alias_output.alias_id().or_from_output_id( - OutputId::new( + &OutputId::new( transaction_payload.id(), index.try_into().context("output index must fit into a u16")?, ) diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 100179cc67..8fe69371f0 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -8,9 +8,7 @@ publish = false [dependencies] anyhow = "1.0.62" identity_iota = { path = "../identity_iota" } -iota-client = { version = "2.0.1-rc.3", default-features = false, features = ["tls", "stronghold"] } -# Remove once iota-client 2.0.1-rc.4 is released. -iota-types = { version = "=1.0.0-rc.1", default-features = false, features = ["block", "std"], optional = true } +iota-client = { version = "2.0.1-rc.4", default-features = false, features = ["tls", "stronghold"] } primitive-types = "0.12.1" rand = "0.8.5" tokio = { version = "1.20.1", default-features = false, features = ["rt"] } diff --git a/examples/utils/utils.rs b/examples/utils/utils.rs index a5ee781c7e..7ca2c3c8c1 100644 --- a/examples/utils/utils.rs +++ b/examples/utils/utils.rs @@ -74,9 +74,14 @@ pub async fn get_address_with_funds( ) -> anyhow::Result
{ let address: Address = get_address(client, stronghold).await?; - request_faucet_funds(client, address, client.get_bech32_hrp()?.as_str(), faucet_endpoint) - .await - .context("failed to request faucet funds")?; + request_faucet_funds( + client, + address, + client.get_bech32_hrp().await?.as_str(), + faucet_endpoint, + ) + .await + .context("failed to request faucet funds")?; Ok(address) } @@ -149,7 +154,7 @@ async fn get_address_balance(client: &Client, address: &str) -> anyhow::Result Result; - /// Resolve an Alias identifier, returning its latest [`OutputId`] and [`AliasOutput`]. async fn get_alias_output(&self, alias_id: AliasId) -> Result<(OutputId, AliasOutput)>; - - // get_rent_structure and get_token_supply technically don't need to be async, but the JS Client only has async - // versions of these so we use async here as well to avoid compatibility issues. - - /// Return the rent structure of the network, indicating the byte costs for outputs. - async fn get_rent_structure(&self) -> Result; - - /// Gets the token supply of the node we're connecting to. - async fn get_token_supply(&self) -> Result; + /// Get the protocol parameters of the node we are trying to connect to. + async fn get_protocol_parameters(&self) -> Result; } /// An extension trait that provides helper functions for publication @@ -180,6 +170,32 @@ pub trait IotaIdentityClientExt: IotaIdentityClient { async fn network_name(&self) -> Result { self.get_network_hrp().await.and_then(NetworkName::try_from) } + + /// Return the rent structure of the network, indicating the byte costs for outputs. + async fn get_rent_structure(&self) -> Result { + self + .get_protocol_parameters() + .await + .map(|parameters| parameters.rent_structure().clone()) + } + + /// Gets the token supply of the node we're connecting to. + async fn get_token_supply(&self) -> Result { + self + .get_protocol_parameters() + .await + .map(|parameters| parameters.token_supply()) + } + + /// Return the Bech32 human-readable part (HRP) of the network. + /// + /// E.g. "iota", "atoi", "smr", "rms". + async fn get_network_hrp(&self) -> Result { + self + .get_protocol_parameters() + .await + .map(|parameters| parameters.bech32_hrp().to_owned()) + } } impl IotaIdentityClientExt for T where T: IotaIdentityClient {} @@ -188,7 +204,10 @@ pub(super) async fn validate_network(client: &T, did: &IotaDID) -> Result<()> where T: IotaIdentityClient + ?Sized, { - let network_hrp: String = client.get_network_hrp().await?; + let network_hrp: String = client + .get_protocol_parameters() + .await + .map(|parameters| parameters.bech32_hrp().to_owned())?; if did.network_str() != network_hrp.as_str() { return Err(Error::NetworkMismatch { expected: did.network_str().to_owned(), diff --git a/identity_iota_core/src/client/iota_client.rs b/identity_iota_core/src/client/iota_client.rs index abe3d8ec88..ae5392fa93 100644 --- a/identity_iota_core/src/client/iota_client.rs +++ b/identity_iota_core/src/client/iota_client.rs @@ -1,7 +1,8 @@ // Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use iota_client::api_types::response::OutputResponse; +use iota_client::block::output::dto::OutputDto; +use iota_client::block::protocol::ProtocolParameters; use iota_client::secret::SecretManager; use iota_client::Client; @@ -12,7 +13,6 @@ use crate::block::output::AliasOutput; use crate::block::output::BasicOutputBuilder; use crate::block::output::Output; use crate::block::output::OutputId; -use crate::block::output::RentStructure; use crate::block::output::UnlockCondition; use crate::block::Block; use crate::client::identity_client::validate_network; @@ -85,7 +85,7 @@ impl IotaClientExt for Client { .map_err(Error::BasicOutputBuildError)? .with_native_tokens(alias_output.native_tokens().clone()) .add_unlock_condition(UnlockCondition::Address(AddressUnlockCondition::new(address))) - .finish_output(self.get_token_supply().map_err(Error::TokenSupplyError)?) + .finish_output(self.get_token_supply().await.map_err(Error::TokenSupplyError)?) .map_err(Error::BasicOutputBuildError)?; let block: Block = self @@ -116,16 +116,23 @@ impl IotaClientExt for Client { #[cfg_attr(feature = "send-sync-client-ext", async_trait::async_trait)] #[cfg_attr(not(feature = "send-sync-client-ext"), async_trait::async_trait(?Send))] impl IotaIdentityClient for Client { - async fn get_network_hrp(&self) -> Result { - self.get_bech32_hrp().map_err(Error::DIDResolutionError) + async fn get_protocol_parameters(&self) -> Result { + self + .get_protocol_parameters() + .await + .map_err(Error::ProtocolParametersError) } async fn get_alias_output(&self, id: AliasId) -> Result<(OutputId, AliasOutput)> { let output_id: OutputId = self.alias_output_id(id).await.map_err(Error::DIDResolutionError)?; - let output_response: OutputResponse = self.get_output(&output_id).await.map_err(Error::DIDResolutionError)?; + let output_dto: OutputDto = self + .get_output(&output_id) + .await + .map(|response| response.output) + .map_err(Error::DIDResolutionError)?; let output: Output = Output::try_from_dto( - &output_response.output, - ::get_token_supply(self).await?, + &output_dto, + ::get_token_supply(self).await?, ) .map_err(Error::OutputConversionError)?; @@ -135,14 +142,6 @@ impl IotaIdentityClient for Client { Err(Error::NotAnAliasOutput(output_id)) } } - - async fn get_rent_structure(&self) -> Result { - Client::get_rent_structure(self) - .map_err(|err| Error::DIDUpdateError("get_rent_structure failed", Some(Box::new(err)))) - } - async fn get_token_supply(&self) -> Result { - self.get_token_supply().map_err(Error::TokenSupplyError) - } } /// Publishes an `alias_output`. diff --git a/identity_iota_core/src/did/iota_did.rs b/identity_iota_core/src/did/iota_did.rs index 539b9511d0..12612efc1d 100644 --- a/identity_iota_core/src/did/iota_did.rs +++ b/identity_iota_core/src/did/iota_did.rs @@ -617,7 +617,7 @@ mod tests { .prop_map(|(bytes, idx)| { let transaction_id = iota_client::block::payload::transaction::TransactionId::new(bytes); let output_id = iota_client::block::output::OutputId::new(transaction_id, idx).unwrap(); - iota_client::block::output::AliasId::from(output_id) + iota_client::block::output::AliasId::from(&output_id) }) } diff --git a/identity_iota_core/src/document/iota_document.rs b/identity_iota_core/src/document/iota_document.rs index b4ed86b5f3..e4d8f6de03 100644 --- a/identity_iota_core/src/document/iota_document.rs +++ b/identity_iota_core/src/document/iota_document.rs @@ -361,7 +361,7 @@ mod client_document { if let Output::Alias(alias_output) = output { let alias_id = if alias_output.alias_id().is_null() { AliasId::from( - OutputId::new( + &OutputId::new( tx_payload.id(), index .try_into() diff --git a/identity_iota_core/src/error.rs b/identity_iota_core/src/error.rs index aa9eeba7e7..1eee348275 100644 --- a/identity_iota_core/src/error.rs +++ b/identity_iota_core/src/error.rs @@ -21,13 +21,16 @@ pub enum Error { #[cfg(feature = "iota-client")] #[error("{0}")] BasicOutputBuildError(#[source] iota_client::block::Error), - #[error("\"{0}\" is not a valid network name")] + #[error("\"{0}\" is not a valid network name in the context of the `iota` did method")] InvalidNetworkName(String), #[cfg(feature = "iota-client")] #[error("unable to obtain the token supply from the client")] TokenSupplyError(#[source] iota_client::Error), #[error("unable to resolve a `{expected}` DID on network `{actual}`")] NetworkMismatch { expected: String, actual: String }, + #[cfg(feature = "iota-client")] + #[error("could not fetch protocol parameters")] + ProtocolParametersError(#[source] iota_client::Error), #[error("invalid state metadata {0}")] InvalidStateMetadata(&'static str), #[error("credential revocation error")] diff --git a/identity_resolver/Cargo.toml b/identity_resolver/Cargo.toml index d9a1b445f4..9782ae211a 100644 --- a/identity_resolver/Cargo.toml +++ b/identity_resolver/Cargo.toml @@ -30,7 +30,7 @@ features = ["send-sync-client-ext", "iota-client"] optional = true [dev-dependencies] -iota-client = { version = "2.0.1-rc.1", default-features = false, features = ["tls"] } +iota-client = { version = "2.0.1-rc.4", default-features = false, features = ["tls"] } tokio = { version = "1.17.0", default-features = false, features = ["rt-multi-thread", "macros"] } [features]