abiparser 0.0.1 → 0.1.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 +4 -4
- data/Manifest.txt +2 -0
- data/README.md +127 -0
- data/lib/abiparser/constructor.rb +2 -4
- data/lib/abiparser/contract.rb +29 -0
- data/lib/abiparser/export/interface.rb +8 -5
- data/lib/abiparser/function.rb +11 -6
- data/lib/abiparser/interface.rb +59 -0
- data/lib/abiparser/param.rb +37 -11
- data/lib/abiparser/utils.rb +40 -0
- data/lib/abiparser/version.rb +2 -3
- data/lib/abiparser.rb +84 -0
- metadata +4 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 43f7d1f45a66ea6fd2deb690979c26f4289a666692bcb84c81420dbab5c2ab8b
         | 
| 4 | 
            +
              data.tar.gz: 487f1407542dc6d6f5e22b2975f4a7828fc0f08f5147961dc44230486bccbe71
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 5fc14d110513a91161272beb5a9e8d41401fe8ba5407d52beb43b782ac2b173108aaea79738b4f75d00439bf17908257376100c1d4166dc34434f936019eddbf
         | 
| 7 | 
            +
              data.tar.gz: ed21d7bcdbb58144832ba46c82d6fae1c1ec22f501936b34902e68c56ab44a556f219c35294cf09a836382252d77e67de231476b027724fcb60e681d3925d90f
         | 
    
        data/Manifest.txt
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -13,6 +13,133 @@ abiparser - application binary interface (abi) parser machinery / helper for Eth | |
| 13 13 | 
             
            ## Usage
         | 
| 14 14 |  | 
| 15 15 |  | 
| 16 | 
            +
            ### Functions Signature Hashes / Selectors & Interface (Type) Ids
         | 
| 17 | 
            +
             | 
| 18 | 
            +
             | 
| 19 | 
            +
            You can calculate the function selectors (or "sighash",
         | 
| 20 | 
            +
            that is, signature hash)
         | 
| 21 | 
            +
            by hashing the function signature
         | 
| 22 | 
            +
            e.g. `supportsInterface(bytes4)` with the Keccak 256-Bit algorithm
         | 
| 23 | 
            +
            and than use the first 4 bytes, that is, `0x01ffc9a7` (out of 32 bytes),
         | 
| 24 | 
            +
            that is, `0x01ffc9a7a5cef8baa21ed3c5c0d7e23accb804b619e9333b597f47a0d84076e2`. Example:
         | 
| 25 | 
            +
             | 
| 26 | 
            +
             | 
| 27 | 
            +
            ``` ruby
         | 
| 28 | 
            +
            require 'abiparser'
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            sig = 'supportsInterface(bytes4)'
         | 
| 31 | 
            +
            pp keccak256( sig )[0,4].hexdigest
         | 
| 32 | 
            +
            #=> "0x01ffc9a7"
         | 
| 33 | 
            +
            ```
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            Note: The `String#hexdigest` (also known as `String#bin_to_hex`) helper
         | 
| 36 | 
            +
            converts a binary string (with `BINARY`/`ASCII-8BIT` encoding)
         | 
| 37 | 
            +
            into a hex(adecimal) string.
         | 
| 38 | 
            +
             | 
| 39 | 
            +
             | 
| 40 | 
            +
            You can calcuate interface (type) ids
         | 
| 41 | 
            +
            by xor-ing (`^`) together the sighashes.
         | 
| 42 | 
            +
            If the interface only has one function than
         | 
| 43 | 
            +
            the interface (type) id equals the function sighash (by definition).
         | 
| 44 | 
            +
             | 
| 45 | 
            +
             | 
| 46 | 
            +
            ``` solidity
         | 
| 47 | 
            +
            interface ERC165 {
         | 
| 48 | 
            +
                /// @notice Query if a contract implements an interface
         | 
| 49 | 
            +
                /// @param interfaceID The interface identifier, as specified in ERC-165
         | 
| 50 | 
            +
                /// @dev Interface identification is specified in ERC-165.
         | 
| 51 | 
            +
                /// @return `true` if the contract implements `interfaceID` and
         | 
| 52 | 
            +
                ///  `interfaceID` is not 0xffffffff, `false` otherwise
         | 
| 53 | 
            +
              function supportsInterface(bytes4 interfaceID) external view returns (bool);
         | 
| 54 | 
            +
            }
         | 
| 55 | 
            +
            // The interface identifier for this interface is 0x01ffc9a7.
         | 
| 56 | 
            +
            ```
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            If you check the sighash for `supportsInterface(bytes4)`,
         | 
