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  }