Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

scale.gno

1.48 Kb · 50 lines
 1package zkgm
 2
 3import (
 4	"errors"
 5	"math"
 6
 7	u256 "gno.land/p/onbloc/math/uint256"
 8)
 9
10// ErrAmountOverflow is returned when a (downscaled) amount does not fit int64,
11// the width of the grc20/banker ledger.
12var ErrAmountOverflow = errors.New("zkgm: amount overflows int64")
13
14// ErrAmountNotDivisible is returned when a source-precision amount carries precision
15// below the ledger's canonical scale,
16// so dividing by the token's scale factor leaves a remainder.
17// It is rejected so cross-chain value is conserved exactly.
18var ErrAmountNotDivisible = errors.New("zkgm: amount not divisible by token scale factor")
19
20// Pow10 returns 10^exp as a uint256.
21// exp is small (a token's decimal excess over the canonical precision),
22// so float pow is exact and sufficient.
23func Pow10(exp int) *u256.Uint {
24	result := math.Pow10(exp)
25
26	return u256.NewUint(uint64(result))
27}
28
29// ScaleDownToInt64 narrows an origin-precision amount to an int64 ledger amount
30// by dividing by 10^scaleExp.
31// scaleExp <= 0 is the identity narrow, used by native and low-decimal tokens.
32func ScaleDownToInt64(amount *u256.Uint, scaleExp int) (int64, error) {
33	value := amount
34
35	if scaleExp > 0 {
36		quotient, remainder := u256.Zero().DivMod(amount, Pow10(scaleExp), u256.Zero())
37		if !remainder.IsZero() {
38			return 0, ErrAmountNotDivisible
39		}
40
41		value = quotient
42	}
43
44	valueUint64, overflow := value.Uint64WithOverflow()
45	if overflow || valueUint64 > uint64(math.MaxInt64) {
46		return 0, ErrAmountOverflow
47	}
48
49	return int64(valueUint64), nil
50}