Ika Move
Guide for integrating Ika dWallet 2PC-MPC protocol into Sui Move contracts. Use when building Move contracts that need cross-chain signing, dWallet creation, presigning, signing, future signing, key importing, or any Ika on-chain integration. Triggers on Move/Sui contract tasks involving dWallets, cross-chain signing, or Ika protocol operations.
安装 / 下载方式
TotalClaw CLI推荐
totalclaw install clawskills:omersadika~ika-movecURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/clawskills%3Aomersadika~ika-move/file -o ika-move.mdGit 仓库获取源码
git clone https://github.com/openclaw/skills/commit/0dc34723ca27e01f5729938db331b7c95948bbae# Ika Move Integration
Build Sui Move contracts integrating Ika dWallet 2PC-MPC for programmable cross-chain signing.
## References (detailed patterns and complete code)
- `references/protocols-detailed.md` - All coordinator function signatures with full parameter lists
- `references/patterns.md` - Complete integration patterns: treasury, DAO governance, imported key wallet, presign pool, events, enums
- `references/typescript-integration.md` - Full TypeScript SDK flows: DKG prep, signing, key import, polling, IkaTransaction API
## Setup
### Move.toml
```toml
[package]
name = "my_project"
edition = "2024.beta"
[dependencies]
Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" }
ika_dwallet_2pc_mpc = { git = "https://github.com/dwallet-labs/ika.git", subdir = "deployed_contracts/testnet/ika_dwallet_2pc_mpc", rev = "main" }
ika = { git = "https://github.com/dwallet-labs/ika.git", subdir = "deployed_contracts/testnet/ika", rev = "main" }
[addresses]
my_project = "0x0"
```
For mainnet: change `testnet` to `mainnet` in paths.
### TypeScript SDK
```bash
pnpm add @ika.xyz/sdk
```
```typescript
import { getNetworkConfig, IkaClient } from '@ika.xyz/sdk';
import { getJsonRpcFullnodeUrl, SuiJsonRpcClient } from '@mysten/sui/jsonRpc';
const suiClient = new SuiJsonRpcClient({ url: getJsonRpcFullnodeUrl('testnet'), network: 'testnet' });
const ikaClient = new IkaClient({ suiClient, config: getNetworkConfig('testnet'), cache: true });
await ikaClient.initialize();
```
## Crypto Constants
### Curves
- `0` = SECP256K1 (Bitcoin, Ethereum)
- `1` = SECP256R1 (WebAuthn)
- `2` = ED25519 (Solana, Substrate)
- `3` = RISTRETTO (Privacy)
### Signature Algorithms (relative to curve)
- SECP256K1: `0`=ECDSA, `1`=Taproot
- SECP256R1: `0`=ECDSA
- ED25519: `0`=EdDSA
- RISTRETTO: `0`=Schnorrkel
### Hash Schemes (relative to curve+algo)
- SECP256K1+ECDSA: `0`=KECCAK256(Ethereum), `1`=SHA256, `2`=DoubleSHA256(Bitcoin)
- SECP256K1+Taproot: `0`=SHA256
- SECP256R1+ECDSA: `0`=SHA256
- ED25519+EdDSA: `0`=SHA512
- RISTRETTO+Schnorrkel: `0`=Merlin
## Core Imports
```rust
use ika::ika::IKA;
use ika_dwallet_2pc_mpc::{
coordinator::DWalletCoordinator,
coordinator_inner::{
DWalletCap, ImportedKeyDWalletCap,
UnverifiedPresignCap, VerifiedPresignCap,
UnverifiedPartialUserSignatureCap, VerifiedPartialUserSignatureCap,
MessageApproval, ImportedKeyMessageApproval
},
sessions_manager::SessionIdentifier
};
use sui::{balance::Balance, coin::Coin, sui::SUI};
```
## Contract Template
```rust
public struct MyContract has key, store {
id: UID,
dwallet_cap: DWalletCap,
presigns: vector<UnverifiedPresignCap>,
ika_balance: Balance<IKA>,
sui_balance: Balance<SUI>,
dwallet_network_encryption_key_id: ID,
}
```
### Required Helpers
```rust
fun random_session(coordinator: &mut DWalletCoordinator, ctx: &mut TxContext): SessionIdentifier {
coordinator.register_session_identifier(ctx.fresh_object_address().to_bytes(), ctx)
}
fun withdraw_payment_coins(self: &mut MyContract, ctx: &mut TxContext): (Coin<IKA>, Coin<SUI>) {
let ika = self.ika_balance.withdraw_all().into_coin(ctx);
let sui = self.sui_balance.withdraw_all().into_coin(ctx);
(ika, sui)
}
fun return_payment_coins(self: &mut MyContract, ika: Coin<IKA>, sui: Coin<SUI>) {
self.ika_balance.join(ika.into_balance());
self.sui_balance.join(sui.into_balance());
}
public fun add_ika_balance(self: &mut MyContract, coin: Coin<IKA>) {
self.ika_balance.join(coin.into_balance());
}
public fun add_sui_balance(self: &mut MyContract, coin: Coin<SUI>) {
self.sui_balance.join(coin.into_balance());
}
```
## DWalletCoordinator
Central shared object for all operations. Pass as `&mut DWalletCoordinator` for mutations, `&DWalletCoordinator` for reads.
Get ID in TypeScript: `ikaClient.ikaConfig.objects.ikaDWalletCoordinator.objectID`
## Capabilities
| Capability | Purpose | Created By |
|---|---|---|
| `DWalletCap` | Authorize signing | DKG |
| `ImportedKeyDWalletCap` | Authorize imported key signing | Import verification |
| `UnverifiedPresignCap` | Presign reference (needs verify) | Presign request |
| `VerifiedPresignCap` | Ready for signing | `verify_presign_cap()` |
| `UnverifiedPartialUserSignatureCap` | Partial sig (needs verify) | Future sign |
| `VerifiedPartialUserSignatureCap` | Ready for completion | `verify_partial_user_signature_cap()` |
| `MessageApproval` | Auth to sign specific message | `approve_message()` |
| `ImportedKeyMessageApproval` | Auth for imported keys | `approve_imported_key_message()` |
## SessionIdentifier
Every protocol op needs a unique `SessionIdentifier`. Create via:
```rust
let session = coordinator.register_session_identifier(ctx.fresh_object_address().to_bytes(), ctx);
```
Rules: create just before use, never reuse, one per operation.
## Payment Pattern
All ops require IKA+SUI fees. Pattern: withdraw all -> perform ops (fees auto-deducted from `&mut Coin`) -> return remainder.
## Protocol: DKG (Create dWallet)
### Shared dWallet (recommended for contracts)
Public user share, network signs without user interaction.
```rust
let (dwallet_cap, _) = coordinator.request_dwallet_dkg_with_public_user_secret_key_share(
dwallet_network_encryption_key_id, curve,
centralized_public_key_share_and_proof, user_public_output, public_user_secret_key_share,
option::none(), // sign_during_dkg_request
session, &mut ika, &mut sui, ctx,
);
```
### Zero-Trust dWallet
Encrypted user share, user must participate in every signature.
```rust
let (dwallet_cap, _) = coordinator.request_dwallet_dkg(
dwallet_network_encryption_key_id, curve,
centralized_public_key_share_and_proof, encrypted_centralized_secret_share_and_proof,
encryption_key_address, user_public_output, signer_public_key,
option::none(), session, &mut ika, &mut sui, ctx,
);
```
**Important:** After zero-trust DKG (or key import), the dWallet is in `AwaitingKeyHolderSignature` state. The user must call `acceptEncryptedUserShare` to transition the dWallet to `Active` state before it can be used for signing:
```typescript
// Wait for DKG to complete and dWallet to reach AwaitingKeyHolderSignature state
const awaitingDWallet = await ikaClient.getDWalletInParticularState(dwalletId, 'AwaitingKeyHolderSignature');
// The encrypted user secret key share ID comes from the DKG transaction event,
// NOT from the dWallet ID.
const encryptedShare = await ikaClient.getEncryptedUserSecretKeyShare(encryptedUserSecretKeyShareId);
const tx = new Transaction();
const ikaTx = new IkaTransaction({ ikaClient, transaction: tx, userShareEncryptionKeys: keys });
await ikaTx.acceptEncryptedUserShare({
dWallet: awaitingDWallet,
encryptedUserSecretKeyShareId: encryptedShare.id,
userPublicOutput: new Uint8Array(dkgData.userPublicOutput),
});
await suiClient.core.signAndExecuteTransaction({ transaction: tx, signer: keypair });
// dWallet is now Active and ready for signing
const activeDWallet = await ikaClient.getDWalletInParticularState(dwalletId, 'Active');
```
This step is NOT needed for shared dWallets (created with `request_dwallet_dkg_with_public_user_secret_key_share`).
### TypeScript DKG Prep
```typescript
import { prepareDKGAsync, UserShareEncryptionKeys, Curve, createRandomSessionIdentifier } from '@ika.xyz/sdk';
const keys = await UserShareEncryptionKeys.fromRootSeedKey(seed, Curve.SECP256K1);
const bytesToHash = createRandomSessionIdentifier(); // bytes hashed to derive the session identifier
const dkgData = await prepareDKGAsync(ikaClient, Curve.SECP256K1, keys, bytesToHash, signerAddress);
const networkKey = await ikaClient.getLatestNetworkEncryptionKey();
// dkgData has: userDKGMessage, userPublicOutput, encryptedUserShareAndProof, userSecretKeyShare
```
### Sign During DKG (optional)
Pass existing presign to get signature during DKG:
```rust
le