commit c3f4480118ba27c913b7f6d29c328035a65ddad2
parent 914cd0f2145e3c26c52993b0e93a184418ad9bcf
Author: Joris Hartog <jorishartog@hotmail.com>
Date: Sun, 27 Sep 2026 11:50:48 +0200
fix(wallet): include hybrid rewards in balance
Diffstat:
10 files changed, 263 insertions(+), 35 deletions(-)
diff --git a/src/adapters/http/ui.rs b/src/adapters/http/ui.rs
@@ -331,6 +331,15 @@ pub(super) fn populate_wallet_reward_flow(row: &mut WalletTransactionRow, block:
.collect();
}
+pub(crate) fn mark_wallet_reward_row(row: &mut WalletTransactionRow, block: Option<&Block>) {
+ row.kind = "reward";
+ row.from = "fees".to_string();
+ row.direction = "reward";
+ if let Some(block) = block {
+ populate_wallet_reward_flow(row, block);
+ }
+}
+
fn transaction_kind(transaction: &Transaction) -> &'static str {
match transaction {
Transaction::Transfer { .. } => "transfer",
@@ -1052,7 +1061,7 @@ mod tests {
};
use super::{
- block_lost_iuna, populate_wallet_reward_flow, ui_block, ui_blocks_from_indexes,
+ block_lost_iuna, mark_wallet_reward_row, ui_block, ui_blocks_from_indexes,
ui_transaction_v2, wallet_transaction_row, wallet_transaction_v2_rows,
};
use crate::adapters::http::types::{WalletTransactionContext, WalletTransactionFilters};
@@ -1244,7 +1253,6 @@ mod tests {
},
)
.unwrap();
- row.kind = "reward";
let committee_row = wallet_transaction_row(
"committee",
&reward_projection,
@@ -1288,8 +1296,11 @@ mod tests {
hash: "block".to_string(),
};
- populate_wallet_reward_flow(&mut row, &block);
+ mark_wallet_reward_row(&mut row, Some(&block));
+ assert_eq!(row.kind, "reward");
+ assert_eq!(row.from, "fees");
+ assert_eq!(row.direction, "reward");
assert_eq!(row.reward_fee_inputs.len(), 2);
assert_eq!(row.reward_total, Some(5));
assert_eq!(row.reward_fee_inputs[0].transaction_kind, "transfer");
diff --git a/src/adapters/wallet_endpoint.rs b/src/adapters/wallet_endpoint.rs
@@ -22,9 +22,9 @@ use crate::{
http::{
types::{WalletTransactionContext, WalletTransactionFilters, WalletTransactionRow},
ui::{
- add_pending_outputs, add_pending_v2_outputs, transaction_v2_input_outpoints,
- wallet_transaction_row_for_addresses, wallet_transaction_rows,
- wallet_transaction_v2_row, wallet_transaction_v2_rows,
+ add_pending_outputs, add_pending_v2_outputs, mark_wallet_reward_row,
+ transaction_v2_input_outpoints, wallet_transaction_row_for_addresses,
+ wallet_transaction_rows, wallet_transaction_v2_row, wallet_transaction_v2_rows,
},
},
p2p::GossipNetwork,
@@ -45,7 +45,8 @@ use crate::{
// over twice the consensus block budget.
const MAX_TRANSACTION_BODY_BYTES: usize = MAX_BLOCK_BYTES * 2 + 4 * 1024;
const MAX_CONCURRENT_TRANSACTION_SUBMISSIONS: usize = 32;
-const MAX_WALLET_ADDRESSES: usize = 10_001;
+// One legacy address plus the maximum external and reward address branches.
+const MAX_WALLET_ADDRESSES: usize = 20_001;
#[derive(Clone)]
struct WalletEndpointState {
@@ -605,10 +606,22 @@ async fn wallet_transactions(
.map_err(internal_error)?
.map_err(internal_error)?
};
+ let reward_blocks = {
+ let node = state.node.lock().await;
+ legacy_rows
+ .iter()
+ .filter(|row| row.kind == "reward")
+ .filter_map(|row| {
+ let block = node.chain().get(row.block_height as usize)?.clone();
+ Some((row.block_height, block))
+ })
+ .collect::<BTreeMap<_, _>>()
+ };
let mut confirmed = legacy_rows
.into_iter()
.filter_map(|row| {
- wallet_transaction_row_for_addresses(
+ let is_reward = row.kind == "reward";
+ let mut item = wallet_transaction_row_for_addresses(
&addresses,
&row.transaction,
&confirmed_outputs,
@@ -618,8 +631,11 @@ async fn wallet_transactions(
timestamp_ms: Some(row.timestamp_ms),
block_finalizer: Some(row.block_finalizer),
},
- )
- .map(|item| (row.sort_key, item))
+ )?;
+ if is_reward {
+ mark_wallet_reward_row(&mut item, reward_blocks.get(&row.block_height));
+ }
+ Some((row.sort_key, item))
})
.collect::<Vec<_>>();
confirmed.extend(decoded_v2.into_iter().filter_map(|(row, transaction)| {
diff --git a/src/domain/wallet.rs b/src/domain/wallet.rs
@@ -485,6 +485,47 @@ mod tests {
}
#[test]
+ fn browser_reward_transfer_vector_matches_node_encoding_and_signatures() {
+ let wallet = Wallet::from_seed("hybrid-wallet-seed");
+ let owner = wallet.hybrid_versioned_address_at(HybridAddressBranch::Reward, 0);
+ let recipient = wallet.hybrid_versioned_address_at(HybridAddressBranch::External, 1);
+ let change = wallet.hybrid_versioned_address_at(HybridAddressBranch::External, 2);
+ let domain = TransactionV2Domain::new("iuna-mainnet-candidate", [0x11; 32]).unwrap();
+ let mut transaction = TransactionV2::Transfer {
+ inputs: vec![TransactionV2Input {
+ outpoint_txid: [0x44; 32],
+ outpoint_index: 8,
+ owner,
+ }],
+ outputs: vec![
+ TransactionV2Output {
+ address: recipient,
+ amount: 1_000_000,
+ },
+ TransactionV2Output {
+ address: change,
+ amount: 995_921,
+ },
+ ],
+ fee: 4_079,
+ authorizations: Vec::new(),
+ };
+ let payload = transaction.signing_bytes(&domain).unwrap();
+ let authorization = wallet.sign_v2_authorization(owner, &payload).unwrap();
+ let TransactionV2::Transfer { authorizations, .. } = &mut transaction else {
+ unreachable!();
+ };
+ authorizations.push(authorization);
+
+ transaction.verify_authorizations(&domain).unwrap();
+ assert_eq!(transaction.encoded_size_bytes(&domain).unwrap(), 4_079);
+ assert_eq!(
+ hex_encode(transaction.transaction_id(&domain).unwrap()),
+ "558cee1dfa1425e0b214681445e3d0641a898e15245f80d4524d2b98d762df88"
+ );
+ }
+
+ #[test]
fn browser_v2_migration_vector_matches_node_encoding_and_signature() {
let wallet = Wallet::from_seed("hybrid-wallet-seed");
let owner = wallet.legacy_versioned_address();
@@ -602,6 +643,14 @@ mod tests {
);
assert_ne!(external_one, external_zero);
assert_ne!(reward_zero, external_one);
+ assert_eq!(
+ Wallet::from_seed("hybrid-wallet-seed").hybrid_address_at(
+ HybridAddressBranch::Reward,
+ 0,
+ AddressNetwork::Mainnet,
+ ),
+ "iuna1pvxpc35gavamxw0tvqj3ms82gwtvchh7mdyzqdttx7ktx7pfkgz4qkaq24k"
+ );
let authorization = first
.sign_v2_authorization(external_one, b"rotated child spend")
diff --git a/tests/lightweight-wallet.test.cjs b/tests/lightweight-wallet.test.cjs
@@ -104,6 +104,11 @@ test('browser crypto derives the same rotating hybrid address vectors as the nod
{ index: 0, address: 'iuna1py9qlrnw6cm3mpz26hwwkww9spaa96zrw2g34gu0p4y3ea5cqhg0qa82x9s' },
{ index: 1, address: 'iuna1pkxdcktlzf5tc2p59xns2nccq7rg5zjhwg2zn5r9u73c5j9jxgk8s0e5l4e' },
]);
+ const rewardAddresses = JSON.parse(quantum.derive_reward_addresses('hybrid-wallet-seed', 2, 'iuna-mainnet-v1'));
+ assert.deepEqual(rewardAddresses, [
+ { index: 0, address: 'iuna1pvxpc35gavamxw0tvqj3ms82gwtvchh7mdyzqdttx7ktx7pfkgz4qkaq24k' },
+ { index: 1, address: 'iuna1p6cj9c3ths75p7vnsdx9tgkvu4jlzs8cxpnh2lc4klsu5fvd0cpxq8ypw45' },
+ ]);
const built = JSON.parse(quantum.build_transfer(JSON.stringify({
seed: 'hybrid-wallet-seed',
@@ -123,6 +128,25 @@ test('browser crypto derives the same rotating hybrid address vectors as the nod
assert.equal(built.envelope.length / 2, 4079);
assert.equal(built.transactionId, 'bda748b6ba9fd6550ca47d580f980a1c00d0050a20992750265a62d23b0b590d');
+ const rewardBuilt = JSON.parse(quantum.build_transfer(JSON.stringify({
+ seed: 'hybrid-wallet-seed',
+ chainId: 'iuna-mainnet-candidate',
+ genesisHash: '11'.repeat(32),
+ recipientAddress: addresses[1].address,
+ amount: '1000000',
+ feeRate: '1',
+ changeIndex: 2,
+ utxos: [{
+ addressBranch: 'reward',
+ addressIndex: 0,
+ outpoint: { txid: '44'.repeat(32), index: 8 },
+ output: { amount: 2000000 },
+ }],
+ })));
+ assert.equal(rewardBuilt.fee, '4079');
+ assert.equal(rewardBuilt.inputCount, 1);
+ assert.equal(rewardBuilt.transactionId, '558cee1dfa1425e0b214681445e3d0641a898e15245f80d4524d2b98d762df88');
+
const migration = JSON.parse(quantum.build_migration(JSON.stringify({
seed: 'hybrid-wallet-seed',
chainId: 'iuna-mainnet-candidate',
diff --git a/wallet/app.js b/wallet/app.js
@@ -8,6 +8,7 @@ import initQuantumCrypto, {
build_migration as buildQuantumMigration,
build_transfer as buildQuantumTransfer,
derive_external_addresses as deriveExternalAddresses,
+ derive_reward_addresses as deriveRewardAddresses,
} from "./crypto/iuna_wallet_crypto.js";
const app = document.querySelector("#app");
@@ -17,7 +18,7 @@ const ALL_TRANSACTION_FILTERS = { transfer: true, mine: true, burn: true, reward
const state = {
store: null, wallet: null, walletMeta: null, status: null, address: "", balance: null,
addresses: [], addressIndex: 0, legacyAddress: "", legacyUtxos: [], hybridUtxos: [],
- derivedAddresses: [], derivedWalletId: null,
+ derivedAddresses: [], derivedRewardAddresses: [], derivedWalletId: null,
hybridSpendable: 0, utxos: [], transactions: [], recentTransactions: [], view: "home", timer: null,
transactionFilters: { ...ALL_TRANSACTION_FILTERS },
transactionPage: { offset: 0, total: 0, hasMore: true, loading: false, error: "" },
@@ -164,37 +165,62 @@ async function fetchWalletData() {
if (Number(state.status.api_version || 0) < 2) throw new Error("The public iuna endpoint must be upgraded for rotating quantum-resistant wallets");
await ensureQuantumCrypto();
const gapLimit = Math.max(1, Number(state.status.hybrid_address_gap_limit || 20));
- let count = gapLimit + 1;
+ let externalCount = gapLimit + 1;
+ let rewardCount = gapLimit;
let derived;
+ let rewardDerived;
const derivationScope = `${state.walletMeta.id}:${state.status.chain_id}`;
if (state.derivedWalletId !== derivationScope) {
state.derivedAddresses = [];
+ state.derivedRewardAddresses = [];
state.derivedWalletId = derivationScope;
}
for (;;) {
- if (state.derivedAddresses.length < count) {
- state.derivedAddresses = JSON.parse(deriveExternalAddresses(state.wallet.seedPhrase, count, state.status.chain_id));
+ if (state.derivedAddresses.length < externalCount) {
+ state.derivedAddresses = JSON.parse(deriveExternalAddresses(state.wallet.seedPhrase, externalCount, state.status.chain_id));
}
- derived = state.derivedAddresses.slice(0, count);
- snapshot = await fetchSnapshot([state.legacyAddress, ...derived.map((item) => item.address)]);
+ if (state.derivedRewardAddresses.length < rewardCount) {
+ state.derivedRewardAddresses = JSON.parse(deriveRewardAddresses(state.wallet.seedPhrase, rewardCount, state.status.chain_id));
+ }
+ derived = state.derivedAddresses.slice(0, externalCount);
+ rewardDerived = state.derivedRewardAddresses.slice(0, rewardCount);
+ snapshot = await fetchSnapshot([
+ state.legacyAddress,
+ ...derived.map((item) => item.address),
+ ...rewardDerived.map((item) => item.address),
+ ]);
const used = new Set(snapshot.addresses.filter((item) => item.used).map((item) => item.address));
- const highestUsed = derived.reduce((highest, item) => used.has(item.address) ? Math.max(highest, item.index) : highest, -1);
- if (highestUsed < count - gapLimit || count >= 10_000) break;
- count = Math.min(10_000, highestUsed + gapLimit + 1);
+ const highestExternal = derived.reduce((highest, item) => used.has(item.address) ? Math.max(highest, item.index) : highest, -1);
+ const highestReward = rewardDerived.reduce((highest, item) => used.has(item.address) ? Math.max(highest, item.index) : highest, -1);
+ const nextExternalCount = highestExternal < externalCount - gapLimit || externalCount >= 10_000
+ ? externalCount
+ : Math.min(10_000, highestExternal + gapLimit + 1);
+ const nextRewardCount = highestReward < rewardCount - gapLimit || rewardCount >= 10_000
+ ? rewardCount
+ : Math.min(10_000, highestReward + gapLimit + 1);
+ if (nextExternalCount === externalCount && nextRewardCount === rewardCount) break;
+ externalCount = nextExternalCount;
+ rewardCount = nextRewardCount;
}
const used = new Set(snapshot.addresses.filter((item) => item.used).map((item) => item.address));
const highestUsed = derived.reduce((highest, item) => used.has(item.address) ? Math.max(highest, item.index) : highest, -1);
state.addressIndex = highestUsed + 1;
const current = derived.find((item) => item.index === state.addressIndex);
if (!current) throw new Error("Wallet address discovery exceeded its recovery limit");
- state.addresses = [state.legacyAddress, ...derived.map((item) => item.address)];
+ state.addresses = [
+ state.legacyAddress,
+ ...derived.map((item) => item.address),
+ ...rewardDerived.map((item) => item.address),
+ ];
state.address = current.address;
- const indexByAddress = new Map(derived.map((item) => [item.address, item.index]));
+ const descriptorByAddress = new Map([
+ ...derived.map((item) => [item.address, { addressIndex: item.index, addressBranch: "external" }]),
+ ...rewardDerived.map((item) => [item.address, { addressIndex: item.index, addressBranch: "reward" }]),
+ ]);
state.legacyUtxos = (snapshot.utxos || []).filter((utxo) => utxo.address === state.legacyAddress);
- state.hybridUtxos = (snapshot.utxos || []).filter((utxo) => indexByAddress.has(utxo.address)).map((utxo) => ({
- ...utxo,
- addressIndex: indexByAddress.get(utxo.address),
- }));
+ state.hybridUtxos = (snapshot.utxos || [])
+ .filter((utxo) => descriptorByAddress.has(utxo.address))
+ .map((utxo) => ({ ...utxo, ...descriptorByAddress.get(utxo.address) }));
state.hybridSpendable = snapshot.addresses.filter((item) => item.version === 1).reduce((sum, item) => sum + Number(item.spendable || 0), 0);
} else {
snapshot = await fetchSnapshot([state.legacyAddress]);
diff --git a/wallet/crypto-wasm/src/lib.rs b/wallet/crypto-wasm/src/lib.rs
@@ -45,10 +45,29 @@ struct TransferRequest {
#[serde(rename_all = "camelCase")]
struct HybridUtxo {
address_index: u32,
+ #[serde(default)]
+ address_branch: HybridAddressBranch,
outpoint: Outpoint,
output: Output,
}
+#[derive(Clone, Copy, Default, Deserialize)]
+#[serde(rename_all = "lowercase")]
+enum HybridAddressBranch {
+ #[default]
+ External,
+ Reward,
+}
+
+impl HybridAddressBranch {
+ fn domain_label(self) -> &'static str {
+ match self {
+ Self::External => "external",
+ Self::Reward => "reward",
+ }
+ }
+}
+
#[derive(Deserialize, Clone)]
struct Outpoint {
txid: String,
@@ -92,12 +111,30 @@ pub fn derive_external_addresses(
count: u32,
network_id: &str,
) -> Result<String, JsValue> {
+ derive_addresses(seed, count, network_id, HybridAddressBranch::External)
+}
+
+#[wasm_bindgen]
+pub fn derive_reward_addresses(
+ seed: &str,
+ count: u32,
+ network_id: &str,
+) -> Result<String, JsValue> {
+ derive_addresses(seed, count, network_id, HybridAddressBranch::Reward)
+}
+
+fn derive_addresses(
+ seed: &str,
+ count: u32,
+ network_id: &str,
+ branch: HybridAddressBranch,
+) -> Result<String, JsValue> {
if count == 0 || count > 10_000 {
return Err(js_error("address count must be between 1 and 10000"));
}
let addresses = (0..count)
.map(|index| {
- let (_, _, address) = hybrid_key(seed, index);
+ let (_, _, address) = hybrid_key(seed, branch, index);
DerivedAddress {
index,
address: encode_address(address, network_id),
@@ -154,7 +191,11 @@ pub fn build_transfer(request_json: &str) -> Result<String, JsValue> {
let mut outputs = vec![(recipient, amount)];
let change = total - required;
if change > 0 {
- let (_, _, change_address) = hybrid_key(&request.seed, request.change_index);
+ let (_, _, change_address) = hybrid_key(
+ &request.seed,
+ HybridAddressBranch::External,
+ request.change_index,
+ );
outputs.push((change_address, change));
}
let size = transfer_encoded_size(&request.chain_id, selected.len(), outputs.len());
@@ -185,7 +226,11 @@ pub fn build_transfer(request_json: &str) -> Result<String, JsValue> {
"v2 transaction ID",
)?);
signing.extend_from_slice(&input.outpoint.index.to_be_bytes());
- let (_, _, owner) = hybrid_key(&request.seed, input.address_index);
+ let (_, _, owner) = hybrid_key(
+ &request.seed,
+ input.address_branch,
+ input.address_index,
+ );
encode_address_bytes(&mut signing, owner);
}
encode_outputs(&mut signing, &outputs)?;
@@ -194,7 +239,11 @@ pub fn build_transfer(request_json: &str) -> Result<String, JsValue> {
let mut envelope = signing.clone();
push_u32(&mut envelope, selected.len())?;
for input in &selected {
- let (public_key, ml_seed, _) = hybrid_key(&request.seed, input.address_index);
+ let (public_key, ml_seed, _) = hybrid_key(
+ &request.seed,
+ input.address_branch,
+ input.address_index,
+ );
let signature = hybrid_signature(&request.seed, ml_seed, &signing)?;
encode_authorization(&mut envelope, 2, &public_key, &signature)?;
}
@@ -232,7 +281,11 @@ pub fn build_migration(request_json: &str) -> Result<String, JsValue> {
.ok_or_else(|| js_error("migration fee exceeds the available legacy balance"))?;
let ed_seed = derive_seed(ED_SEED_DOMAIN, &request.seed);
let ed_public = SigningKey::from_bytes(&ed_seed).verifying_key().to_bytes();
- let (_, _, destination) = hybrid_key(&request.seed, request.destination_index);
+ let (_, _, destination) = hybrid_key(
+ &request.seed,
+ HybridAddressBranch::External,
+ request.destination_index,
+ );
let mut signing = encode_prefix(&request.chain_id, genesis_hash)?;
signing.push(4);
@@ -270,13 +323,17 @@ pub fn build_migration(request_json: &str) -> Result<String, JsValue> {
built_json(envelope, fee, request.utxos.len())
}
-fn hybrid_key(seed: &str, index: u32) -> ([u8; HYBRID_PUBLIC_KEY_BYTES], [u8; 32], Address) {
+fn hybrid_key(
+ seed: &str,
+ branch: HybridAddressBranch,
+ index: u32,
+) -> ([u8; HYBRID_PUBLIC_KEY_BYTES], [u8; 32], Address) {
let ed_seed = derive_seed(ED_SEED_DOMAIN, seed);
let parent_ml_seed = derive_seed(ML_SEED_DOMAIN, seed);
- let ml_seed = if index == 0 {
+ let ml_seed = if matches!(branch, HybridAddressBranch::External) && index == 0 {
parent_ml_seed
} else {
- derive_child_seed(parent_ml_seed, index)
+ derive_child_seed(parent_ml_seed, branch, index)
};
let ed_public = SigningKey::from_bytes(&ed_seed).verifying_key().to_bytes();
let ml_public = ml_public_key(ml_seed);
@@ -333,10 +390,16 @@ fn derive_seed(domain: &str, seed: &str) -> [u8; 32] {
hasher.finalize().into()
}
-fn derive_child_seed(parent: [u8; 32], index: u32) -> [u8; 32] {
+fn derive_child_seed(
+ parent: [u8; 32],
+ branch: HybridAddressBranch,
+ index: u32,
+) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(ML_CHILD_DOMAIN.as_bytes());
- hasher.update(b":external:");
+ hasher.update(b":");
+ hasher.update(branch.domain_label().as_bytes());
+ hasher.update(b":");
hasher.update(index.to_be_bytes());
hasher.update(b":");
hasher.update(parent);
diff --git a/wallet/crypto/iuna_wallet_crypto.d.ts b/wallet/crypto/iuna_wallet_crypto.d.ts
@@ -7,11 +7,14 @@ export function build_transfer(request_json: string): string;
export function derive_external_addresses(seed: string, count: number, network_id: string): string;
+export function derive_reward_addresses(seed: string, count: number, network_id: string): string;
+
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly derive_external_addresses: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
+ readonly derive_reward_addresses: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
readonly build_transfer: (a: number, b: number, c: number) => void;
readonly build_migration: (a: number, b: number, c: number) => void;
readonly __wbindgen_export: (a: number, b: number) => number;
diff --git a/wallet/crypto/iuna_wallet_crypto.js b/wallet/crypto/iuna_wallet_crypto.js
@@ -96,6 +96,41 @@ export function derive_external_addresses(seed, count, network_id) {
wasm.__wbindgen_export3(deferred4_0, deferred4_1, 1);
}
}
+
+/**
+ * @param {string} seed
+ * @param {number} count
+ * @param {string} network_id
+ * @returns {string}
+ */
+export function derive_reward_addresses(seed, count, network_id) {
+ let deferred4_0;
+ let deferred4_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(seed, wasm.__wbindgen_export, wasm.__wbindgen_export2);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(network_id, wasm.__wbindgen_export, wasm.__wbindgen_export2);
+ const len1 = WASM_VECTOR_LEN;
+ wasm.derive_reward_addresses(retptr, ptr0, len0, count, ptr1, len1);
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
+ var ptr3 = r0;
+ var len3 = r1;
+ if (r3) {
+ ptr3 = 0; len3 = 0;
+ throw takeObject(r2);
+ }
+ deferred4_0 = ptr3;
+ deferred4_1 = len3;
+ return getStringFromWasm0(ptr3, len3);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_export3(deferred4_0, deferred4_1, 1);
+ }
+}
function __wbg_get_imports() {
const import0 = {
__proto__: null,
diff --git a/wallet/crypto/iuna_wallet_crypto_bg.wasm b/wallet/crypto/iuna_wallet_crypto_bg.wasm
Binary files differ.
diff --git a/wallet/crypto/iuna_wallet_crypto_bg.wasm.d.ts b/wallet/crypto/iuna_wallet_crypto_bg.wasm.d.ts
@@ -2,6 +2,7 @@
/* eslint-disable */
export const memory: WebAssembly.Memory;
export const derive_external_addresses: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
+export const derive_reward_addresses: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
export const build_transfer: (a: number, b: number, c: number) => void;
export const build_migration: (a: number, b: number, c: number) => void;
export const __wbindgen_export: (a: number, b: number) => number;