Skip to content
This repository has been archived by the owner on Jun 30, 2021. It is now read-only.

Eth blockchain transaction #1028

Merged
merged 31 commits into from
Jun 24, 2019
Merged

Eth blockchain transaction #1028

merged 31 commits into from
Jun 24, 2019

Conversation

T-Dnzt
Copy link

@T-Dnzt T-Dnzt commented May 28, 2019

Issue/Task Number: 699
Closes #699

Overview

This PR adds 2 new blockchain actions to allow sending Eth or Tokens from a hot wallet.

Changes

  • Add EthBlockchain.Transaction.send(%{from: "0xsender", to: "0xreceiver", amount: amount})
  • Add EthBlockchain.Transaction.send(%{from:" 0xsender", to: "0xreceiver", amount: amount, contract_address: "0xcontract_address"})
  • Fixed wallet generation and moved it to the Keychain app.

Implementation Details

We use the send_raw_transaction method from geth to submit an offline signed and encoded transaction to the network.
The transaction is generated in the EthBlockchain app, then signed in the Keychain app, so the private key doesn't leave the Keychain app.
A few settings have been added to set default value to some parameters:

default_gas_price: 20_000_000_000,
default_eth_transaction_gas_limit: 21_000,
default_contract_transaction_gas_limit: 90_000,
chain_id: 1

This settings are arbitrarily set and may/should/will need to be updated in the future.
There is a limitation to this implementation where you need to wait until a transaction gets included in a block before making a new one from the same account. (due to the nonce that needs to be incremented and equal to the current number of mined transaction for the account).

Usage

There is a new folder at the root of the project named local_geth_testnet that contains a README file to setup a local geth testnet with some initial data.

Follow this guide then you will be able to test the following by replacing the different addresses with the one obtained:

Send ETH:

EthBlockchain.Transaction.send(%{from: "0xprimary_address", to: "0xrecipient_address", amount: 123})

Send OMG:

EthBlockchain.Transaction.send({from: "0xprimary_address", to: "0xrecipient_address", amount: 123, contract_address: "0xcontract_address"})

You can also check the balance of an address with:

EthBlockchain.Balance.get(%{address: "0xprimary_address", contract_addresses: ["0x0000000000000000000000000000000000000000", "0xcontract_address"]})

which will output the balance of ETH and OMG for the specified address.

@unnawut unnawut added this to the v2.0 milestone Jun 11, 2019
@mederic-p mederic-p changed the title [WIP] Blockchain transaction Eth blockchain transaction Jun 14, 2019
@mederic-p mederic-p self-assigned this Jun 14, 2019
.gitignore Outdated Show resolved Hide resolved
apps/eth_blockchain/lib/eth_blockchain/abi.ex Outdated Show resolved Hide resolved
apps/eth_blockchain/lib/eth_blockchain/transaction.ex Outdated Show resolved Hide resolved
apps/eth_blockchain/lib/eth_blockchain/transaction.ex Outdated Show resolved Hide resolved
apps/eth_blockchain/lib/eth_blockchain/transaction.ex Outdated Show resolved Hide resolved
@mederic-p mederic-p changed the title Eth blockchain transaction [WIP] Eth blockchain transaction Jun 17, 2019
@mederic-p mederic-p changed the title [WIP] Eth blockchain transaction Eth blockchain transaction Jun 17, 2019
@mederic-p mederic-p requested a review from unnawut June 17, 2019 09:55
Copy link
Contributor

@unnawut unnawut left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried running this on my local machine. Works like magic!

iex> EthBlockchain.Transaction.send({"0x33dbe8d0cddd178bc2aad4b194855d2b912dbfe1", "0x3230f3a6bc7c5fbec52eb533e762722bb339a140", 123, "0x90fa40efd96489b98a73d15aa226c2d64099a3d3"})
[debug] QUERY OK source="keychain" db=3.2ms queue=0.1ms
SELECT k0."encrypted_private_key" FROM "keychain" AS k0 WHERE (k0."wallet_id" = $1) ["0x33dbe8d0cddd178bc2aad4b194855d2b912dbfe1"]
{:ok, "0x5e22da6ead930b248b46034020f0b1ac9754527f8571a2e43479f970ece3ca4a"}
> omgtoken.balanceOf(eth.accounts[0])
99999999999999999877

> omgtoken.balanceOf(eth.accounts[1])
123

tools/local_geth_testnet/console.sh Outdated Show resolved Hide resolved
@unnawut unnawut added this to Review in eWallet via automation Jun 18, 2019
@T-Dnzt T-Dnzt requested a review from sirn June 19, 2019 07:29
Copy link
Contributor

@sirn sirn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly nitpicking, otherwise looks ok to me.

Also, do we want to reject 0x000...000 from being inserted? (Or was this already a thing? I can’t remember)

"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0xffffffff",
"config": {
"chainId": 1,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should change chainId to something else other than 1. This ID collides with mainnet. We used to use 90325 for our internal ETH testnet a while ago (it reads 0 = O, 3 = Mi, 2 = Se(cond), 5 = Go).

fi

echo "Starting geth console..."
geth --identity "local-geth" --rpc --rpccorsdomain "*" --datadir "${DATA_DIR}" --nodiscover --rpcapi "db,eth,net,web3" --nat "any" console
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be better to run this with --dev if we’re running private local chain.


import Utils.Helpers.Encoding

def balance_of(address) when byte_size(address) == 42 do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use something like balance_of(0x <> _ = address) instead?

@@ -77,6 +77,14 @@ defmodule EthBlockchain.Adapter do
GenServer.stop(pid)
end

@spec adapter_or_default(atom() | nil) :: atom()
def adapter_or_default(adapter \\ nil) do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function seems specific to adapter and adapter_or_default/0 doesn’t seems to get used, should you change this to call(nil, func_spec, pid) that did resolve adapter from default adapter instead?

gas_price = Application.get_env(:eth_blockchain, :default_gas_price)

send(
{from_address, to_address, amount, "0x0000000000000000000000000000000000000000", gas_price},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might help readability if we put this to @eth_address 😅

def send({from_address, to_address, amount, contract_address}, adapter, pid)
when is_binary(contract_address) do
gas_price = Application.get_env(:eth_blockchain, :default_gas_price)
send({from_address, to_address, amount, contract_address, gas_price}, adapter, pid)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be able to simplify default gas price retrieving with (for both eth/contract):

def send({_, _, _, _} = t, adapter, pid) do
  gas_price = Application.get_env(:eth_blockchain, :default_gas_price)
  t2 = Tuple.append(t, gas_price)
  send(t2, adapter, pid)
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, it might be easier if we use map instead of tuple.

s
] = rlp

{init, data} = if to == <<>>, do: {init_or_data, <<>>}, else: {<<>>, init_or_data}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨👮 THIS IS if POLICE 👮‍♀ 🚔
YOU MUST SHOW YOUR ERLANG LICENSE


Please use case 😢

{init, data} =
  case to do
    <<>> -> {init_or_data, <<>>}
    _    -> {<<>>, init_or_data}
  end

@mederic-p mederic-p requested a review from unnawut June 24, 2019 03:32
@@ -11,7 +11,7 @@ config :eth_blockchain,
default_gas_price: 20_000_000_000,
default_eth_transaction_gas_limit: 21_000,
default_contract_transaction_gas_limit: 90_000,
chain_id: 90325
chain_id: 90_325
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add a code comment noting where 90_325 number came from?

@@ -55,4 +65,6 @@ defmodule EthBlockchain.Balance do
error
end
end

defp do_get(_, _, _), do: {:error, :invalid_parameters}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid parameter checking should be done closer to where the data enters the system, i.e. controller and gates. Data should be safe by the time it reaches this module and throws an exception about unmatched function.

cc: @sirn for a second opinion?

assert Enum.member?(balances, {"0x0000000000000000000000000000000000000002", 123})
end

test_with_auths "returns an error when given a non-existing address" do
response =
request("/blockchain_wallet.get_balances", %{
"address" => "0x00000000000000000000000000000000000000000"
"address" => EthBlockchain.eth_address()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This attribute is for a non-existing wallet address, so I think it's better to be a random address than EthBlockchain.eth_address()

@mederic-p mederic-p merged commit 5e99fe6 into master Jun 24, 2019
eWallet automation moved this from Review to Done Jun 24, 2019
@mederic-p mederic-p deleted the 699-blockchain-transaction branch June 24, 2019 10:39
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
eWallet
  
5-Done
Development

Successfully merging this pull request may close these issues.

Handle Ethereum transactions
5 participants