github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/types/balance.go (about) 1 package types 2 3 import ( 4 "fmt" 5 "math" 6 "math/big" 7 8 "github.com/onflow/cadence" 9 "github.com/onflow/cadence/fixedpoint" 10 ) 11 12 var ( 13 AttoScale = 18 14 UFixedScale = fixedpoint.Fix64Scale 15 UFixedToAttoConversionScale = AttoScale - UFixedScale 16 UFixToAttoConversionMultiplier = new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(UFixedToAttoConversionScale)), nil) 17 18 OneFlowInUFix64 = cadence.UFix64(uint64(math.Pow(10, float64(UFixedScale)))) 19 OneFlowBalance = Balance(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(AttoScale)), nil)) 20 EmptyBalance = Balance(new(big.Int)) 21 ) 22 23 // Balance represents the balance of an address 24 // in the evm environment (Flow EVM), balances are kept in attoflow (1e-18 flow); 25 // the smallest denomination of FLOW token (similar to how Wei is used to store Eth) 26 // But A Cadence FLOW Vault uses a Cadence.UFix64 to store values in Flow, which means 27 // 1e-8 is the smallest value that can be stored on the vault. 28 // The balance here considers the highest precision (attoflow) but utility 29 // function has been provided for conversion from/to UFix64 to prevent accidental 30 // conversion errors and dealing with rounding errors. 31 type Balance *big.Int 32 33 // NewBalanceconstructs a new balance from an atto flow value 34 func NewBalance(inp *big.Int) Balance { 35 return Balance(inp) 36 } 37 38 // NewBalanceFromUFix64 constructs a new balance from flow value (how its stored in Cadence Flow) 39 func NewBalanceFromUFix64(inp cadence.UFix64) Balance { 40 return new(big.Int).Mul( 41 new(big.Int).SetUint64(uint64(inp)), 42 UFixToAttoConversionMultiplier) 43 } 44 45 // CopyBalance creates a copy of the balance 46 func CopyBalance(inp Balance) Balance { 47 return Balance(new(big.Int).Set(inp)) 48 } 49 50 // BalanceToBigInt convert balance into big int 51 func BalanceToBigInt(bal Balance) *big.Int { 52 return (*big.Int)(bal) 53 } 54 55 // ConvertBalanceToUFix64 casts the balance into a UFix64, 56 // 57 // Warning! The smallest unit of Flow token that a FlowVault (Cadence) could store is 1e10^-8, 58 // so transfering smaller values (or values with smalls fractions) could result in loss in 59 // conversion. The rounded flag should be used to prevent loss of assets. 60 func ConvertBalanceToUFix64(bal Balance) (value cadence.UFix64, roundedOff bool, err error) { 61 converted := new(big.Int).Div(bal, UFixToAttoConversionMultiplier) 62 if !converted.IsUint64() { 63 // this should never happen 64 err = fmt.Errorf("balance can't be casted to a uint64") 65 } 66 return cadence.UFix64(converted.Uint64()), BalanceConvertionToUFix64ProneToRoundingError(bal), err 67 68 } 69 70 // BalanceConvertionToUFix64ProneToRoundingError returns true 71 // if casting to UFix64 could result in rounding error 72 func BalanceConvertionToUFix64ProneToRoundingError(bal Balance) bool { 73 return new(big.Int).Mod(bal, UFixToAttoConversionMultiplier).BitLen() != 0 74 } 75 76 // Subtract balance 2 from balance 1 and returns the result as a new balance 77 func SubBalance(bal1 Balance, bal2 Balance) (Balance, error) { 78 if (*big.Int)(bal1).Cmp(bal2) == -1 { 79 return nil, ErrInvalidBalance 80 } 81 return new(big.Int).Sub(bal1, bal2), nil 82 } 83 84 // AddBalance balance 2 to balance 1 and returns the result as a new balance 85 func AddBalance(bal1 Balance, bal2 Balance) (Balance, error) { 86 return new(big.Int).Add(bal1, bal2), nil 87 } 88 89 // MakeABalanceInFlow makes a balance object that has `amount` Flow Token in it 90 func MakeABalanceInFlow(amount uint64) Balance { 91 return NewBalance(new(big.Int).Mul(OneFlowBalance, new(big.Int).SetUint64(amount))) 92 }