| 59 | 
            +
            that is, `0x01ffc9a7`  (see above)
         | 
| 60 | 
            +
            than -  bingo! - the  interface id for ERC165 matches up.
         | 
| 61 | 
            +
             | 
| 62 | 
            +
             | 
| 63 | 
            +
            Let's try to calculate the ERC20 standard (fungible) token interface
         | 
| 64 | 
            +
            where the official id is `0x36372b07` by xor-ing (`^`) together all function sighashes:
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            ``` ruby
         | 
| 67 | 
            +
            pp (keccak256('totalSupply()')[0,4] ^
         | 
| 68 | 
            +
                keccak256('balanceOf(address)')[0,4] ^
         | 
| 69 | 
            +
                keccak256('allowance(address,address)')[0,4] ^
         | 
| 70 | 
            +
                keccak256('transfer(address,uint256)')[0,4] ^
         | 
| 71 | 
            +
                keccak256('approve(address,uint256)')[0,4] ^
         | 
| 72 | 
            +
                keccak256('transferFrom(address,address,uint256)')[0,4]).hexdigest
         | 
| 73 | 
            +
            #=> "0x36372b07"
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            # or where   def sig(bin) = keccak256(bin)[0,4])
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            pp (sig('totalSupply()') ^
         | 
| 78 | 
            +
                sig('balanceOf(address)') ^
         | 
| 79 | 
            +
                sig('allowance(address,address)') ^
         | 
| 80 | 
            +
                sig('transfer(address,uint256)') ^
         | 
| 81 | 
            +
                sig('approve(address,uint256)') ^
         | 
| 82 | 
            +
                sig('transferFrom(address,address,uint256)')).hexdigest
         | 
| 83 | 
            +
            #=> "0x36372b07"
         | 
| 84 | 
            +
            ```
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            Voila!
         | 
| 87 | 
            +
            Or re(use) the builtin pre-defined interfaces. Example:
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            ``` ruby
         | 
| 90 | 
            +
            pp IERC165.inteface_id             #=> "0x01ffc9a7"
         | 
| 91 | 
            +
            pp IERC20.interface_id             #=> "0x36372b07"
         | 
| 92 | 
            +
            pp IERC721.interface_id            #=> "0x80ac58cd"
         | 
| 93 | 
            +
            pp IERC721_METADATA.interface_id   #=> "0x5b5e139f"
         | 
| 94 | 
            +
            pp IERC721_ENUMERABLE.interface_id #=> "0x780e9d63"
         | 
| 95 | 
            +
            ```
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            Yes, you can. Define your own interface. Let's have a looksie
         | 
| 98 | 
            +
            at the built-ins. Example:
         | 
| 99 | 
            +
             | 
| 100 | 
            +
            ``` ruby
         | 
| 101 | 
            +
            IERC165 = ABI::Interface.new(
         | 
| 102 | 
            +
              'supportsInterface(bytes4)'
         | 
| 103 | 
            +
            )
         | 
| 104 | 
            +
             | 
| 105 | 
            +
            IERC20  = ABI::Interface.new(
         | 
| 106 | 
            +
               'totalSupply()',
         | 
| 107 | 
            +
               'balanceOf(address)',
         | 
| 108 | 
            +
               'allowance(address,address)',
         | 
| 109 | 
            +
               'transfer(address,uint256)',
         | 
| 110 | 
            +
               'approve(address,uint256)',
         | 
| 111 | 
            +
               'transferFrom(address,address,uint256)'
         | 
| 112 | 
            +
            )
         | 
| 113 | 
            +
             | 
| 114 | 
            +
            IERC721 = ABI::Interface.new(
         | 
| 115 | 
            +
              'balanceOf(address)',
         | 
| 116 | 
            +
              'ownerOf(uint256)',
         | 
| 117 | 
            +
              'approve(address,uint256)',
         | 
| 118 | 
            +
              'getApproved(uint256)',
         | 
| 119 | 
            +
              'setApprovalForAll(address,bool)',
         | 
| 120 | 
            +
              'isApprovedForAll(address,address)',
         | 
| 121 | 
            +
              'transferFrom(address,address,uint256)',
         | 
| 122 | 
            +
              'safeTransferFrom(address,address,uint256)',
         | 
| 123 | 
            +
              'safeTransferFrom(address,address,uint256,bytes)' )
         | 
| 124 | 
            +
             | 
| 125 | 
            +
            IERC721_METADATA = ABI::Interface.new(
         | 
| 126 | 
            +
              'name()',
         | 
| 127 | 
            +
              'symbol()',
         | 
| 128 | 
            +
              'tokenURI(uint256)' )
         | 
| 129 | 
            +
             | 
| 130 | 
            +
            IERC721_ENUMERABLE = ABI::Interface.new(
         | 
| 131 | 
            +
              'tokenOfOwnerByIndex(address,uint256)',
         | 
| 132 | 
            +
              'totalSupply()',
         | 
| 133 | 
            +
              'tokenByIndex(uint256)' )
         | 
| 134 | 
            +
             | 
| 135 | 
            +
            ...
         | 
| 136 | 
            +
            ```
         | 
| 137 | 
            +
             | 
| 138 | 
            +
             | 
| 139 | 
            +
            To be continued...
         | 
| 140 | 
            +
             | 
| 141 | 
            +
             | 
| 142 | 
            +
             | 
| 16 143 |  | 
| 17 144 |  | 
| 18 145 | 
             
            ## License
         | 
    
        data/lib/abiparser/contract.rb
    CHANGED
    
    | @@ -63,8 +63,37 @@ class Contract | |
| 63 63 | 
             
                  @events = events
         | 
| 64 64 | 
             
                  @has_receive = has_receive
         | 
| 65 65 | 
             
                  @has_fallback = has_fallback
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  @selectors = {}
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  ## auto-add selectors (hashed signatures)
         | 
| 70 | 
            +
                  @funcs.each do |func|
         | 
| 71 | 
            +
                     sighash = func.sighash
         | 
| 72 | 
            +
                     puts "0x#{sighash} => #{func.sig}"
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                     ## assert - no duplicates allowed
         | 
| 75 | 
            +
                     if @selectors[sighash]
         | 
| 76 | 
            +
                        puts "!! ERROR - duplicate function signature #{func.sig}; already in use; sorry"
         | 
| 77 | 
            +
                        exit 1
         | 
| 78 | 
            +
                     end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                     @selectors[sighash] = func
         | 
| 81 | 
            +
                  end
         | 
| 66 82 | 
             
              end
         | 
| 67 83 |  | 
| 84 | 
            +
             | 
| 85 | 
            +
              ## return hexstrings of sig(natures) - why? why not?
         | 
| 86 | 
            +
              ## rename to sighashes - why? why not?
         | 
| 87 | 
            +
              def selectors()  @selectors.keys;  end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
             | 
| 90 | 
            +
             def support?( sig )
         | 
| 91 | 
            +
               Utils.support?( @selectors.keys, sig )
         | 
| 92 | 
            +
             end
         | 
| 93 | 
            +
             alias_method :supports?, :support?   ## add alternate spelling - why? why not?
         | 
| 94 | 
            +
             | 
| 95 | 
            +
             | 
| 96 | 
            +
             | 
| 68 97 | 
             
              def constructor() @ctor; end
         | 
| 69 98 | 
             
              def functions() @funcs; end
         | 
| 70 99 |  | 
| @@ -6,11 +6,14 @@ class Contract | |
| 6 6 | 
             
                buf = ''
         | 
| 7 7 | 
             
                buf << "interface #{name} {"
         | 
| 8 8 |  | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 9 | 
            +
             | 
| 10 | 
            +
            #  include constructor - why? why not?
         | 
| 11 | 
            +
            #
         | 
| 12 | 
            +
            #   if @ctor
         | 
| 13 | 
            +
            #      buf << "\n"
         | 
| 14 | 
            +
            #      buf << "// Constructor\n"
         | 
| 15 | 
            +
            #      buf << "#{@ctor.decl}\n"
         | 
| 16 | 
            +
            #    end
         | 
| 14 17 |  | 
| 15 18 | 
             
                if payable_functions.size > 0
         | 
| 16 19 | 
             
                  buf << "\n"
         | 
    
        data/lib/abiparser/function.rb
    CHANGED
    
    | @@ -7,9 +7,9 @@ class Function | |
| 7 7 | 
             
                inputs  = o['inputs'].map {|param| Param.parse( param ) }
         | 
| 8 8 | 
             
                outputs = o['outputs'].map {|param| Param.parse( param ) }
         | 
| 9 9 |  | 
| 10 | 
            -
                payable | 
| 11 | 
            -
                 | 
| 12 | 
            -
                pure | 
| 10 | 
            +
                payable  = nil
         | 
| 11 | 
            +
                constant = nil
         | 
| 12 | 
            +
                pure     = nil
         | 
| 13 13 |  | 
| 14 14 | 
             
                ## old soliditity before v0.6
         | 
| 15 15 | 
             
                ##  newer version uses stateMutability
         | 
| @@ -92,11 +92,16 @@ class Function | |
| 92 92 | 
             
                  buf << "(#{buf2.join(',')})"
         | 
| 93 93 | 
             
                end
         | 
| 94 94 | 
             
                buf
         | 
| 95 | 
            -
             | 
| 95 | 
            +
              end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
              def sighash
         | 
| 98 | 
            +
                keccak256( sig )[0,4].hexdigest
         | 
| 99 | 
            +
              end
         | 
| 96 100 |  | 
| 97 101 |  | 
| 98 102 | 
             
              def doc
         | 
| 99 | 
            -
                   | 
| 103 | 
            +
                  ## note: text with markdown formatting
         | 
| 104 | 
            +
                  buf = "function **#{@name}**"
         | 
| 100 105 | 
             
                  if @inputs.empty?
         | 
| 101 106 | 
             
                    buf << "()"
         | 
| 102 107 | 
             
                  else
         | 
| @@ -134,7 +139,7 @@ class Function | |
| 134 139 | 
             
                end
         | 
| 135 140 | 
             
                buf << ";"
         | 
| 136 141 | 
             
                buf
         | 
| 137 | 
            -
            end
         | 
| 142 | 
            +
              end
         | 
| 138 143 |  | 
| 139 144 |  | 
| 140 145 | 
             
            def types
         | 
| @@ -0,0 +1,59 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            module ABI
         | 
| 3 | 
            +
             | 
| 4 | 
            +
             | 
| 5 | 
            +
              ## rename to QueryInterface or SupportInterface
         | 
| 6 | 
            +
              ##   or InterfaceType or InterfaceId or such - why? why not?
         | 
| 7 | 
            +
            class Interface
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              attr_reader :interface_id
         | 
| 10 | 
            +
             | 
| 11 | 
            +
             | 
| 12 | 
            +
              ##
         | 
| 13 | 
            +
              ## todo/fix:  make sure full function defs get passed in (not only sigs!!!)
         | 
| 14 | 
            +
              def initialize( *functions )
         | 
| 15 | 
            +
                @functions = functions
         | 
| 16 | 
            +
                @selectors = {}
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                @functions.each do |func|
         | 
| 19 | 
            +
                  sig = func
         | 
| 20 | 
            +
                  sighash =  keccak256( sig )[0,4].hexdigest
         | 
| 21 | 
            +
                  puts "0x#{sighash} => #{sig}"
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  ## assert - no duplicates allowed
         | 
| 24 | 
            +
                  if @selectors[sighash]
         | 
| 25 | 
            +
                    puts "!! ERROR - duplicate function signature #{sig}; already in use; sorry"
         | 
| 26 | 
            +
                    exit 1
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  @selectors[sighash] = sig
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
                @interface_id = calc_interface_id
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
             | 
| 35 | 
            +
              def calc_interface_id
         | 
| 36 | 
            +
                interface_id = nil
         | 
| 37 | 
            +
                @selectors.each do |sighash,_|
         | 
| 38 | 
            +
                  sighash = sighash.hex_to_bin   ## note: convert to binary string (from hexstring)!!
         | 
| 39 | 
            +
                  interface_id = if interface_id.nil?
         | 
| 40 | 
            +
                    sighash   ## init with sighash
         | 
| 41 | 
            +
                  else
         | 
| 42 | 
            +
                    interface_id ^ sighash   ## use xor
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
                interface_id.hexdigest
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
             | 
| 49 | 
            +
              ## return hexstrings of sig(natures) - why? why not?
         | 
| 50 | 
            +
              ## rename to sighashes - why? why not?
         | 
| 51 | 
            +
              def selectors()  @selectors.keys;  end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              def support?( sig )
         | 
| 54 | 
            +
                 Utils.support?( @selectors.keys, sig )
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
              alias_method :supports?, :support?   ## add alternate spelling - why? why not?
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            end  ## class Interface
         | 
