Skip to content

Add core client traits for read-only and read-write IOTA operations #1640

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

Merged
merged 41 commits into from
May 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
c48daf8
Add core client traits for read-only and read-write IOTA operations
itsyaasir Apr 15, 2025
798b71c
Refactor CoreClient traits to streamline async handling and remove un…
itsyaasir Apr 15, 2025
dc29aa1
Refactor CoreClient trait to use generic signer type in method signature
itsyaasir Apr 16, 2025
625d381
Remove network_id method from client module
itsyaasir Apr 17, 2025
56cee17
controllerCap and delegation token, creation of identity with control…
UMR1352 Apr 23, 2025
21af844
Merge branch 'main' into feat/client-interface
itsyaasir Apr 24, 2025
f2de088
use delegation token and controller token interchangeably
UMR1352 Apr 24, 2025
30809a2
delegation token revocation and unrevocation
UMR1352 Apr 25, 2025
541c5b5
delete delegation token
UMR1352 Apr 25, 2025
ded4494
Refactor client traits and implement CoreClient interface for identit…
itsyaasir Apr 28, 2025
c53e8d6
Update CoreClientReadOnly trait and add OptionalSync bounds to Transa…
itsyaasir Apr 28, 2025
6b62ff1
make WASM code work with controller token abstraction, delegate token Tx
UMR1352 Apr 28, 2025
1da0357
Refactor client module and fix object lookup error handling
itsyaasir Apr 28, 2025
2e35981
clippy & fmt
UMR1352 Apr 28, 2025
bf97fb1
Enhance CoreClientReadOnly trait with detailed documentation for obje…
itsyaasir Apr 29, 2025
8d7a4f2
fix issue with ts examples
UMR1352 Apr 29, 2025
efeb65d
cargo fix
UMR1352 Apr 29, 2025
92ee433
format move pkg
UMR1352 Apr 30, 2025
f4d0741
use Move 2024 macros where possible
UMR1352 Apr 30, 2025
7650cce
Update Move.toml to use edition 2024
UMR1352 Apr 30, 2025
1cb218e
new upgrade script and updated setup to have toml cli
UMR1352 Apr 30, 2025
e8f9ce8
fix type in CI workflow
UMR1352 Apr 30, 2025
b4fa4cb
Merge branch 'main' into feat/controller-token
UMR1352 Apr 30, 2025
cd4914f
fix toml init
eike-hass Apr 30, 2025
d78a4c8
overwrite Move.lock after messing things up
UMR1352 Apr 30, 2025
f6db688
Deploy devnet (#1659)
github-actions[bot] Apr 30, 2025
f15b129
Fixed several issues for the wasm32 build
chrisgitiota Apr 30, 2025
622bce5
Deploy testnet (#1660)
github-actions[bot] May 1, 2025
bd8a041
fix ts docs
UMR1352 May 1, 2025
68c881d
Merge branch 'feat/controller-token' into feat/client-interface
UMR1352 May 1, 2025
6f37a88
Make code compile
UMR1352 May 1, 2025
4b0d777
adapt asset txs
UMR1352 May 1, 2025
34236a4
fix examples
UMR1352 May 1, 2025
72cf958
Partially update identity_wasm to use generic CoreClient
UMR1352 May 2, 2025
89b1982
adapt all TS transactions
UMR1352 May 2, 2025
43965d5
update ts examples
UMR1352 May 2, 2025
351e10f
Merge branch 'main' into feat/client-interface
UMR1352 May 2, 2025
97a2996
Several send-sync related feature flag fixes
chrisgitiota May 2, 2025
e8730af
Fix TS examples
UMR1352 May 2, 2025
7c8c55d
Use "send-sync-client-ext" feature flag instead target_arch = "wasm32…
chrisgitiota May 2, 2025
c45376e
Use "send-sync" feature flag instead of "send-sync-client-ext" in Ide…
chrisgitiota May 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bindings/grpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ path = "src/main.rs"
anyhow = "1.0"
futures = { version = "0.3" }
identity_eddsa_verifier = { path = "../../identity_eddsa_verifier" }
identity_iota = { path = "../../identity_iota", features = ["resolver", "sd-jwt", "domain-linkage", "domain-linkage-fetch", "status-list-2021", "iota-client", "send-sync-storage"] }
identity_iota = { path = "../../identity_iota", features = ["resolver", "sd-jwt", "domain-linkage", "domain-linkage-fetch", "status-list-2021", "iota-client", "send-sync"] }
identity_jose = { path = "../../identity_jose" }
identity_storage = { path = "../../identity_storage", features = ["memstore"] }
identity_stronghold = { path = "../../identity_stronghold", features = ["send-sync-storage"] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export async function createIdentity(): Promise<void> {
console.log("Creating new identity");
const { output: identity } = await identityClient
.createIdentity(unpublished)
.finish()
.finish(identityClient.readOnly())
.buildAndExecute(identityClient);
did = identity.didDocument().id();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export async function updateIdentity() {
// create new identity for this account and publish document for it
const { output: identity } = await identityClient
.createIdentity(unpublished)
.finish()
.finish(identityClient.readOnly())
.buildAndExecute(identityClient);
const did = identity.didDocument().id();

Expand Down Expand Up @@ -59,7 +59,7 @@ export async function updateIdentity() {
let controllerToken = await identity.getControllerToken(identityClient);

let maybePendingProposal = await identity
.updateDidDocument(resolved.clone(), controllerToken!)
.updateDidDocument(resolved.clone(), controllerToken!, identityClient.readOnly())
.withGasBudget(TEST_GAS_BUDGET)
.buildAndExecute(identityClient)
.then(result => result.output);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export async function resolveIdentity() {
// create new identity for this account and publish document for it
const { output: identity } = await identityClient
.createIdentity(unpublished)
.finish()
.finish(identityClient.readOnly())
.buildAndExecute(identityClient);
const did = identity.didDocument().id();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export async function deactivateIdentity() {
// create new identity for this account and publish document for it
const { output: identity } = await identityClient
.createIdentity(unpublished)
.finish()
.finish(identityClient.readOnly())
.buildAndExecute(identityClient);
const did = identity.didDocument().id();

Expand All @@ -28,7 +28,7 @@ export async function deactivateIdentity() {
const controllerToken = await identity.getControllerToken(identityClient);
// Deactivate the DID.
await identity
.deactivateDid(controllerToken!)
.deactivateDid(controllerToken!, identityClient.readOnly())
.withGasBudget(TEST_GAS_BUDGET)
.buildAndExecute(identityClient);

Expand All @@ -43,7 +43,7 @@ export async function deactivateIdentity() {
// Re-activate the DID by publishing a valid DID document.
console.log("Publishing this:", JSON.stringify(resolved, null, 2));
await identity
.updateDidDocument(resolved, controllerToken!)
.updateDidDocument(resolved, controllerToken!, identityClient.readOnly())
.withGasBudget(TEST_GAS_BUDGET)
.buildAndExecute(identityClient);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export async function deleteIdentityDID() {
// create new identity for this account and publish document for it
const { output: identity } = await identityClient
.createIdentity(unpublished)
.finish()
.finish(identityClient.readOnly())
.buildAndExecute(identityClient);
const did = identity.didDocument().id();

Expand All @@ -29,7 +29,7 @@ export async function deleteIdentityDID() {

// delete the DID.
await identity
.deleteDid(controllerToken!)
.deleteDid(controllerToken!, identityClient.readOnly())
.withGasBudget(TEST_GAS_BUDGET)
.buildAndExecute(identityClient);

Expand All @@ -51,7 +51,7 @@ export async function deleteIdentityDID() {
// Trying to update a deleted DID must fail!
try {
await identity
.updateDidDocument(resolved, controllerToken!)
.updateDidDocument(resolved, controllerToken!, identityClient.readOnly())
.withGasBudget(TEST_GAS_BUDGET)
.buildAndExecute(identityClient);
} catch (_) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export async function createVC() {
const [unpublishedIssuerDocument, issuerFragment] = await createDocumentForNetwork(issuerStorage, network);
const { output: issuerIdentity } = await issuerClient
.createIdentity(unpublishedIssuerDocument)
.finish()
.finish(issuerClient.readOnly())
.buildAndExecute(issuerClient);
const issuerDocument = issuerIdentity.didDocument();

Expand All @@ -39,7 +39,7 @@ export async function createVC() {
const [unpublishedAliceDocument] = await createDocumentForNetwork(aliceStorage, network);
const { output: aliceIdentity } = await aliceClient
.createIdentity(unpublishedAliceDocument)
.finish()
.finish(aliceClient.readOnly())
.buildAndExecute(aliceClient);
const aliceDocument = aliceIdentity.didDocument();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export async function createVP() {
const [unpublishedIssuerDocument, issuerFragment] = await createDocumentForNetwork(issuerStorage, network);
const { output: issuerIdentity } = await issuerClient
.createIdentity(unpublishedIssuerDocument)
.finish()
.finish(issuerClient.readOnly())
.buildAndExecute(issuerClient);
const issuerDocument = issuerIdentity.didDocument();

Expand All @@ -55,7 +55,7 @@ export async function createVP() {
const [unpublishedAliceDocument, aliceFragment] = await createDocumentForNetwork(aliceStorage, network);
const { output: aliceIdentity } = await aliceClient
.createIdentity(unpublishedAliceDocument)
.finish()
.finish(aliceClient.readOnly())
.buildAndExecute(aliceClient);
const aliceDocument = aliceIdentity.didDocument();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export async function revokeVC() {
const [unpublishedIssuerDocument, issuerFragment] = await createDocumentForNetwork(issuerStorage, network);
const { output: issuerIdentity } = await issuerClient
.createIdentity(unpublishedIssuerDocument)
.finish()
.finish(issuerClient.readOnly())
.buildAndExecute(issuerClient);
let issuerDocument = issuerIdentity.didDocument();

Expand All @@ -61,7 +61,7 @@ export async function revokeVC() {
const [unpublishedAliceDocument, aliceFragment] = await createDocumentForNetwork(aliceStorage, network);
const { output: aliceIdentity } = await aliceClient
.createIdentity(unpublishedAliceDocument)
.finish()
.finish(aliceClient.readOnly())
.buildAndExecute(aliceClient);
const aliceDocument = aliceIdentity.didDocument();

Expand All @@ -77,7 +77,7 @@ export async function revokeVC() {

// Publish the updated document.
await issuerIdentity
.updateDidDocument(issuerDocument, issuerIdentityToken!)
.updateDidDocument(issuerDocument, issuerIdentityToken!, issuerClient.readOnly())
.withGasBudget(TEST_GAS_BUDGET)
.buildAndExecute(issuerClient);

Expand Down Expand Up @@ -133,7 +133,7 @@ export async function revokeVC() {

// Publish the changes.
await issuerIdentity
.updateDidDocument(issuerDocument, issuerIdentityToken!)
.updateDidDocument(issuerDocument, issuerIdentityToken!, issuerClient.readOnly())
.withGasBudget(TEST_GAS_BUDGET)
.buildAndExecute(issuerClient);

Expand Down Expand Up @@ -163,7 +163,7 @@ export async function revokeVC() {

// Publish the changes.
await issuerIdentity
.updateDidDocument(issuerDocument, issuerIdentityToken!)
.updateDidDocument(issuerDocument, issuerIdentityToken!, issuerClient.readOnly())
.withGasBudget(TEST_GAS_BUDGET)
.buildAndExecute(issuerClient);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export async function advancedTransaction(): Promise<void> {

const [txDataBcs, signatures, tx] = await aliceClient
.createIdentity(new IotaDocument(aliceClient.network()))
.finish()
.finish(aliceClient.readOnly())
.withSender(aliceClient.senderAddress())
.withSponsor(aliceClient.readOnly(), (tx_data: TransactionDataBuilder) => bobSponsorFn(tx_data, bobClient))
.then(txBuilder => txBuilder.build(aliceClient));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export async function customResolution() {
// create new identity for this account and publish document for it, DID of it will be resolved later on
const { output: identity } = await identityClient
.createIdentity(unpublished)
.finish()
.finish(identityClient.readOnly())
.buildAndExecute(identityClient);
const did = identity.didDocument().id();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export async function domainLinkage() {
// create new identity for this account and publish document for it
const { output: identity } = await identityClient
.createIdentity(unpublished)
.finish()
.finish(identityClient.readOnly())
.buildAndExecute(identityClient);
const document = identity.didDocument();
const did = document.id();
Expand All @@ -54,7 +54,9 @@ export async function domainLinkage() {
});
document.insertService(linkedDomainService.toService());
const controllerToken = await identity.getControllerToken(identityClient);
await identity.updateDidDocument(document, controllerToken!).buildAndExecute(identityClient);
await identity.updateDidDocument(document, controllerToken!, identityClient.readOnly()).buildAndExecute(
identityClient,
);

let updatedDidDocument = identity.didDocument();
console.log("Updated DID document:", JSON.stringify(updatedDidDocument, null, 2));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export async function sdJwt() {
const [unpublishedIssuerDocument, issuerFragment] = await createDocumentForNetwork(issuerStorage, network);
const { output: issuerIdentity } = await issuerClient
.createIdentity(unpublishedIssuerDocument)
.finish()
.finish(issuerClient.readOnly())
.buildAndExecute(issuerClient);
const issuerDocument = issuerIdentity.didDocument();

Expand All @@ -48,7 +48,7 @@ export async function sdJwt() {
const [unpublishedAliceDocument, aliceFragment] = await createDocumentForNetwork(aliceStorage, network);
const { output: aliceIdentity } = await aliceClient
.createIdentity(unpublishedAliceDocument)
.finish()
.finish(aliceClient.readOnly())
.buildAndExecute(aliceClient);
const aliceDocument = aliceIdentity.didDocument();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export async function statusList2021() {
const [unpublishedIssuerDocument, issuerFragment] = await createDocumentForNetwork(issuerStorage, network);
const { output: issuerIdentity } = await issuerClient
.createIdentity(unpublishedIssuerDocument)
.finish()
.finish(issuerClient.readOnly())
.buildAndExecute(issuerClient);
const issuerDocument = issuerIdentity.didDocument();

Expand All @@ -43,7 +43,7 @@ export async function statusList2021() {
const [unpublishedAliceDocument] = await createDocumentForNetwork(aliceStorage, network);
const { output: aliceIdentity } = await aliceClient
.createIdentity(unpublishedAliceDocument)
.finish()
.finish(aliceClient.readOnly())
.buildAndExecute(aliceClient);
const aliceDocument = aliceIdentity.didDocument();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export async function zkp() {
);
const { output: issuerIdentity } = await issuerClient
.createIdentity(unpublishedIssuerDocument)
.finish()
.finish(issuerClient.readOnly())
.buildAndExecute(issuerClient);
const issuerDocument = issuerIdentity.didDocument();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export async function zkp_revocation() {
unpublishedIssuerDocument.insertService(service);
const { output: issuerIdentity } = await issuerClient
.createIdentity(unpublishedIssuerDocument)
.finish()
.finish(issuerClient.readOnly())
.buildAndExecute(issuerClient);
let issuerDocument = issuerIdentity.didDocument();

Expand All @@ -55,7 +55,7 @@ export async function zkp_revocation() {
const [unpublishedholderDocument] = await createDocumentForNetwork(holderStorage, network);
const { output: holderIdentity } = await holderClient
.createIdentity(unpublishedholderDocument)
.finish()
.finish(holderClient.readOnly())
.buildAndExecute(holderClient);
const holderDocument = holderIdentity.didDocument();

Expand Down Expand Up @@ -196,7 +196,10 @@ export async function zkp_revocation() {
// Update the RevocationBitmap service in the issuer's DID Document.
// This revokes the credential's unique index.
issuerDocument.revokeCredentials("my-revocation-service", 5);
await issuerIdentity.updateDidDocument(issuerDocument, issuerIdentityToken!).buildAndExecute(issuerClient);
await issuerIdentity.updateDidDocument(issuerDocument, issuerIdentityToken!, issuerClient.readOnly())
.buildAndExecute(
issuerClient,
);
issuerDocument = issuerIdentity.didDocument();

// Holder checks if his credential has been revoked by the Issuer
Expand Down
16 changes: 16 additions & 0 deletions bindings/wasm/identity_wasm/lib/core_client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { IotaClient } from "@iota/iota-sdk/client";
import { PublicKey } from "@iota/iota-sdk/cryptography";
import { TransactionSigner } from "~identity_wasm";

export interface CoreClientReadOnly {
packageId(): string;
network(): string;
iotaClient(): IotaClient;
// TODO: add all interface's methods.
}

export interface CoreClient<S extends TransactionSigner> extends CoreClientReadOnly {
signer(): S;
senderAddress(): string;
senderPublicKey(): PublicKey;
}
1 change: 1 addition & 0 deletions bindings/wasm/identity_wasm/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from "./key_id_storage";
export * from "~identity_wasm";

export * from "./controller";
export * from "./core_client";
export * from "./proposal";
export * from "./transaction_internal";

Expand Down
10 changes: 7 additions & 3 deletions bindings/wasm/identity_wasm/lib/proposal.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2021-2025 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { ConfigChange, IdentityClient, SendAction, UpdateDid } from "~identity_wasm";
import { ConfigChange, ControllerToken, IdentityClient, OnChainIdentity, SendAction, UpdateDid } from "~identity_wasm";
import { Transaction, TransactionBuilder } from "./transaction_internal";

export type Action = UpdateDid | SendAction | ConfigChange;
Expand All @@ -20,6 +20,10 @@ export interface Proposal<A extends Action> {
votes: bigint;
voters: Set<string>;
expirationEpoch?: bigint;
approve: (client: IdentityClient) => TransactionBuilder<ApproveProposal>;
intoTx: (client: IdentityClient) => TransactionBuilder<ExecuteProposal<A>>;
approve: (
identity: OnChainIdentity,
controllerToken: ControllerToken,
client: IdentityClient,
) => TransactionBuilder<ApproveProposal>;
intoTx: (controllerToken: ControllerToken, client: IdentityClient) => TransactionBuilder<ExecuteProposal<A>>;
}
15 changes: 8 additions & 7 deletions bindings/wasm/identity_wasm/lib/transaction_internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@

import { IotaObjectRef, IotaTransactionBlockResponse, TransactionEffects } from "@iota/iota-sdk/client";
import { TransactionDataBuilder } from "@iota/iota-sdk/transactions";
import { IdentityClient, IdentityClientReadOnly } from "~identity_wasm";
import { CoreClient, CoreClientReadOnly } from "core_client";
import { TransactionSigner } from "~identity_wasm";

export interface TransactionOutput<T extends Transaction<unknown>> {
response: IotaTransactionBlockResponse;
output: Awaited<ReturnType<T["apply"]>>;
}

export interface Transaction<Output> {
buildProgrammableTransaction(client: IdentityClientReadOnly): Promise<Uint8Array>;
apply(effects: TransactionEffects, client: IdentityClientReadOnly): Promise<Output>;
buildProgrammableTransaction(client: CoreClientReadOnly): Promise<Uint8Array>;
apply(effects: TransactionEffects, client: CoreClientReadOnly): Promise<Output>;
}

export type SponsorFn = (tx_data: TransactionDataBuilder) => Promise<string>;
Expand All @@ -24,8 +25,8 @@ export interface TransactionBuilder<T extends Transaction<unknown>> {
withGasOwner(owner: string): TransactionBuilder<T>;
withGasPayment(payment: IotaObjectRef[]): TransactionBuilder<T>;
withSender(sender: String): TransactionBuilder<T>;
withSignature(client: IdentityClient): TransactionBuilder<T>;
withSponsor(client: IdentityClientReadOnly, sponsorFn: SponsorFn): Promise<TransactionBuilder<T>>;
build(client: IdentityClient): Promise<[Uint8Array, string[], T]>;
buildAndExecute(client: IdentityClient): Promise<TransactionOutput<T>>;
withSignature<S extends TransactionSigner>(client: CoreClient<S>): TransactionBuilder<T>;
withSponsor(client: CoreClientReadOnly, sponsorFn: SponsorFn): Promise<TransactionBuilder<T>>;
build<S extends TransactionSigner>(client: CoreClient<S>): Promise<[Uint8Array, string[], T]>;
buildAndExecute<S extends TransactionSigner>(client: CoreClient<S>): Promise<TransactionOutput<T>>;
}
10 changes: 10 additions & 0 deletions bindings/wasm/identity_wasm/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use identity_iota::storage::key_id_storage::KeyIdStorageResult;
use identity_iota::storage::key_storage::KeyStorageError;
use identity_iota::storage::key_storage::KeyStorageErrorKind;
use identity_iota::storage::key_storage::KeyStorageResult;
use iota_interaction_ts::AdapterError;
use std::borrow::Cow;
use std::fmt::Debug;
use std::fmt::Display;
Expand Down Expand Up @@ -312,6 +313,15 @@ impl From<identity_iota::credential::sd_jwt_vc::Error> for WasmError<'_> {
}
}

impl From<AdapterError> for WasmError<'_> {
fn from(error: AdapterError) -> Self {
Self {
name: Cow::Borrowed("TsSdkError"),
message: Cow::Owned(ErrorMessage(&error).to_string()),
}
}
}

/// Convenience struct to convert Result<JsValue, JsValue> to errors in the Rust library.
pub struct JsValueResult(pub(crate) Result<JsValue>);

Expand Down
Loading
Loading