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

Smart Contract Support #68

Merged
merged 53 commits into from
May 6, 2022
Merged

Smart Contract Support #68

merged 53 commits into from
May 6, 2022

Conversation

kurotaky
Copy link
Collaborator

@kurotaky kurotaky commented Apr 2, 2022

I plan to create a smart contract feature that will allow for the following.

[1] pry(main)> contract = Eth::Contract.create(file: 'spec/fixtures/contracts/greeter.sol')
=> #<Eth::Contract::Greeter:0x00007faf95142b88>
[2] pry(main)> address = contract.deploy_and_wait("Hello from eth.rb!")
=> "0x351f54cdc59570c99b577b272b98b8eef5e8a6f6"

I am currently building:

  • Smart contract functionality like ethereum.rb
  • Support for Ethereum transactions (EIP-1559)
  • Add testing
  • Add documentation

@codecov-commenter
Copy link

codecov-commenter commented Apr 2, 2022

Codecov Report

Merging #68 (fd58fe8) into main (f243cd4) will increase coverage by 0.02%.
The diff coverage is 100.00%.

@@            Coverage Diff             @@
##             main      #68      +/-   ##
==========================================
+ Coverage   99.70%   99.73%   +0.02%     
==========================================
  Files          55       67      +12     
  Lines        3409     3753     +344     
==========================================
+ Hits         3399     3743     +344     
  Misses         10       10              
Impacted Files Coverage Δ
lib/eth.rb 100.00% <100.00%> (ø)
lib/eth/client.rb 100.00% <100.00%> (ø)
lib/eth/contract.rb 100.00% <100.00%> (ø)
lib/eth/contract/event.rb 100.00% <100.00%> (ø)
lib/eth/contract/function.rb 100.00% <100.00%> (ø)
lib/eth/contract/function_input.rb 100.00% <100.00%> (ø)
lib/eth/contract/function_output.rb 100.00% <100.00%> (ø)
lib/eth/contract/initializer.rb 100.00% <100.00%> (ø)
spec/eth/client_spec.rb 100.00% <100.00%> (ø)
spec/eth/contract/event_spec.rb 100.00% <100.00%> (ø)
... and 5 more

📣 Codecov can now indicate which changes are the most critical in Pull Requests. Learn more

Copy link
Owner

@q9f q9f left a comment

Choose a reason for hiding this comment

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

Hey, thanks.

I left some early comments, mainly to avoid redundancy with existing code (abi, units, utils).

One thing that bothered me in Ethereum.rb is that the Contract always contains a client. It should be the other way around; you have a client and pass a contract to deploy (just like transactions). What do you think?

In general, I would suggest writing tests first and building everything against the spec so that we know what does what and what functions how. A nice side effect would be 100% coverage 😁

@name = name
@code = code
@abi = abi
@client = client
Copy link
Owner

Choose a reason for hiding this comment

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

This is a reverse dependency. A contract should not contain a client but rather a client should be able to deploy and wait.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I plan to implement deploy_and_wait in client.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I consider the following plan & interface.

before

@contract.deploy_and_wait
@contract.transact_and_wait.function_name(params)  
@contract.call.function_name(params)

after

@client.deploy_and_wait(contract)
@client.transact_and_wait(contract, function_name, params)
@client.call(contract, function_name, params)

end

def address=(addr)
@address = addr
Copy link
Owner

Choose a reason for hiding this comment

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

address should always be an Eth::Address for security reasons.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I now use Eth::Address 📝

@deployment = Eth::Contract::Deployment.new(tx, @client)
end

def deploy_and_wait(*params, **args, &block)
Copy link
Owner

Choose a reason for hiding this comment

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

All these functions should be implemented for the client not the contract. See transfer_and_wait.

end

def estimate(*params)
result = @client.eth_estimate_gas(deploy_args(params))
Copy link
Owner

Choose a reason for hiding this comment

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

This or use Tx.estimate_intrinsic_gas().

else
tx = send_transaction(call_args(fun, args))
end
return Ethereum::Transaction.new(tx, @client, call_payload(fun, args), args)
Copy link
Owner

Choose a reason for hiding this comment

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

Eth::Tx?

@@ -0,0 +1,115 @@
module Eth
class Contract::Encoder
def encode(type, value)
Copy link
Owner

Choose a reason for hiding this comment

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

See Eth::Abi.encode()

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removed dependency on Contract::Encoder using Eth::Abi.encode().