| 59 | 
            +
            end  # module ABI
         | 
    
        data/lib/abiparser/param.rb
    CHANGED
    
    | @@ -1,19 +1,35 @@ | |
| 1 1 | 
             
            module ABI
         | 
| 2 2 | 
             
            class Param
         | 
| 3 | 
            -
             | 
| 4 | 
            -
                attr_reader :type, :name
         | 
| 3 | 
            +
                attr_reader :type, :name, :internal_type
         | 
| 5 4 |  | 
| 6 5 | 
             
                def self.parse( o )
         | 
| 7 | 
            -
                  type | 
| 8 | 
            -
                   | 
| 9 | 
            -
                   | 
| 6 | 
            +
                  type          = o['type']
         | 
| 7 | 
            +
                  internal_type = o['internalType']
         | 
| 8 | 
            +
                  name          = o['name']
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  new( type, name,
         | 
| 11 | 
            +
                         internal_type: internal_type )
         | 
| 10 12 | 
             
                end
         | 
| 11 13 |  | 
| 12 | 
            -
                 | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 14 | 
            +
                ### check - find a "better" name for internal_type
         | 
| 15 | 
            +
                ##            use a keyword param - why? why not?
         | 
| 16 | 
            +
                def initialize( type, name=nil,
         | 
| 17 | 
            +
                                internal_type: nil )  ## note: type goes first!!!
         | 
| 18 | 
            +
                  @type          = type
         | 
| 19 | 
            +
                  ## note: convert empty string "" to nil - why? why not?
         | 
| 20 | 
            +
                  @name          = if name && name.empty?
         | 
| 21 | 
            +
                                         nil
         | 
| 22 | 
            +
                                   else
         | 
| 23 | 
            +
                                      name
         | 
| 24 | 
            +
                                   end
         | 
| 25 | 
            +
                  @internal_type = if internal_type && internal_type.empty?
         | 
| 26 | 
            +
                                          nil
         | 
| 27 | 
            +
                                   else
         | 
| 28 | 
            +
                                      internal_type
         | 
| 29 | 
            +
                                   end
         | 
| 15 30 | 
             
                end
         | 
| 16 31 |  | 
| 32 | 
            +
             | 
| 17 33 | 
             
                def sig
         | 
| 18 34 | 
             
                  buf = "#{@type}"
         | 
| 19 35 | 
             
                  buf
         | 
| @@ -21,16 +37,26 @@ class Param | |
| 21 37 |  | 
| 22 38 | 
             
                def doc
         | 
| 23 39 | 
             
                    buf = ''
         | 
| 24 | 
            -
                     | 
| 25 | 
            -
             | 
| 40 | 
            +
                    if @internal_type && @internal_type != @type
         | 
| 41 | 
            +
                      buf << "#{@internal_type} "
         | 
| 42 | 
            +
                    else
         | 
| 43 | 
            +
                      buf << "#{@type} "
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                    buf <<  (@name ?  @name : '_')
         | 
| 26 46 | 
             
                    buf
         | 
| 27 47 | 
             
                end
         | 
| 28 48 |  | 
| 29 49 | 
             
                def decl
         | 
| 30 50 | 
             
                  buf = ''
         | 
| 31 51 | 
             
                  buf << "#{@type} "
         | 
