Skip to content

Commit aaff21f

Browse files
authored
Merge pull request #215 from BitGo/BTC-3184-amount-wrapper-negative
fix: clamp negative amounts to 0 in AmountWrapper deserializer
2 parents 962b78c + 3736162 commit aaff21f

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)