Module: BlockGiven::Utils
- Defined in:
- lib/block_given/utils.rb
Overview
Stateless helpers, mirroring viem's utils (parseUnits, formatUnits, keccak256, ...).
Constant Summary collapse
- ZERO_ADDRESS =
"0x0000000000000000000000000000000000000000"- BLOCK_TAGS =
%w[latest earliest pending safe finalized].freeze
Class Method Summary collapse
- .address?(value) ⇒ Boolean
- .bin_to_hex(bin) ⇒ Object
-
.block_tag(value) ⇒ Object
Accepts an Integer, a hex QUANTITY or a block tag (:latest, "pending", ...).
- .checksum_address(value) ⇒ Object
- .format_ether(value) ⇒ Object
- .format_gwei(value) ⇒ Object
-
.format_units(value, decimals) ⇒ Object
1_500_000, 6 -> "1.5".
- .hex?(value) ⇒ Boolean
- .hex_to_bin(hex) ⇒ Object
- .hex_to_int(hex) ⇒ Object
-
.keccak256(data) ⇒ Object
keccak256 of raw bytes (or of the bytes represented by a 0x hex string).
-
.pad_hex(hex, bytes: 32) ⇒ Object
Left-pads a hex value to 32 bytes (used for event topics).
- .parse_ether(value) ⇒ Object
- .parse_gwei(value) ⇒ Object
-
.parse_units(value, decimals) ⇒ Object
"1.5", 6 -> 1_500_000.
- .prefix_hex(hex) ⇒ Object
- .same_address?(a, b) ⇒ Boolean
- .snake_case(name) ⇒ Object
- .strip_hex(hex) ⇒ Object
- .to_decimal(value) ⇒ Object
-
.to_hex(value) ⇒ Object
Integer -> "0x1a" (no leading zeros, as JSON-RPC QUANTITY expects).
Class Method Details
.address?(value) ⇒ Boolean
61 62 63 |
# File 'lib/block_given/utils.rb', line 61 def address?(value) value.is_a?(String) && value.match?(/\A0x[0-9a-fA-F]{40}\z/) end |
.bin_to_hex(bin) ⇒ Object
46 47 48 |
# File 'lib/block_given/utils.rb', line 46 def bin_to_hex(bin) "0x#{bin.unpack1('H*')}" end |
.block_tag(value) ⇒ Object
Accepts an Integer, a hex QUANTITY or a block tag (:latest, "pending", ...).
112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/block_given/utils.rb', line 112 def block_tag(value) case value when nil then "latest" when Integer then to_hex(value) when Symbol then block_tag(value.to_s) when String return value if hex?(value) || BLOCK_TAGS.include?(value) raise InvalidArgumentError, "invalid block tag: #{value.inspect}" else raise InvalidArgumentError, "invalid block: #{value.inspect}" end end |
.checksum_address(value) ⇒ Object
65 66 67 68 69 70 |
# File 'lib/block_given/utils.rb', line 65 def checksum_address(value) value = value.address if value.respond_to?(:address) && !value.is_a?(String) raise InvalidAddressError, "invalid address: #{value.inspect}" unless address?(value) Eth::Address.new(value).checksummed end |
.format_ether(value) ⇒ Object
94 |
# File 'lib/block_given/utils.rb', line 94 def format_ether(value) = format_units(value, 18) |
.format_gwei(value) ⇒ Object
96 |
# File 'lib/block_given/utils.rb', line 96 def format_gwei(value) = format_units(value, 9) |
.format_units(value, decimals) ⇒ Object
1_500_000, 6 -> "1.5"
86 87 88 89 90 91 |
# File 'lib/block_given/utils.rb', line 86 def format_units(value, decimals) decimal = BigDecimal(value.to_i) / (BigDecimal(10)**decimals) str = decimal.to_s("F") str = str.sub(/\.?0+\z/, "") if str.include?(".") str end |
.hex?(value) ⇒ Boolean
14 15 16 |
# File 'lib/block_given/utils.rb', line 14 def hex?(value) value.is_a?(String) && value.match?(/\A0x[0-9a-fA-F]*\z/) end |
.hex_to_bin(hex) ⇒ Object
42 43 44 |
# File 'lib/block_given/utils.rb', line 42 def hex_to_bin(hex) [strip_hex(hex)].pack("H*") end |
.hex_to_int(hex) ⇒ Object
35 36 37 38 39 40 |
# File 'lib/block_given/utils.rb', line 35 def hex_to_int(hex) return nil if hex.nil? return hex if hex.is_a?(Integer) Integer(strip_hex(hex), 16) end |
.keccak256(data) ⇒ Object
keccak256 of raw bytes (or of the bytes represented by a 0x hex string).
56 57 58 59 |
# File 'lib/block_given/utils.rb', line 56 def keccak256(data) bytes = hex?(data) ? hex_to_bin(data) : data.to_s bin_to_hex(Eth::Util.keccak256(bytes)) end |
.pad_hex(hex, bytes: 32) ⇒ Object
Left-pads a hex value to 32 bytes (used for event topics).
51 52 53 |
# File 'lib/block_given/utils.rb', line 51 def pad_hex(hex, bytes: 32) "0x#{strip_hex(hex).rjust(bytes * 2, '0')}" end |
.parse_ether(value) ⇒ Object
93 |
# File 'lib/block_given/utils.rb', line 93 def parse_ether(value) = parse_units(value, 18) |
.parse_gwei(value) ⇒ Object
95 |
# File 'lib/block_given/utils.rb', line 95 def parse_gwei(value) = parse_units(value, 9) |
.parse_units(value, decimals) ⇒ Object
"1.5", 6 -> 1_500_000. Accepts String, Integer, Float, Rational, BigDecimal.
77 78 79 80 81 82 83 |
# File 'lib/block_given/utils.rb', line 77 def parse_units(value, decimals) decimal = to_decimal(value) scaled = decimal * (BigDecimal(10)**decimals) raise InvalidArgumentError, "#{value} has more than #{decimals} decimals" unless scaled.frac.zero? scaled.to_i end |
.prefix_hex(hex) ⇒ Object
18 19 20 |
# File 'lib/block_given/utils.rb', line 18 def prefix_hex(hex) hex.start_with?("0x") ? hex : "0x#{hex}" end |
.same_address?(a, b) ⇒ Boolean
72 73 74 |
# File 'lib/block_given/utils.rb', line 72 def same_address?(a, b) a.to_s.downcase == b.to_s.downcase end |
.snake_case(name) ⇒ Object
125 126 127 128 129 130 131 132 |
# File 'lib/block_given/utils.rb', line 125 def snake_case(name) name.to_s .sub(/\A_+/, "") .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') .gsub(/([a-z\d])([A-Z])/, '\1_\2') .tr("-", "_") .downcase end |
.strip_hex(hex) ⇒ Object
22 23 24 |
# File 'lib/block_given/utils.rb', line 22 def strip_hex(hex) hex.start_with?("0x") ? hex[2..] : hex end |
.to_decimal(value) ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/block_given/utils.rb', line 98 def to_decimal(value) case value when BigDecimal then value when Integer then BigDecimal(value) when Float then BigDecimal(value.to_s) when Rational then BigDecimal(value, 40) when String then BigDecimal(value.strip) else raise InvalidArgumentError, "cannot convert #{value.inspect} to a decimal" end rescue ::ArgumentError raise InvalidArgumentError, "cannot convert #{value.inspect} to a decimal" end |
.to_hex(value) ⇒ Object
Integer -> "0x1a" (no leading zeros, as JSON-RPC QUANTITY expects).
27 28 29 30 31 32 33 |
# File 'lib/block_given/utils.rb', line 27 def to_hex(value) case value when Integer then "0x#{value.to_s(16)}" when String then prefix_hex(value) else raise InvalidArgumentError, "cannot convert #{value.inspect} to hex" end end |