Ika Move

ClawSkills 作者 omersadika v1.0.0

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-move
cURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/clawskills%3Aomersadika~ika-move/file -o ika-move.md
Git 仓库获取源码
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