Class: AbiProxy

Inherits:
Object
  • Object
show all
Defined in:
lib/rubysol/abi_proxy.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(contract_class) ⇒ AbiProxy

Returns a new instance of AbiProxy.



9
10
11
12
13
14
15
16
17
18
19
# File 'lib/rubysol/abi_proxy.rb', line 9

def initialize(contract_class)
  @contract_class = contract_class
  @generated = false

  parents = contract_class.linearized_parents 
  if parents.empty?
    ## do nothing
  else 
    _merge_state_variables( parents)
  end
end

Instance Attribute Details

#contract_classObject

todo: make data private!!!

make  read access available via #each !!!


7
8
9
# File 'lib/rubysol/abi_proxy.rb', line 7

def contract_class
  @contract_class
end

Class Method Details

.contract_classesObject

keep a list of generated classes (only needed/possible to generatae once)



23
# File 'lib/rubysol/abi_proxy.rb', line 23

def self.contract_classes() @classes ||= []; end

Instance Method Details

#_contract_classesObject



24
# File 'lib/rubysol/abi_proxy.rb', line 24

def _contract_classes() self.class.contract_classes; end

#_generate_functions(contract_class) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/rubysol/abi_proxy.rb', line 43

def _generate_functions( contract_class )
  ## start with simple (no parents) for now

   sigs = contract_class.sigs
   puts "#{sigs.size} function signatures in #{contract_class.name}:"
   pp sigs

   ## note: only generate once for now!!!!
   ##        maybe check later if new sigs?? possible? why? why not?
   if _contract_classes.include?( contract_class )
       puts "   already generated!"
   else
     ## generate global function (e.g. ERC20() or such)
     Generator.global_function( contract_class )

     # sigs.each do |name, definition|
     #    Generator.typed_function( contract_class, name, 
     #                                  inputs: definition[:inputs] )
     #  end
     _contract_classes << contract_class
   end
end

#_merge_state_variables(parents) ⇒ Object



74
75
76
77
78
79
80
81
82
# File 'lib/rubysol/abi_proxy.rb', line 74

def _merge_state_variables( parents )
  puts "[debug] AbiProxy#merge_parent_state_variables - #{contract_class}"
  parent_state_variables = parents.map(&:state_variable_definitions).reverse
  vars = parent_state_variables.reduce( {} ) { |mem,h| mem.merge(h) }
                               .merge( contract_class.state_variable_definitions)
  puts "[debug]   merged state_variables:"
  pp vars
  contract_class.state_variable_definitions = vars    
end

#generate_functionsObject



29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/rubysol/abi_proxy.rb', line 29

def generate_functions
  @generated = true

  puts "==> generate (typed) functions for #{@contract_class.name}"
  
  parents = @contract_class.linearized_parents 
  ## revesee order - why? why not?
  parents.each do |parent|
    _generate_functions( parent )
  end
  _generate_functions( @contract_class )
end

#generated?Boolean

generated? - use flag to keep track of code generation (only one time needed/required)

Returns:

  • (Boolean)


28
# File 'lib/rubysol/abi_proxy.rb', line 28

def generated?() @generated; end

#public_abiObject Also known as: public_api



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/rubysol/abi_proxy.rb', line 86

def public_abi
  ### note: calculate for now on-the-fly - why? why not?
  ##   cache results - why? why not?
  contracts = [@contract_class] + @contract_class.linearized_parents
  ## note: use reverse order - 
  ##         most concreate comes last (for override)
  contracts = contracts.reverse  


  ## todo/fix: add (contract) klass for source to data???  - why? why not?
  data = {}

  contracts.each do |klass|
    klass.sigs.each do |name, definition|
         if definition[:options].include?( :public )
            ## check for override 
            ##   and issue info for now 
              if data.has_key?( name )
                ## Solidity lets developers change how a function in the parent contract is implemented
                ##  in the derived class. This is known as function overriding. 
                ##  The function in the parent contract needs to be declared with
                ##  the keyword virtual to indicate that it can be overridden 
                ## in the deriving contract.
                ##  
                ##   todo: check for virtual keyword - why? why not?
                  if name == :constructor
                    puts "   overriding constructor in #{klass.name}"
                  else
                    puts "   overriding function #{name} in #{klass.name}"
                  end
              end
              data[name] = definition  
         else
            puts "   skip non-public sig - #{name} #{definition.inspect}"
         end
    end
  end

  data
end

#public_abi_as_jsonObject

rename to to_abi_json or export_abi_json or solidity_abi_json or ??



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/rubysol/abi_proxy.rb', line 130

def public_abi_as_json
 ##
 ## todo/fix: add events too!!!
 ## todo/fix:  add input parameter names too!!!!

# json format:    
#      Type - defines the nature of the function (receive, fallback, constructor) 
#      Name - defines the name of the function
#      Inputs - array of objects with name, type, components
#      Outputs - array of objects similar to inputs
#      stateMutability - defines the mutability of the function (pure, view, non-payable or payable) 
#
#  "type": "constructor",
#  "inputs": [
#   { "type": "string", "name": "symbol" },
#   { "type": "string", "name": "name" }
#  ]
#
#  "type": "function",
#  "name": "balanceOf",
#  "stateMutability": "view",
#    "inputs": [
#      { "type": "address", "name": "owner"}
#    ],
#    "outputs": [
#      { "type": "uint256"}
#    ]

   data = []
 
   public_abi.each do |name, definition|
                 inputs = definition[:inputs].map do |input|
                                           ## todo: use a _arg1, _arg2, 
                                           ##   count or such - why?
                                        { 'type' => input.to_s,
                                          'name' => '_'
                                        }
                                   end  

                  state_mutability = 'nonpayable'  ## default is nonpayable (double check)
                  state_mutability = 'view'   if definition[:options].include?( :view )

             if name == :constructor
                 data << { 
                            'type'            => 'constructor', 
                            'stateMutability' => state_mutability,
                            'inputs'          =>  inputs
                          }     
             else
                 ## check if outputs is a single entry or array or nil or hash?
                 outputs = definition[:outputs].is_a?( Array ) ?
                                    definition[:outputs]  : [definition[:outputs]] 
                 outputs = outputs.map do |output|
                                           ## todo: use a _arg1, _arg2, 
                                           ##   count or such - why?
                                        { 'type' => output.to_s,
                                          'name' => '_'
                                        }
                                   end  

                 data << {
                            'type'     => 'function', 
                            'name'     =>  name.to_s,                    
                            'stateMutability' => state_mutability,
                            'inputs'   =>  inputs,
                            'outputs'  =>  outputs,
                         }
             end              
   end
   data   
end

#public_abi_to_jsonObject



203
204
205
# File 'lib/rubysol/abi_proxy.rb', line 203

def public_abi_to_json
    JSON.pretty_generate( public_abi_as_json )
end