package precision import ( "math" "math/big" ) type ( // Converter is a cached wrapper on `convert` function. It caches base and // target precisions and factor. converter struct { base uint32 // base precision target uint32 // target precision factor *big.Int } // Fixed8Converter is a converter with base precision of Fixed8. It uses // int64 values because there is a guarantee that balance contract will // operate with `Deposit` and `Withdraw` amounts that less than 2**53-1. // This is a JSON bound that uses neo node. Neo-go has int64 limit for // `smartcontract.Parameter` of integer type. Fixed8Converter struct { converter } ) const fixed8Precision = 8 // convert is the function that converts `n` to desired precision by using // factor value. func convert(n, factor *big.Int, decreasePrecision bool) *big.Int { if decreasePrecision { return new(big.Int).Div(n, factor) } return new(big.Int).Mul(n, factor) } // NewConverter returns Fixed8Converter. func NewConverter(precision uint32) Fixed8Converter { var c Fixed8Converter c.SetBalancePrecision(precision) return c } func (c converter) toTarget(n *big.Int) *big.Int { return convert(n, c.factor, c.base > c.target) } func (c converter) toBase(n *big.Int) *big.Int { return convert(n, c.factor, c.base < c.target) } // ToFixed8 converts n of balance contract precision to Fixed8 precision. func (c Fixed8Converter) ToFixed8(n int64) int64 { return c.toBase(new(big.Int).SetInt64(n)).Int64() } // ToBalancePrecision converts n of Fixed8 precision to balance contract precision. func (c Fixed8Converter) ToBalancePrecision(n int64) int64 { return c.toTarget(new(big.Int).SetInt64(n)).Int64() } // SetBalancePrecision prepares converter to work. func (c *Fixed8Converter) SetBalancePrecision(precision uint32) { exp := int(precision) - fixed8Precision if exp < 0 { exp = -exp } c.base = fixed8Precision c.target = precision c.factor = new(big.Int).SetInt64(int64(math.Pow10(exp))) } // Convert is a wrapper of convert function. Use cached `converter` struct // if fromPrecision and toPrecision are constant. func Convert(fromPrecision, toPrecision uint32, n *big.Int) *big.Int { var decreasePrecision bool exp := int(toPrecision) - int(fromPrecision) if exp < 0 { decreasePrecision = true exp = -exp } factor := new(big.Int).SetInt64(int64(math.Pow10(exp))) return convert(n, factor, decreasePrecision) }