diff --git a/.github/actions/rust/sccache/setup-sccache/action.yml b/.github/actions/rust/sccache/setup-sccache/action.yml index b3e5ca173..b6cb31307 100644 --- a/.github/actions/rust/sccache/setup-sccache/action.yml +++ b/.github/actions/rust/sccache/setup-sccache/action.yml @@ -12,7 +12,7 @@ runs: if: inputs.os == 'macos-latest' shell: bash run: | - brew update --preinstall + brew update --auto-update brew install sccache - name: Install sccache (ubuntu-24.04) diff --git a/bindings/wasm/iota_interaction_ts/Cargo.toml b/bindings/wasm/iota_interaction_ts/Cargo.toml index 3dce460b7..6b76276c7 100644 --- a/bindings/wasm/iota_interaction_ts/Cargo.toml +++ b/bindings/wasm/iota_interaction_ts/Cargo.toml @@ -18,6 +18,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] anyhow = "1.0.75" async-trait = { version = "0.1", default-features = false } +bcs = "0.1.6" bls12_381_plus = "0.8.17" cfg-if = "1.0.0" console_error_panic_hook = { version = "0.1" } diff --git a/bindings/wasm/iota_interaction_ts/lib/index.ts b/bindings/wasm/iota_interaction_ts/lib/index.ts new file mode 100644 index 000000000..ea51e7468 --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/index.ts @@ -0,0 +1,4 @@ +// Copyright 2020-2025 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export * as move_calls from "./move_calls"; diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/create.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/create.ts new file mode 100644 index 000000000..1aecf07f6 --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/create.ts @@ -0,0 +1,27 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { Transaction } from "@iota/iota.js/transactions"; + +export function create( + inner_bytes: Uint8Array, + inner_type: string, + mutable: boolean, + transferable: boolean, + deletable: boolean, + packageId: string, +): Promise { + const tx = new Transaction(); + const inner_arg = tx.pure(inner_bytes); + const mutableArg = tx.pure.bool(mutable); + const transferableArg = tx.pure.bool(transferable); + const deletableArg = tx.pure.bool(deletable); + + tx.moveCall({ + target: `${packageId}::asset::new_with_config`, + typeArguments: [inner_type], + arguments: [inner_arg, mutableArg, transferableArg, deletableArg], + }); + + return tx.build(); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/delete.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/delete.ts new file mode 100644 index 000000000..088388a9c --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/delete.ts @@ -0,0 +1,21 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { ObjectRef, Transaction } from "@iota/iota.js/transactions"; + +export function remove( + asset: ObjectRef, + asset_type: string, + packageId: string, +): Promise { + const tx = new Transaction(); + const asset_arg = tx.objectRef(asset); + + tx.moveCall({ + target: `${packageId}::asset::delete`, + typeArguments: [asset_type], + arguments: [asset_arg], + }); + + return tx.build(); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/index.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/index.ts new file mode 100644 index 000000000..feaf3adfc --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/index.ts @@ -0,0 +1,7 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export * from "./create"; +export * from "./delete"; +export * from "./transfer"; +export * from "./update"; diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/transfer.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/transfer.ts new file mode 100644 index 000000000..2301be933 --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/transfer.ts @@ -0,0 +1,80 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { SharedObjectRef } from "@iota/iota.js/dist/cjs/bcs/types"; +import { ObjectRef, Transaction } from "@iota/iota.js/transactions"; + +export function transfer( + asset: ObjectRef, + assetType: string, + recipient: string, + packageId: string, +): Promise { + const tx = new Transaction(); + const assetArg = tx.objectRef(asset); + const recipientArg = tx.pure.address(recipient); + + tx.moveCall({ + target: `${packageId}::asset::transfer`, + typeArguments: [assetType], + arguments: [assetArg, recipientArg], + }); + + return tx.build(); +} + +function makeTx( + proposal: SharedObjectRef, + cap: ObjectRef, + asset: ObjectRef, + assetType: string, + packageId: string, + functionName: string, +): Promise { + const tx = new Transaction(); + const proposalArg = tx.sharedObjectRef(proposal); + const capArg = tx.objectRef(cap); + const assetArg = tx.objectRef(asset); + + tx.moveCall({ + target: `${packageId}::asset::${functionName}`, + typeArguments: [assetType], + arguments: [proposalArg, capArg, assetArg], + }); + + return tx.build(); +} + +export function acceptProposal( + proposal: SharedObjectRef, + recipientCap: ObjectRef, + asset: ObjectRef, + assetType: string, + packageId: string, +): Promise { + return makeTx( + proposal, + recipientCap, + asset, + assetType, + packageId, + "accept", + ); +} + +export function concludeOrCancel( + proposal: SharedObjectRef, + senderCap: ObjectRef, + asset: ObjectRef, + assetType: string, + packageId: string, +): Promise { + return makeTx( + proposal, + senderCap, + asset, + assetType, + packageId, + "conclude_or_cancel", + ); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/update.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/update.ts new file mode 100644 index 000000000..60b0de6f9 --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/asset/update.ts @@ -0,0 +1,23 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { ObjectRef, Transaction } from "@iota/iota.js/transactions"; + +export function update( + asset: ObjectRef, + content: Uint8Array, + contentType: string, + packageId: string, +): Promise { + const tx = new Transaction(); + const contentArg = tx.pure(content); + const assetArg = tx.objectRef(asset); + + tx.moveCall({ + target: `${packageId}::asset::update`, + typeArguments: [contentType], + arguments: [assetArg, contentArg], + }); + + return tx.build(); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/borrow_asset.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/borrow_asset.ts new file mode 100644 index 000000000..8fff37c9e --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/borrow_asset.ts @@ -0,0 +1,140 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { SharedObjectRef } from "@iota/iota.js/dist/cjs/bcs/types"; +import { IotaObjectData } from "@iota/iota.js/dist/cjs/client"; +import { ObjectRef, Transaction, TransactionArgument } from "@iota/iota.js/transactions"; +import { getControllerDelegation, putBackDelegationToken } from "../utils"; + +export function proposeBorrow( + identity: SharedObjectRef, + capability: ObjectRef, + objects: string[], + packageId: string, + expiration?: number, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const identityArg = tx.sharedObjectRef(identity); + const exp = tx.pure.option("u64", expiration); + const objectsArg = tx.pure.vector("id", objects); + + tx.moveCall({ + target: `${packageId}::identity::propose_borrow`, + arguments: [identityArg, delegationToken, exp, objectsArg], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + return tx.build(); +} + +export function executeBorrow( + identity: SharedObjectRef, + capability: ObjectRef, + proposalId: string, + objects: IotaObjectData[], + intentFn: (arg0: Transaction, arg1: Map) => void, + packageId: string, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const proposal = tx.pure.id(proposalId); + const identityArg = tx.sharedObjectRef(identity); + + let action = tx.moveCall({ + target: `${packageId}::identity::execute_proposal`, + typeArguments: [`${packageId}::borrow_proposal::Borrow`], + arguments: [identityArg, delegationToken, proposal], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + const objectArgMap = new Map(); + for (const obj of objects) { + const recvObj = tx.receivingRef(obj); + const objArg = tx.moveCall({ + target: `${packageId}::identity::execute_borrow`, + typeArguments: [obj.type!], + arguments: [identityArg, action, recvObj], + }); + + objectArgMap.set(obj.objectId, [objArg, obj]); + } + + intentFn(tx, objectArgMap); + + for (const [obj, objData] of objectArgMap.values()) { + tx.moveCall({ + target: `${packageId}::borrow_proposal::put_back`, + typeArguments: [objData.type!], + arguments: [action, obj], + }); + } + + tx.moveCall({ + target: `${packageId}::transfer_proposal::conclude_borrow`, + arguments: [action], + }); + + return tx.build(); +} + +export function createAndExecuteBorrow( + identity: SharedObjectRef, + capability: ObjectRef, + objects: IotaObjectData[], + intentFn: (arg0: Transaction, arg1: Map) => void, + packageId: string, + expiration?: number, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const identityArg = tx.sharedObjectRef(identity); + const exp = tx.pure.option("u64", expiration); + const objectsArg = tx.pure.vector("id", objects.map(obj => obj.objectId)); + + const proposal = tx.moveCall({ + target: `${packageId}::identity::propose_borrow`, + arguments: [identityArg, delegationToken, exp, objectsArg], + }); + + let action = tx.moveCall({ + target: `${packageId}::identity::execute_proposal`, + typeArguments: [`${packageId}::borrow_proposal::Borrow`], + arguments: [identityArg, delegationToken, proposal], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + const objectArgMap = new Map(); + for (const obj of objects) { + const recvObj = tx.receivingRef(obj); + const objArg = tx.moveCall({ + target: `${packageId}::identity::execute_borrow`, + typeArguments: [obj.type!], + arguments: [identityArg, action, recvObj], + }); + + objectArgMap.set(obj.objectId, [objArg, obj]); + } + + intentFn(tx, objectArgMap); + + for (const [obj, objData] of objectArgMap.values()) { + tx.moveCall({ + target: `${packageId}::borrow_proposal::put_back`, + typeArguments: [objData.type!], + arguments: [action, obj], + }); + } + + tx.moveCall({ + target: `${packageId}::transfer_proposal::conclude_borrow`, + arguments: [action], + }); + return tx.build(); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/config.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/config.ts new file mode 100644 index 000000000..c870586e4 --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/config.ts @@ -0,0 +1,73 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { SharedObjectRef } from "@iota/iota.js/dist/cjs/bcs/types"; +import { ObjectRef, Transaction } from "@iota/iota.js/transactions"; +import { getControllerDelegation, putBackDelegationToken } from "../utils"; + +export function proposeConfigChange( + identity: SharedObjectRef, + controllerCap: ObjectRef, + controllersToAdd: [string, number][], + controllersToRemove: string[], + controllersToUpdate: [string, number][], + packageId: string, + expiration?: number, + threshold?: number, +): Promise { + const tx = new Transaction(); + const addressesToAdd = tx.pure.vector("address", controllersToAdd.map(c => c[0])); + const vpsToAdd = tx.pure.vector("u64", controllersToAdd.map(c => c[1])); + const controllersToAddArg = tx.moveCall({ + target: `${packageId}::utils::vec_map_from_keys_values`, + typeArguments: ["address", "u64"], + arguments: [addressesToAdd, vpsToAdd], + }); + + const idsToUpdate = tx.pure.vector("id", controllersToUpdate.map(c => c[0])); + const vpsToUpdate = tx.pure.vector("u64", controllersToUpdate.map(c => c[1])); + const controllersToUpdateArg = tx.moveCall({ + target: `${packageId}::utils::vec_map_from_keys_values`, + typeArguments: ["id", "u64"], + arguments: [idsToUpdate, vpsToUpdate], + }); + + const identityArg = tx.sharedObjectRef(identity); + const cap = tx.objectRef(controllerCap); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const thresholdArg = tx.pure.option("u64", threshold); + const exp = tx.pure.option("u64", expiration); + const controllersToRemoveArg = tx.pure.vector("id", controllersToRemove); + + tx.moveCall({ + target: `${packageId}::identity::propose_config_change`, + arguments: [identityArg, delegationToken, exp, thresholdArg, controllersToAddArg, controllersToRemoveArg, + controllersToUpdateArg], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + return tx.build(); +} + +export function executeConfigChange( + identity: SharedObjectRef, + capability: ObjectRef, + proposalId: string, + packageId: string, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const proposal = tx.pure.id(proposalId); + const identityArg = tx.sharedObjectRef(identity); + + tx.moveCall({ + target: `${packageId}::identity::execute_config_change`, + arguments: [identityArg, delegationToken, proposal], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + return tx.build(); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/controller_execution.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/controller_execution.ts new file mode 100644 index 000000000..59bd0f9ce --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/controller_execution.ts @@ -0,0 +1,112 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { SharedObjectRef } from "@iota/iota.js/dist/cjs/bcs/types"; +import { ObjectRef, Transaction, TransactionArgument } from "@iota/iota.js/transactions"; +import { getControllerDelegation, putBackDelegationToken } from "../utils"; + +export function proposeControllerExecution( + identity: SharedObjectRef, + capability: ObjectRef, + controllerCapId: string, + packageId: string, + expiration?: number, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const identityArg = tx.sharedObjectRef(identity); + const exp = tx.pure.option("u64", expiration); + const controllerCapIdArg = tx.pure.id(controllerCapId); + + tx.moveCall({ + target: `${packageId}::identity::propose_controller_execution`, + arguments: [identityArg, delegationToken, controllerCapIdArg, exp], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + return tx.build(); +} + +export function executeControllerExecution( + identity: SharedObjectRef, + capability: ObjectRef, + proposalId: string, + controllerCapRef: ObjectRef, + intentFn: (arg0: Transaction, arg1: TransactionArgument) => void, + packageId: string, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const proposal = tx.pure.id(proposalId); + const identityArg = tx.sharedObjectRef(identity); + + let action = tx.moveCall({ + target: `${packageId}::identity::execute_proposal`, + typeArguments: [`${packageId}::borrow_proposal::Borrow`], + arguments: [identityArg, delegationToken, proposal], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + const receiving = tx.receivingRef(controllerCapRef); + const BorrowedControllerCap = tx.moveCall({ + target: `${packageId}::identity::borrow_controller_cap`, + arguments: [identityArg, action, receiving], + }); + + intentFn(tx, BorrowedControllerCap); + + tx.moveCall({ + target: `${packageId}::controller_proposal::put_back`, + arguments: [action, BorrowedControllerCap], + }); + + return tx.build(); +} + +export function createAndExecuteControllerExecution( + identity: SharedObjectRef, + capability: ObjectRef, + controllerCapRef: ObjectRef, + intentFn: (arg0: Transaction, arg1: TransactionArgument) => void, + packageId: string, + expiration?: number, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const identityArg = tx.sharedObjectRef(identity); + const exp = tx.pure.option("u64", expiration); + const controller_cap_id = tx.pure.id(controllerCapRef.objectId); + + const proposal = tx.moveCall({ + target: `${packageId}::identity::propose_controller_execution`, + arguments: [identityArg, delegationToken, controller_cap_id, exp], + }); + + let action = tx.moveCall({ + target: `${packageId}::identity::execute_proposal`, + typeArguments: [`${packageId}::borrow_proposal::Borrow`], + arguments: [identityArg, delegationToken, proposal], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + const receiving = tx.receivingRef(controllerCapRef); + const borrowedControllerCap = tx.moveCall({ + target: `${packageId}::identity::borrow_controller_cap`, + arguments: [identityArg, action, receiving], + }); + + intentFn(tx, borrowedControllerCap); + + tx.moveCall({ + target: `${packageId}::controller_proposal::put_back`, + arguments: [action, borrowedControllerCap], + }); + + return tx.build(); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/create.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/create.ts new file mode 100644 index 000000000..c81cde59a --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/create.ts @@ -0,0 +1,49 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { Transaction } from "@iota/iota.js/transactions"; +import { getClockRef } from "../utils"; + +export function create(didDoc: Uint8Array, packageId: string): Promise { + const tx = new Transaction(); + const didDocArg = tx.pure.vector("u8", didDoc); + const clock = getClockRef(tx); + + tx.moveCall({ + target: `${packageId}::identity::new`, + arguments: [didDocArg, clock], + }); + + return tx.build(); +} + +export function newWithControllers( + didDoc: Uint8Array, + controllers: [string, number][], + threshold: number, + packageId: string, +): Promise { + const tx = new Transaction(); + const ids = tx.pure.vector("address", controllers.map(controller => controller[0])); + const vps = tx.pure.vector("u64", controllers.map(controller => controller[1])); + const controllersArg = tx.moveCall({ + target: `${packageId}::utils::vec_map_from_keys_values`, + typeArguments: ["address", "u64"], + arguments: [ids, vps], + }); + const controllersThatCanDelegate = tx.moveCall({ + target: "0x2::vec_map::empty", + typeArguments: ["address", "u64"], + arguments: [], + }); + const didDocArg = tx.pure.vector("u8", didDoc); + const clock = getClockRef(tx); + const thresholdArg = tx.pure.u64(threshold); + + tx.moveCall({ + target: `${packageId}::identity::new_with_controllers`, + arguments: [didDocArg, controllersArg, controllersThatCanDelegate, thresholdArg, clock], + }); + + return tx.build(); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/deactivate.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/deactivate.ts new file mode 100644 index 000000000..af37bfb20 --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/deactivate.ts @@ -0,0 +1,52 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { SharedObjectRef } from "@iota/iota.js/dist/cjs/bcs/types"; +import { ObjectRef, Transaction } from "@iota/iota.js/transactions"; +import { getClockRef, getControllerDelegation, putBackDelegationToken } from "../utils"; + +export function proposeDeactivation( + identity: SharedObjectRef, + capability: ObjectRef, + packageId: string, + expiration?: number, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const identityArg = tx.sharedObjectRef(identity); + const exp = tx.pure.option("u64", expiration); + const clock = getClockRef(tx); + + tx.moveCall({ + target: `${packageId}::identity::propose_deactivation`, + arguments: [identityArg, delegationToken, exp, clock], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + return tx.build(); +} + +export function executeDeactivation( + identity: SharedObjectRef, + capability: ObjectRef, + proposalId: string, + packageId: string, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const proposal = tx.pure.id(proposalId); + const identityArg = tx.sharedObjectRef(identity); + const clock = getClockRef(tx); + + tx.moveCall({ + target: `${packageId}::identity::execute_deactivation`, + arguments: [identityArg, delegationToken, proposal, clock], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + return tx.build(); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/index.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/index.ts new file mode 100644 index 000000000..808816d04 --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/index.ts @@ -0,0 +1,12 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export * from "./borrow_asset"; +export * from "./config"; +export * from "./controller_execution"; +export * from "./create"; +export * from "./deactivate"; +export * from "./proposal"; +export * from "./send_asset"; +export * from "./update"; +export * from "./upgrade"; diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/proposal.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/proposal.ts new file mode 100644 index 000000000..6c3ba0960 --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/proposal.ts @@ -0,0 +1,30 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { SharedObjectRef } from "@iota/iota.js/dist/cjs/bcs/types"; +import { ObjectRef, Transaction } from "@iota/iota.js/transactions"; +import { getControllerDelegation, putBackDelegationToken } from "../utils"; + +export function approve( + identity: SharedObjectRef, + capability: ObjectRef, + proposalId: string, + proposalType: string, + packageId: string, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const identityArg = tx.sharedObjectRef(identity); + const proposal = tx.pure.id(proposalId); + + tx.moveCall({ + target: `${packageId}::identity::approve_proposal`, + typeArguments: [proposalType], + arguments: [identityArg, delegationToken, proposal], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + return tx.build(); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/send_asset.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/send_asset.ts new file mode 100644 index 000000000..8063641b3 --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/send_asset.ts @@ -0,0 +1,69 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { SharedObjectRef } from "@iota/iota.js/dist/cjs/bcs/types"; +import { ObjectRef, Transaction } from "@iota/iota.js/transactions"; +import { getControllerDelegation, putBackDelegationToken } from "../utils"; + +export function proposeSend( + identity: SharedObjectRef, + capability: ObjectRef, + transferMap: [string, string][], + packageId: string, + expiration?: number, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const identityArg = tx.sharedObjectRef(identity); + const exp = tx.pure.option("u64", expiration); + const objects = tx.pure.vector("id", transferMap.map(t => t[0])); + const recipients = tx.pure.vector("address", transferMap.map(t => t[1])); + + tx.moveCall({ + target: `${packageId}::identity::propose_send`, + arguments: [identityArg, delegationToken, exp, objects, recipients], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + return tx.build(); +} + +export function executeSend( + identity: SharedObjectRef, + capability: ObjectRef, + proposalId: string, + objects: [ObjectRef, string][], + packageId: string, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const proposal = tx.pure.id(proposalId); + const identityArg = tx.sharedObjectRef(identity); + + let action = tx.moveCall({ + target: `${packageId}::identity::execute_proposal`, + typeArguments: [`${packageId}::transfer_proposal::Send`], + arguments: [identityArg, delegationToken, proposal], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + for (const [obj, objType] of objects) { + const recv_obj = tx.receivingRef(obj); + tx.moveCall({ + target: `${packageId}::identity::execute_send`, + typeArguments: [objType], + arguments: [identityArg, action, recv_obj], + }); + } + + tx.moveCall({ + target: `${packageId}::transfer_proposal::complete_send`, + arguments: [action], + }); + + return tx.build(); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/update.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/update.ts new file mode 100644 index 000000000..76b355801 --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/update.ts @@ -0,0 +1,54 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { SharedObjectRef } from "@iota/iota.js/dist/cjs/bcs/types"; +import { ObjectRef, Transaction } from "@iota/iota.js/transactions"; +import { getClockRef, getControllerDelegation, putBackDelegationToken } from "../utils"; + +export function proposeUpdate( + identity: SharedObjectRef, + capability: ObjectRef, + didDoc: Uint8Array, + packageId: string, + expiration?: number, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const identityArg = tx.sharedObjectRef(identity); + const exp = tx.pure.option("u64", expiration); + const doc = tx.pure.vector("u8", didDoc); + const clock = getClockRef(tx); + + tx.moveCall({ + target: `${packageId}::identity::propose_update`, + arguments: [identityArg, delegationToken, doc, exp, clock], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + return tx.build(); +} + +export function executeUpdate( + identity: SharedObjectRef, + capability: ObjectRef, + proposalId: string, + packageId: string, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const [delegationToken, borrow] = getControllerDelegation(tx, cap, packageId); + const proposal = tx.pure.id(proposalId); + const identityArg = tx.sharedObjectRef(identity); + const clock = getClockRef(tx); + + tx.moveCall({ + target: `${packageId}::identity::execute_update`, + arguments: [identityArg, delegationToken, proposal, clock], + }); + + putBackDelegationToken(tx, cap, delegationToken, borrow, packageId); + + return tx.build(); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/upgrade.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/upgrade.ts new file mode 100644 index 000000000..4097c19a8 --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/identity/upgrade.ts @@ -0,0 +1,43 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { SharedObjectRef } from "@iota/iota.js/dist/cjs/bcs/types"; +import { ObjectRef, Transaction } from "@iota/iota.js/transactions"; + +export function proposeUpgrade( + identity: SharedObjectRef, + capability: ObjectRef, + packageId: string, + expiration?: number, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const identityArg = tx.sharedObjectRef(identity); + const exp = tx.pure.option("u64", expiration); + + tx.moveCall({ + target: `${packageId}::identity::propose_upgrade`, + arguments: [identityArg, cap, exp], + }); + + return tx.build(); +} + +export function executeUpgrade( + identity: SharedObjectRef, + capability: ObjectRef, + proposalId: string, + packageId: string, +): Promise { + const tx = new Transaction(); + const cap = tx.objectRef(capability); + const proposal = tx.pure.id(proposalId); + const identityArg = tx.sharedObjectRef(identity); + + tx.moveCall({ + target: `${packageId}::identity::execute_upgrade`, + arguments: [identityArg, cap, proposal], + }); + + return tx.build(); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/index.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/index.ts new file mode 100644 index 000000000..7c8b6e125 --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/index.ts @@ -0,0 +1,6 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export * as asset from "./asset"; +export * as identity from "./identity"; +export * from "./migration"; diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/migration.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/migration.ts new file mode 100644 index 000000000..eb0c7df3b --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/migration.ts @@ -0,0 +1,34 @@ +// Copyright 2020-2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { SharedObjectRef } from "@iota/iota.js/dist/cjs/bcs/types"; +import { ObjectRef, Transaction } from "@iota/iota.js/transactions"; +import { getClockRef } from "./utils"; + +export function migrateDidOutput( + didOutput: ObjectRef, + migrationRegistry: SharedObjectRef, + packageId: string, + creationTimestamp?: number, +): Promise { + const tx = new Transaction(); + const did_output = tx.objectRef(didOutput); + const migration_registry = tx.sharedObjectRef(migrationRegistry); + const clock = getClockRef(tx); + let timestamp; + if (creationTimestamp) { + timestamp = tx.pure.u64(creationTimestamp); + } else { + timestamp = tx.moveCall({ + target: "0x2::clock::timestamp_ms", + arguments: [clock], + }); + } + + tx.moveCall({ + target: `${packageId}::migration::migrate_alias_output`, + arguments: [did_output, migration_registry, timestamp, clock], + }); + + return tx.build(); +} diff --git a/bindings/wasm/iota_interaction_ts/lib/move_calls/utils.ts b/bindings/wasm/iota_interaction_ts/lib/move_calls/utils.ts new file mode 100644 index 000000000..d659552b8 --- /dev/null +++ b/bindings/wasm/iota_interaction_ts/lib/move_calls/utils.ts @@ -0,0 +1,31 @@ +import { Transaction, TransactionArgument, TransactionResult } from "@iota/iota.js/transactions"; +import { IOTA_CLOCK_OBJECT_ID } from "@iota/iota.js/utils"; + +export function getClockRef(tx: Transaction): TransactionArgument { + return tx.sharedObjectRef({ objectId: IOTA_CLOCK_OBJECT_ID, initialSharedVersion: 1, mutable: false }); +} + +export function getControllerDelegation( + tx: Transaction, + controllerCap: TransactionArgument, + packageId: string, +): [TransactionArgument, TransactionArgument] { + const [token, borrow] = tx.moveCall({ + target: `${packageId}::controller::borrow`, + arguments: [controllerCap], + }); + return [token, borrow]; +} + +export function putBackDelegationToken( + tx: Transaction, + controllerCap: TransactionArgument, + delegationToken: TransactionArgument, + borrow: TransactionArgument, + packageId: string, +) { + tx.moveCall({ + target: `${packageId}::controller::put_back`, + arguments: [controllerCap, delegationToken, borrow], + }); +} diff --git a/bindings/wasm/iota_interaction_ts/package-lock.json b/bindings/wasm/iota_interaction_ts/package-lock.json index 2a9def84c..4021b9c90 100644 --- a/bindings/wasm/iota_interaction_ts/package-lock.json +++ b/bindings/wasm/iota_interaction_ts/package-lock.json @@ -9,6 +9,7 @@ "version": "1.4.0", "license": "Apache-2.0", "dependencies": { + "@iota/iota-sdk": "^0.4.0", "@iota/iota.js": "file:../../../../iota/sdk/typescript", "@noble/ed25519": "^1.7.3", "@noble/hashes": "^1.4.0", @@ -46,7 +47,7 @@ }, "../../../../iota/sdk/typescript": { "name": "@iota/iota-sdk", - "version": "0.3.0", + "version": "0.3.1", "license": "Apache-2.0", "dependencies": { "@graphql-typed-document-node/core": "^3.2.0", @@ -93,6 +94,34 @@ "../../../../iotaledger/iota/sdk/typescript": { "extraneous": true }, + "node_modules/@0no-co/graphql.web": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.0.12.tgz", + "integrity": "sha512-BTDjjsV/zSPy5fqItwm+KWUfh9CSe9tTtR6rCB72ddtkAxdcHbi4Ir4r/L1Et4lyxmL+i7Rb3m9sjLLi9tYrzA==", + "license": "MIT", + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" + }, + "peerDependenciesMeta": { + "graphql": { + "optional": true + } + } + }, + "node_modules/@0no-co/graphqlsp": { + "version": "1.12.16", + "resolved": "https://registry.npmjs.org/@0no-co/graphqlsp/-/graphqlsp-1.12.16.tgz", + "integrity": "sha512-B5pyYVH93Etv7xjT6IfB7QtMBdaaC07yjbhN6v8H7KgFStMkPvi+oWYBTibMFRMY89qwc9H8YixXg8SXDVgYWw==", + "license": "MIT", + "dependencies": { + "@gql.tada/internal": "^1.0.0", + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0" + }, + "peerDependencies": { + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", + "typescript": "^5.0.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", @@ -275,6 +304,92 @@ "node": ">=10.0.0" } }, + "node_modules/@gql.tada/cli-utils": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@gql.tada/cli-utils/-/cli-utils-1.6.3.tgz", + "integrity": "sha512-jFFSY8OxYeBxdKi58UzeMXG1tdm4FVjXa8WHIi66Gzu9JWtCE6mqom3a8xkmSw+mVaybFW5EN2WXf1WztJVNyQ==", + "license": "MIT", + "dependencies": { + "@0no-co/graphqlsp": "^1.12.13", + "@gql.tada/internal": "1.0.8", + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0" + }, + "peerDependencies": { + "@0no-co/graphqlsp": "^1.12.13", + "@gql.tada/svelte-support": "1.0.1", + "@gql.tada/vue-support": "1.0.1", + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "@gql.tada/svelte-support": { + "optional": true + }, + "@gql.tada/vue-support": { + "optional": true + } + } + }, + "node_modules/@gql.tada/internal": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@gql.tada/internal/-/internal-1.0.8.tgz", + "integrity": "sha512-XYdxJhtHC5WtZfdDqtKjcQ4d7R1s0d1rnlSs3OcBEUbYiPoJJfZU7tWsVXuv047Z6msvmr4ompJ7eLSK5Km57g==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.0.5" + }, + "peerDependencies": { + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", + "typescript": "^5.0.0" + } + }, + "node_modules/@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "license": "MIT", + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@iota/bcs": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@iota/bcs/-/bcs-0.2.1.tgz", + "integrity": "sha512-T+iv5gZhUZP7BiDY7+Ir4MA2rYmyGNZA2b+nxjv219Fp8klFt+l38OWA+1RgJXrCmzuZ+M4hbMAeHhHziURX6Q==", + "license": "Apache-2.0", + "dependencies": { + "bs58": "^6.0.0" + } + }, + "node_modules/@iota/iota-sdk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@iota/iota-sdk/-/iota-sdk-0.4.0.tgz", + "integrity": "sha512-uhHcQGN3G/gJi62aOKmvgiloaNAC61fEsV4GKAKVVv5kUP60p6Q3S5xQL3OoYf6kiAUUhaFoAr4keiEQDZp5aw==", + "license": "Apache-2.0", + "dependencies": { + "@graphql-typed-document-node/core": "^3.2.0", + "@iota/bcs": "0.2.1", + "@noble/curves": "^1.4.2", + "@noble/hashes": "^1.4.0", + "@scure/bip32": "^1.4.0", + "@scure/bip39": "^1.3.0", + "@suchipi/femver": "^1.0.0", + "bech32": "^2.0.0", + "gql.tada": "^1.8.2", + "graphql": "^16.9.0", + "tweetnacl": "^1.0.3", + "valibot": "^0.36.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@iota/iota-sdk/node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "license": "Unlicense" + }, "node_modules/@iota/iota.js": { "resolved": "../../../../iota/sdk/typescript", "link": true @@ -404,6 +519,33 @@ "node": ">=v12.0.0" } }, + "node_modules/@noble/curves": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.7.0.tgz", + "integrity": "sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.6.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.0.tgz", + "integrity": "sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@noble/ed25519": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz", @@ -466,6 +608,42 @@ "node": ">= 8" } }, + "node_modules/@scure/base": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.1.tgz", + "integrity": "sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.0.tgz", + "integrity": "sha512-82q1QfklrUUdXJzjuRU7iG7D7XiFx5PHYVS0+oeNKhyDLT7WPqs6pBcM2W5ZdwOwKCwoE1Vy1se+DHjcXwCYnA==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.7.0", + "@noble/hashes": "~1.6.0", + "@scure/base": "~1.2.1" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.0.tgz", + "integrity": "sha512-Dop+ASYhnrwm9+HA/HwXg7j2ZqM6yk2fyLWb5znexjctFY3+E+eU8cIWI0Pql0Qx4hPZCijlGq4OL71g+Uz30A==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.6.0", + "@scure/base": "~1.2.1" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@stablelib/binary": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", @@ -561,6 +739,12 @@ "@stablelib/wipe": "^1.0.1" } }, + "node_modules/@suchipi/femver": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@suchipi/femver/-/femver-1.0.0.tgz", + "integrity": "sha512-bprE8+K5V+DPX7q2e2K57ImqNBdfGHDIWaGI5xHxZoxbKOuQZn4wzPiUxOAHnsUr3w3xHrWXwN7gnG/iIuEMIg==", + "license": "MIT" + }, "node_modules/@transmute/did-context": { "version": "0.6.1-unstable.37", "resolved": "https://registry.npmjs.org/@transmute/did-context/-/did-context-0.6.1-unstable.37.tgz", @@ -1355,6 +1539,12 @@ "dev": true, "license": "MIT" }, + "node_modules/base-x": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.0.tgz", + "integrity": "sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==", + "license": "MIT" + }, "node_modules/base64-arraybuffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", @@ -1395,6 +1585,12 @@ "tweetnacl": "^0.14.3" } }, + "node_modules/bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==", + "license": "MIT" + }, "node_modules/big-integer": { "version": "1.6.52", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", @@ -1507,6 +1703,15 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs58": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "license": "MIT", + "dependencies": { + "base-x": "^5.0.0" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -3206,6 +3411,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gql.tada": { + "version": "1.8.10", + "resolved": "https://registry.npmjs.org/gql.tada/-/gql.tada-1.8.10.tgz", + "integrity": "sha512-FrvSxgz838FYVPgZHGOSgbpOjhR+yq44rCzww3oOPJYi0OvBJjAgCiP6LEokZIYND2fUTXzQAyLgcvgw1yNP5A==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.0.5", + "@0no-co/graphqlsp": "^1.12.13", + "@gql.tada/cli-utils": "1.6.3", + "@gql.tada/internal": "1.0.8" + }, + "bin": { + "gql-tada": "bin/cli.js", + "gql.tada": "bin/cli.js" + }, + "peerDependencies": { + "typescript": "^5.0.0" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -3213,6 +3437,15 @@ "dev": true, "license": "ISC" }, + "node_modules/graphql": { + "version": "16.10.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.10.0.tgz", + "integrity": "sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ==", + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, "node_modules/growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -6880,6 +7113,12 @@ "dev": true, "license": "MIT" }, + "node_modules/valibot": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.36.0.tgz", + "integrity": "sha512-CjF1XN4sUce8sBK9TixrDqFM7RwNkuXdJu174/AwmQUB62QbCQADg5lLe8ldBalFgtj1uKj+pKwDJiNo4Mn+eQ==", + "license": "MIT" + }, "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", diff --git a/bindings/wasm/iota_interaction_ts/src/asset_move_calls.rs b/bindings/wasm/iota_interaction_ts/src/asset_move_calls.rs index f09e1c530..ca2d7e09e 100644 --- a/bindings/wasm/iota_interaction_ts/src/asset_move_calls.rs +++ b/bindings/wasm/iota_interaction_ts/src/asset_move_calls.rs @@ -1,9 +1,16 @@ // Copyright 2020-2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use identity_iota_interaction::types::execution_status::CommandArgumentError; +use js_sys::Uint8Array; use serde::Serialize; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::JsValue; +use crate::bindings::WasmObjectRef; +use crate::bindings::WasmSharedObjectRef; use crate::error::TsSdkError; +use crate::error::WasmError; use identity_iota_interaction::types::base_types::IotaAddress; use identity_iota_interaction::types::base_types::ObjectID; use identity_iota_interaction::types::base_types::ObjectRef; @@ -13,6 +20,56 @@ use identity_iota_interaction::AssetMoveCalls; use identity_iota_interaction::MoveType; use identity_iota_interaction::ProgrammableTransactionBcs; +#[wasm_bindgen(module = "move_calls/asset")] +extern "C" { + #[wasm_bindgen(js_name = "create", catch)] + pub(crate) async fn new_asset( + inner_bytes: &[u8], + inner_type: &str, + mutable: bool, + transferable: bool, + deletable: bool, + package: &str, + ) -> Result; + + #[wasm_bindgen(catch, js_name = "remove")] + pub(crate) async fn delete(asset: WasmObjectRef, asset_type: &str, package: &str) -> Result; + + #[wasm_bindgen(catch)] + pub(crate) async fn update( + asset: WasmObjectRef, + content: &[u8], + content_type: &str, + package: &str, + ) -> Result; + + #[wasm_bindgen(catch)] + pub(crate) async fn transfer( + asset: WasmObjectRef, + asset_type: &str, + recipient: &str, + package: &str, + ) -> Result; + + #[wasm_bindgen(js_name = "acceptProposal", catch)] + pub(crate) async fn accept_proposal( + proposal: WasmSharedObjectRef, + recipient_cap: WasmObjectRef, + asset: WasmObjectRef, + asset_type: &str, + package: &str, + ) -> Result; + + #[wasm_bindgen(js_name = "concludeOrCancel", catch)] + pub(crate) async fn conclude_or_cancel( + proposal: WasmSharedObjectRef, + sender_cap: WasmObjectRef, + asset: WasmObjectRef, + asset_type: &str, + package: &str, + ) -> Result; +} + pub struct AssetMoveCallsTsSdk {} impl AssetMoveCalls for AssetMoveCallsTsSdk { @@ -25,11 +82,32 @@ impl AssetMoveCalls for AssetMoveCallsTsSdk { deletable: bool, package: ObjectID, ) -> Result { - unimplemented!(); + let inner_bytes = bcs::to_bytes(&inner).map_err(|_| CommandArgumentError::InvalidBCSBytes)?; + let inner_type = T::move_type(package).to_string(); + let package = package.to_string(); + + futures::executor::block_on(new_asset( + &inner_bytes, + &inner_type, + mutable, + transferable, + deletable, + &package, + )) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn delete(asset: ObjectRef, package: ObjectID) -> Result { - unimplemented!(); + let asset = asset.into(); + let asset_type = T::move_type(package).to_string(); + let package = package.to_string(); + + futures::executor::block_on(delete(asset, &asset_type, &package)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn transfer( @@ -37,7 +115,15 @@ impl AssetMoveCalls for AssetMoveCallsTsSdk { recipient: IotaAddress, package: ObjectID, ) -> Result { - unimplemented!(); + let asset = asset.into(); + let asset_type = T::move_type(package).to_string(); + let recipient = recipient.to_string(); + let package = package.to_string(); + + futures::executor::block_on(transfer(asset, &asset_type, &recipient, &package)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn make_tx( @@ -55,20 +141,38 @@ impl AssetMoveCalls for AssetMoveCallsTsSdk { proposal: (ObjectID, SequenceNumber), recipient_cap: ObjectRef, asset: ObjectRef, - asset_type_param: TypeTag, + asset_type: TypeTag, package: ObjectID, ) -> Result { - unimplemented!(); + let proposal = (proposal.0, proposal.1, true).into(); + let asset = asset.into(); + let asset_type = asset_type.to_canonical_string(true); + let recipient = recipient_cap.into(); + let package = package.to_string(); + + futures::executor::block_on(accept_proposal(proposal, recipient, asset, &asset_type, &package)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn conclude_or_cancel( proposal: (ObjectID, SequenceNumber), sender_cap: ObjectRef, asset: ObjectRef, - asset_type_param: TypeTag, + asset_type: TypeTag, package: ObjectID, ) -> Result { - unimplemented!(); + let proposal = (proposal.0, proposal.1, true).into(); + let asset = asset.into(); + let asset_type = asset_type.to_canonical_string(true); + let sender = sender_cap.into(); + let package = package.to_string(); + + futures::executor::block_on(conclude_or_cancel(proposal, sender, asset, &asset_type, &package)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn update( @@ -76,6 +180,14 @@ impl AssetMoveCalls for AssetMoveCallsTsSdk { new_content: T, package: ObjectID, ) -> Result { - unimplemented!(); + let asset = asset.into(); + let content_type = T::move_type(package).to_string(); + let content = bcs::to_bytes(&new_content).map_err(|_| CommandArgumentError::InvalidBCSBytes)?; + let package = package.to_string(); + + futures::executor::block_on(update(asset, &content, &content_type, &package)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } } diff --git a/bindings/wasm/iota_interaction_ts/src/bindings/wasm_types.rs b/bindings/wasm/iota_interaction_ts/src/bindings/wasm_types.rs index 68d6b2277..cb9a1c55e 100644 --- a/bindings/wasm/iota_interaction_ts/src/bindings/wasm_types.rs +++ b/bindings/wasm/iota_interaction_ts/src/bindings/wasm_types.rs @@ -3,17 +3,24 @@ use identity_iota_interaction::rpc_types::OwnedObjectRef; use identity_iota_interaction::types::base_types::IotaAddress; +use identity_iota_interaction::types::base_types::ObjectID; +use identity_iota_interaction::types::base_types::ObjectRef; +use identity_iota_interaction::types::base_types::SequenceNumber; +use identity_iota_interaction::types::execution_status::CommandArgumentError; use identity_iota_interaction::types::execution_status::ExecutionStatus; +use identity_iota_interaction::types::object::Owner; use identity_iota_interaction::ProgrammableTransactionBcs; use js_sys::Promise; use serde::Deserialize; use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::JsCast; use wasm_bindgen::JsValue; use wasm_bindgen_futures::JsFuture; use crate::bindings::WasmIotaClient; use crate::common::into_sdk_type; use crate::console_log; +use crate::error::TsSdkError; // TODO: fix/add // not available anymore @@ -61,6 +68,12 @@ extern "C" { #[wasm_bindgen(typescript_type = "Promise")] pub type PromiseBalance; + #[wasm_bindgen(typescript_type = "Transaction")] + pub type WasmTransactionBuilder; + + #[wasm_bindgen(typescript_type = "TransactionArgument")] + pub type WasmTransactionArgument; + #[wasm_bindgen(typescript_type = "IotaObjectData")] pub type WasmIotaObjectData; @@ -116,6 +129,14 @@ extern "C" { #[derive(Clone)] pub type WasmExecutionStatus; + #[wasm_bindgen(typescript_type = "ObjectRef")] + #[derive(Clone)] + pub type WasmObjectRef; + + #[wasm_bindgen(typescript_type = "SharedObjectRef")] + #[derive(Clone)] + pub type WasmSharedObjectRef; + #[wasm_bindgen(typescript_type = "OwnedObjectRef")] #[derive(Clone)] pub type WasmOwnedObjectRef; @@ -141,6 +162,58 @@ extern "C" { pub type PromiseIotaTransactionBlockResponseAdapter; } +impl From for WasmObjectRef { + fn from(value: ObjectRef) -> Self { + let json_obj = serde_json::json!({ + "objectId": value.0, + "version": value.1, + "digest": value.2, + }); + + serde_wasm_bindgen::to_value(&json_obj) + .expect("a JSON object is a JS value") + // safety: `json_obj` was constructed following TS ObjectRef's interface. + .unchecked_into() + } +} + +impl From<(ObjectID, SequenceNumber, bool)> for WasmSharedObjectRef { + fn from(value: (ObjectID, SequenceNumber, bool)) -> Self { + let json_obj = serde_json::json!({ + "objectId": value.0, + "initialSharedVersion": value.1, + "mutable": value.2, + }); + + serde_wasm_bindgen::to_value(&json_obj) + .expect("a JSON object is a JS value") + // safety: `json_obj` was constructed following TS SharedObjectRef's interface. + .unchecked_into() + } +} + +impl TryFrom for WasmSharedObjectRef { + type Error = TsSdkError; + fn try_from(value: OwnedObjectRef) -> Result { + let Owner::Shared { initial_shared_version } = value.owner else { + return Err(TsSdkError::CommandArgumentError(CommandArgumentError::TypeMismatch)); + }; + let obj_id = value.object_id(); + + Ok((obj_id, initial_shared_version, true).into()) + } +} + +impl WasmSharedObjectRef { + #[allow(dead_code)] + pub(crate) fn immutable(self) -> Self { + const JS_FALSE: JsValue = JsValue::from_bool(false); + + let _ = js_sys::Reflect::set(&self, &JsValue::from_str("mutable"), &JS_FALSE); + self + } +} + #[wasm_bindgen(module = "/lib/iota_client_helpers.ts")] extern "C" { #[wasm_bindgen(typescript_type = "IotaTransactionBlockResponseAdapter")] diff --git a/bindings/wasm/iota_interaction_ts/src/error.rs b/bindings/wasm/iota_interaction_ts/src/error.rs index 2a0996914..dc30256a1 100644 --- a/bindings/wasm/iota_interaction_ts/src/error.rs +++ b/bindings/wasm/iota_interaction_ts/src/error.rs @@ -183,13 +183,13 @@ pub fn stringify_js_error(result: Result) -> StdResult { #[derive(ThisError, Debug)] pub enum TsSdkError { #[error("[TsSdkError] PackageUpgradeError: {0}")] - PackageUpgradeError(PackageUpgradeError), + PackageUpgradeError(#[from] PackageUpgradeError), #[error("[TsSdkError] CommandArgumentError: {0}")] - CommandArgumentError(CommandArgumentError), + CommandArgumentError(#[from] CommandArgumentError), #[error("[TsSdkError] ExecutionFailureStatus: {0}")] - ExecutionFailureStatus(ExecutionFailureStatus), + ExecutionFailureStatus(#[from] ExecutionFailureStatus), #[error("[TsSdkError] TypeArgumentError: {0}")] - TypeArgumentError(TypeArgumentError), + TypeArgumentError(#[from] TypeArgumentError), #[error("[TsSdkError] WasmError:{{\n name: {0},\n message: {1}\n}}")] WasmError(String, String), #[error("[TsSdkError] JsSysError: {0}")] diff --git a/bindings/wasm/iota_interaction_ts/src/identity_move_calls.rs b/bindings/wasm/iota_interaction_ts/src/identity_move_calls.rs index 166e818eb..29035f3ea 100644 --- a/bindings/wasm/iota_interaction_ts/src/identity_move_calls.rs +++ b/bindings/wasm/iota_interaction_ts/src/identity_move_calls.rs @@ -1,11 +1,21 @@ // Copyright 2020-2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use serde::Serialize; +use js_sys::Uint8Array; +use std::cell::Cell; use std::collections::HashSet; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::JsCast; +use wasm_bindgen::JsValue; -use super::TransactionBuilderAdapter; +use crate::bindings::WasmIotaObjectData; +use crate::bindings::WasmObjectRef; +use crate::bindings::WasmSharedObjectRef; +use crate::bindings::WasmTransactionArgument; +use crate::bindings::WasmTransactionBuilder; use crate::error::TsSdkError; +use crate::error::WasmError; +use crate::transaction_builder::TransactionBuilderTsSdk; use identity_iota_interaction::rpc_types::IotaObjectData; use identity_iota_interaction::rpc_types::OwnedObjectRef; use identity_iota_interaction::types::base_types::IotaAddress; @@ -20,11 +30,194 @@ use identity_iota_interaction::IdentityMoveCalls; use identity_iota_interaction::MoveType; use identity_iota_interaction::ProgrammableTransactionBcs; +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(typescript_type = "[string, number]")] + pub(crate) type WasmControllerCouple; + + #[wasm_bindgen(typescript_type = "[string, string]")] + pub(crate) type WasmTransferCouple; + + #[wasm_bindgen(typescript_type = "[ObjectRef, string]")] + pub(crate) type WasmObjectRefAndType; + + #[wasm_bindgen(typescript_type = "Map")] + pub(crate) type WasmTxArgumentMap; +} + +#[wasm_bindgen(module = "move_calls/identity")] +extern "C" { + #[wasm_bindgen(js_name = "create", catch)] + async fn identity_new(did: &[u8], package: &str) -> Result; + + #[wasm_bindgen(js_name = "newWithControllers", catch)] + async fn identity_new_with_controllers( + did: &[u8], + controllers: Vec, + threshold: u64, + package: &str, + ) -> Result; + + #[wasm_bindgen(js_name = "approve", catch)] + async fn approve_proposal( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + proposal: &str, + proposal_type: &str, + package: &str, + ) -> Result; + + #[wasm_bindgen(js_name = "proposeDeactivation", catch)] + async fn propose_deactivation( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + package: &str, + expiration: Option, + ) -> Result; + + #[wasm_bindgen(js_name = "executeDeactivation", catch)] + async fn execute_deactivation( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + proposal: &str, + package: &str, + ) -> Result; + + #[wasm_bindgen(js_name = "proposeUpgrade", catch)] + async fn propose_upgrade( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + package: &str, + expiration: Option, + ) -> Result; + + #[wasm_bindgen(js_name = "executeUpgrade", catch)] + async fn execute_upgrade( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + proposal: &str, + package: &str, + ) -> Result; + + #[wasm_bindgen(js_name = "proposeSend", catch)] + async fn propose_send( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + assets: Vec, + package: &str, + expiration: Option, + ) -> Result; + + #[wasm_bindgen(js_name = "executeSend", catch)] + async fn execute_send( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + proposal: &str, + assets: Vec, + package: &str, + ) -> Result; + + #[wasm_bindgen(js_name = "proposeUpdate", catch)] + async fn propose_update( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + did_doc: &[u8], + package: &str, + expiration: Option, + ) -> Result; + + #[wasm_bindgen(js_name = "executeUpdate", catch)] + async fn execute_update( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + proposal: &str, + package: &str, + ) -> Result; + + #[wasm_bindgen(js_name = "proposeBorrow", catch)] + async fn propose_borrow( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + objects: Vec, + package: &str, + expiration: Option, + ) -> Result; + + #[wasm_bindgen(js_name = "executeBorrow", catch)] + async fn execute_borrow( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + proposal: &str, + objects: Vec, + intent_fn: &dyn Fn(WasmTransactionBuilder, WasmTxArgumentMap), + package: &str, + ) -> Result; + + #[wasm_bindgen(js_name = "createAndExecuteBorrow", catch)] + async fn create_and_execute_borrow( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + objects: Vec, + intent_fn: &dyn Fn(WasmTransactionBuilder, WasmTxArgumentMap), + package: &str, + expiration: Option, + ) -> Result; + + #[wasm_bindgen(js_name = "proposeConfigChange", catch)] + async fn propose_config_change( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + controllers_to_add: Vec, + controllers_to_remove: Vec, + controllers_to_update: Vec, + package: &str, + expiration: Option, + threshold: Option, + ) -> Result; + + #[wasm_bindgen(js_name = "executeConfigChange", catch)] + async fn execute_config_change( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + proposal: &str, + package: &str, + ) -> Result; + + #[wasm_bindgen(js_name = "proposeControllerExecution", catch)] + async fn propose_controller_execution( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + controller_cap_id: &str, + package: &str, + expiration: Option, + ) -> Result; + + #[wasm_bindgen(js_name = "executeControllerExecution", catch)] + async fn execute_controller_execution( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + proposal: &str, + controller_cap_ref: WasmObjectRef, + intent_fn: &dyn Fn(WasmTransactionBuilder, WasmTransactionArgument), + package: &str, + ) -> Result; + + #[wasm_bindgen(js_name = "createAndExecuteControllerExecution", catch)] + async fn create_and_execute_controller_execution( + identity: WasmSharedObjectRef, + capability: WasmObjectRef, + controller_cap_ref: WasmObjectRef, + intent_fn: &dyn Fn(WasmTransactionBuilder, WasmTransactionArgument), + package: &str, + expiration: Option, + ) -> Result; +} + pub struct IdentityMoveCallsTsSdk {} impl IdentityMoveCalls for IdentityMoveCallsTsSdk { type Error = TsSdkError; - type NativeTxBuilder = (); // TODO: Set this to the wasm32... type that is wrapped by IdentityMoveCallsTsSdk + type NativeTxBuilder = WasmTransactionBuilder; fn propose_borrow( identity: OwnedObjectRef, @@ -33,7 +226,21 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { expiration: Option, package_id: ObjectID, ) -> Result { - todo!() + let identity = identity.try_into()?; + let controller_cap = capability.into(); + let package_id = package_id.to_string(); + let objects = objects.into_iter().map(|obj| obj.to_string()).collect(); + + futures::executor::block_on(propose_borrow( + identity, + controller_cap, + objects, + &package_id, + expiration, + )) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn execute_borrow>( @@ -44,7 +251,31 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { intent_fn: F, package: ObjectID, ) -> Result { - todo!() + let identity = identity.try_into()?; + let capability = capability.into(); + let proposal = proposal_id.to_string(); + let package = package.to_string(); + let objects = objects + .into_iter() + .map(|obj| serde_wasm_bindgen::to_value(&obj).map(WasmIotaObjectData::from)) + .collect::, _>>() + .map_err(WasmError::from)?; + + // Use cell to move `intent_fn` inside `closure` without actually moving it. + // This ensures that `closure` is an `impl Fn(..)` instead of `impl FnOnce(..)` like `intent_fn`. + let wrapped_intent_fn = Cell::new(Some(intent_fn)); + let closure = |tx_builder: WasmTransactionBuilder, args: WasmTxArgumentMap| { + let mut builder = TransactionBuilderTsSdk::new(tx_builder); + let args = serde_wasm_bindgen::from_value(args.into()).expect("failed to convert JS argument map"); + wrapped_intent_fn.take().unwrap()(&mut builder, &args); + }; + + futures::executor::block_on(execute_borrow( + identity, capability, &proposal, objects, &closure, &package, + )) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn create_and_execute_borrow>( @@ -55,7 +286,30 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { expiration: Option, package_id: ObjectID, ) -> anyhow::Result { - todo!() + let identity = identity.try_into()?; + let capability = capability.into(); + let package = package_id.to_string(); + let objects = objects + .into_iter() + .map(|obj| serde_wasm_bindgen::to_value(&obj).map(WasmIotaObjectData::from)) + .collect::, _>>() + .map_err(WasmError::from)?; + + // Use cell to move `intent_fn` inside `closure` without actually moving it. + // This ensures that `closure` is an `impl Fn(..)` instead of `impl FnOnce(..)` like `intent_fn`. + let wrapped_intent_fn = Cell::new(Some(intent_fn)); + let closure = |tx_builder: WasmTransactionBuilder, args: WasmTxArgumentMap| { + let mut builder = TransactionBuilderTsSdk::new(tx_builder); + let args = serde_wasm_bindgen::from_value(args.into()).expect("failed to convert JS argument map"); + wrapped_intent_fn.take().unwrap()(&mut builder, &args); + }; + + futures::executor::block_on(create_and_execute_borrow( + identity, capability, objects, &closure, &package, expiration, + )) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn propose_config_change( @@ -72,7 +326,38 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { I1: IntoIterator, I2: IntoIterator, { - unimplemented!(); + let identity = identity.try_into()?; + let capability = controller_cap.into(); + let package = package.to_string(); + + let controllers_to_add = controllers_to_add + .into_iter() + .map(|controller| serde_wasm_bindgen::to_value(&controller).map(WasmControllerCouple::from)) + .collect::, _>>() + .map_err(WasmError::from)?; + let controllers_to_remove = controllers_to_remove + .into_iter() + .map(|controller| controller.to_string()) + .collect(); + let controllers_to_update = controllers_to_update + .into_iter() + .map(|controller| serde_wasm_bindgen::to_value(&controller).map(WasmControllerCouple::from)) + .collect::, _>>() + .map_err(WasmError::from)?; + + futures::executor::block_on(propose_config_change( + identity, + capability, + controllers_to_add, + controllers_to_remove, + controllers_to_update, + &package, + expiration, + threshold, + )) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn execute_config_change( @@ -81,7 +366,15 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { proposal_id: ObjectID, package: ObjectID, ) -> Result { - unimplemented!(); + let identity = identity.try_into()?; + let capability = controller_cap.into(); + let proposal = proposal_id.to_string(); + let package = package.to_string(); + + futures::executor::block_on(execute_config_change(identity, capability, &proposal, &package)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn propose_controller_execution( @@ -91,7 +384,21 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { expiration: Option, package_id: ObjectID, ) -> Result { - todo!() + let identity = identity.try_into()?; + let controller_cap = capability.into(); + let package_id = package_id.to_string(); + let borrowed_cap = controller_cap_id.to_string(); + + futures::executor::block_on(propose_controller_execution( + identity, + controller_cap, + &borrowed_cap, + &package_id, + expiration, + )) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn execute_controller_execution>( @@ -102,7 +409,32 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { intent_fn: F, package: ObjectID, ) -> Result { - todo!() + let identity = identity.try_into()?; + let capability = capability.into(); + let proposal = proposal_id.to_string(); + let package = package.to_string(); + let borrowing_cap = borrowing_controller_cap_ref.into(); + + // Use cell to move `intent_fn` inside `closure` without actually moving it. + // This ensures that `closure` is an `impl Fn(..)` instead of `impl FnOnce(..)` like `intent_fn`. + let wrapped_intent_fn = Cell::new(Some(intent_fn)); + let closure = |tx_builder: WasmTransactionBuilder, args: WasmTransactionArgument| { + let mut builder = TransactionBuilderTsSdk::new(tx_builder); + let args = serde_wasm_bindgen::from_value(args.into()).expect("failed to convert JS argument map"); + wrapped_intent_fn.take().unwrap()(&mut builder, &args); + }; + + futures::executor::block_on(execute_controller_execution( + identity, + capability, + &proposal, + borrowing_cap, + &closure, + &package, + )) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn create_and_execute_controller_execution( @@ -116,11 +448,39 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { where F: ControllerIntentFnInternalT, { - todo!() + let identity = identity.try_into()?; + let capability = capability.into(); + let package = package_id.to_string(); + let borrowing_cap = borrowing_controller_cap_ref.into(); + + // Use cell to move `intent_fn` inside `closure` without actually moving it. + // This ensures that `closure` is an `impl Fn(..)` instead of `impl FnOnce(..)` like `intent_fn`. + let wrapped_intent_fn = Cell::new(Some(intent_fn)); + let closure = |tx_builder: WasmTransactionBuilder, args: WasmTransactionArgument| { + let mut builder = TransactionBuilderTsSdk::new(tx_builder); + let args = serde_wasm_bindgen::from_value(args.into()).expect("failed to convert JS argument map"); + wrapped_intent_fn.take().unwrap()(&mut builder, &args); + }; + + futures::executor::block_on(create_and_execute_controller_execution( + identity, + capability, + borrowing_cap, + &closure, + &package, + expiration, + )) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn new_identity(did_doc: &[u8], package_id: ObjectID) -> Result { - unimplemented!(); + let package = package_id.to_string(); + futures::executor::block_on(identity_new(did_doc, &package)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn new_with_controllers( @@ -128,8 +488,21 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { controllers: C, threshold: u64, package_id: ObjectID, - ) -> Result { - unimplemented!(); + ) -> Result + where + C: IntoIterator, + { + let package = package_id.to_string(); + let controllers = controllers + .into_iter() + .map(|controller| serde_wasm_bindgen::to_value(&controller).map(|js_value| js_value.unchecked_into())) + .collect::, _>>() + .map_err(|e| WasmError::from(e))?; + + futures::executor::block_on(identity_new_with_controllers(did_doc, controllers, threshold, &package)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn propose_deactivation( @@ -138,7 +511,14 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { expiration: Option, package_id: ObjectID, ) -> Result { - unimplemented!(); + let identity = identity.try_into()?; + let capability = capability.into(); + let package = package_id.to_string(); + + futures::executor::block_on(propose_deactivation(identity, capability, &package, expiration)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn execute_deactivation( @@ -147,7 +527,15 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { proposal_id: ObjectID, package_id: ObjectID, ) -> Result { - unimplemented!(); + let identity = identity.try_into()?; + let capability = capability.into(); + let proposal = proposal_id.to_string(); + let package = package_id.to_string(); + + futures::executor::block_on(execute_deactivation(identity, capability, &proposal, &package)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn approve_proposal( @@ -156,7 +544,21 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { proposal_id: ObjectID, package: ObjectID, ) -> Result { - unimplemented!(); + let identity = identity.try_into()?; + let controller_cap = controller_cap.into(); + let proposal_id = proposal_id.to_string(); + let package_id = package.to_string(); + + futures::executor::block_on(approve_proposal( + identity, + controller_cap, + &proposal_id, + &T::move_type(package).to_canonical_string(true), + &package_id, + )) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn propose_send( @@ -166,7 +568,25 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { expiration: Option, package_id: ObjectID, ) -> Result { - todo!() + let identity = identity.try_into()?; + let controller_cap = capability.into(); + let package_id = package_id.to_string(); + let transfer_map = transfer_map + .into_iter() + .map(|tx| serde_wasm_bindgen::to_value(&tx).map(JsValue::into)) + .collect::, _>>() + .map_err(|e| WasmError::from(e))?; + + futures::executor::block_on(propose_send( + identity, + controller_cap, + transfer_map, + &package_id, + expiration, + )) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn create_and_execute_send( @@ -187,7 +607,20 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { objects: Vec<(ObjectRef, TypeTag)>, package: ObjectID, ) -> Result { - todo!() + let identity = identity.try_into()?; + let controller_cap = capability.into(); + let proposal = proposal_id.to_string(); + let package_id = package.to_string(); + let objects = objects + .into_iter() + .map(|tx| serde_wasm_bindgen::to_value(&tx).map(JsValue::into)) + .collect::, _>>() + .map_err(|e| WasmError::from(e))?; + + futures::executor::block_on(execute_send(identity, controller_cap, &proposal, objects, &package_id)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn propose_update( @@ -197,7 +630,21 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { expiration: Option, package_id: ObjectID, ) -> Result { - unimplemented!(); + let identity = identity.try_into()?; + let controller_cap = capability.into(); + let did_doc = did_doc.as_ref(); + let package_id = package_id.to_string(); + + futures::executor::block_on(propose_update( + identity, + controller_cap, + did_doc, + &package_id, + expiration, + )) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn execute_update( @@ -206,7 +653,15 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { proposal_id: ObjectID, package_id: ObjectID, ) -> Result { - unimplemented!(); + let identity = identity.try_into()?; + let controller_cap = capability.into(); + let proposal = proposal_id.to_string(); + let package_id = package_id.to_string(); + + futures::executor::block_on(execute_update(identity, controller_cap, &proposal, &package_id)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn propose_upgrade( @@ -215,7 +670,14 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { expiration: Option, package_id: ObjectID, ) -> Result { - todo!() + let identity = identity.try_into()?; + let capability = capability.into(); + let package = package_id.to_string(); + + futures::executor::block_on(propose_upgrade(identity, capability, &package, expiration)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } fn execute_upgrade( @@ -224,6 +686,14 @@ impl IdentityMoveCalls for IdentityMoveCallsTsSdk { proposal_id: ObjectID, package_id: ObjectID, ) -> Result { - todo!() + let identity = identity.try_into()?; + let capability = capability.into(); + let proposal = proposal_id.to_string(); + let package = package_id.to_string(); + + futures::executor::block_on(execute_upgrade(identity, capability, &proposal, &package)) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(TsSdkError::from) } } diff --git a/bindings/wasm/iota_interaction_ts/src/migration_move_calls.rs b/bindings/wasm/iota_interaction_ts/src/migration_move_calls.rs index cea88d502..b738cd6dc 100644 --- a/bindings/wasm/iota_interaction_ts/src/migration_move_calls.rs +++ b/bindings/wasm/iota_interaction_ts/src/migration_move_calls.rs @@ -9,8 +9,25 @@ use identity_iota_interaction::types::transaction::ObjectArg; use identity_iota_interaction::types::IOTA_FRAMEWORK_PACKAGE_ID; use identity_iota_interaction::MigrationMoveCalls; use identity_iota_interaction::ProgrammableTransactionBcs; +use js_sys::Uint8Array; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::JsValue; +use crate::bindings::WasmObjectRef; +use crate::bindings::WasmSharedObjectRef; use crate::error::TsSdkError; +use crate::error::WasmError; + +#[wasm_bindgen(module = "move_calls")] +extern "C" { + #[wasm_bindgen(js_name = "migrateDidOutput", catch)] + async fn migrate_did_output_impl( + did_output: WasmObjectRef, + migration_registry: WasmSharedObjectRef, + package: &str, + creation_timestamp: Option, + ) -> Result; +} pub struct MigrationMoveCallsTsSdk {} @@ -23,6 +40,18 @@ impl MigrationMoveCalls for MigrationMoveCallsTsSdk { migration_registry: OwnedObjectRef, package: ObjectID, ) -> anyhow::Result { - unimplemented!(); + let did_output = did_output.into(); + let package = package.to_string(); + let migration_registry = migration_registry.try_into()?; + + futures::executor::block_on(migrate_did_output_impl( + did_output, + migration_registry, + &package, + creation_timestamp, + )) + .map(|js_arr| js_arr.to_vec()) + .map_err(WasmError::from) + .map_err(Self::Error::from) } } diff --git a/bindings/wasm/iota_interaction_ts/src/transaction_builder.rs b/bindings/wasm/iota_interaction_ts/src/transaction_builder.rs index ad71a347d..9fa4dbd71 100644 --- a/bindings/wasm/iota_interaction_ts/src/transaction_builder.rs +++ b/bindings/wasm/iota_interaction_ts/src/transaction_builder.rs @@ -4,15 +4,12 @@ use std::ops::Deref; use std::ops::DerefMut; +use crate::bindings::WasmTransactionBuilder; use crate::error::TsSdkError; use identity_iota_interaction::ProgrammableTransactionBcs; use identity_iota_interaction::TransactionBuilderT; -// TODO: When the rust type wrapping the native TS transaction-builder has been -// developed, replace the NativeTsTransactionBuilderBindingWrapper type -// with the final type name (NativeTsTransactionBuilderBindingWrapper is -// also imported in identity_iota_core/src/rebased/...) -pub type NativeTsTransactionBuilderBindingWrapper = (); +pub type NativeTsTransactionBuilderBindingWrapper = WasmTransactionBuilder; pub struct TransactionBuilderTsSdk { pub(crate) builder: NativeTsTransactionBuilderBindingWrapper,