fix(amm): LE-serialize instruction words; correct ELF→ProgramBinary docs; clarify sharedWalletIsOpen

This commit is contained in:
Andrea Franz 2026-07-23 15:36:11 +02:00 committed by r4bbit
parent f1fc061664
commit e03164baf3
5 changed files with 27 additions and 8 deletions

View File

@ -285,6 +285,9 @@ bool AmmUiBackend::sharedWalletIsOpen()
// the real on-disk wallet, so the user saw no accounts. Keying off accounts
// alone means a genuinely-open shared wallet (Basecamp) is still adopted,
// while a closed standalone core correctly falls through to open-from-disk.
// Tradeoff: a shared wallet that is open but holds ZERO accounts is treated
// as closed here, so it won't be adopted — an accepted edge, preferable to
// the default-sequencer false-positive that keying off the address caused.
return !QJsonArray::fromVariantList(m_logos->logos_execution_zone.list_accounts()).isEmpty();
}
@ -783,8 +786,18 @@ QString AmmUiBackend::swapExactInput(QString defAHex, QString defBHex, QString u
// this file) plus the program's id as hex, not the raw ELF: the program is
// already deployed and referenced by id. There is no program_dependencies
// arg — the sequencer resolves the AMM's chained token/twap calls on-chain.
const QByteArray instructionBytes(reinterpret_cast<const char*>(instruction.data()),
static_cast<int>(instruction.size() * sizeof(uint32_t)));
// Serialize the u32 instruction words to bytes explicitly as little-endian,
// matching the protocol's LE-u32 wire format. A reinterpret_cast of the
// in-memory vector would be host-endian-dependent and byte-swap on a
// big-endian host, making the guest decode a different instruction.
QByteArray instructionBytes;
instructionBytes.reserve(static_cast<int>(instruction.size() * sizeof(uint32_t)));
for (const uint32_t w : instruction) {
instructionBytes.append(static_cast<char>(w & 0xFF));
instructionBytes.append(static_cast<char>((w >> 8) & 0xFF));
instructionBytes.append(static_cast<char>((w >> 16) & 0xFF));
instructionBytes.append(static_cast<char>((w >> 24) & 0xFF));
}
// Derive the deployed AMM program id from the ELF and hex-encode it as the
// canonical 32-byte hex (little-endian per u32 word — matches `spel

View File

@ -81,8 +81,9 @@ private:
void refreshSequencerAddr();
void saveWallet();
// Returns the deployed AMM program ELF bytes from $AMM_PROGRAM_BIN, or an empty
// QByteArray (with a qWarning) if the env var is unset/unreadable/empty.
// Returns the deployed AMM program-binary bytes (a RISC Zero ProgramBinary
// .bin, not a raw ELF) from $AMM_PROGRAM_BIN, or an empty QByteArray (with a
// qWarning) if the env var is unset/unreadable/empty.
QByteArray loadAmmElf();
// Probe the configured sequencer over HTTP and update sequencerReachable.

View File

@ -46,7 +46,8 @@ class AmmUiBackend
// AMM
// Derives the AMM pool's PDAs (config/pool/vaults/current-tick) from the
// deployed AMM program's ELF (see AMM_PROGRAM_BIN) and reads the pool's
// deployed AMM program binary (see AMM_PROGRAM_BIN — a RISC Zero
// ProgramBinary .bin, not a raw ELF) and reads the pool's
// on-chain reserves. Returns `{ exists: false }` if the AMM program bin
// isn't configured, the AMM isn't initialized, or the pool has no
// liquidity yet.

View File

@ -106,8 +106,10 @@ pub unsafe extern "C" fn amm_client_free_words(w: AmmWords) {
}
}
/// Computes the `ProgramId` (Image ID) of a compiled guest ELF. Returns
/// `false` on an invalid ELF, leaving `out` unwritten.
/// Computes the `ProgramId` (Image ID) of a deployed program binary — the RISC
/// Zero `ProgramBinary` (`.bin`) format, NOT a raw ELF (the `elf` bytes are
/// decoded via `ProgramBinary::decode`). Returns `false` on invalid input,
/// leaving `out` unwritten.
///
/// # Safety
/// `elf` must be valid for reads of `elf_len` bytes, and `out` must be a

View File

@ -6,7 +6,9 @@ use nssa_core::{account::AccountId, program::ProgramId};
use risc0_binfmt::ProgramBinary;
use twap_oracle_core::compute_current_tick_account_pda;
/// Computes the `ProgramId` (Image ID) of a compiled guest ELF, the same way
/// Computes the `ProgramId` (Image ID) of a deployed program binary — the RISC
/// Zero `ProgramBinary` (`.bin`) format produced by the guest build, NOT a raw
/// ELF (the `elf` bytes are decoded via `ProgramBinary::decode`) — the same way
/// the sequencer/wallet does when deploying a program.
pub fn program_id_from_elf(elf: &[u8]) -> Result<ProgramId, String> {
let binary = ProgramBinary::decode(elf).map_err(|e| format!("{e:?}"))?;