Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sending a transaction #7

Open
woniesong92 opened this issue Feb 15, 2018 · 25 comments
Open

Sending a transaction #7

woniesong92 opened this issue Feb 15, 2018 · 25 comments

Comments

@woniesong92
Copy link

Is there a way to call a function (i.e. send a transaction) with this library?
If I wanted to programmatically call a function that updates blockchain state, what's the best way to do it?

@astudnev
Copy link
Contributor

Signing transactions is not implemented in this GEM.

@drselump14
Copy link

@astudnev Do you have a plan to implement it?

@astudnev
Copy link
Contributor

No direct plan, but would be very nice

@lucasperez
Copy link

I am thinking to implement it.... Any ideas? Someone wants to collaborate?

@hswick
Copy link

hswick commented Mar 12, 2018

Don't mean to steal anyone's thunder. But I have basic functionality for sendTransaction (not ready yet for arrays) in my library here https://github.com/hswick/w3 and I am looking for collaborators as I can only work on it part time.

There is also https://github.com/EthWorks/ethereum.rb which is fairly developed

@alex-kampa
Copy link

alex-kampa commented Mar 13, 2018

Hey people, why reinvent the wheel, for signing transactions you can use https://github.com/se3000/ruby-eth - would be more useful to try and fix some of the quirks of that library (one of them I will fix as soon as time permits...)

Then you can simply do:

#=================
web3 = Web3::Eth::Rpc.new host: 'ropsten.infura.io',
port: 443,
connect_options: {
open_timeout: 20,
read_timeout: 140,
use_ssl: true,
rpc_path: '/keyxxxxxx'
}

res = web3.eth.getTransactionCount ['.....acct.......', 'pending']
tc = res.to_i(16)

tx = Eth::Tx.new({
data: "0x075624e1", # this is incrementTwice() - to do: hex data from any function input
gas_limit: 210_000,
gas_price: 20_000_000,
nonce: tc,
to: "0xc015edDe79C543A4a7aa7e54EC590cB9cCC5E6ae",
value: 0,
})

key = Eth::Key.new priv: '....acct_private_key.....'
tx.sign key
puts tx.hash
res = web3.eth.sendRawTransaction([tx.hex])
#=================

The more tricky part (from my point of view) is to properly encode the data - this seems to be possible with web3-eth but need to test it.

@alex-kampa
Copy link

alex-kampa commented Mar 13, 2018