module Eth
class Contract::Formatter

UNITS = {
Copy link
Owner

Choose a reason for hiding this comment

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

See Eth::Unit::

tether: 1000000000000000000000000000000
}

def valid_address?(address_string)
Copy link
Owner

Choose a reason for hiding this comment

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

Eth::Address.new(...).valid?

return !(address.match(/[0-9a-fA-F]+/).nil?)
end

def from_bool(boolval)
Copy link
Owner

Choose a reason for hiding this comment

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

Wondering what this is used for? Might want to live in Eth::Util

eth.gemspec Outdated
@@ -48,4 +48,7 @@ Gem::Specification.new do |spec|

# scrypt for encrypted key derivation
spec.add_dependency "scrypt", "~> 3.0"

# activesupport for smart contract support
spec.add_dependency "activesupport", "~> 7.0"
Copy link
Owner

Choose a reason for hiding this comment

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

where is this used?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It was used in present? and underscore methods.
I will probably remove it later when it is no longer needed.

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 those are both one-line methods that could be copied and pasted into Eth::Util or similar rather than pull in the entirety of activesupport

Copy link
Owner

Choose a reason for hiding this comment

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

Yes, that's what I was thinking. Keep dependencies as low as possible.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Remove the dependency on activesupport and use the methods of Ruby itself.

@kurotaky
Copy link
Collaborator Author

kurotaky commented Apr 2, 2022

Thank you for your comment. I will write a test and try to avoid redundancy 😄
Certainly, having a client and passing Contract to the client for deployment seems like a good idea.

@q9f
Copy link
Owner

q9f commented Apr 17, 2022

Also, add yourself to the AUTHORS file :)

@w4ll3
Copy link

w4ll3 commented Apr 25, 2022

Hi there, checking in on the status of this PR, would be very helpful to implement EIP-1271 for Sign-In with Ethereum spruceid/siwe-ruby#15, let me know if there is anything I can do to help!

@q9f q9f mentioned this pull request Apr 25, 2022
@kurotaky
Copy link
Collaborator Author

@w4ll3 Thank you. I'll call you when I need help!

@kurotaky kurotaky requested a review from q9f May 5, 2022 15:32
@kurotaky kurotaky self-assigned this May 5, 2022
@kurotaky kurotaky marked this pull request as ready for review May 5, 2022 15:32
@kurotaky
Copy link
Collaborator Author

kurotaky commented May 5, 2022

@q9f
Thank you for your waiting 😄 spec and docs now have 100% coverage.
I have implemented the functionality to interact with a minimum of smart contract.

Copy link
Owner

@q9f q9f left a comment

Choose a reason for hiding this comment

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

This is beautiful, thank you for taking the time to merge it in!


# -*- encoding : ascii-8bit -*-

require "forwardable"
Copy link
Owner

Choose a reason for hiding this comment

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

do we need this as dependency in the gemspec?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removed as not needed here.

# @param address [String] contract address.
# @return [Object] returns the result of the call.
def transact(contract, function_name, *args, **kwargs)
gas_limit = Tx.estimate_intrinsic_gas(contract.bin) - Tx::DEFAULT_GAS_LIMIT + 53000
Copy link
Owner

Choose a reason for hiding this comment

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

just a tiny nitpick: let's create a Tx::CREATE_GAS = 32_000 constant that we can use here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

OK, I'll try to fix it.

lib/eth/client.rb Outdated Show resolved Hide resolved
lib/eth/client.rb Outdated Show resolved Hide resolved
spec/fixtures/contracts/test_contract.sol Outdated Show resolved Hide resolved
kurotaky and others added 6 commits May 6, 2022 21:21
Co-authored-by: Afr Schoe <58883403+q9f@users.noreply.github.com>
Co-authored-by: Afr Schoe <58883403+q9f@users.noreply.github.com>
Co-authored-by: Afr Schoe <58883403+q9f@users.noreply.github.com>
@kurotaky
Copy link
Collaborator Author

kurotaky commented May 6, 2022

@q9f I have corrected the points you just reviewed!

@q9f q9f merged commit 07befbe into main May 6, 2022
@q9f q9f deleted the smart-contract-support branch May 6, 2022 13:12
@q9f
Copy link
Owner

q9f commented May 6, 2022

Epic!

@q9f q9f added the enhancement New feature or request label May 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants