Optimise vested amounts computation using math/big#3456
Conversation
Continuous-vesting proration is amount * elapsed / duration, which is an integer computation. Going through sdk.Dec allocates a scaled big.Int per coin only to truncate the extra precision back away. Use math/big.Int directly and skip the round trip. While at it: * rename the loop-local "x" in PeriodicVestingAccount.GetVestedCoins to "elapsed" so it matches the continuous-vesting variable naming * correct the Validate() error string on continuous and periodic vesting accounts: the predicate fails when start-time >= end-time, so "cannot be before end-time" was reversed * cover two non-aligned timestamps in TestGetVestedCoinsContVestingAcc
|
The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3456 +/- ##
==========================================
- Coverage 59.29% 59.27% -0.03%
==========================================
Files 2126 2126
Lines 175702 175701 -1
==========================================
- Hits 104183 104138 -45
- Misses 62448 62481 +33
- Partials 9071 9082 +11
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
PR SummaryMedium Risk Overview Also corrects the inverted validation error message for start/end time ordering in both continuous and periodic vesting accounts, renames a periodic loop-local variable for clarity, and adds test cases covering pro-rata vesting at non-aligned timestamps. Reviewed by Cursor Bugbot for commit 09773ea. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit cea1851. Configure here.
| vestedAmt := ovc.Amount.ToDec().Mul(s).RoundInt() | ||
| vestedCoins = append(vestedCoins, sdk.NewCoin(ovc.Denom, vestedAmt)) | ||
| vested := new(big.Int).Mul(ovc.Amount.BigInt(), elapsed) | ||
| vested.Quo(vested, duration) |
There was a problem hiding this comment.
Rounding behavior changed from bankers rounding to truncation
High Severity
The old code used sdk.Dec arithmetic with RoundInt(), which applies bankers rounding (round-half-to-even). The new big.Int code uses Quo which truncates toward zero. This changes vested amounts by up to 1 unit per denomination at non-aligned timestamps. For example, 1000 * 7/24 previously yielded 292 (rounded) but now yields 291 (truncated). In a blockchain context this is a consensus-breaking change — nodes running different versions will disagree on vesting state.
Reviewed by Cursor Bugbot for commit cea1851. Configure here.
There was a problem hiding this comment.
yup and labeled as such. Reviewers, please advise if I can avoid this.


Continuous-vesting proration is amount * elapsed / duration, which is an integer computation. Going through sdk.Dec allocates a scaled big.Int per coin only to truncate the extra precision back away. Use math/big.Int directly and skip the round trip.
While at it: