Skip to content

Commit 3736162

Browse files
committed
fix: clamp negative amounts to 0 in AmountWrapper deserializer
The staking service can send negative remainingStakingAmount (e.g. "-2282880") when the unstake amount exceeds the current balance. The u64 deserializer rejected these with "invalid digit found in string", preventing the intent from being processed at all. The intent builder already guards with > 0 checks before using amount values (e.g. partial unstake in build.rs), so clamping negatives to 0 at deserialization is safe and lets the full unstake path proceed correctly. Ticket: BTC-3184
1 parent 962b78c commit 3736162

1 file changed

Lines changed: 14 additions & 3 deletions

File tree

packages/wasm-solana/src/intent/types.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,13 @@ pub struct AmountWrapper {
139139
pub symbol: Option<String>,
140140
}
141141

142-
/// Deserialize amount from either string or number (for JS BigInt compatibility)
142+
/// Deserialize amount from either string or number (for JS BigInt compatibility).
143+
///
144+
/// Negative values are clamped to 0 rather than rejected. The staking service can
145+
/// send negative `remainingStakingAmount` when the unstake amount exceeds the current
146+
/// balance. Callers already guard with `> 0` checks (e.g. build.rs partial unstake),
147+
/// so clamping is safe and avoids a deserialization error that would prevent the
148+
/// intent from being processed at all.
143149
fn deserialize_amount<'de, D>(deserializer: D) -> Result<u64, D::Error>
144150
where
145151
D: serde::Deserializer<'de>,
@@ -166,14 +172,19 @@ where
166172
where
167173
E: de::Error,
168174
{
169-
u64::try_from(v).map_err(|_| de::Error::custom("negative amount"))
175+
Ok(u64::try_from(v).unwrap_or(0))
170176
}
171177

172178
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
173179
where
174180
E: de::Error,
175181
{
176-
v.parse().map_err(de::Error::custom)
182+
// Try u64 first, fall back to i64 parse and clamp negatives to 0
183+
v.parse::<u64>().or_else(|_| {
184+
v.parse::<i64>()
185+
.map(|n| u64::try_from(n).unwrap_or(0))
186+
.map_err(de::Error::custom)
187+
})
177188
}
178189
}
179190

0 commit comments

Comments
 (0)