Ika dWallet Instructions
Veil integrates Ika’s dWallet infrastructure to allow native Bitcoin and Ethereum to be used as collateral on Solana without bridging. A dWallet is a programmable cross-chain wallet governed jointly by the user and Ika’s decentralised MPC network.
How it works:
- User creates a dWallet on the Ika network (via Ika SDK or the Veil frontend wizard)
- User transfers the dWallet’s authority to Veil’s CPI PDA
- User calls
IkaRegister— Veil verifies authority and creates anIkaDwalletPosition - The dWallet can now only sign Bitcoin/Ethereum transactions if Veil approves (via
IkaSign) - When the user wants to exit,
IkaReleasetransfers authority back and closes the position
Veil CPI Authority PDA: seeds ["__ika_cpi_authority"] on the Veil program ID
Ika Program ID: 87W54kGYFQ1rgWqMeu4XTPHWXWmXSQCcjm8vCTfiq1oY
IkaDwalletPosition Account
Discriminator: VEILIKA! · Size: 128 bytes
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 8 | discriminator | VEILIKA! |
| 8 | 32 | owner | User wallet |
| 40 | 32 | pool | Associated lending pool |
| 72 | 32 | dwallet | Ika dWallet account address |
| 104 | 8 | usd_value | Collateral value at registration (USD cents, u64) |
| 112 | 2 | curve | Curve type (see below) |
| 114 | 2 | signature_scheme | Signing scheme (see below) |
| 116 | 1 | status | 0 = Active, 1 = Released, 2 = Liquidated |
| 117 | 1 | bump | PDA bump |
| 118 | 10 | _pad | — |
PDA: seeds ["ika_pos", pool, user]
Curve Types
| Value | Constant | Chain |
|---|---|---|
| 0 | SECP256K1 | Bitcoin, Ethereum |
| 1 | SECP256R1 | WebAuthn |
| 2 | CURVE25519 | Solana, Ed25519 |
| 3 | RISTRETTO | Substrate / sr25519 |
Signature Schemes
| Value | Constant | Use Case |
|---|---|---|
| 0 | ECDSA_KECCAK256 | Ethereum transactions |
| 1 | ECDSA_SHA256 | Bitcoin legacy, WebAuthn |
| 2 | ECDSA_DOUBLE_SHA256 | Bitcoin BIP143 |
| 3 | TAPROOT_SHA256 | Bitcoin Taproot |
| 4 | ECDSA_BLAKE2B256 | Zcash |
| 5 | EDDSA_SHA512 | Ed25519 (Solana native) |
| 6 | SCHNORRKEL_MERLIN | Substrate sr25519 |
IkaRegister
Discriminator: 0x11 (17)
Register a dWallet as collateral. Verifies that the dWallet’s authority has been transferred to Veil’s CPI PDA, then creates an IkaDwalletPosition.
The dWallet authority must already be the Veil CPI PDA before this instruction is called. Use the Ika SDK’s transferDWalletAuthority (or the Veil frontend wizard) to perform this transfer first.
Accounts
| # | Name | Flags | Description |
|---|---|---|---|
| 0 | user | signer, writable | Must match dWallet’s previous authority transfer initiator |
| 1 | pool | readonly | Lending pool the position will be linked to |
| 2 | dwallet | readonly | Ika dWallet account (owned by Ika program) |
| 3 | ika_position | writable | New IkaDwalletPosition PDA — seeds: ["ika_pos", pool, user] |
| 4 | cpi_authority | readonly | Veil CPI authority PDA — seeds: ["__ika_cpi_authority"] |
| 5 | system_program | readonly | — |
Instruction Data
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 1 | discriminator | 0x11 |
| 1 | 8 | usd_value | Declared collateral value in USD cents (u64 LE) |
| 9 | 2 | curve | dWallet curve type (u16 LE) |
| 11 | 2 | signature_scheme | Signing scheme (u16 LE) |
| 13 | 1 | position_bump | Bump for the IkaDwalletPosition PDA |
| 14 | 1 | cpi_authority_bump | Bump for the CPI authority PDA |
Validation
The instruction verifies:
dwallet.discriminator == 2(Ika account type = dWallet)dwallet.state == 1(Active — DKG complete)dwallet.authority == cpi_authority— Veil already controls this dWallet
Example
import { ikaRegisterIx } from './lib/ika/instructions';
import { findCpiAuthority, findIkaPosition } from './lib/ika/pda';
import { DWalletCurve, SignatureScheme } from './lib/ika/types';
import { PROGRAM_ID } from './lib/veil/constants';
const [cpiAuthority, cpiAuthorityBump] = await findCpiAuthority(PROGRAM_ID);
const [ikaPosition, positionBump] = await findIkaPosition(pool, user, PROGRAM_ID);
const ix = ikaRegisterIx(
user,
pool,
dwalletAddress,
ikaPosition,
cpiAuthority,
1_200_000n, // $12,000.00 in cents
DWalletCurve.SECP256K1,
SignatureScheme.ECDSA_SHA256,
positionBump,
cpiAuthorityBump,
);IkaRelease
Discriminator: 0x12 (18)
Release a registered dWallet. CPIs transfer_dwallet on the Ika program to return authority to the user, then marks the position as Released.
Accounts
| # | Name | Flags | Description |
|---|---|---|---|
| 0 | user | signer, writable | Must be ika_position.owner |
| 1 | pool | readonly | — |
| 2 | dwallet | writable | Ika dWallet account |
| 3 | ika_position | writable | — |
| 4 | caller_program | readonly | Veil program ID |
| 5 | cpi_authority | readonly | — |
| 6 | ika_program | readonly | 87W54kGYFQ1rgWqMeu4XTPHWXWmXSQCcjm8vCTfiq1oY |
Instruction Data
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 1 | discriminator | 0x12 |
| 1 | 1 | cpi_authority_bump | Needed to sign the Ika CPI |
Example
import { ikaReleaseIx } from './lib/ika/instructions';
import { PROGRAM_ID } from './lib/veil/constants';
import { IKA_PROGRAM_ID } from './lib/ika/types';
const ix = ikaReleaseIx(
user,
pool,
dwalletAddress,
ikaPosition,
PROGRAM_ID,
cpiAuthority,
cpiAuthorityBump,
);IkaSign
Discriminator: 0x13 (19)
Approve a cross-chain message for signing by the Ika MPC network. CPIs approve_message on the Ika program, which creates a MessageApproval account that the Ika nodes observe and sign.
This is used for on-chain governance of Bitcoin/Ethereum transactions: only Veil can approve messages for a registered dWallet, so the MPC network won’t sign any transaction unless Veil’s program logic permits it.
Accounts
| # | Name | Flags | Description |
|---|---|---|---|
| 0 | user | signer, writable | Must be ika_position.owner |
| 1 | coordinator | readonly | Ika DWalletCoordinator PDA |
| 2 | message_approval | writable | New Ika MessageApproval PDA (created by this instruction) |
| 3 | dwallet | readonly | — |
| 4 | ika_position | readonly | Must be Active |
| 5 | caller_program | readonly | Veil program ID |
| 6 | cpi_authority | readonly | — |
| 7 | system_program | readonly | — |
| 8 | ika_program | readonly | — |
Instruction Data
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 1 | discriminator | 0x13 |
| 1 | 32 | message_digest | SHA-256 hash of the message to sign |
| 33 | 32 | message_metadata_digest | Metadata digest (zero-fill if unused) |
| 65 | 32 | user_pubkey | User’s 32-byte public key |
| 97 | 2 | signature_scheme | Signing scheme (u16 LE) |
| 99 | 1 | msg_approval_bump | Bump for the MessageApproval PDA |
| 100 | 1 | cpi_authority_bump | — |
Total instruction data: 101 bytes
Example
import { ikaSignIx } from './lib/ika/instructions';
import { findCoordinator, findMessageApproval } from './lib/ika/pda';
import { SignatureScheme } from './lib/ika/types';
import { PROGRAM_ID } from './lib/veil/constants';
const messageDigest = sha256(bitcoinTransaction); // 32 bytes
const metadataDigest = new Uint8Array(32); // zeros if unused
const [coordinator] = await findCoordinator();
const [messageApproval, msgApprovalBump] = await findMessageApproval(
dwalletAddress,
messageDigest,
metadataDigest,
SignatureScheme.ECDSA_SHA256,
);
const ix = ikaSignIx(
user,
coordinator,
messageApproval,
dwalletAddress,
ikaPosition,
PROGRAM_ID,
cpiAuthority,
messageDigest,
metadataDigest,
user.toBytes(),
SignatureScheme.ECDSA_SHA256,
msgApprovalBump,
cpiAuthorityBump,
);