ethereum.rb 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|