-
Notifications
You must be signed in to change notification settings - Fork 4k
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()),
), nil
Option 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
}