dWallet Accounts
Pre-Alpha Disclaimer: This is an early pre-alpha release for exploring the SDK and starting development only. There is no real MPC signing — all signatures are generated by a single mock signer, not a distributed network. Do not submit any real transactions for signing or rely on any security guarantees. The dWallet keys, trust model, and signing protocol are not final; do not rely on any key material until mainnet. All interfaces, APIs, and data formats are subject to change without notice. The Solana program and all on-chain data will be wiped periodically and everything will be deleted when we transition to Ika Alpha 1. This software is provided “as is” without warranty of any kind; use is entirely at your own risk and dWallet Labs assumes no liability for any damages arising from its use.
Overview
A dWallet is an on-chain account that represents a distributed signing key. It is created through Distributed Key Generation (DKG) and stored as a PDA owned by the dWallet program.
DWallet Account Layout
DWallet PDA:
Seeds: ["dwallet", curve_byte, public_key_bytes]
Program: DWALLET_PROGRAM_ID
| Offset | Field | Size | Description |
|---|---|---|---|
| 0 | discriminator | 1 | Account type identifier |
| 1 | version | 1 | 1 |
| 2 | authority | 32 | Who can approve messages (user or CPI PDA) |
| 34 | public_key | 65 | dWallet public key (padded to 65 bytes) |
| 99 | public_key_len | 1 | Actual public key length (32 or 33) |
| 100 | curve | 1 | Curve type identifier |
| 101 | is_imported | 1 | Whether the key was imported vs created |
The authority field determines who can call approve_message for this dWallet:
- A user pubkey – the user signs the
approve_messageinstruction directly - A CPI authority PDA – a program controls the dWallet via CPI
Creating a dWallet
dWallets are created through the gRPC API, not directly on-chain. The flow:
- User sends a
DKGrequest via gRPC with their key share - The Ika network runs the 2PC-MPC DKG protocol
- The NOA calls
CommitDWalleton-chain to create the dWallet account - The dWallet’s authority is set to the user
#![allow(unused)]
fn main() {
// Client-side: request DKG via gRPC
let request = DWalletRequest::DKG {
dwallet_network_encryption_public_key: nek_bytes,
curve: DWalletCurve::Secp256k1,
centralized_public_key_share_and_proof: user_share,
encrypted_centralized_secret_share_and_proof: encrypted_share,
encryption_key: enc_key,
user_public_output: user_output,
signer_public_key: signer_pk,
};
}
Transferring Authority
To give a program control over a dWallet, transfer its authority to the program’s CPI authority PDA:
#![allow(unused)]
fn main() {
// Derive the CPI authority PDA for your program
let (cpi_authority, _) = Pubkey::find_program_address(
&[b"__ika_cpi_authority"],
&your_program_id,
);
// TransferOwnership instruction (called by current authority)
let ix = Instruction::new_with_bytes(
dwallet_program_id,
&transfer_data, // [IX_TRANSFER_OWNERSHIP, new_authority(32)]
vec![
AccountMeta::new_readonly(current_authority, true), // signer
AccountMeta::new(dwallet_pda, false), // writable
],
);
}
After transfer, the dWallet’s authority field equals the CPI authority PDA, and only the owning program can approve messages.
Via CPI (Program-to-Program Transfer)
If a program already controls a dWallet, it can transfer authority to another program’s CPI PDA:
#![allow(unused)]
fn main() {
let ctx = DWalletContext {
dwallet_program,
cpi_authority,
caller_program,
cpi_authority_bump,
};
ctx.transfer_dwallet(dwallet, new_authority)?;
}
Supported Curves
| Curve | ID | Key Size | Chains |
|---|---|---|---|
| Secp256k1 | 0 | 33 bytes (compressed) | Bitcoin, Ethereum, BSC |
| Secp256r1 | 1 | 33 bytes (compressed) | WebAuthn, Apple Secure Enclave |
| Curve25519 | 2 | 32 bytes | Solana, Sui, general Ed25519 |
| Ristretto | 3 | 32 bytes | Substrate, Polkadot |
Reading dWallet Data Off-Chain
The ika-solana-sdk-types crate provides PDA derivation helpers:
#![allow(unused)]
fn main() {
use ika_sdk_types::pda::*;
let (system_state, _) = find_system_state_address(&program_id);
let (validator, _) = find_validator_address(&program_id, &identity);
let (validator_list, _) = find_validator_list_address(&program_id);
}