| 32 | 
            -
                  buf <<  (@name | 
| 52 | 
            +
                  buf <<  (@name ? @name :  '_')
         | 
| 53 | 
            +
                  ## use inline comment - why? why not?
         | 
| 54 | 
            +
                  if @internal_type && @internal_type != @type
         | 
| 55 | 
            +
                     buf << " /* #{@internal_type} */"
         | 
| 56 | 
            +
                  end
         | 
| 33 57 | 
             
                  buf
         | 
| 34 58 | 
             
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
             | 
| 35 61 | 
             
            end  ## class Param
         | 
| 36 62 | 
             
            end  ## module ABI
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            module ABI
         | 
| 2 | 
            +
            module Helpers
         | 
| 3 | 
            +
             | 
| 4 | 
            +
             | 
| 5 | 
            +
              SIGHASH_RX = /\A
         | 
| 6 | 
            +
                            (0x)?
         | 
| 7 | 
            +
                            (?<sighash>[0-9a-f]{8})
         | 
| 8 | 
            +
                            \z/ix
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def support?( selectors, sig )
         | 
| 11 | 
            +
                if sig.is_a?( Interface )
         | 
| 12 | 
            +
                  iface = sig
         | 
| 13 | 
            +
                  iface.selectors.each do |sighash|
         | 
| 14 | 
            +
                      unless selectors.include?( sighash )
         | 
| 15 | 
            +
                        puts "  sighash >#{sighash}< not found in interface"
         | 
| 16 | 
            +
                        return false
         | 
| 17 | 
            +
                      end
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                  true
         | 
| 20 | 
            +
                else
         | 
| 21 | 
            +
                  sighash =  if m=SIGHASH_RX.match( sig )
         | 
| 22 | 
            +
                              m[:sighash].downcase  ## assume it's sighash (hexstring)
         | 
| 23 | 
            +
                             else
         | 
| 24 | 
            +
                              ## for convenience allow (white)spaces; auto-strip - why? why not?
         | 
| 25 | 
            +
                              sig = sig.gsub( /[ \r\t\n]/, '' )
         | 
| 26 | 
            +
                              keccak256( sig )[0,4].hexdigest
         | 
| 27 | 
            +
                             end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  selectors.include?( sighash ) ? true : false
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end  # module Helpers
         | 
| 33 | 
            +
             | 
| 34 | 
            +
             | 
| 35 | 
            +
            module Utils
         | 
| 36 | 
            +
              extend Helpers
         | 
| 37 | 
            +
              ## e.g. Utils.supports?( selectors, sig ) etc.
         | 
| 38 | 
            +
            end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            end  # module ABI
         | 
    
        data/lib/abiparser/version.rb
    CHANGED
    
    
    
        data/lib/abiparser.rb
    CHANGED
    
    | @@ -6,9 +6,27 @@ require 'digest-lite' | |
| 6 6 | 
             
            ## extend String
         | 
| 7 7 | 
             
            class String
         | 
| 8 8 | 
             
              alias_method :hexdigest, :bin_to_hex   ## note: bin_to_hex added via Bytes!!!
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                # given two numeric strings,
         | 
| 11 | 
            +
                # returns the bitwise xor string
         | 
| 12 | 
            +
                def xor(other)
         | 
| 13 | 
            +
                    a = self.bytes
         | 
| 14 | 
            +
                    b = other.bytes
         | 
| 15 | 
            +
                    ## todo/check: cut-off on lower count (lc) - why? why not?
         | 
| 16 | 
            +
                    lc = (a.size < b.size) ? a.size : b.size
         | 
| 17 | 
            +
                    c = []
         | 
| 18 | 
            +
                    lc.times do |i|
         | 
| 19 | 
            +
                       c << (a[i] ^ b[i])
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                    c = c.pack( 'C*' )
         | 
| 22 | 
            +
                    puts "#{self.bin_to_hex} ^ #{other.bin_to_hex} = #{c.bin_to_hex}<"
         | 
| 23 | 
            +
                    c
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
                alias_method :^, :xor
         | 
| 9 26 | 
             
            end  # class String
         | 
| 10 27 |  | 
| 11 28 |  | 
| 29 | 
            +
             | 
| 12 30 | 
             
            def keccak256( bin )
         | 
| 13 31 | 
             
              Digest::KeccakLite.new( 256 ).digest( bin )
         | 
| 14 32 | 
             
            end
         | 
| @@ -24,12 +42,78 @@ require_relative 'abiparser/version'    # note: let version always go first | |
| 24 42 | 
             
            require_relative 'abiparser/param'
         | 
| 25 43 | 
             
            require_relative 'abiparser/constructor'
         | 
| 26 44 | 
             
            require_relative 'abiparser/function'
         | 
| 45 | 
            +
            require_relative 'abiparser/utils'
         | 
| 27 46 | 
             
            require_relative 'abiparser/contract'
         | 
| 47 | 
            +
            require_relative 'abiparser/interface'
         | 
| 28 48 |  | 
| 29 49 | 
             
            require_relative 'abiparser/export/interface.rb'
         | 
| 30 50 |  | 
| 31 51 |  | 
| 32 52 |  | 
| 53 | 
            +
             | 
| 54 | 
            +
            ## note: make "global" constants - why? why not?
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            ## IERC165  0x01ffc9a7
         | 
| 57 | 
            +
            IERC165 = ABI::Interface.new(
         | 
| 58 | 
            +
              'supportsInterface(bytes4)',
         | 
| 59 | 
            +
            )
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            ## IERC20  0x36372b07
         | 
| 62 | 
            +
            IERC20  = ABI::Interface.new(
         | 
| 63 | 
            +
               'totalSupply()',
         | 
| 64 | 
            +
               'balanceOf(address)',
         | 
| 65 | 
            +
               'allowance(address,address)',
         | 
| 66 | 
            +
               'transfer(address,uint256)',
         | 
| 67 | 
            +
               'approve(address,uint256)',
         | 
| 68 | 
            +
               'transferFrom(address,address,uint256)'
         | 
| 69 | 
            +
            )
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            ## IERC20_NAME 0x06fdde03
         | 
| 72 | 
            +
            IERC20_NAME = ABI::Interface.new(
         | 
| 73 | 
            +
              'name()'
         | 
| 74 | 
            +
            )
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            ## IERC20_SYMBOL 0x95d89b41
         | 
| 77 | 
            +
            IERC20_SYMBOL = ABI::Interface.new(
         | 
| 78 | 
            +
              'symbol()'
         | 
| 79 | 
            +
            )
         | 
| 80 | 
            +
             | 
| 81 | 
            +
            ## IERC20_DECIMALS 0x313ce567
         | 
| 82 | 
            +
            IERC20_DECIMALS = ABI::Interface.new(
         | 
| 83 | 
            +
              'decimals()'
         | 
| 84 | 
            +
            )
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            ## IERC721  0x80ac58cd
         | 
| 87 | 
            +
            IERC721 = ABI::Interface.new(
         | 
| 88 | 
            +
              'balanceOf(address)',
         | 
| 89 | 
            +
              'ownerOf(uint256)',
         | 
| 90 | 
            +
              'approve(address,uint256)',
         | 
| 91 | 
            +
              'getApproved(uint256)',
         | 
| 92 | 
            +
              'setApprovalForAll(address,bool)',
         | 
| 93 | 
            +
              'isApprovedForAll(address,address)',
         | 
| 94 | 
            +
              'transferFrom(address,address,uint256)',
         | 
| 95 | 
            +
              'safeTransferFrom(address,address,uint256)',
         | 
| 96 | 
            +
              'safeTransferFrom(address,address,uint256,bytes)'
         | 
| 97 | 
            +
            )
         | 
| 98 | 
            +
             | 
| 99 | 
            +
            ## IERC721_METADATA  0x5b5e139f
         | 
| 100 | 
            +
            IERC721_METADATA   = ABI::Interface.new(
         | 
| 101 | 
            +
              'name()',
         | 
| 102 | 
            +
              'symbol()',
         | 
| 103 | 
            +
              'tokenURI(uint256)'
         | 
| 104 | 
            +
            )
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            ## IERC721_ENUMERABLE  0x780e9d63
         | 
| 107 | 
            +
            IERC721_ENUMERABLE   = ABI::Interface.new(
         | 
| 108 | 
            +
              'tokenOfOwnerByIndex(address,uint256)',
         | 
| 109 | 
            +
              'totalSupply()',
         | 
| 110 | 
            +
              'tokenByIndex(uint256)'
         | 
| 111 | 
            +
            )
         | 
| 112 | 
            +
             | 
| 113 | 
            +
             | 
| 114 | 
            +
             | 
| 115 | 
            +
             | 
| 116 | 
            +
             | 
| 33 117 | 
             
            module ABI
         | 
| 34 118 | 
             
              def self.read( path )  Contract.read( path ); end
         | 
| 35 119 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: abiparser
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0 | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Gerald Bauer
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022-12- | 
| 11 | 
            +
            date: 2022-12-27 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: cocos
         | 
| @@ -105,7 +105,9 @@ files: | |
| 105 105 | 
             
            - lib/abiparser/contract.rb
         | 
| 106 106 | 
             
            - lib/abiparser/export/interface.rb
         | 
| 107 107 | 
             
            - lib/abiparser/function.rb
         | 
| 108 | 
            +
            - lib/abiparser/interface.rb
         | 
| 108 109 | 
             
            - lib/abiparser/param.rb
         | 
| 110 | 
            +
            - lib/abiparser/utils.rb
         | 
| 109 111 | 
             
            - lib/abiparser/version.rb
         | 
| 110 112 | 
             
            homepage: https://github.com/rubycocos/blockchain
         | 
| 111 113 | 
             
            licenses:
         |