github.com/lmittmann/w3@v0.20.0/util.go (about)

     1  package w3
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"math/big"
     7  	"strings"
     8  
     9  	"github.com/ethereum/go-ethereum/common"
    10  )
    11  
    12  // Common [big.Int]'s.
    13  var (
    14  	Big0     = new(big.Int)
    15  	Big1     = big.NewInt(1)
    16  	Big2     = big.NewInt(2)
    17  	Big10    = big.NewInt(10)
    18  	BigGwei  = big.NewInt(1_000000000)
    19  	BigEther = big.NewInt(1_000000000_000000000)
    20  
    21  	// Max Uint Values.
    22  	BigMaxUint256 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 256), Big1)
    23  	BigMaxUint248 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 248), Big1)
    24  	BigMaxUint240 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 240), Big1)
    25  	BigMaxUint232 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 232), Big1)
    26  	BigMaxUint224 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 224), Big1)
    27  	BigMaxUint216 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 216), Big1)
    28  	BigMaxUint208 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 208), Big1)
    29  	BigMaxUint200 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 200), Big1)
    30  	BigMaxUint192 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 192), Big1)
    31  	BigMaxUint184 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 184), Big1)
    32  	BigMaxUint176 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 176), Big1)
    33  	BigMaxUint168 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 168), Big1)
    34  	BigMaxUint160 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 160), Big1)
    35  	BigMaxUint152 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 152), Big1)
    36  	BigMaxUint144 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 144), Big1)
    37  	BigMaxUint136 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 136), Big1)
    38  	BigMaxUint128 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 128), Big1)
    39  	BigMaxUint120 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 120), Big1)
    40  	BigMaxUint112 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 112), Big1)
    41  	BigMaxUint104 = new(big.Int).Sub(new(big.Int).Lsh(Big1, 104), Big1)
    42  	BigMaxUint96  = new(big.Int).Sub(new(big.Int).Lsh(Big1, 96), Big1)
    43  	BigMaxUint88  = new(big.Int).Sub(new(big.Int).Lsh(Big1, 88), Big1)
    44  	BigMaxUint80  = new(big.Int).Sub(new(big.Int).Lsh(Big1, 80), Big1)
    45  	BigMaxUint72  = new(big.Int).Sub(new(big.Int).Lsh(Big1, 72), Big1)
    46  	BigMaxUint64  = new(big.Int).Sub(new(big.Int).Lsh(Big1, 64), Big1)
    47  	BigMaxUint56  = new(big.Int).Sub(new(big.Int).Lsh(Big1, 56), Big1)
    48  	BigMaxUint48  = new(big.Int).Sub(new(big.Int).Lsh(Big1, 48), Big1)
    49  	BigMaxUint40  = new(big.Int).Sub(new(big.Int).Lsh(Big1, 40), Big1)
    50  	BigMaxUint32  = new(big.Int).Sub(new(big.Int).Lsh(Big1, 32), Big1)
    51  	BigMaxUint24  = new(big.Int).Sub(new(big.Int).Lsh(Big1, 24), Big1)
    52  	BigMaxUint16  = new(big.Int).Sub(new(big.Int).Lsh(Big1, 16), Big1)
    53  	BigMaxUint8   = new(big.Int).Sub(new(big.Int).Lsh(Big1, 8), Big1)
    54  )
    55  
    56  // Zero Values.
    57  var (
    58  	Addr0 common.Address
    59  	Hash0 common.Hash
    60  )
    61  
    62  // A returns an address from a hexstring or panics if the hexstring does not
    63  // represent a valid address.
    64  //
    65  // Use [common.HexToAddress] to get the address from a hexstring without
    66  // panicking.
    67  func A(hexAddr string) (addr common.Address) {
    68  	if has0xPrefix(hexAddr) {
    69  		hexAddr = hexAddr[2:]
    70  	}
    71  
    72  	n, err := hex.Decode(addr[:], []byte(hexAddr))
    73  	if err != nil {
    74  		panic(fmt.Sprintf("invalid address %q: %v", hexAddr, err))
    75  	} else if n != 20 {
    76  		panic(fmt.Sprintf("invalid address %q: must have 20 bytes", hexAddr))
    77  	}
    78  	return addr
    79  }
    80  
    81  // APtr returns an address pointer from a hexstring or panics if the hexstring
    82  // does not represent a valid address.
    83  func APtr(hexAddress string) *common.Address {
    84  	addr := A(hexAddress)
    85  	return &addr
    86  }
    87  
    88  // B returns a byte slice from a hexstring or panics if the hexstring does not
    89  // represent a valid byte slice.
    90  //
    91  // Use [common.FromHex] to get the byte slice from a hexstring without
    92  // panicking.
    93  func B(hexBytes ...string) (bytes []byte) {
    94  	for _, s := range hexBytes {
    95  		if has0xPrefix(s) {
    96  			s = s[2:]
    97  		}
    98  
    99  		b, err := hex.DecodeString(s)
   100  		if err != nil {
   101  			panic(fmt.Sprintf("invalid bytes %q: %v", s, err))
   102  		}
   103  		bytes = append(bytes, b...)
   104  	}
   105  	return bytes
   106  }
   107  
   108  // H returns a hash from a hexstring or panics if the hexstring does not
   109  // represent a valid hash.
   110  //
   111  // Use [common.HexToHash] to get the hash from a hexstring without panicking.
   112  func H(hexHash string) (hash common.Hash) {
   113  	if has0xPrefix(hexHash) {
   114  		hexHash = hexHash[2:]
   115  	}
   116  
   117  	n, err := hex.Decode(hash[:], []byte(hexHash))
   118  	if err != nil {
   119  		panic(fmt.Sprintf("invalid hash %q: %v", hexHash, err))
   120  	} else if n != 32 {
   121  		panic(fmt.Sprintf("invalid hash %q: must have 32 bytes", hexHash))
   122  	}
   123  	return hash
   124  }
   125  
   126  // I returns a [big.Int] from a hexstring or decimal number string (with
   127  // optional unit) or panics if the parsing fails.
   128  //
   129  // I supports the units "ether" or "eth" and "gwei" for decimal number strings.
   130  // E.g.:
   131  //
   132  //	w3.I("1 ether")   -> 1000000000000000000
   133  //	w3.I("10 gwei")   -> 10000000000
   134  //
   135  // Fractional digits that exceed the units maximum number of fractional digits
   136  // are ignored. E.g.:
   137  //
   138  //	w3.I("0.000000123456 gwei") -> 123
   139  func I(strInt string) *big.Int {
   140  	if has0xPrefix(strInt) {
   141  		return parseHexBig(strInt[2:])
   142  	}
   143  	return parseDecimal(strInt)
   144  }
   145  
   146  func parseHexBig(hexBig string) *big.Int {
   147  	bigInt, ok := new(big.Int).SetString(hexBig, 16)
   148  	if !ok {
   149  		panic(fmt.Sprintf("invalid hex big %q", "0x"+hexBig))
   150  	}
   151  	return bigInt
   152  }
   153  
   154  func parseDecimal(strBig string) *big.Int {
   155  	numberUnit := strings.SplitN(strBig, " ", 2)
   156  	integerFraction := strings.SplitN(numberUnit[0], ".", 2)
   157  	integer, ok := new(big.Int).SetString(integerFraction[0], 10)
   158  	if !ok {
   159  		panic(fmt.Sprintf("str big %q must be number", strBig))
   160  	}
   161  
   162  	// len == 1
   163  	if len(numberUnit) == 1 {
   164  		if len(integerFraction) > 1 {
   165  			panic(fmt.Sprintf("str big %q without unit must be integer", strBig))
   166  		}
   167  		return integer
   168  	}
   169  
   170  	// len == 2
   171  	unit := strings.ToLower(numberUnit[1])
   172  	switch unit {
   173  	case "ether", "eth":
   174  		integer.Mul(integer, BigEther)
   175  	case "gwei":
   176  		integer.Mul(integer, BigGwei)
   177  	default:
   178  		panic(fmt.Sprintf("str big %q has invalid unit %q", strBig, unit))
   179  	}
   180  
   181  	// integer
   182  	if len(integerFraction) == 1 {
   183  		return integer
   184  	}
   185  
   186  	// float
   187  	fraction, ok := new(big.Int).SetString(integerFraction[1], 10)
   188  	if !ok {
   189  		panic(fmt.Sprintf("str big %q must be number", strBig))
   190  	}
   191  
   192  	decimals := len(integerFraction[1])
   193  	switch unit {
   194  	case "ether", "eth":
   195  		if fraction.Cmp(BigEther) >= 0 {
   196  			panic(fmt.Sprintf("str big %q exceeds precision", strBig))
   197  		}
   198  		fraction.Mul(fraction, new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(18-decimals)), nil))
   199  	case "gwei":
   200  		if fraction.Cmp(BigGwei) >= 0 {
   201  			panic(fmt.Sprintf("str big %q exceeds precision", strBig))
   202  		}
   203  		fraction.Mul(fraction, new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(9-decimals)), nil))
   204  	}
   205  
   206  	return integer.Add(integer, fraction)
   207  }
   208  
   209  // FromWei returns the given Wei as decimal with the given number of decimals.
   210  func FromWei(wei *big.Int, decimals uint8) string {
   211  	if wei == nil {
   212  		return fmt.Sprint(nil)
   213  	}
   214  
   215  	d := new(big.Int).Exp(Big10, big.NewInt(int64(decimals)), nil)
   216  
   217  	sign := ""
   218  	if wei.Sign() < 0 {
   219  		sign = "-"
   220  	}
   221  	wei = new(big.Int).Abs(wei)
   222  
   223  	z, m := new(big.Int).DivMod(wei, d, new(big.Int))
   224  	if m.Cmp(new(big.Int)) == 0 {
   225  		return sign + z.String()
   226  	}
   227  	s := strings.TrimRight(fmt.Sprintf("%0*s", decimals, m.String()), "0")
   228  	return sign + z.String() + "." + s
   229  }
   230  
   231  // has0xPrefix validates hexStr begins with '0x' or '0X'.
   232  func has0xPrefix(hexStr string) bool {
   233  	return len(hexStr) >= 2 && hexStr[0] == '0' && (hexStr[1] == 'x' || hexStr[1] == 'X')
   234  }
   235  
   236  // BigMin returns the smaller of the two big integers.
   237  func BigMin(a, b *big.Int) *big.Int {
   238  	if a.Cmp(b) < 0 {
   239  		return a
   240  	}
   241  	return b
   242  }
   243  
   244  // BigMax returns the larger of the two big integers.
   245  func BigMax(a, b *big.Int) *big.Int {
   246  	if a.Cmp(b) > 0 {
   247  		return a
   248  	}
   249  	return b
   250  }