@hswick - apart from the signing, all the necessary functions to send transactions seem to be implemented in a pretty comprehensive way in the Ethereum.rb gem (https://github.com/EthWorks/ethereum.rb) which does have some minor quirks but generally works (only with parity at the moment). However, that gem does not expose most of its useful functions, such as input data encoding, so instead of trying to redo, we could work on doing that. What do you think?

@hswick
Copy link

hswick commented Mar 13, 2018

@alex-kampa I like the simplicity of ruby-eth for signing transactions. Anyone looking on this thread would probably benefit from the use of it.

In regards to ethereum.rb I address this in my README. I'm a fairly opinionated person (as I think conviction makes good software), and I have actually been stealing some of the internals for w3 from ethereum.rb (which I reference). It isn't a matter of functionality, it is about design. My design isn't based on just becoming feature parity with something like web3.js, it is about surpassing it.

@ToJen
Copy link

ToJen commented Apr 3, 2018

@hswick I just went through your w3 library, it looks promising. I'll check it out.

@marknguyen85
Copy link

I'm also trying to send transaction as @woniesong92
my code here

        key = Eth::Key.new priv: privateKey
        gas_limit = 200000
        gas_price = $web3.eth.gasPrice().to_i(16)
        nonce = $web3.eth.getTransactionCount([key.address, 'pending']).to_i(16)
        tx = Eth::Tx.new({
                gas_limit: 210000,
                gas_price: gas_price,
                nonce: nonce,
                from: key.address,
                to: address_to,
                value: amount,
                data: ""
            })

        tx.sign(key)
        
        result = $web3.eth.sendRawTransaction(tx.hex)

then error respose

{
    "status": 500,
    "error": "Internal Server Error",
    "exception": "#<RuntimeError: Error code 400 on request https://rinkeby.infura.io/kEICAYHkrSFjduGKSOR5 {\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":\"0xf86480843b9aca0083033450945dc73424b8bb75d22cd728dc8dbb2aad77f5fd4680801ba096c8949ec52baa4ef55fdedbc138ed330717a7495ecc70cffd7d4ce05d4cb389a06f3c88b4323cd4f6f0d8bfdb51e788faff621733d48f77622cd598341edb6b15\",\"id\":6401146}>",
    "traces": {
        "Application Trace": [
            {
                "id": 5,
                "trace": "app/walletapi/eth_client.rb:45:in `drawal'"
            },
            {
                "id": 6,
                "trace": "app/controllers/api/v1/wallets_controller.rb:137:in `withdrawal'"
            }
        ],
        "Framework Trace": [
            {
                "id": 0,
                "trace": "web3-eth (0.2.16) lib/web3/eth/rpc.rb:44:in `block in request'"

please help me.

@jlstr
Copy link

jlstr commented Jun 13, 2018

Any luck with that problem @marknguyen85?

@jlstr
Copy link

jlstr commented Jun 13, 2018

Hello @alex-kampa,

In your example above:

tx = Eth::Tx.new({
  data: "0x075624e1", # this is incrementTwice() - to do: hex data from any function input
  gas_limit: 210_000,
  gas_price: 20_000_000,
  nonce: tc,
  to: "0xc015edDe79C543A4a7aa7e54EC590cB9cCC5E6ae",
  value: 0,
})

Could you please be more clear as to what goes in the data field? it seems this is what @marknguyen85 Could be missing as well?

Thank you very much.

@marknguyen85
Copy link

marknguyen85 commented Jun 14, 2018

i've resolved with code below

result = $web3.eth.sendRawTransaction([tx.hex])

@jlstr i think data is not require

@jlstr
Copy link

jlstr commented Jun 14, 2018

Awesome thanks!

@marknguyen85 May I ask one follow up Question, How do you get a contract object?

I'm trying to load it from a Ruby Hash:

contract = web3.eth.contract(Abi)
contract_instance = contract.at('0x0.....')

Where Abi is the standard Contract, ie. a Ruby Array behind the scenes
But it does not work!

The above does not allow me to do:
contract_instance.balanceOf('0x....')
Throws NoMethodError and I wonder If the ABI has to be in a specific format? any ideas,

Please Help.

@marknguyen85
Copy link

marknguyen85 commented Jun 18, 2018

@jlstr I'm also problems as you with methods of constract instance

@marknguyen85
Copy link

@jlstr
I found the cause of the error, Abi must be formatted string instead of array
ex
Abi = []

format to => Abi = '[]'

@jlstr
Copy link

jlstr commented Jun 18, 2018

Awesome! Thank you @marknguyen85, And How are you calling contract methods?

@marknguyen85
Copy link

@jlstr
as you, i don't know how to calling contract methods. When call contract method alway get error
Function transfer is not constant: transfer, requires to sign transaction

i found in this gem code

def call_contract contract_address, method_name, args
        function = functions[method_name]
        raise "No method found in ABI: #{method_name}" unless function
        raise "Function #{method_name} is not constant: #{method_name}, requires to sign transaction" unless function.constant
        function.do_call web3_rpc, contract_address, args
      end

=>
raise "Function #{method_name} is not constant: #{method_name}, requires to sign transaction"

have you any idea for this processing?

@jlstr
Copy link

jlstr commented Jun 19, 2018

Hello @marknguyen85, I have figured it out, and let me tell you, you're in the right track, but the key is that you have to serialize the entire contract method you'll call according to the ABI Spec. Once serialized, you will get a long HEX string that looks like: 0xcdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001

That hex string goes in the data field of the TX:

tx = Eth::Tx.new({
data: hex_data,
gas_limit: 210_000,
gas_price: gas_price,
nonce: nonce,
to: contract_address,
from: address_that_is_signing_this_transaction,
value: 0
})

The rest is exactly as you have in your example, but remember that the to will always be the contract's address in Ethereum.

Let me know if require any further help.
-Jose

@marknguyen85
Copy link

marknguyen85 commented Jun 20, 2018

@jlstr thanks you.
I have read the link that you submitted (ABI Spec) but don't know how to create data_hash. Can you just me how to generate param hex?

00000000000000000000000000000000000000000000000000000000000000045
or
0000000000000000000000000000000000000000000000000000000000000001

@jlstr
Copy link

jlstr commented Jun 20, 2018

The answer to your Question is very broad, in the hex strings you have pasted above, what are you trying to represent? a number (uint256)?

I will teach you how I personally generate a uint256 as an example so that you have an idea of what to do next, let say you want to pass the decimal value 10 to a smart contract's method:

value = 10

First you have to convert it into WEI, easy enough, just multiply by a 10^18 constant

value = value * 1_000_000_000_000_000_000

Now, you have to convert it to hexadecimal:

hex_value = "%x" % (value)

Finally, pad the hexadecimal value with 0s to complete a 64 bit long hex string that's required by Ethereum:

hex_value = hex_value.rjust(64, "0")

This example will translate a decimal number like 10 into a uint256 type, I have examples for other types, but I hope this will give you an idea of how to do it.

Kindly,
Jose

@marknguyen85
Copy link

@jlstr thanks

@alex-kampa
Copy link

alex-kampa commented Jun 22, 2018

@jlstr - some of the encoding was also done by @hswick at https://github.com/hswick/w3/blob/master/lib/w3/encoder.rb

It does not seem to handle all cases though - for example arrays as inputs are probably a bit tricky, and this includes strings which are handled like arrays as far as i know. If anyone here manages to do the encoding in the most generic way, please let us know.

@alex-kampa
Copy link

BTW, the specs for the encoding are here: http://solidity.readthedocs.io/en/develop/abi-spec.html

@jlstr
Copy link

jlstr commented Jun 22, 2018

Thank you @alex-kampa I did use that very same spec in order to do the parsing, too bad it's so coarse.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants