-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Description
When delegating to validators, sometimes there is a precision loss that causes an incorrect number to be displayed when querying the delegation.
It is easier to trigger this case when the values for validatorTokens and validatorDelegatorShares do not match.
Example
Validator state:
validatorTokens: "10132421222471611505485287"
validatorDelegatorShares: "10142563785454078365766009.473933091465315992"
Delegation:
amount: "2000000000000000000"
Expected result: 2000000000000000000
Actual result: 1999999999999999999.999999999999999999
Possible cause and fixes
Option 1: Fix in Query Layer (Simpler)
Modify the delegation query to round the result to the nearest integer.
cosmos-sdk/x/staking/keeper/grpc_query.go
Line 597 in 79fcc30
| sdk.NewCoin(bondDenom, val.TokensFromShares(del.Shares).TruncateInt()), |
return types.NewDelegationResp(
del.DelegatorAddress,
del.GetValidatorAddr(),
del.Shares,
sdk.NewCoin(bondDenom, val.TokensFromSharesRoundUp(del.Shares).TruncateInt()),
), nilOption 2: Refactor SharesFromTokens function
Refactor the SharesFromTokens function to use decimal division instead of integer division:
cosmos-sdk/x/staking/types/validator.go
Line 336 in 79fcc30
| func (v Validator) SharesFromTokens(amt math.Int) (math.LegacyDec, error) { |
The function performs integer division (
QuoInt) which causes precision loss during the calculation.
We can fix this by refactoring to Quo instead which the TokensFromShares function already uses:
func (v Validator) SharesFromTokens(amt math.Int) (math.LegacyDec, error) {
if v.Tokens.IsZero() {
return math.LegacyZeroDec(), ErrInsufficientShares
}
return v.GetDelegatorShares().MulInt(amt).Quo(math.LegacyNewDecFromInt(v.GetTokens())), nil
}