Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

TestWhat It Verifies
test_create_proposal_successProposal PDA created with correct fields
test_create_proposal_already_existsFails when proposal account is non-empty
test_cast_vote_yes_successVote recorded, yes_votes incremented
test_cast_vote_no_successNo vote recorded, no_votes incremented
test_cast_vote_double_vote_failsSecond vote by same voter fails
test_cast_vote_closed_proposal_failsVoting 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:

  1. Wait for mock to initialize program state (DWalletCoordinator + NEK)
  2. Create dWallet via CommitDWallet
  3. Transfer authority to voting program’s CPI PDA
  4. Create a voting proposal (quorum = 3)
  5. Cast 3 YES votes (last triggers approve_message CPI)
  6. Verify MessageApproval PDA exists with status = Pending
  7. Sign with mock and verify signature on-chain

Assertions

The E2E test verifies:

  • dWallet authority matches CPI PDA after transfer
  • Proposal yes_votes = 3 and status = Approved after quorum
  • MessageApproval exists with correct dwallet and message_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>