Module: EthTool
- Defined in:
- lib/eth_tool.rb,
lib/eth_tool/version.rb
Constant Summary collapse
- VERSION =
"0.1.2"- @@gas_limit =
60000- @@gas_price =
5_000_000_000
Class Attribute Summary collapse
-
.logger ⇒ Object
Returns the value of attribute logger.
Class Method Summary collapse
- .confirmations(txhash) ⇒ Object
- .confirmed?(txhash, number) ⇒ Boolean
-
.dec_to_hex(value) ⇒ Object
helper methods #########################################################.
- .fee ⇒ Object
- .fill_eth(private_key, to) ⇒ Object
- .gas_limit=(gas_limit) ⇒ Object
- .gas_price=(gas_price) ⇒ Object
- .generate_addresses_from_xprv(xprv, amount) ⇒ Object
- .generate_raw_transaction(private_key, value, data, gas_limit, gas_price = nil, to = nil, nonce = nil) ⇒ Object
- .get_eth_balance(address) ⇒ Object
- .get_private_key_from_keystore(dir, address, passphrase) ⇒ Object
- .get_private_key_from_xprv(xprv, index) ⇒ Object
- .get_token_balance(address, token_contract_address, token_decimals) ⇒ Object
- .mined?(txhash) ⇒ Boolean
- .padding(str) ⇒ Object
- .rpc ⇒ Object
- .rpc=(url) ⇒ Object
- .sweep_eth(private_key, to) ⇒ Object
- .sweep_token(private_key, token_contract_address, token_decimals, to) ⇒ Object
- .token_transfer_success?(txhash) ⇒ Boolean
- .transfer_eth(private_key, amount, gas_limit, gas_price, to) ⇒ Object
- .transfer_token(private_key, token_contract_address, token_decimals, amount, gas_limit, gas_price, to) ⇒ Object
- .tx_replace(private_key, txhash, gas_price) ⇒ Object
- .wait_for_miner(txhash, timeout: 1200, step: 20) ⇒ Object
- .wputs(file, text) ⇒ Object
Class Attribute Details
.logger ⇒ Object
Returns the value of attribute logger.
32 33 34 |
# File 'lib/eth_tool.rb', line 32 def logger @logger end |
Class Method Details
.confirmations(txhash) ⇒ Object
192 193 194 195 196 197 198 199 200 |
# File 'lib/eth_tool.rb', line 192 def self.confirmations(txhash) tx = @@rpc.eth_get_transaction_by_hash(txhash)["result"] return 0 unless (tx and (not tx['blockNumber'].nil?)) block_number = tx['blockNumber'].to_i(16) current_block_number = @@rpc.eth_block_number["result"].to_i(16) current_block_number - block_number end |
.confirmed?(txhash, number) ⇒ Boolean
180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/eth_tool.rb', line 180 def self.confirmed?(txhash, number) tx = @@rpc.eth_get_transaction_by_hash(txhash)["result"] return false unless (tx and (not tx['blockNumber'].nil?)) block_number = tx['blockNumber'].to_i(16) current_block_number = @@rpc.eth_block_number["result"].to_i(16) confirmations = current_block_number - block_number confirmations >= number end |
.dec_to_hex(value) ⇒ Object
helper methods #########################################################
214 215 216 |
# File 'lib/eth_tool.rb', line 214 def self.dec_to_hex(value) '0x'+value.to_s(16) end |
.fee ⇒ Object
27 28 29 |
# File 'lib/eth_tool.rb', line 27 def self.fee BigDecimal(@@gas_limit) * BigDecimal(@@gas_price) / 10**18.to_f end |
.fill_eth(private_key, to) ⇒ Object
113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/eth_tool.rb', line 113 def self.fill_eth(private_key, to) # 目标地址上现有eth eth_balance = get_eth_balance(to) # 目标地址上需要填充满这么多eth amount = BigDecimal(@@gas_limit) * BigDecimal(@@gas_price) / 10**18 return unless eth_balance < amount # 如果有足够多的eth,就直接返回 transfer_eth(private_key, (amount-eth_balance), @@gas_limit, @@gas_price, to) end |
.gas_limit=(gas_limit) ⇒ Object
19 20 21 |
# File 'lib/eth_tool.rb', line 19 def self.gas_limit=(gas_limit) @@gas_limit = gas_limit end |
.gas_price=(gas_price) ⇒ Object
23 24 25 |
# File 'lib/eth_tool.rb', line 23 def self.gas_price=(gas_price) @@gas_price = gas_price end |
.generate_addresses_from_xprv(xprv, amount) ⇒ Object
150 151 152 153 154 155 156 157 158 |
# File 'lib/eth_tool.rb', line 150 def self.generate_addresses_from_xprv(xprv, amount) result = [] wallet = Bip44::Wallet.from_xprv(xprv) amount.times do |i| sub_wallet = wallet.sub_wallet("m/#{i}") result << sub_wallet.ethereum_address end result end |
.generate_raw_transaction(private_key, value, data, gas_limit, gas_price = nil, to = nil, nonce = nil) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/eth_tool.rb', line 49 def self.generate_raw_transaction(private_key, value, data, gas_limit, gas_price = nil, to = nil, nonce = nil) key = ::Eth::Key.new priv: private_key address = key.address gas_price_in_dec = gas_price.nil? ? @@rpc.eth_gas_price["result"].to_i(16) : gas_price nonce = nonce.nil? ? @@rpc.eth_get_transaction_count(address, 'pending')["result"].to_i(16) : nonce args = { from: address, value: 0, data: '0x0', nonce: nonce, gas_limit: gas_limit, gas_price: gas_price_in_dec } args[:value] = (value * 10**18).to_i if value args[:data] = data if data args[:to] = to if to tx = Eth::Tx.new(args) tx.sign key tx.hex end |
.get_eth_balance(address) ⇒ Object
44 45 46 47 |
# File 'lib/eth_tool.rb', line 44 def self.get_eth_balance(address) result = @@rpc.eth_get_balance(address)['result'].to_i(16) BigDecimal(result) / BigDecimal(10**18) end |
.get_private_key_from_keystore(dir, address, passphrase) ⇒ Object
140 141 142 143 144 145 146 147 148 |
# File 'lib/eth_tool.rb', line 140 def self.get_private_key_from_keystore(dir, address, passphrase) path = File.join(dir, '*') Dir[path].each do |file| if file.end_with?(address[2..-1]) key = ::Eth::Key.decrypt(File.read(file), passphrase) return key.private_key.to_hex end end end |
.get_private_key_from_xprv(xprv, index) ⇒ Object
160 161 162 163 164 |
# File 'lib/eth_tool.rb', line 160 def self.get_private_key_from_xprv(xprv, index) wallet = Bip44::Wallet.from_xprv(xprv) sub_wallet = wallet.sub_wallet("m/#{index}") return sub_wallet.private_key, sub_wallet.ethereum_address end |
.get_token_balance(address, token_contract_address, token_decimals) ⇒ Object
37 38 39 40 41 42 |
# File 'lib/eth_tool.rb', line 37 def self.get_token_balance(address, token_contract_address, token_decimals) data = '0x70a08231' + padding(address) # Ethereum::Function.calc_id('balanceOf(address)') # 70a08231 result = @@rpc.eth_call({to: token_contract_address, data: data})['result'].to_i(16) BigDecimal(result) / BigDecimal(10**token_decimals) end |
.mined?(txhash) ⇒ Boolean
175 176 177 178 |
# File 'lib/eth_tool.rb', line 175 def self.mined?(txhash) tx = @@rpc.eth_get_transaction_by_hash(txhash)["result"] tx and (not tx['blockNumber'].nil?) end |
.padding(str) ⇒ Object
218 219 220 221 222 223 |
# File 'lib/eth_tool.rb', line 218 def self.padding(str) if str =~ /^0x[a-f0-9]*/ str = str[2 .. str.length-1] end str.rjust(64, '0') end |
.rpc ⇒ Object
15 16 17 |
# File 'lib/eth_tool.rb', line 15 def self.rpc @@rpc end |
.rpc=(url) ⇒ Object
11 12 13 |
# File 'lib/eth_tool.rb', line 11 def self.rpc=(url) @@rpc = Ethereum::HttpClient.new(url) end |
.sweep_eth(private_key, to) ⇒ Object
104 105 106 107 108 109 110 111 |
# File 'lib/eth_tool.rb', line 104 def self.sweep_eth(private_key, to) address = ::Eth::Key.new(priv: private_key).address eth_balance = get_eth_balance(address) keep = BigDecimal(@@gas_limit) * BigDecimal(@@gas_price) / 10**18 amount = eth_balance - keep return if amount <= 0 transfer_eth(private_key, amount, @@gas_limit, @@gas_price, to) end |
.sweep_token(private_key, token_contract_address, token_decimals, to) ⇒ Object
97 98 99 100 101 102 |
# File 'lib/eth_tool.rb', line 97 def self.sweep_token(private_key, token_contract_address, token_decimals, to) address = ::Eth::Key.new(priv: private_key).address token_balance = get_token_balance(address, token_contract_address, token_decimals) return if token_balance == 0 transfer_token(private_key, token_contract_address, token_decimals, token_balance, @@gas_limit, @@gas_price, to) end |
.token_transfer_success?(txhash) ⇒ Boolean
202 203 204 205 206 207 208 209 210 |
# File 'lib/eth_tool.rb', line 202 def self.token_transfer_success?(txhash) tx = @@rpc.eth_get_transaction_by_hash(txhash)["result"] return false unless (tx and (not tx['blockNumber'].nil?)) receipt = @@rpc.eth_get_transaction_receipt(txhash)["result"] return false unless receipt return false if (receipt['status'] && receipt['status'] == '0x0') end |
.transfer_eth(private_key, amount, gas_limit, gas_price, to) ⇒ Object
87 88 89 90 91 92 93 94 |
# File 'lib/eth_tool.rb', line 87 def self.transfer_eth(private_key, amount, gas_limit, gas_price, to) if amount < (1.0/10**18) logger.info "转账金额不能小于以太坊最小单位" return end rawtx = generate_raw_transaction(private_key, amount, nil, gas_limit, gas_price, to) @@rpc.eth_send_raw_transaction(rawtx) end |
.transfer_token(private_key, token_contract_address, token_decimals, amount, gas_limit, gas_price, to) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/eth_tool.rb', line 73 def self.transfer_token(private_key, token_contract_address, token_decimals, amount, gas_limit, gas_price, to) if amount < (1.0/10**token_decimals) logger.info "转账金额不能小于精度最小单位(#{token_contract_address}, #{token_decimals})" return end # 生成raw transaction amount_in_wei = (amount * (10**token_decimals)).to_i data = '0xa9059cbb' + padding(to) + padding(dec_to_hex(amount_in_wei)) # Ethereum::Function.calc_id('transfer(address,uint256)') # a9059cbb rawtx = generate_raw_transaction(private_key, 0, data, gas_limit, gas_price, token_contract_address) @@rpc.eth_send_raw_transaction(rawtx) end |
.tx_replace(private_key, txhash, gas_price) ⇒ Object
125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/eth_tool.rb', line 125 def self.tx_replace(private_key, txhash, gas_price) tx = @@rpc.eth_get_transaction_by_hash(txhash)["result"] return if tx.nil? value = tx["value"].to_i(16) data = tx["input"] gas_limit = tx["gas"].to_i(16) gas_price = gas_price to = tx["to"] nonce = tx["nonce"].to_i(16) rawtx = generate_raw_transaction(private_key, value, data, gas_limit, gas_price, to, nonce) @@rpc.eth_send_raw_transaction(rawtx) end |
.wait_for_miner(txhash, timeout: 1200, step: 20) ⇒ Object
166 167 168 169 170 171 172 173 |
# File 'lib/eth_tool.rb', line 166 def self.wait_for_miner(txhash, timeout: 1200, step: 20) start_time = Time.now loop do raise Timeout::Error if ((Time.now - start_time) > timeout) return true if mined?(txhash) sleep step end end |
.wputs(file, text) ⇒ Object
225 226 227 |
# File 'lib/eth_tool.rb', line 225 def self.wputs(file, text) File.open(file, 'a') { |f| f.puts(text) } end |