Skip to content

Commit b91da83

Browse files
Add support for signed transactions with ruby_eth gem. Use contract.key = Eth::Key.new(...) to prepare contract to use custom key. Then just use contract.deploy(...) or contract.transact(...), etc. Also 3 helper methods in client get_balance, get_nonce, get_nonce
1 parent a145dac commit b91da83

7 files changed

+86
-10
lines changed

ethereum.gemspec

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Gem::Specification.new do |spec|
2929
spec.add_development_dependency "rake", "~> 12.0"
3030
spec.add_development_dependency "rspec", "~> 3.5"
3131
spec.add_development_dependency "pry", "~> 0.10"
32+
spec.add_development_dependency "eth", "~> 0.4"
3233

3334
spec.add_dependency "activesupport", "~> 5.0"
3435
spec.add_dependency "digest-sha3", "~> 1.1"

lib/ethereum/client.rb

+13-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def initialize(log = false)
1111
@id = 0
1212
@log = log
1313
@batch = nil
14-
14+
@formatter = Ethereum::Formatter.new
1515
if @log == true
1616
@logger = Logger.new("/tmp/ethereum_ruby_http.log")
1717
end
@@ -56,6 +56,18 @@ def encode_params(params)
5656
params.map(&method(:int_to_hex))
5757
end
5858

59+
def get_balance(address)
60+
eth_get_balance(address)["result"].to_i(16)
61+
end
62+
63+
def get_chain
64+
net_version["result"].to_i(16)
65+
end
66+
67+
def get_nonce(address)
68+
eth_get_transaction_count(address)["result"].to_i(16)
69+
end
70+
5971
def send_command(command,args)
6072
if ["eth_getBalance", "eth_call"].include?(command)
6173
args << "latest"

lib/ethereum/contract.rb

+27-8
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,31 @@ def deploy_args(params)
5858
end
5959

6060
def send_transaction(tx_args)
61-
if key
62-
Eth.configure { |c| c.chain_id = @client.net_version["result"].to_i }
63-
tx = Eth::Tx.new({ from: key.address, to: main_address, value: value, data: data, nonce: 0, gas_limit: 1_000_000, gas_price: gas_price})
64-
tx.sign key
65-
else
6661
@client.eth_send_transaction(tx_args)["result"]
67-
end
62+
end
63+
64+
def send_raw_transaction(payload, to = nil)
65+
Eth.configure { |c| c.chain_id = @client.get_chain }
66+
args = {
67+
from: key.address,
68+
value: 0,
69+
data: payload,
70+
nonce: @client.get_nonce(key.address),
71+
gas_limit: 4_000_000,
72+
gas_price: 20_000_000_000
73+
}
74+
args[:to] = to if to
75+
tx = Eth::Tx.new(args)
76+
tx.sign key
77+
@client.eth_send_raw_transaction(tx.hex)["result"]
6878
end
6979

7080
def deploy(*params)
71-
tx = send_transaction(deploy_args(params))
81+
if key
82+
tx = send_raw_transaction(deploy_payload(params))
83+
else
84+
tx = send_transaction(deploy_args(params))
85+
end
7286
tx_failed = tx.nil? || tx == "0x0000000000000000000000000000000000000000000000000000000000000000"
7387
raise IOError, "Failed to deploy, did you unlock #{sender} account? Transaction hash: #{tx}" if tx_failed
7488
@deployment = Ethereum::Deployment.new(tx, @client)
@@ -113,7 +127,11 @@ def call(fun, *args)
113127
end
114128

115129
def transact(fun, *args)
116-
tx = send_transaction(call_args(fun, args))
130+
if key
131+
tx = send_raw_transaction(call_payload(fun, args), address)
132+
else
133+
tx = send_transaction(call_args(fun, args))
134+
end
117135
return Ethereum::Transaction.new(tx, @client, call_payload(fun, args), args)
118136
end
119137

@@ -170,6 +188,7 @@ def build
170188
class_methods = Class.new do
171189
extend Forwardable
172190
def_delegators :parent, :deploy_payload, :deploy_args, :call_payload, :call_args
191+
def_delegators :parent, :signed_deploy, :key, :key=
173192
def_delegators :parent, :gas, :gas_price, :gas=, :gas_price=
174193
def_delegators :parent, :abi, :deployment, :events
175194
def_delegators :parent, :estimate, :deploy, :deploy_and_wait

lib/ethereum/version.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module Ethereum
2-
VERSION = "2.0.9"
2+
VERSION = "2.1.0"
33
end

spec/ethereum/client_spec.rb

+26
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,30 @@
4949
it_behaves_like "json rpc method", {"jsonrpc":"2.0","method":"eth_getBalance","params":["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"],"id":1}
5050
end
5151

52+
describe ".get_balance" do
53+
let (:response) { '{"jsonrpc":"2.0","result":"0xd30beea08891180","id":1}' }
54+
it "returns account balance as integer" do
55+
expect(client).to receive(:send_single).and_return(response)
56+
expect(client.get_balance("0x407d73d8a49eeb85d32cf465507dd71d507100c1")). to eq 950469433750000000
57+
end
58+
end
59+
60+
describe ".get_chain" do
61+
let (:request) { {"jsonrpc":"2.0","method":"net_version","params":[],"id":1} }
62+
let (:response) { '{"jsonrpc":"2.0","result":"0xd30beea08891180","id":1}' }
63+
it "returns chain no" do
64+
expect(client).to receive(:send_single).once.with(request.to_json).and_return(response)
65+
expect(client.get_chain). to eq 950469433750000000
66+
end
67+
end
68+
69+
describe ".get_nonce" do
70+
let (:request) { {"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0x407d73d8a49eeb85d32cf465507dd71d507100c1"],"id":1} }
71+
let (:response) { '{"jsonrpc":"2.0","result":"0xd30beea08891180","id":1}' }
72+
it "returns chain no" do
73+
expect(client).to receive(:send_single).once.with(request.to_json).and_return(response)
74+
expect(client.get_nonce("0x407d73d8a49eeb85d32cf465507dd71d507100c1")). to eq 950469433750000000
75+
end
76+
end
77+
5278
end

spec/ethereum/contract_spec.rb

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'spec_helper'
2+
require 'eth'
23

34
describe Ethereum::Contract do
45

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
require 'eth'
2+
require 'spec_helper'
3+
4+
describe Ethereum do
5+
6+
let(:client) { Ethereum::Singleton.instance }
7+
let(:path) { "#{Dir.pwd}/spec/fixtures/TestContract.sol" }
8+
let(:private_hex) { "3a9f0de356f75c0af771119c6ada8c6f911d61a07bd3efcf91eedb28bd42e83f" }
9+
10+
it "deploys with key set value and checks value", blockchain: true do
11+
contract = Ethereum::Contract.create(file: path)
12+
contract.key = Eth::Key.new priv: private_hex
13+
contract.deploy_and_wait("Aloha!")
14+
contract.transact_and_wait.set("greeting", "Aloha!")
15+
expect(contract.call.get("greeting")).to eq ["Aloha!", "żółć"]
16+
end
17+
end

0 commit comments

Comments
 (0)