Component: pallets/exodus @ 0162da46, src/types/exodus_request.rs:383-391.
Description: The Perbill bounty is scaled to uint32 for the recall(uint256,uint256,uint256) metadata slot:
let scaled_bounty = multiply_by_rational_with_rounding(
bounty.deconstruct() as u128, 1u128 << 32, 1_000_000_000, Rounding::Down)?;
let bounty_uint32 = scaled_bounty as u32; // <-- wrap!
Perbill::from_percent(100) → deconstruct() = 1_000_000_000 → scaled_bounty = exactly 2^32 → as u32 truncates to 0. The existing tests only cover 1%.
Impact: A user setting a 100% bounty encodes 0 instead: the EVM relayer gets nothing. Self-inflicted; no other party can exploit it (the value is written by the submitter).
Reproduction: ExodusRequest::evm_bridge_out(..., Perbill::from_percent(100), ...) → get_message → the last 4 bytes of the metadata slot are 0x00000000 instead of 0xFFFFFFFF.
Severity: Low. Reason: a real correctness bug at the upper bound, with no attacker path and no cross-party fund loss.
Recommendation: Clamp before casting (scaled_bounty.min(u32::MAX as u128) as u32 or unique_saturated_into::<u32>()); add boundary tests for 0%/100%.
Verification: VERIFIED (static).