Skip to content

Commit

Permalink
Update 18-decimal-handling.md
Browse files Browse the repository at this point in the history
  • Loading branch information
samricotta authored and alpe committed Sep 30, 2024
1 parent f77cb17 commit 2cfe465
Showing 1 changed file with 16 additions and 70 deletions.
86 changes: 16 additions & 70 deletions docs/build/building-modules/18-decimal-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,33 @@ These changes require a state migration to update existing decimal values to the

## Why the Change?

* **Enhanced Precision**: `Dec` uses the [apd](https://github.com/cockroachdb/apd) library for arbitrary precision decimals, suitable for accurate financial calculations.
* **Immutable Operations**: `Dec` operations are safer for concurrent use as they do not mutate the original values.
* **Better Performance**: `Dec` operations are faster and more efficient than `LegacyDec`.`
* Historically we have wrapped a `big.Int` to represent decimals in the Cosmos SDK and never had a decimal type. Finally, we have a decimal type that is more efficient and accurate.
* `Dec` uses the [apd](https://github.com/cockroachdb/apd) library for arbitrary precision decimals, suitable for accurate financial calculations.
* `Dec` operations are safer for concurrent use as they do not mutate the original values.
* `Dec` operations are faster and more efficient than `LegacyDec`.

## Using `Dec` in Modules that haven't used `LegacyDec`

If you are creating a new module or updating an existing module that has not used `LegacyDec`, you can directly use `Dec` without any changes.

As an example we will use `DecCoin` which is a common type used in the Cosmos SDK.
-- math.NewLegacyDecFromInt64(100)
++ math.NewDecFromInt64(100)

-- math.LegacyNewDecWithPrec(100, 18)
++ math.NewDecWithPrec(100, 18)

```protobuf
message DecCoin {
option (gogoproto.equal) = true;
-- math.LegacyNewDecFromStr("100")
++ math.NewDecFromStr("100")

string denom = 1;
string amount = 2 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.Dec",
(gogoproto.nullable) = false
];
}
```
-- math.LegacyNewDecFromStr("100.000000000000000000").Quo(math.LegacyNewDecFromInt(2))
++ math.NewDecFromStr("100.000000000000000000").Quo(math.NewDecFromInt(2))

How you can implement `Dec` in your module:
-- math.LegacyNewDecFromStr("100.000000000000000000").Add(math.LegacyNewDecFromInt(2))
++ math.NewDecFromStr("100.000000000000000000").Add(math.NewDecFromInt(2))

```go
import (
"cosmossdk.io/math"
)
-- math.LegacyNewDecFromStr("100.000000000000000000").Sub(math.LegacyNewDecFromInt(2))
++ math.NewDecFromStr("100.000000000000000000").Sub(math.NewDecFromInt(2))

example := math.NewDecFromInt64(100)
```

## Modules migrating from `LegacyDec` to `Dec`

Expand All @@ -59,58 +53,10 @@ The reason for the state breaking change is the difference in precision handling
* **LegacyDec**: Fixed precision of 18 decimal places.
* **Dec**: Flexible precision up to 34 decimal places using the apd library.

## Byte Representation Changes Example

The change in precision handling directly impacts the byte representation of decimal values:

**Legacy Dec Byte Representation:**
`2333435363738393030303030303030303030303030303030303030`

This example includes the value 123456789 followed by 18 zeros to maintain the fixed precision.

**New Dec Byte Representation:**
`0a03617364121031323334353637383900000000000000`

This example shows the value 123456789 without additional padding, reflecting the flexible precision handling of the new Dec type.

## Impact of Precision Change

The increase in precision from 18 to 34 decimal places allows for more detailed decimal values but requires data migration. This change in how data is formatted and stored is a key aspect of why the transition is considered state-breaking.

## Example of State-Breaking Change

The protobuf definitions for DecCoin illustrate the change in the custom type for the amount field.

**Before:**

```protobuf
message DecCoin {
option (gogoproto.equal) = true;
string denom = 1;
string amount = 2 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
}
```

**After:**

```protobuf
message DecCoin {
option (gogoproto.equal) = true;
string denom = 1;
string amount = 2 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.Dec",
(gogoproto.nullable) = false
];
}
```

## Converting `LegacyDec` to `Dec` without storing the data

If you would like to convert a `LegacyDec` to a `Dec` without a state migration changing how the data is handled internally within the application logic and not how it's stored or represented. You can use the following methods.
Expand Down

0 comments on commit 2cfe465

Please sign in to comment.