Testing
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.
The voting example includes tests at two levels: Mollusk (instruction-level) and E2E (full lifecycle).
Mollusk Tests
Mollusk tests verify individual instructions in isolation. No validator needed.
#![allow(unused)]
fn main() {
use mollusk_svm::Mollusk;
use solana_instruction::Instruction;
fn setup() -> (Mollusk, Pubkey) {
let program_id = Pubkey::new_unique();
let mollusk = Mollusk::new(&program_id, PROGRAM_PATH);
(mollusk, program_id)
}
#[test]
fn test_create_proposal_success() {
let (mollusk, program_id) = setup();
let creator = Pubkey::new_unique();
let proposal_id = [0x01u8; 32];
let (proposal_pda, proposal_bump) =
Pubkey::find_program_address(&[b"proposal", &proposal_id], &program_id);
let ix = build_create_proposal_ix(/* ... */);
let result = mollusk.process_instruction(&ix, &accounts);
assert!(result.program_result.is_ok());
let prop_data = &result.resulting_accounts[0].1.data;
assert_eq!(prop_data[0], 1); // discriminator
assert_eq!(read_u32(prop_data, 171), 3); // quorum
}
}
What to Test with Mollusk
| Test | What It Verifies |
|---|---|
test_create_proposal_success | Proposal PDA created with correct fields |
test_create_proposal_already_exists | Fails when proposal account is non-empty |
test_cast_vote_yes_success | Vote recorded, yes_votes incremented |
test_cast_vote_no_success | No vote recorded, no_votes incremented |
test_cast_vote_double_vote_fails | Second vote by same voter fails |
test_cast_vote_closed_proposal_fails | Voting on approved proposal fails |
Mollusk is fast (no network, no runtime startup) and tests instruction logic in isolation. However, it cannot test the CPI path (quorum triggering approve_message) because it runs a single program.
E2E Tests
The E2E demo runs the full lifecycle against Solana devnet and the pre-alpha dWallet gRPC service at pre-alpha-dev-1.ika.ika-network.net:443:
cargo run -p e2e-voting -- <DWALLET_PROGRAM_ID> <VOTING_PROGRAM_ID>
The E2E test performs all 7 steps:
- Wait for mock to initialize program state (DWalletCoordinator + NEK)
- Create dWallet via
CommitDWallet - Transfer authority to voting program’s CPI PDA
- Create a voting proposal (quorum = 3)
- Cast 3 YES votes (last triggers
approve_messageCPI) - Verify MessageApproval PDA exists with status = Pending
- Sign with mock and verify signature on-chain
Assertions
The E2E test verifies:
- dWallet authority matches CPI PDA after transfer
- Proposal
yes_votes= 3 andstatus= Approved after quorum - MessageApproval exists with correct
dwalletandmessage_hash - Signature is committed and readable
See chains/solana/examples/voting/e2e/src/main.rs for the full implementation.
Running Tests
# Mollusk tests (fast, no validator)
cargo test -p ika-example-voting
# E2E (runs against devnet)
cd chains/solana/examples/voting/e2e
cargo run -- <DWALLET_PROGRAM_ID> <VOTING_PROGRAM_ID>