feat(amm): decode_config in amm_client_ffi (reads token/twap program ids from AMM config)

This commit is contained in:
Andrea Franz 2026-07-13 22:19:46 +02:00 committed by r4bbit
parent 3b9ca241c2
commit f3a14f051a
3 changed files with 87 additions and 1 deletions

View File

@ -46,6 +46,16 @@ typedef struct FfiPoolView {
bool ok; bool ok;
} FfiPoolView; } FfiPoolView;
/**
* C-ABI mirror of `pool::ConfigView`.
*/
typedef struct FfiConfigView {
uint32_t token_program_id[8];
uint32_t twap_oracle_program_id[8];
uint8_t authority[32];
bool ok;
} FfiConfigView;
/** /**
* Builds the RISC0 instruction words for a `SwapExactInput`. `amount_in` and * Builds the RISC0 instruction words for a `SwapExactInput`. `amount_in` and
* `min_out` are little-endian encoded `u128` values (`[u8; 16]`). The * `min_out` are little-endian encoded `u128` values (`[u8; 16]`). The
@ -132,4 +142,14 @@ void amm_client_current_tick_pda(const ProgramId *twap,
*/ */
bool amm_client_decode_pool(const uint8_t *bytes, uintptr_t len, struct FfiPoolView *out); bool amm_client_decode_pool(const uint8_t *bytes, uintptr_t len, struct FfiPoolView *out);
/**
* Decodes an `AmmConfig` account's raw bytes into `out`. Returns `false` on
* decode failure, leaving `out` unwritten.
*
* # Safety
* `bytes` must be valid for reads of `len` bytes, and `out` must be a
* valid, non-null pointer to writable memory for a `FfiConfigView`.
*/
bool amm_client_decode_config(const uint8_t *bytes, uintptr_t len, struct FfiConfigView *out);
#endif /* AMM_CLIENT_FFI_H */ #endif /* AMM_CLIENT_FFI_H */

View File

@ -45,6 +45,15 @@ pub struct FfiPoolView {
pub ok: bool, pub ok: bool,
} }
/// C-ABI mirror of `pool::ConfigView`.
#[repr(C)]
pub struct FfiConfigView {
pub token_program_id: [u32; 8],
pub twap_oracle_program_id: [u32; 8],
pub authority: [u8; 32],
pub ok: bool,
}
/// # Safety /// # Safety
/// `p` must be a valid, non-null pointer to a readable `[u8; 32]`. /// `p` must be a valid, non-null pointer to a readable `[u8; 32]`.
unsafe fn acc(p: *const [u8; 32]) -> AccountId { unsafe fn acc(p: *const [u8; 32]) -> AccountId {
@ -201,3 +210,30 @@ pub unsafe extern "C" fn amm_client_decode_pool(
Err(_) => false, Err(_) => false,
} }
} }
/// Decodes an `AmmConfig` account's raw bytes into `out`. Returns `false` on
/// decode failure, leaving `out` unwritten.
///
/// # Safety
/// `bytes` must be valid for reads of `len` bytes, and `out` must be a
/// valid, non-null pointer to writable memory for a `FfiConfigView`.
#[no_mangle]
pub unsafe extern "C" fn amm_client_decode_config(
bytes: *const u8,
len: usize,
out: *mut FfiConfigView,
) -> bool {
let b = core::slice::from_raw_parts(bytes, len);
match pool::decode_config(b) {
Ok(v) => {
*out = FfiConfigView {
token_program_id: v.token_program_id,
twap_oracle_program_id: v.twap_oracle_program_id,
authority: v.authority,
ok: true,
};
true
}
Err(_) => false,
}
}

View File

@ -2,7 +2,7 @@
//! can read reserves / fees / vault ids without depending on `amm_core` //! can read reserves / fees / vault ids without depending on `amm_core`
//! directly. //! directly.
use amm_core::PoolDefinition; use amm_core::{AmmConfig, PoolDefinition};
pub struct PoolView { pub struct PoolView {
pub def_a: [u8; 32], pub def_a: [u8; 32],
@ -31,9 +31,25 @@ pub fn decode_pool(bytes: &[u8]) -> Result<PoolView, String> {
}) })
} }
pub struct ConfigView {
pub token_program_id: [u32; 8],
pub twap_oracle_program_id: [u32; 8],
pub authority: [u8; 32],
}
pub fn decode_config(bytes: &[u8]) -> Result<ConfigView, String> {
let c: AmmConfig = borsh::from_slice(bytes).map_err(|e| format!("{e:?}"))?;
Ok(ConfigView {
token_program_id: c.token_program_id,
twap_oracle_program_id: c.twap_oracle_program_id,
authority: c.authority.into_value(),
})
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use amm_core::PoolDefinition; use amm_core::PoolDefinition;
use nssa_core::account::AccountId;
use super::*; use super::*;
@ -44,4 +60,18 @@ mod tests {
let v = decode_pool(&bytes).unwrap(); let v = decode_pool(&bytes).unwrap();
assert_eq!(v.reserve_a, 0); assert_eq!(v.reserve_a, 0);
} }
#[test]
fn decode_config_roundtrip() {
let c = AmmConfig {
token_program_id: [7u32; 8],
twap_oracle_program_id: [9u32; 8],
authority: AccountId::new([0u8; 32]),
};
let bytes = borsh::to_vec(&c).unwrap();
let v = decode_config(&bytes).unwrap();
assert_eq!(v.token_program_id, [7u32; 8]);
assert_eq!(v.twap_oracle_program_id, [9u32; 8]);
assert_eq!(v.authority, [0u8; 32]);
}
} }