ethereum.rb 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.travis.yml +26 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/LICENSE.txt +21 -0
- data/README.md +183 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/install_parity +29 -0
- data/bin/setup +7 -0
- data/contracts/AccountingLib.sol +112 -0
- data/contracts/AuditorInterface.sol +4 -0
- data/contracts/AuditorRegistry.sol +14 -0
- data/contracts/CustodianInterface.sol +27 -0
- data/contracts/CustodianRegistry.sol +40 -0
- data/contracts/DigixConfiguration.sol +68 -0
- data/contracts/Directory.sol +67 -0
- data/contracts/DoublyLinked.sol +54 -0
- data/contracts/GenericInterface.sol +56 -0
- data/contracts/GenericRegistry.sol +15 -0
- data/contracts/Gold.sol +105 -0
- data/contracts/GoldRegistry.sol +82 -0
- data/contracts/GoldTokenLedger.sol +3 -0
- data/contracts/Interface.sol +27 -0
- data/contracts/Minter.sol +3 -0
- data/contracts/Recaster.sol +3 -0
- data/contracts/Testing.sol +59 -0
- data/contracts/VendorInterface.sol +82 -0
- data/contracts/VendorRegistry.sol +39 -0
- data/contracts/classic/Digixbot.sol +106 -0
- data/contracts/classic/DigixbotConfiguration.sol +62 -0
- data/contracts/classic/DigixbotEthereum.sol +86 -0
- data/contracts/classic/DigixbotUsers.sol +103 -0
- data/contracts/classic/Gold.sol +497 -0
- data/contracts/classic/GoldRegistry.sol +503 -0
- data/contracts/classic/GoldTokenLedger.sol +560 -0
- data/contracts/classic/GoldTokenMinter.sol +607 -0
- data/contracts/classic/ParticipantRegistry.sol +94 -0
- data/contracts/classic/QueueSample.sol +54 -0
- data/ethereum.gemspec +35 -0
- data/lib/ethereum.rb +24 -0
- data/lib/ethereum/client.rb +97 -0
- data/lib/ethereum/contract.rb +266 -0
- data/lib/ethereum/contract_event.rb +25 -0
- data/lib/ethereum/contract_initializer.rb +54 -0
- data/lib/ethereum/deployment.rb +49 -0
- data/lib/ethereum/formatter.rb +172 -0
- data/lib/ethereum/function.rb +20 -0
- data/lib/ethereum/function_input.rb +13 -0
- data/lib/ethereum/function_output.rb +14 -0
- data/lib/ethereum/http_client.rb +38 -0
- data/lib/ethereum/initializer.rb +27 -0
- data/lib/ethereum/ipc_client.rb +46 -0
- data/lib/ethereum/project_initializer.rb +28 -0
- data/lib/ethereum/railtie.rb +10 -0
- data/lib/ethereum/singleton.rb +39 -0
- data/lib/ethereum/solidity.rb +47 -0
- data/lib/ethereum/transaction.rb +36 -0
- data/lib/ethereum/version.rb +3 -0
- data/lib/tasks/ethereum_contract.rake +27 -0
- data/lib/tasks/ethereum_node.rake +51 -0
- data/lib/tasks/ethereum_test.rake +32 -0
- data/lib/tasks/ethereum_transaction.rake +24 -0
- metadata +198 -0
@@ -0,0 +1,94 @@
|
|
1
|
+
contract ParticipantRegistry {
|
2
|
+
|
3
|
+
enum ParticipantTypes { Admin, Vendor, Custodian, Auditor }
|
4
|
+
struct ParticipantDatabase {
|
5
|
+
mapping (address => bool) auditors;
|
6
|
+
mapping (address => bool) vendors;
|
7
|
+
mapping (address => bool) custodians;
|
8
|
+
mapping (address => bool) registrars;
|
9
|
+
}
|
10
|
+
|
11
|
+
address owner;
|
12
|
+
ParticipantDatabase participantdb;
|
13
|
+
|
14
|
+
event AddParticipant(address indexed participant, uint indexed participanttype);
|
15
|
+
event RemoveParticipant(address indexed participant, uint indexed participanttype);
|
16
|
+
|
17
|
+
modifier ifowner { if (msg.sender == owner) _ }
|
18
|
+
modifier ifregistrar { if ((participantdb.registrars[tx.origin]) || (tx.origin == owner)) _ }
|
19
|
+
modifier onlyvendor { if (isVendor(tx.origin) == true) _ }
|
20
|
+
modifier onlycustodian { if (isCustodian(tx.origin) == true) _ }
|
21
|
+
modifier onlyauditor { if (isAuditor(tx.origin) == true) _ }
|
22
|
+
|
23
|
+
function ParticipantRegistry() {
|
24
|
+
owner = msg.sender;
|
25
|
+
}
|
26
|
+
|
27
|
+
function getOwner() returns (address oa) {
|
28
|
+
oa = owner;
|
29
|
+
}
|
30
|
+
|
31
|
+
function setOwner(address nown) ifowner {
|
32
|
+
owner = nown;
|
33
|
+
}
|
34
|
+
|
35
|
+
function registerAdmin(address regraddr) ifowner {
|
36
|
+
participantdb.registrars[regraddr] = true;
|
37
|
+
AddParticipant(regraddr, uint(ParticipantTypes.Admin));
|
38
|
+
}
|
39
|
+
|
40
|
+
function unregisterAdmin(address regraddr) ifowner {
|
41
|
+
participantdb.registrars[regraddr] = false;
|
42
|
+
RemoveParticipant(regraddr, uint(ParticipantTypes.Admin));
|
43
|
+
}
|
44
|
+
|
45
|
+
function registerVendor(address vendoraddress) ifregistrar {
|
46
|
+
participantdb.vendors[vendoraddress] = true;
|
47
|
+
AddParticipant(vendoraddress, uint(ParticipantTypes.Vendor));
|
48
|
+
}
|
49
|
+
|
50
|
+
function unregisterVendor(address vendoraddress) ifregistrar {
|
51
|
+
participantdb.vendors[vendoraddress] = false;
|
52
|
+
RemoveParticipant(vendoraddress, uint(ParticipantTypes.Vendor));
|
53
|
+
}
|
54
|
+
|
55
|
+
function registerCustodian(address custodianaddress) ifregistrar {
|
56
|
+
participantdb.custodians[custodianaddress] = true;
|
57
|
+
AddParticipant(custodianaddress, uint(ParticipantTypes.Custodian));
|
58
|
+
}
|
59
|
+
|
60
|
+
function unregisterCustodian(address custodianaddress) ifregistrar {
|
61
|
+
participantdb.custodians[custodianaddress] = false;
|
62
|
+
RemoveParticipant(custodianaddress, uint(ParticipantTypes.Custodian));
|
63
|
+
}
|
64
|
+
|
65
|
+
function registerAuditor(address auditoraddress) ifregistrar {
|
66
|
+
participantdb.auditors[auditoraddress] = true;
|
67
|
+
AddParticipant(auditoraddress, uint(ParticipantTypes.Auditor));
|
68
|
+
}
|
69
|
+
|
70
|
+
function unregisterAuditor(address auditoraddress) ifregistrar {
|
71
|
+
participantdb.auditors[auditoraddress] = false;
|
72
|
+
RemoveParticipant(auditoraddress, uint(ParticipantTypes.Auditor));
|
73
|
+
}
|
74
|
+
|
75
|
+
function isVendor(address vendoraddress) returns (bool) {
|
76
|
+
return participantdb.vendors[vendoraddress];
|
77
|
+
}
|
78
|
+
|
79
|
+
function isCustodian(address custodianaddress) returns (bool) {
|
80
|
+
return participantdb.custodians[custodianaddress];
|
81
|
+
}
|
82
|
+
|
83
|
+
function isAuditor(address auditoraddress) returns (bool) {
|
84
|
+
return participantdb.auditors[auditoraddress];
|
85
|
+
}
|
86
|
+
|
87
|
+
function isRegistrar(address regraddr) returns (bool) {
|
88
|
+
return participantdb.registrars[regraddr];
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
//#include [ParticipantRegistry]
|
@@ -0,0 +1,54 @@
|
|
1
|
+
////////////////////////////////////////////////////////////
|
2
|
+
// This is an example contract hacked together at a meetup.
|
3
|
+
// It is by far not complete and only used to show some
|
4
|
+
// features of Solidity.
|
5
|
+
////////////////////////////////////////////////////////////
|
6
|
+
contract QueueContract
|
7
|
+
{
|
8
|
+
struct Queue {
|
9
|
+
uint[] data;
|
10
|
+
uint front;
|
11
|
+
uint back;
|
12
|
+
}
|
13
|
+
/// @dev the number of elements stored in the queue.
|
14
|
+
function length(Queue storage q) constant internal returns (uint) {
|
15
|
+
return q.back - q.front;
|
16
|
+
}
|
17
|
+
/// @dev the number of elements this queue can hold
|
18
|
+
function capacity(Queue storage q) constant internal returns (uint) {
|
19
|
+
return q.data.length - 1;
|
20
|
+
}
|
21
|
+
/// @dev push a new element to the back of the queue
|
22
|
+
function push(Queue storage q, uint data) internal
|
23
|
+
{
|
24
|
+
if ((q.back + 1) % q.data.length == q.front)
|
25
|
+
return; // throw;
|
26
|
+
q.data[q.back] = data;
|
27
|
+
q.back = (q.back + 1) % q.data.length;
|
28
|
+
}
|
29
|
+
/// @dev remove and return the element at the front of the queue
|
30
|
+
function pop(Queue storage q) internal returns (uint r)
|
31
|
+
{
|
32
|
+
if (q.back == q.front)
|
33
|
+
return; // throw;
|
34
|
+
r = q.data[q.front];
|
35
|
+
delete q.data[q.front];
|
36
|
+
q.front = (q.front + 1) % q.data.length;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
contract QueueUserMayBeDeliveryDroneCotnrol is QueueContract {
|
41
|
+
Queue requests;
|
42
|
+
function QueueUserMayBeDeliveryDroneCotnrol() {
|
43
|
+
requests.data.length = 200;
|
44
|
+
}
|
45
|
+
function addRequest(uint d) {
|
46
|
+
push(requests, d);
|
47
|
+
}
|
48
|
+
function popRequest() returns (uint) {
|
49
|
+
return pop(requests);
|
50
|
+
}
|
51
|
+
function queueLength() returns (uint) {
|
52
|
+
return length(requests);
|
53
|
+
}
|
54
|
+
}
|
data/ethereum.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ethereum/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ethereum.rb"
|
8
|
+
spec.version = Ethereum::VERSION
|
9
|
+
spec.authors = ["Marek Kirejczyk"]
|
10
|
+
spec.email = ["marek.kirejczyk@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Ruby Ethereum client using the JSON-RPC interface}
|
13
|
+
spec.description = %q{Ethereum.rb is Ruby Ethereum client using the JSON-RPC interface. Provides interface for sending transactions, creating and interacting with contracts as well as usefull toolkit to work with Ethereum node.}
|
14
|
+
spec.homepage = "https://github.com/marekkirejczyk/ethereum.rb"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
if spec.respond_to?(:metadata)
|
18
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
19
|
+
else
|
20
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
21
|
+
end
|
22
|
+
|
23
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
24
|
+
spec.bindir = "exe"
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
+
spec.require_paths = ["lib", "bin"]
|
27
|
+
|
28
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
29
|
+
spec.add_development_dependency "rake", "~> 12.0"
|
30
|
+
spec.add_development_dependency "rspec"
|
31
|
+
spec.add_development_dependency "pry"
|
32
|
+
|
33
|
+
spec.add_dependency "activesupport", "~> 5.0.1"
|
34
|
+
spec.add_dependency "digest-sha3", "~> 1.1.0"
|
35
|
+
end
|
data/lib/ethereum.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "ethereum/version"
|
2
|
+
require 'active_support'
|
3
|
+
require 'active_support/core_ext'
|
4
|
+
require 'digest/sha3'
|
5
|
+
|
6
|
+
module Ethereum
|
7
|
+
require 'ethereum/client'
|
8
|
+
require 'ethereum/ipc_client'
|
9
|
+
require 'ethereum/http_client'
|
10
|
+
require 'ethereum/singleton'
|
11
|
+
require 'ethereum/solidity'
|
12
|
+
require 'ethereum/initializer'
|
13
|
+
require 'ethereum/contract'
|
14
|
+
require 'ethereum/function'
|
15
|
+
require 'ethereum/function_input'
|
16
|
+
require 'ethereum/function_output'
|
17
|
+
require 'ethereum/contract_event'
|
18
|
+
require 'ethereum/formatter'
|
19
|
+
require 'ethereum/transaction'
|
20
|
+
require 'ethereum/deployment'
|
21
|
+
require 'ethereum/project_initializer'
|
22
|
+
require 'ethereum/contract_initializer'
|
23
|
+
require 'ethereum/railtie' if defined?(Rails)
|
24
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Ethereum
|
2
|
+
class Client
|
3
|
+
# https://github.com/ethereum/wiki/wiki/JSON-RPC
|
4
|
+
RPC_COMMANDS = %w(web3_clientVersion web3_sha3 net_version net_peerCount net_listening eth_protocolVersion eth_syncing eth_coinbase eth_mining eth_hashrate eth_gasPrice eth_accounts eth_blockNumber eth_getBalance eth_getStorageAt eth_getTransactionCount eth_getBlockTransactionCountByHash eth_getBlockTransactionCountByNumber eth_getUncleCountByBlockHash eth_getUncleCountByBlockNumber eth_getCode eth_sign eth_sendTransaction eth_sendRawTransaction eth_call eth_estimateGas eth_getBlockByHash eth_getBlockByNumber eth_getTransactionByHash eth_getTransactionByBlockHashAndIndex eth_getTransactionByBlockNumberAndIndex eth_getTransactionReceipt eth_getUncleByBlockHashAndIndex eth_getUncleByBlockNumberAndIndex eth_getCompilers eth_compileLLL eth_compileSolidity eth_compileSerpent eth_newFilter eth_newBlockFilter eth_newPendingTransactionFilter eth_uninstallFilter eth_getFilterChanges eth_getFilterLogs eth_getLogs eth_getWork eth_submitWork eth_submitHashrate db_putString db_getString db_putHex db_getHex shh_post shh_version shh_newIdentity shh_hasIdentity shh_newGroup shh_addToGroup shh_newFilter shh_uninstallFilter shh_getFilterChanges shh_getMessages)
|
5
|
+
# https://github.com/ethereum/go-ethereum/wiki/Management-APIs
|
6
|
+
RPC_MANAGEMENT_COMMANDS = %w(admin_addPeer admin_datadir admin_nodeInfo admin_peers admin_setSolc admin_startRPC admin_startWS admin_stopRPC admin_stopWS debug_backtraceAt debug_blockProfile debug_cpuProfile debug_dumpBlock debug_gcStats debug_getBlockRlp debug_goTrace debug_memStats debug_seedHash debug_setHead debug_setBlockProfileRate debug_stacks debug_startCPUProfile debug_startGoTrace debug_stopCPUProfile debug_stopGoTrace debug_traceBlock debug_traceBlockByNumber debug_traceBlockByHash debug_traceBlockFromFile debug_traceTransaction debug_verbosity debug_vmodule debug_writeBlockProfile debug_writeMemProfile miner_hashrate miner_makeDAG miner_setExtra miner_setGasPrice miner_start miner_startAutoDAG miner_stop miner_stopAutoDAG personal_importRawKey personal_listAccounts personal_lockAccount personal_newAccount personal_unlockAccount personal_sendTransaction txpool_content txpool_inspect txpool_status)
|
7
|
+
|
8
|
+
attr_accessor :command, :id, :log, :logger, :default_account
|
9
|
+
|
10
|
+
def initialize(log = false)
|
11
|
+
@id = 0
|
12
|
+
@log = log
|
13
|
+
@batch = nil
|
14
|
+
|
15
|
+
if @log == true
|
16
|
+
@logger = Logger.new("/tmp/ethereum_ruby_http.log")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.create(host_or_ipcpath, log = false)
|
21
|
+
return IpcClient.new(host_or_ipcpath, log) if host_or_ipcpath.end_with? '.ipc'
|
22
|
+
return HttpClient.new(host_or_ipcpath, log) if host_or_ipcpath.start_with? 'http'
|
23
|
+
raise ArgumentError.new('Unable to detect client type')
|
24
|
+
end
|
25
|
+
|
26
|
+
def batch
|
27
|
+
@batch = []
|
28
|
+
|
29
|
+
yield
|
30
|
+
result = send_batch(@batch)
|
31
|
+
|
32
|
+
@batch = nil
|
33
|
+
reset_id
|
34
|
+
|
35
|
+
return result
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_id
|
39
|
+
@id += 1
|
40
|
+
return @id
|
41
|
+
end
|
42
|
+
|
43
|
+
def reset_id
|
44
|
+
@id = 0
|
45
|
+
end
|
46
|
+
|
47
|
+
def default_account
|
48
|
+
@default_account || eth_accounts["result"][0]
|
49
|
+
end
|
50
|
+
|
51
|
+
def int_to_hex(n)
|
52
|
+
return "0x#{n.to_s(16)}"
|
53
|
+
end
|
54
|
+
|
55
|
+
# https://github.com/ethereum/wiki/wiki/JSON-RPC#output-hex-values
|
56
|
+
def encode_params(params)
|
57
|
+
return params.map do |p|
|
58
|
+
if p.is_a?(Integer)
|
59
|
+
int_to_hex(p)
|
60
|
+
else
|
61
|
+
p
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
(RPC_COMMANDS + RPC_MANAGEMENT_COMMANDS).each do |rpc_command|
|
67
|
+
method_name = rpc_command.underscore
|
68
|
+
define_method method_name do |*args|
|
69
|
+
command = rpc_command
|
70
|
+
if ["eth_getBalance", "eth_call"].include?(command)
|
71
|
+
args << "latest"
|
72
|
+
end
|
73
|
+
payload = {jsonrpc: "2.0", method: command, params: encode_params(args), id: get_id}
|
74
|
+
|
75
|
+
if @log == true
|
76
|
+
@logger.info("Sending #{payload.to_json}")
|
77
|
+
end
|
78
|
+
|
79
|
+
if @batch
|
80
|
+
@batch << payload
|
81
|
+
return true
|
82
|
+
else
|
83
|
+
read = send_single(payload.to_json)
|
84
|
+
output = JSON.parse(read)
|
85
|
+
if @log == true
|
86
|
+
@logger.info("Received #{output.to_json}")
|
87
|
+
end
|
88
|
+
reset_id
|
89
|
+
return output
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
@@ -0,0 +1,266 @@
|
|
1
|
+
module Ethereum
|
2
|
+
class Contract
|
3
|
+
|
4
|
+
DEFAULT_GAS_PRICE = 60000000000
|
5
|
+
|
6
|
+
DEFAULT_GAS = 3000000
|
7
|
+
|
8
|
+
attr_accessor :code, :name, :functions, :abi, :constructor_inputs, :events, :class_object
|
9
|
+
|
10
|
+
def initialize(name, code, abi)
|
11
|
+
@name = name
|
12
|
+
@code = code
|
13
|
+
@abi = abi
|
14
|
+
@functions = []
|
15
|
+
@events = []
|
16
|
+
@constructor_inputs = @abi.detect {|x| x["type"] == "constructor"}["inputs"] rescue nil
|
17
|
+
@abi.select {|x| x["type"] == "function" }.each do |abifun|
|
18
|
+
@functions << Ethereum::Function.new(abifun)
|
19
|
+
end
|
20
|
+
@abi.select {|x| x["type"] == "event" }.each do |abievt|
|
21
|
+
@events << Ethereum::ContractEvent.new(abievt)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.from_file(path, client = Ethereum::Singleton.instance)
|
26
|
+
@init = Ethereum::Initializer.new(path, client)
|
27
|
+
contracts = @init.build_all
|
28
|
+
raise "No contracts complied" if contracts.empty?
|
29
|
+
contracts.first.class_object.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.from_blockchain(name, address, abi, client = Ethereum::Singleton.instance)
|
33
|
+
contract = Ethereum::Contract.new(name, nil, abi)
|
34
|
+
contract.build(client)
|
35
|
+
contract_instance = contract.class_object.new
|
36
|
+
contract_instance.at address
|
37
|
+
contract_instance
|
38
|
+
end
|
39
|
+
|
40
|
+
def build(connection)
|
41
|
+
class_name = @name.camelize
|
42
|
+
functions = @functions
|
43
|
+
constructor_inputs = @constructor_inputs
|
44
|
+
binary = @code
|
45
|
+
events = @events
|
46
|
+
abi = @abi
|
47
|
+
|
48
|
+
class_methods = Class.new do
|
49
|
+
|
50
|
+
define_method "connection".to_sym do
|
51
|
+
connection
|
52
|
+
end
|
53
|
+
|
54
|
+
define_method :deploy do |*params|
|
55
|
+
formatter = Ethereum::Formatter.new
|
56
|
+
deploy_code = binary
|
57
|
+
deploy_arguments = ""
|
58
|
+
if constructor_inputs.present?
|
59
|
+
raise "Missing constructor parameter" and return if params.length != constructor_inputs.length
|
60
|
+
constructor_inputs.each_index do |i|
|
61
|
+
args = [constructor_inputs[i]["type"], params[i]]
|
62
|
+
deploy_arguments << formatter.to_payload(args)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
deploy_payload = deploy_code + deploy_arguments
|
66
|
+
deploytx = connection.eth_send_transaction({from: self.sender, data: "0x" + deploy_payload})["result"]
|
67
|
+
raise "Failed to deploy, did you unlock #{self.sender} account? Transaction hash: #{deploytx}" if deploytx.nil? || deploytx == "0x0000000000000000000000000000000000000000000000000000000000000000"
|
68
|
+
instance_variable_set("@deployment", Ethereum::Deployment.new(deploytx, connection))
|
69
|
+
end
|
70
|
+
|
71
|
+
define_method :estimate do |*params|
|
72
|
+
formatter = Ethereum::Formatter.new
|
73
|
+
deploy_code = binary
|
74
|
+
deploy_arguments = ""
|
75
|
+
if constructor_inputs.present?
|
76
|
+
raise "Missing constructor parameter" and return if params.length != constructor_inputs.length
|
77
|
+
constructor_inputs.each_index do |i|
|
78
|
+
args = [constructor_inputs[i]["type"], params[i]]
|
79
|
+
deploy_arguments << formatter.to_payload(args)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
deploy_payload = deploy_code + deploy_arguments
|
83
|
+
deploytx = connection.eth_estimate_gas({from: self.sender, data: "0x" + deploy_payload})["result"]
|
84
|
+
end
|
85
|
+
|
86
|
+
define_method :events do
|
87
|
+
return events
|
88
|
+
end
|
89
|
+
|
90
|
+
define_method :abi do
|
91
|
+
return abi
|
92
|
+
end
|
93
|
+
|
94
|
+
define_method :deployment do
|
95
|
+
instance_variable_get("@deployment")
|
96
|
+
end
|
97
|
+
|
98
|
+
define_method :deploy_and_wait do |time = 200.seconds, *params, **args, &block|
|
99
|
+
self.deploy(*params)
|
100
|
+
self.deployment.wait_for_deployment(time, **args, &block)
|
101
|
+
instance_variable_set("@address", self.deployment.contract_address)
|
102
|
+
self.events.each do |event|
|
103
|
+
event.set_address(self.deployment.contract_address)
|
104
|
+
event.set_client(connection)
|
105
|
+
end
|
106
|
+
self.deployment.contract_address
|
107
|
+
end
|
108
|
+
|
109
|
+
define_method :at do |addr|
|
110
|
+
instance_variable_set("@address", addr)
|
111
|
+
self.events.each do |event|
|
112
|
+
event.set_address(addr)
|
113
|
+
event.set_client(connection)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
define_method :address do
|
118
|
+
instance_variable_get("@address")
|
119
|
+
end
|
120
|
+
|
121
|
+
define_method :as do |addr|
|
122
|
+
instance_variable_set("@sender", addr)
|
123
|
+
end
|
124
|
+
|
125
|
+
define_method :sender do
|
126
|
+
instance_variable_get("@sender") || connection.default_account
|
127
|
+
end
|
128
|
+
|
129
|
+
define_method :set_gas_price do |gp|
|
130
|
+
instance_variable_set("@gas_price", gp)
|
131
|
+
end
|
132
|
+
|
133
|
+
define_method :gas_price do
|
134
|
+
instance_variable_get("@gas_price") || DEFAULT_GAS_PRICE
|
135
|
+
end
|
136
|
+
|
137
|
+
define_method :set_gas do |gas|
|
138
|
+
instance_variable_set("@gas", gas)
|
139
|
+
end
|
140
|
+
|
141
|
+
define_method :gas do
|
142
|
+
instance_variable_get("@gas") || DEFAULT_GAS
|
143
|
+
end
|
144
|
+
|
145
|
+
events.each do |evt|
|
146
|
+
define_method "nf_#{evt.name.underscore}".to_sym do |params = {}|
|
147
|
+
params[:to_block] ||= "latest"
|
148
|
+
params[:from_block] ||= "0x0"
|
149
|
+
params[:address] ||= instance_variable_get("@address")
|
150
|
+
params[:topics] = evt.signature
|
151
|
+
payload = {topics: [params[:topics]], fromBlock: params[:from_block], toBlock: params[:to_block], address: params[:address]}
|
152
|
+
filter_id = connection.new_filter(payload)
|
153
|
+
return filter_id["result"]
|
154
|
+
end
|
155
|
+
|
156
|
+
define_method "gfl_#{evt.name.underscore}".to_sym do |filter_id|
|
157
|
+
formatter = Ethereum::Formatter.new
|
158
|
+
logs = connection.get_filter_logs(filter_id)
|
159
|
+
collection = []
|
160
|
+
logs["result"].each do |result|
|
161
|
+
inputs = evt.input_types
|
162
|
+
outputs = inputs.zip(result["topics"][1..-1])
|
163
|
+
data = {blockNumber: result["blockNumber"].hex, transactionHash: result["transactionHash"], blockHash: result["blockHash"], transactionIndex: result["transactionIndex"].hex, topics: []}
|
164
|
+
outputs.each do |output|
|
165
|
+
data[:topics] << formatter.from_payload(output)
|
166
|
+
end
|
167
|
+
collection << data
|
168
|
+
end
|
169
|
+
return collection
|
170
|
+
end
|
171
|
+
|
172
|
+
define_method "gfc_#{evt.name.underscore}".to_sym do |filter_id|
|
173
|
+
formatter = Ethereum::Formatter.new
|
174
|
+
logs = connection.get_filter_changes(filter_id)
|
175
|
+
collection = []
|
176
|
+
logs["result"].each do |result|
|
177
|
+
inputs = evt.input_types
|
178
|
+
outputs = inputs.zip(result["topics"][1..-1])
|
179
|
+
data = {blockNumber: result["blockNumber"].hex, transactionHash: result["transactionHash"], blockHash: result["blockHash"], transactionIndex: result["transactionIndex"].hex, topics: []}
|
180
|
+
outputs.each do |output|
|
181
|
+
data[:topics] << formatter.from_payload(output)
|
182
|
+
end
|
183
|
+
collection << data
|
184
|
+
end
|
185
|
+
return collection
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
functions.each do |fun|
|
191
|
+
|
192
|
+
fun_count = functions.select {|x| x.name == fun.name }.count
|
193
|
+
derived_function_name = (fun_count == 1) ? "#{fun.name.underscore}" : "#{fun.name.underscore}__#{fun.inputs.collect {|x| x.type}.join("__")}"
|
194
|
+
call_function_name = "call_#{derived_function_name}".to_sym
|
195
|
+
call_function_name_alias = "c_#{derived_function_name}".to_sym
|
196
|
+
call_raw_function_name = "call_raw_#{derived_function_name}".to_sym
|
197
|
+
call_raw_function_name_alias = "cr_#{derived_function_name}".to_sym
|
198
|
+
transact_function_name = "transact_#{derived_function_name}".to_sym
|
199
|
+
transact_function_name_alias = "t_#{derived_function_name}".to_sym
|
200
|
+
transact_and_wait_function_name = "transact_and_wait_#{derived_function_name}".to_sym
|
201
|
+
transact_and_wait_function_name_alias = "tw_#{derived_function_name}".to_sym
|
202
|
+
|
203
|
+
define_method call_raw_function_name do |*args|
|
204
|
+
formatter = Ethereum::Formatter.new
|
205
|
+
arg_types = fun.inputs.collect(&:type)
|
206
|
+
connection = self.connection
|
207
|
+
return {result: :error, message: "missing parameters for #{fun.function_string}" } if arg_types.length != args.length
|
208
|
+
payload = []
|
209
|
+
payload << fun.signature
|
210
|
+
arg_types.zip(args).each do |arg|
|
211
|
+
payload << formatter.to_payload(arg)
|
212
|
+
end
|
213
|
+
raw_result = connection.eth_call({to: self.address, from: self.sender, data: "0x" + payload.join()})
|
214
|
+
raw_result = raw_result["result"]
|
215
|
+
formatted_result = fun.outputs.collect {|x| x.type }.zip(raw_result.gsub(/^0x/,'').scan(/.{64}/))
|
216
|
+
output = formatted_result.collect {|x| formatter.from_payload(x) }
|
217
|
+
return {data: "0x" + payload.join(), raw: raw_result, formatted: output}
|
218
|
+
end
|
219
|
+
|
220
|
+
define_method call_function_name do |*args|
|
221
|
+
data = self.send(call_raw_function_name, *args)
|
222
|
+
output = data[:formatted]
|
223
|
+
if output.length == 1
|
224
|
+
return output[0]
|
225
|
+
else
|
226
|
+
return output
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
define_method transact_function_name do |*args|
|
231
|
+
formatter = Ethereum::Formatter.new
|
232
|
+
arg_types = fun.inputs.collect(&:type)
|
233
|
+
connection = self.connection
|
234
|
+
return {result: :error, message: "missing parameters for #{fun.function_string}" } if arg_types.length != args.length
|
235
|
+
payload = []
|
236
|
+
payload << fun.signature
|
237
|
+
arg_types.zip(args).each do |arg|
|
238
|
+
payload << formatter.to_payload(arg)
|
239
|
+
end
|
240
|
+
txid = connection.eth_send_transaction({to: self.address, from: self.sender, data: "0x" + payload.join()})["result"]
|
241
|
+
return Ethereum::Transaction.new(txid, self.connection, payload.join(), args)
|
242
|
+
end
|
243
|
+
|
244
|
+
define_method transact_and_wait_function_name do |*args|
|
245
|
+
function_name = "transact_#{derived_function_name}".to_sym
|
246
|
+
tx = self.send(function_name, *args)
|
247
|
+
tx.wait_for_miner
|
248
|
+
return tx
|
249
|
+
end
|
250
|
+
|
251
|
+
alias_method call_function_name_alias, call_function_name
|
252
|
+
alias_method call_raw_function_name_alias, call_raw_function_name
|
253
|
+
alias_method transact_function_name_alias, transact_function_name
|
254
|
+
alias_method transact_and_wait_function_name_alias, transact_and_wait_function_name
|
255
|
+
|
256
|
+
end
|
257
|
+
end
|
258
|
+
if Object.const_defined?(class_name)
|
259
|
+
Object.send(:remove_const, class_name)
|
260
|
+
end
|
261
|
+
Object.const_set(class_name, class_methods)
|
262
|
+
@class_object = class_methods
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
266
|
+
end
|