-
Notifications
You must be signed in to change notification settings - Fork 42
Open
Labels
bugSomething isn't workingSomething isn't working
Milestone
Description
We've been seeing an uptick of the following error in Sentry:
amount argument must be of type String, represent a positive number and have at most 7 digits after the decimal
Sentry reports that this error is being handled. Claude has generated the below explanation of the error. It appears to be a relatively benign error that the app is swallowing but is still being reported to Sentry. Let's quickly confirm that:
- Confirm that this is actually a benign error that is not adversely affecting users
- If benign, figure out how to suppress this reports. If not benign, fix the issue
The error originates from **`stellar/js-stellar-base`** — specifically `Operation.isValidAmount()` in [`src/operation.js`](https://github.com/stellar/js-stellar-base/blob/master/src/operation.js#L420-L449). It's **not** a Freighter bug — it's the Stellar SDK rejecting an invalid amount before the transaction is even built.
## The Call Chain in Freighter
When you hit "Send" on the `/account/sendPayment` route:
1. **`Send` component** (`extension/src/popup/views/Send/index.tsx`) renders `SendAmount`
2. `SendAmount` triggers `fetchData` from **`useSimulateTxData`** hook
3. This calls **`getBuiltTx()`** → **`getOperation()`**
4. `getOperation()` calls one of:
- `Operation.payment({ destination, asset, amount })` — regular payment
- `Operation.createAccount({ destination, startingBalance: amount })` — unfunded account
- `Operation.pathPaymentStrictSend({ sendAmount: amount, ... })` — path payment/swap
5. The SDK's `isValidAmount(amount)` **rejects** the value and throws the error
## What `isValidAmount` Checks
```javascript
static isValidAmount(value, allowZero = false) {
if (typeof value !== 'string') return false; // Must be a string
amount = new BigNumber(value);
if (
(!allowZero && amount.isZero()) || // No zero (for most ops)
amount.isNegative() || // No negatives
amount.times(10000000).gt(MAX_INT64) || // No overflow
amount.decimalPlaces() > 7 || // Max 7 decimal places
amount.isNaN() || !amount.isFinite() // Must be a valid number
) return false;
}```
## Most Likely Cause in Freighter's Flow
The amount passed to `getOperation()` comes from Redux state via `cleanAmount(amount)`:
```javascript
export const cleanAmount = (s: string) => s.replace(/[^0-9.]/g, "");```
This strips commas and non-numeric chars, but the `formatAmountPreserveCursor` function in the input UI **truncates decimals to `decimals` places** (default 7). The problem likely happens when:
1. **The amount has commas** — `cleanAmount("1,000.5")` → `"1000.5"` :white_check_mark: (this works fine)
2. **The amount is `"0"` or empty** — `cleanAmount("")` → `""` which is **not a valid number string** → :x:
3. **Floating point from calculations** — if any intermediate JS number produces something like `"1e-8"` (scientific notation) or `"0.123456789"` (>7 decimals)
4. **The `amount` field in Redux state is `"0"` (the initial value)** and the user triggers simulation before entering an amount — `isValidAmount("0", allowZero=false)` → :x:
**The most common trigger**: the `amount` field defaults to `"0"` in Redux initial state, and if the simulation runs before the user changes it, `Operation.payment({ amount: "0" })` fails because zero is not allowed for payment operations.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working