Skip to content

Precision Loss in Delegation Queries Causes Incorrect Amount Display #25263

@kingpinXD

Description

@kingpinXD

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.

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:

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
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions