2022-09-05 16:57:11 -04:00
"use strict" ;
2022-11-30 15:44:23 -05:00
/ * *
* About Interface
*
* @ _subsection api / abi : Interfaces [ interfaces ]
* /
2022-09-05 16:57:11 -04:00
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
exports . Interface = exports . Indexed = exports . ErrorDescription = exports . TransactionDescription = exports . LogDescription = exports . Result = exports . checkResultErrors = void 0 ;
const index _js _1 = require ( "../crypto/index.js" ) ;
const index _js _2 = require ( "../hash/index.js" ) ;
2022-09-15 22:58:45 -04:00
const index _js _3 = require ( "../utils/index.js" ) ;
2022-09-05 16:57:11 -04:00
const abi _coder _js _1 = require ( "./abi-coder.js" ) ;
const abstract _coder _js _1 = require ( "./coders/abstract-coder.js" ) ;
Object . defineProperty ( exports , "checkResultErrors" , { enumerable : true , get : function ( ) { return abstract _coder _js _1 . checkResultErrors ; } } ) ;
Object . defineProperty ( exports , "Result" , { enumerable : true , get : function ( ) { return abstract _coder _js _1 . Result ; } } ) ;
const fragments _js _1 = require ( "./fragments.js" ) ;
const typed _js _1 = require ( "./typed.js" ) ;
class LogDescription {
fragment ;
name ;
signature ;
topic ;
args ;
constructor ( fragment , topic , args ) {
const name = fragment . name , signature = fragment . format ( ) ;
2022-09-15 22:58:45 -04:00
( 0 , index _js _3 . defineProperties ) ( this , {
2022-09-05 16:57:11 -04:00
fragment , name , signature , topic , args
} ) ;
}
}
exports . LogDescription = LogDescription ;
class TransactionDescription {
fragment ;
name ;
args ;
signature ;
selector ;
value ;
constructor ( fragment , selector , args , value ) {
const name = fragment . name , signature = fragment . format ( ) ;
2022-09-15 22:58:45 -04:00
( 0 , index _js _3 . defineProperties ) ( this , {
2022-09-05 16:57:11 -04:00
fragment , name , args , signature , selector , value
} ) ;
}
}
exports . TransactionDescription = TransactionDescription ;
class ErrorDescription {
fragment ;
name ;
args ;
signature ;
selector ;
constructor ( fragment , selector , args ) {
const name = fragment . name , signature = fragment . format ( ) ;
2022-09-15 22:58:45 -04:00
( 0 , index _js _3 . defineProperties ) ( this , {
2022-09-05 16:57:11 -04:00
fragment , name , args , signature , selector
} ) ;
}
}
exports . ErrorDescription = ErrorDescription ;
class Indexed {
hash ;
_isIndexed ;
static isIndexed ( value ) {
return ! ! ( value && value . _isIndexed ) ;
}
constructor ( hash ) {
2022-09-15 22:58:45 -04:00
( 0 , index _js _3 . defineProperties ) ( this , { hash , _isIndexed : true } ) ;
2022-09-05 16:57:11 -04:00
}
}
exports . Indexed = Indexed ;
// https://docs.soliditylang.org/en/v0.8.13/control-structures.html?highlight=panic#panic-via-assert-and-error-via-require
const PanicReasons = {
"0" : "generic panic" ,
"1" : "assert(false)" ,
"17" : "arithmetic overflow" ,
"18" : "division or modulo by zero" ,
"33" : "enum overflow" ,
"34" : "invalid encoded storage byte array accessed" ,
"49" : "out-of-bounds array access; popping on an empty array" ,
"50" : "out-of-bounds access of an array or bytesN" ,
"65" : "out of memory" ,
"81" : "uninitialized function" ,
} ;
const BuiltinErrors = {
"0x08c379a0" : {
signature : "Error(string)" ,
name : "Error" ,
inputs : [ "string" ] ,
reason : ( message ) => {
return ` reverted with reason string ${ JSON . stringify ( message ) } ` ;
}
} ,
"0x4e487b71" : {
signature : "Panic(uint256)" ,
name : "Panic" ,
inputs : [ "uint256" ] ,
reason : ( code ) => {
let reason = "unknown panic code" ;
if ( code >= 0 && code <= 0xff && PanicReasons [ code . toString ( ) ] ) {
reason = PanicReasons [ code . toString ( ) ] ;
}
return ` reverted with panic code 0x ${ code . toString ( 16 ) } ( ${ reason } ) ` ;
}
}
} ;
2022-11-30 15:44:23 -05:00
/ * *
* An Interface abstracts many of the low - level details for
* encoding and decoding the data on the blockchain .
*
* An ABI provides information on how to encode data to send to
* a Contract , how to decode the results and events and how to
* interpret revert errors .
*
* The ABI can be specified by [ any supported format ] ( InterfaceAbi ) .
* /
2022-09-05 16:57:11 -04:00
class Interface {
2022-09-15 22:58:45 -04:00
/ * *
* All the Contract ABI members ( i . e . methods , events , errors , etc ) .
* /
2022-09-05 16:57:11 -04:00
fragments ;
2022-09-15 22:58:45 -04:00
/ * *
* The Contract constructor .
* /
2022-09-05 16:57:11 -04:00
deploy ;
2023-01-30 22:29:09 -05:00
/ * *
* The Fallback method , if any .
* /
fallback ;
/ * *
* If receiving ether is supported .
* /
receive ;
2022-09-05 16:57:11 -04:00
# errors ;
# events ;
# functions ;
// #structs: Map<string, StructFragment>;
# abiCoder ;
2022-11-30 15:44:23 -05:00
/ * *
* Create a new Interface for the % % fragments % % .
* /
2022-09-05 16:57:11 -04:00
constructor ( fragments ) {
let abi = [ ] ;
if ( typeof ( fragments ) === "string" ) {
abi = JSON . parse ( fragments ) ;
}
else {
abi = fragments ;
}
this . # functions = new Map ( ) ;
this . # errors = new Map ( ) ;
this . # events = new Map ( ) ;
// this.#structs = new Map();
2022-09-27 03:45:27 -04:00
const frags = [ ] ;
for ( const a of abi ) {
try {
frags . push ( fragments _js _1 . Fragment . from ( a ) ) ;
}
2022-10-01 01:34:06 -04:00
catch ( error ) {
console . log ( "EE" , error ) ;
}
2022-09-27 03:45:27 -04:00
}
2022-09-15 22:58:45 -04:00
( 0 , index _js _3 . defineProperties ) ( this , {
2022-09-27 03:45:27 -04:00
fragments : Object . freeze ( frags )
2022-09-05 16:57:11 -04:00
} ) ;
2023-01-30 22:29:09 -05:00
let fallback = null ;
let receive = false ;
2022-09-05 16:57:11 -04:00
this . # abiCoder = this . getAbiCoder ( ) ;
// Add all fragments by their signature
2023-01-30 22:29:09 -05:00
this . fragments . forEach ( ( fragment , index ) => {
2022-09-05 16:57:11 -04:00
let bucket ;
switch ( fragment . type ) {
case "constructor" :
if ( this . deploy ) {
2022-09-15 22:58:45 -04:00
console . log ( "duplicate definition - constructor" ) ;
2022-09-05 16:57:11 -04:00
return ;
}
//checkNames(fragment, "input", fragment.inputs);
2022-09-15 22:58:45 -04:00
( 0 , index _js _3 . defineProperties ) ( this , { deploy : fragment } ) ;
2022-09-05 16:57:11 -04:00
return ;
2023-01-30 22:29:09 -05:00
case "fallback" :
if ( fragment . inputs . length === 0 ) {
receive = true ;
}
else {
( 0 , index _js _3 . assertArgument ) ( ! fallback || fragment . payable !== fallback . payable , "conflicting fallback fragments" , ` fragments[ ${ index } ] ` , fragment ) ;
fallback = fragment ;
receive = fallback . payable ;
}
return ;
2022-09-05 16:57:11 -04:00
case "function" :
//checkNames(fragment, "input", fragment.inputs);
//checkNames(fragment, "output", (<FunctionFragment>fragment).outputs);
bucket = this . # functions ;
break ;
case "event" :
//checkNames(fragment, "input", fragment.inputs);
bucket = this . # events ;
break ;
case "error" :
bucket = this . # errors ;
break ;
default :
return ;
}
2022-09-15 22:58:45 -04:00
// Two identical entries; ignore it
2022-09-05 16:57:11 -04:00
const signature = fragment . format ( ) ;
if ( bucket . has ( signature ) ) {
return ;
}
bucket . set ( signature , fragment ) ;
} ) ;
// If we do not have a constructor add a default
if ( ! this . deploy ) {
2022-09-15 22:58:45 -04:00
( 0 , index _js _3 . defineProperties ) ( this , {
2022-10-01 01:34:06 -04:00
deploy : fragments _js _1 . ConstructorFragment . from ( "constructor()" )
2022-09-05 16:57:11 -04:00
} ) ;
}
2023-01-30 22:29:09 -05:00
( 0 , index _js _3 . defineProperties ) ( this , { fallback , receive } ) ;
2022-09-05 16:57:11 -04:00
}
2022-09-15 22:58:45 -04:00
/ * *
* Returns the entire Human - Readable ABI , as an array of
* signatures , optionally as % % minimal % % strings , which
* removes parameter names and unneceesary spaces .
* /
format ( minimal ) {
const format = ( minimal ? "minimal" : "full" ) ;
2022-09-05 16:57:11 -04:00
const abi = this . fragments . map ( ( f ) => f . format ( format ) ) ;
return abi ;
}
2022-09-15 22:58:45 -04:00
/ * *
* Return the JSON - encoded ABI . This is the format Solidiy
* returns .
* /
formatJson ( ) {
const abi = this . fragments . map ( ( f ) => f . format ( "json" ) ) ;
// We need to re-bundle the JSON fragments a bit
return JSON . stringify ( abi . map ( ( j ) => JSON . parse ( j ) ) ) ;
}
/ * *
* The ABI coder that will be used to encode and decode binary
* data .
* /
2022-09-05 16:57:11 -04:00
getAbiCoder ( ) {
2022-11-30 15:44:23 -05:00
return abi _coder _js _1 . AbiCoder . defaultAbiCoder ( ) ;
2022-09-05 16:57:11 -04:00
}
// Find a function definition by any means necessary (unless it is ambiguous)
# getFunction ( key , values , forceUnique ) {
// Selector
2022-09-15 22:58:45 -04:00
if ( ( 0 , index _js _3 . isHexString ) ( key ) ) {
2022-09-05 16:57:11 -04:00
const selector = key . toLowerCase ( ) ;
for ( const fragment of this . # functions . values ( ) ) {
2022-09-15 22:58:45 -04:00
if ( selector === fragment . selector ) {
2022-09-05 16:57:11 -04:00
return fragment ;
}
}
2023-01-27 17:29:49 -05:00
return null ;
2022-09-05 16:57:11 -04:00
}
// It is a bare name, look up the function (will return null if ambiguous)
if ( key . indexOf ( "(" ) === - 1 ) {
const matching = [ ] ;
for ( const [ name , fragment ] of this . # functions ) {
if ( name . split ( "(" /* fix:) */ ) [ 0 ] === key ) {
matching . push ( fragment ) ;
}
}
if ( values ) {
const lastValue = ( values . length > 0 ) ? values [ values . length - 1 ] : null ;
let valueLength = values . length ;
let allowOptions = true ;
if ( typed _js _1 . Typed . isTyped ( lastValue ) && lastValue . type === "overrides" ) {
allowOptions = false ;
valueLength -- ;
}
// Remove all matches that don't have a compatible length. The args
// may contain an overrides, so the match may have n or n - 1 parameters
for ( let i = matching . length - 1 ; i >= 0 ; i -- ) {
const inputs = matching [ i ] . inputs . length ;
if ( inputs !== valueLength && ( ! allowOptions || inputs !== valueLength - 1 ) ) {
matching . splice ( i , 1 ) ;
}
}
// Remove all matches that don't match the Typed signature
for ( let i = matching . length - 1 ; i >= 0 ; i -- ) {
const inputs = matching [ i ] . inputs ;
for ( let j = 0 ; j < values . length ; j ++ ) {
// Not a typed value
if ( ! typed _js _1 . Typed . isTyped ( values [ j ] ) ) {
continue ;
}
// We are past the inputs
if ( j >= inputs . length ) {
if ( values [ j ] . type === "overrides" ) {
continue ;
}
matching . splice ( i , 1 ) ;
break ;
}
// Make sure the value type matches the input type
if ( values [ j ] . type !== inputs [ j ] . baseType ) {
matching . splice ( i , 1 ) ;
break ;
}
}
}
}
// We found a single matching signature with an overrides, but the
// last value is something that cannot possibly be an options
if ( matching . length === 1 && values && values . length !== matching [ 0 ] . inputs . length ) {
const lastArg = values [ values . length - 1 ] ;
if ( lastArg == null || Array . isArray ( lastArg ) || typeof ( lastArg ) !== "object" ) {
matching . splice ( 0 , 1 ) ;
}
}
2023-01-27 17:29:49 -05:00
if ( matching . length === 0 ) {
return null ;
}
2022-11-09 02:57:02 -05:00
if ( matching . length > 1 && forceUnique ) {
2022-09-05 16:57:11 -04:00
const matchStr = matching . map ( ( m ) => JSON . stringify ( m . format ( ) ) ) . join ( ", " ) ;
2023-01-27 17:29:49 -05:00
( 0 , index _js _3 . assertArgument ) ( false , ` ambiguous function description (i.e. matches ${ matchStr } ) ` , "key" , key ) ;
2022-09-05 16:57:11 -04:00
}
return matching [ 0 ] ;
}
// Normalize the signature and lookup the function
2022-10-01 01:34:06 -04:00
const result = this . # functions . get ( fragments _js _1 . FunctionFragment . from ( key ) . format ( ) ) ;
2022-09-05 16:57:11 -04:00
if ( result ) {
return result ;
}
2023-01-27 17:29:49 -05:00
return null ;
2022-09-05 16:57:11 -04:00
}
2022-09-15 22:58:45 -04:00
/ * *
* Get the function name for % % key % % , which may be a function selector ,
* function name or function signature that belongs to the ABI .
* /
2022-09-05 16:57:11 -04:00
getFunctionName ( key ) {
2023-01-27 17:29:49 -05:00
const fragment = this . # getFunction ( key , null , false ) ;
( 0 , index _js _3 . assertArgument ) ( fragment , "no matching function" , "key" , key ) ;
return fragment . name ;
2022-09-05 16:57:11 -04:00
}
2022-09-15 22:58:45 -04:00
/ * *
* Get the [ [ FunctionFragment ] ] for % % key % % , which may be a function
* selector , function name or function signature that belongs to the ABI .
*
* If % % values % % is provided , it will use the Typed API to handle
* ambiguous cases where multiple functions match by name .
*
* If the % % key % % and % % values % % do not refine to a single function in
* the ABI , this will throw .
* /
2022-09-05 16:57:11 -04:00
getFunction ( key , values ) {
return this . # getFunction ( key , values || null , true ) ;
}
2023-01-22 16:47:02 -05:00
/ * *
* Iterate over all functions , calling % % callback % % , sorted by their name .
* /
forEachFunction ( callback ) {
const names = Array . from ( this . # functions . keys ( ) ) ;
names . sort ( ( a , b ) => a . localeCompare ( b ) ) ;
for ( let i = 0 ; i < names . length ; i ++ ) {
const name = names [ i ] ;
callback ( ( this . # functions . get ( name ) ) , i ) ;
}
}
2022-09-05 16:57:11 -04:00
// Find an event definition by any means necessary (unless it is ambiguous)
# getEvent ( key , values , forceUnique ) {
// EventTopic
2022-09-15 22:58:45 -04:00
if ( ( 0 , index _js _3 . isHexString ) ( key ) ) {
2022-09-05 16:57:11 -04:00
const eventTopic = key . toLowerCase ( ) ;
for ( const fragment of this . # events . values ( ) ) {
2022-09-15 22:58:45 -04:00
if ( eventTopic === fragment . topicHash ) {
2022-09-05 16:57:11 -04:00
return fragment ;
}
}
2023-01-27 17:29:49 -05:00
return null ;
2022-09-05 16:57:11 -04:00
}
// It is a bare name, look up the function (will return null if ambiguous)
if ( key . indexOf ( "(" ) === - 1 ) {
const matching = [ ] ;
for ( const [ name , fragment ] of this . # events ) {
if ( name . split ( "(" /* fix:) */ ) [ 0 ] === key ) {
matching . push ( fragment ) ;
}
}
if ( values ) {
// Remove all matches that don't have a compatible length.
for ( let i = matching . length - 1 ; i >= 0 ; i -- ) {
if ( matching [ i ] . inputs . length < values . length ) {
matching . splice ( i , 1 ) ;
}
}
// Remove all matches that don't match the Typed signature
for ( let i = matching . length - 1 ; i >= 0 ; i -- ) {
const inputs = matching [ i ] . inputs ;
for ( let j = 0 ; j < values . length ; j ++ ) {
// Not a typed value
if ( ! typed _js _1 . Typed . isTyped ( values [ j ] ) ) {
continue ;
}
// Make sure the value type matches the input type
if ( values [ j ] . type !== inputs [ j ] . baseType ) {
matching . splice ( i , 1 ) ;
break ;
}
}
}
}
2023-01-27 17:29:49 -05:00
if ( matching . length === 0 ) {
return null ;
}
2022-11-09 02:57:02 -05:00
if ( matching . length > 1 && forceUnique ) {
2023-01-27 17:29:49 -05:00
const matchStr = matching . map ( ( m ) => JSON . stringify ( m . format ( ) ) ) . join ( ", " ) ;
( 0 , index _js _3 . assertArgument ) ( false , ` ambiguous event description (i.e. matches ${ matchStr } ) ` , "key" , key ) ;
2022-09-05 16:57:11 -04:00
}
return matching [ 0 ] ;
}
// Normalize the signature and lookup the function
2022-10-01 01:34:06 -04:00
const result = this . # events . get ( fragments _js _1 . EventFragment . from ( key ) . format ( ) ) ;
2022-09-05 16:57:11 -04:00
if ( result ) {
return result ;
}
2023-01-27 17:29:49 -05:00
return null ;
2022-09-05 16:57:11 -04:00
}
2022-09-15 22:58:45 -04:00
/ * *
* Get the event name for % % key % % , which may be a topic hash ,
* event name or event signature that belongs to the ABI .
* /
2022-09-05 16:57:11 -04:00
getEventName ( key ) {
2023-01-27 17:29:49 -05:00
const fragment = this . # getEvent ( key , null , false ) ;
( 0 , index _js _3 . assertArgument ) ( fragment , "no matching event" , "key" , key ) ;
return fragment . name ;
2022-09-05 16:57:11 -04:00
}
2022-09-15 22:58:45 -04:00
/ * *
* Get the [ [ EventFragment ] ] for % % key % % , which may be a topic hash ,
* event name or event signature that belongs to the ABI .
*
* If % % values % % is provided , it will use the Typed API to handle
* ambiguous cases where multiple events match by name .
*
* If the % % key % % and % % values % % do not refine to a single event in
* the ABI , this will throw .
* /
2022-09-05 16:57:11 -04:00
getEvent ( key , values ) {
return this . # getEvent ( key , values || null , true ) ;
}
2023-01-22 16:47:02 -05:00
/ * *
* Iterate over all events , calling % % callback % % , sorted by their name .
* /
forEachEvent ( callback ) {
const names = Array . from ( this . # events . keys ( ) ) ;
names . sort ( ( a , b ) => a . localeCompare ( b ) ) ;
for ( let i = 0 ; i < names . length ; i ++ ) {
const name = names [ i ] ;
callback ( ( this . # events . get ( name ) ) , i ) ;
}
}
2022-09-15 22:58:45 -04:00
/ * *
* Get the [ [ ErrorFragment ] ] for % % key % % , which may be an error
* selector , error name or error signature that belongs to the ABI .
*
* If % % values % % is provided , it will use the Typed API to handle
* ambiguous cases where multiple errors match by name .
*
* If the % % key % % and % % values % % do not refine to a single error in
* the ABI , this will throw .
* /
2022-09-05 16:57:11 -04:00
getError ( key , values ) {
2022-09-15 22:58:45 -04:00
if ( ( 0 , index _js _3 . isHexString ) ( key ) ) {
2022-09-05 16:57:11 -04:00
const selector = key . toLowerCase ( ) ;
if ( BuiltinErrors [ selector ] ) {
2022-10-01 01:34:06 -04:00
return fragments _js _1 . ErrorFragment . from ( BuiltinErrors [ selector ] . signature ) ;
2022-09-05 16:57:11 -04:00
}
for ( const fragment of this . # errors . values ( ) ) {
2022-09-15 22:58:45 -04:00
if ( selector === fragment . selector ) {
2022-09-05 16:57:11 -04:00
return fragment ;
}
}
2023-01-27 17:29:49 -05:00
return null ;
2022-09-05 16:57:11 -04:00
}
// It is a bare name, look up the function (will return null if ambiguous)
if ( key . indexOf ( "(" ) === - 1 ) {
const matching = [ ] ;
for ( const [ name , fragment ] of this . # errors ) {
if ( name . split ( "(" /* fix:) */ ) [ 0 ] === key ) {
matching . push ( fragment ) ;
}
}
if ( matching . length === 0 ) {
if ( key === "Error" ) {
2022-10-01 01:34:06 -04:00
return fragments _js _1 . ErrorFragment . from ( "error Error(string)" ) ;
2022-09-05 16:57:11 -04:00
}
if ( key === "Panic" ) {
2022-10-01 01:34:06 -04:00
return fragments _js _1 . ErrorFragment . from ( "error Panic(uint256)" ) ;
2022-09-05 16:57:11 -04:00
}
2023-01-27 17:29:49 -05:00
return null ;
2022-09-05 16:57:11 -04:00
}
else if ( matching . length > 1 ) {
2023-01-27 17:29:49 -05:00
const matchStr = matching . map ( ( m ) => JSON . stringify ( m . format ( ) ) ) . join ( ", " ) ;
( 0 , index _js _3 . assertArgument ) ( false , ` ambiguous error description (i.e. ${ matchStr } ) ` , "name" , key ) ;
2022-09-05 16:57:11 -04:00
}
return matching [ 0 ] ;
}
// Normalize the signature and lookup the function
2022-10-01 01:34:06 -04:00
key = fragments _js _1 . ErrorFragment . from ( key ) . format ( ) ;
2022-09-05 16:57:11 -04:00
if ( key === "Error(string)" ) {
2022-10-01 01:34:06 -04:00
return fragments _js _1 . ErrorFragment . from ( "error Error(string)" ) ;
2022-09-05 16:57:11 -04:00
}
if ( key === "Panic(uint256)" ) {
2022-10-01 01:34:06 -04:00
return fragments _js _1 . ErrorFragment . from ( "error Panic(uint256)" ) ;
2022-09-05 16:57:11 -04:00
}
const result = this . # errors . get ( key ) ;
if ( result ) {
return result ;
}
2023-01-27 17:29:49 -05:00
return null ;
2022-09-05 16:57:11 -04:00
}
2023-01-22 16:47:02 -05:00
/ * *
* Iterate over all errors , calling % % callback % % , sorted by their name .
* /
forEachError ( callback ) {
const names = Array . from ( this . # errors . keys ( ) ) ;
names . sort ( ( a , b ) => a . localeCompare ( b ) ) ;
for ( let i = 0 ; i < names . length ; i ++ ) {
const name = names [ i ] ;
callback ( ( this . # errors . get ( name ) ) , i ) ;
}
}
2022-09-05 16:57:11 -04:00
// Get the 4-byte selector used by Solidity to identify a function
2022-09-15 22:58:45 -04:00
/ *
getSelector ( fragment : ErrorFragment | FunctionFragment ) : string {
if ( typeof ( fragment ) === "string" ) {
const matches : Array < Fragment > = [ ] ;
2022-09-05 16:57:11 -04:00
2022-09-15 22:58:45 -04:00
try { matches . push ( this . getFunction ( fragment ) ) ; } catch ( error ) { }
try { matches . push ( this . getError ( < string > fragment ) ) ; } catch ( _ ) { }
2022-09-05 16:57:11 -04:00
2022-09-15 22:58:45 -04:00
if ( matches . length === 0 ) {
logger . throwArgumentError ( "unknown fragment" , "key" , fragment ) ;
} else if ( matches . length > 1 ) {
logger . throwArgumentError ( "ambiguous fragment matches function and error" , "key" , fragment ) ;
2022-09-05 16:57:11 -04:00
}
2022-09-15 22:58:45 -04:00
fragment = matches [ 0 ] ;
2022-09-05 16:57:11 -04:00
}
2022-09-15 22:58:45 -04:00
return dataSlice ( id ( fragment . format ( ) ) , 0 , 4 ) ;
}
* /
2022-09-05 16:57:11 -04:00
// Get the 32-byte topic hash used by Solidity to identify an event
2022-09-15 22:58:45 -04:00
/ *
getEventTopic ( fragment : EventFragment ) : string {
2022-09-05 16:57:11 -04:00
//if (typeof(fragment) === "string") { fragment = this.getEvent(eventFragment); }
2022-09-15 22:58:45 -04:00
return id ( fragment . format ( ) ) ;
2022-09-05 16:57:11 -04:00
}
2022-09-15 22:58:45 -04:00
* /
2022-09-05 16:57:11 -04:00
_decodeParams ( params , data ) {
return this . # abiCoder . decode ( params , data ) ;
}
_encodeParams ( params , values ) {
return this . # abiCoder . encode ( params , values ) ;
}
2022-09-15 22:58:45 -04:00
/ * *
* Encodes a ` ` tx . data ` ` object for deploying the Contract with
* the % % values % % as the constructor arguments .
* /
2022-09-05 16:57:11 -04:00
encodeDeploy ( values ) {
return this . _encodeParams ( this . deploy . inputs , values || [ ] ) ;
}
2022-09-15 22:58:45 -04:00
/ * *
* Decodes the result % % data % % ( e . g . from an ` ` eth _call ` ` ) for the
* specified error ( see [ [ getError ] ] for valid values for
* % % key % % ) .
*
* Most developers should prefer the [ [ parseResult ] ] method instead ,
* which will automatically detect a ` ` CALL _EXCEPTION ` ` and throw the
* corresponding error .
* /
2022-09-05 16:57:11 -04:00
decodeErrorResult ( fragment , data ) {
if ( typeof ( fragment ) === "string" ) {
2023-01-27 17:29:49 -05:00
const f = this . getError ( fragment ) ;
( 0 , index _js _3 . assertArgument ) ( f , "unknown error" , "fragment" , fragment ) ;
fragment = f ;
2022-09-05 16:57:11 -04:00
}
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( ( 0 , index _js _3 . dataSlice ) ( data , 0 , 4 ) === fragment . selector , ` data signature does not match error ${ fragment . name } . ` , "data" , data ) ;
2022-09-15 22:58:45 -04:00
return this . _decodeParams ( fragment . inputs , ( 0 , index _js _3 . dataSlice ) ( data , 4 ) ) ;
}
/ * *
* Encodes the transaction revert data for a call result that
* reverted from the the Contract with the sepcified % % error % %
2023-01-27 17:29:49 -05:00
* ( see [ [ getError ] ] for valid values for % % fragment % % ) with the % % values % % .
2022-09-15 22:58:45 -04:00
*
* This is generally not used by most developers , unless trying to mock
* a result from a Contract .
* /
2023-01-27 17:29:49 -05:00
encodeErrorResult ( fragment , values ) {
if ( typeof ( fragment ) === "string" ) {
const f = this . getError ( fragment ) ;
( 0 , index _js _3 . assertArgument ) ( f , "unknown error" , "fragment" , fragment ) ;
fragment = f ;
}
2022-09-15 22:58:45 -04:00
return ( 0 , index _js _3 . concat ) ( [
fragment . selector ,
2022-09-05 16:57:11 -04:00
this . _encodeParams ( fragment . inputs , values || [ ] )
] ) ;
}
2022-09-15 22:58:45 -04:00
/ * *
* Decodes the % % data % % from a transaction ` ` tx . data ` ` for
* the function specified ( see [ [ getFunction ] ] for valid values
2023-01-27 17:29:49 -05:00
* for % % fragment % % ) .
2022-09-15 22:58:45 -04:00
*
* Most developers should prefer the [ [ parseTransaction ] ] method
* instead , which will automatically detect the fragment .
* /
2023-01-27 17:29:49 -05:00
decodeFunctionData ( fragment , data ) {
if ( typeof ( fragment ) === "string" ) {
const f = this . getFunction ( fragment ) ;
( 0 , index _js _3 . assertArgument ) ( f , "unknown function" , "fragment" , fragment ) ;
fragment = f ;
}
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( ( 0 , index _js _3 . dataSlice ) ( data , 0 , 4 ) === fragment . selector , ` data signature does not match function ${ fragment . name } . ` , "data" , data ) ;
2022-09-15 22:58:45 -04:00
return this . _decodeParams ( fragment . inputs , ( 0 , index _js _3 . dataSlice ) ( data , 4 ) ) ;
}
/ * *
* Encodes the ` ` tx . data ` ` for a transaction that calls the function
2023-01-27 17:29:49 -05:00
* specified ( see [ [ getFunction ] ] for valid values for % % fragment % % ) with
2022-09-15 22:58:45 -04:00
* the % % values % % .
* /
2023-01-27 17:29:49 -05:00
encodeFunctionData ( fragment , values ) {
if ( typeof ( fragment ) === "string" ) {
const f = this . getFunction ( fragment ) ;
( 0 , index _js _3 . assertArgument ) ( f , "unknown function" , "fragment" , fragment ) ;
fragment = f ;
}
2022-09-15 22:58:45 -04:00
return ( 0 , index _js _3 . concat ) ( [
fragment . selector ,
2022-09-05 16:57:11 -04:00
this . _encodeParams ( fragment . inputs , values || [ ] )
] ) ;
}
2022-09-15 22:58:45 -04:00
/ * *
* Decodes the result % % data % % ( e . g . from an ` ` eth _call ` ` ) for the
* specified function ( see [ [ getFunction ] ] for valid values for
* % % key % % ) .
*
* Most developers should prefer the [ [ parseResult ] ] method instead ,
* which will automatically detect a ` ` CALL _EXCEPTION ` ` and throw the
* corresponding error .
* /
2022-09-05 16:57:11 -04:00
decodeFunctionResult ( fragment , data ) {
if ( typeof ( fragment ) === "string" ) {
2023-01-27 17:29:49 -05:00
const f = this . getFunction ( fragment ) ;
( 0 , index _js _3 . assertArgument ) ( f , "unknown function" , "fragment" , fragment ) ;
fragment = f ;
2022-09-05 16:57:11 -04:00
}
let message = "invalid length for result data" ;
2022-09-15 22:58:45 -04:00
const bytes = ( 0 , index _js _3 . getBytesCopy ) ( data ) ;
2022-09-05 16:57:11 -04:00
if ( ( bytes . length % 32 ) === 0 ) {
try {
return this . # abiCoder . decode ( fragment . outputs , bytes ) ;
}
catch ( error ) {
message = "could not decode result data" ;
}
}
// Call returned data with no error, but the data is junk
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assert ) ( false , message , "BAD_DATA" , {
2022-09-15 22:58:45 -04:00
value : ( 0 , index _js _3 . hexlify ) ( bytes ) ,
2022-09-05 16:57:11 -04:00
info : { method : fragment . name , signature : fragment . format ( ) }
} ) ;
}
2022-10-20 05:03:32 -04:00
makeError ( _data , tx ) {
const data = ( 0 , index _js _3 . getBytes ) ( _data , "data" ) ;
2022-11-30 15:44:23 -05:00
const error = abi _coder _js _1 . AbiCoder . getBuiltinCallException ( "call" , tx , data ) ;
2022-10-20 05:03:32 -04:00
// Not a built-in error; try finding a custom error
if ( ! error . message . match ( /could not decode/ ) ) {
2022-09-15 22:58:45 -04:00
const selector = ( 0 , index _js _3 . hexlify ) ( data . slice ( 0 , 4 ) ) ;
2022-10-20 05:03:32 -04:00
error . message = "execution reverted (unknown custom error)" ;
2023-01-27 17:29:49 -05:00
const ef = this . getError ( selector ) ;
if ( ef ) {
2022-09-05 16:57:11 -04:00
try {
2022-10-20 05:03:32 -04:00
error . revert = {
name : ef . name ,
signature : ef . format ( ) ,
args : this . # abiCoder . decode ( ef . inputs , data . slice ( 4 ) )
} ;
error . reason = error . revert . signature ;
error . message = ` execution reverted: ${ error . reason } ` ;
2022-09-05 16:57:11 -04:00
}
2022-10-20 05:03:32 -04:00
catch ( e ) {
error . message = ` execution reverted (coult not decode custom error) ` ;
2022-09-05 16:57:11 -04:00
}
}
}
2022-10-20 05:03:32 -04:00
// Add the invocation, if available
const parsed = this . parseTransaction ( tx ) ;
if ( parsed ) {
error . invocation = {
method : parsed . name ,
signature : parsed . signature ,
args : parsed . args
} ;
}
return error ;
2022-09-05 16:57:11 -04:00
}
2022-09-15 22:58:45 -04:00
/ * *
* Encodes the result data ( e . g . from an ` ` eth _call ` ` ) for the
* specified function ( see [ [ getFunction ] ] for valid values
2023-01-27 17:29:49 -05:00
* for % % fragment % % ) with % % values % % .
2022-09-15 22:58:45 -04:00
*
* This is generally not used by most developers , unless trying to mock
* a result from a Contract .
* /
2023-01-27 17:29:49 -05:00
encodeFunctionResult ( fragment , values ) {
if ( typeof ( fragment ) === "string" ) {
const f = this . getFunction ( fragment ) ;
( 0 , index _js _3 . assertArgument ) ( f , "unknown function" , "fragment" , fragment ) ;
fragment = f ;
}
2022-09-15 22:58:45 -04:00
return ( 0 , index _js _3 . hexlify ) ( this . # abiCoder . encode ( fragment . outputs , values || [ ] ) ) ;
2022-09-05 16:57:11 -04:00
}
/ *
spelunk ( inputs : Array < ParamType > , values : ReadonlyArray < any > , processfunc : ( type : string , value : any ) => Promise < any > ) : Promise < Array < any >> {
const promises : Array < Promise < >> = [ ] ;
const process = function ( type : ParamType , value : any ) : any {
if ( type . baseType === "array" ) {
return descend ( type . child
}
if ( type . === "address" ) {
}
} ;
const descend = function ( inputs : Array < ParamType > , values : ReadonlyArray < any > ) {
if ( inputs . length !== values . length ) { throw new Error ( "length mismatch" ) ; }
} ;
const result : Array < any > = [ ] ;
values . forEach ( ( value , index ) => {
if ( value == null ) {
topics . push ( null ) ;
} else if ( param . baseType === "array" || param . baseType === "tuple" ) {
logger . throwArgumentError ( "filtering with tuples or arrays not supported" , ( "contract." + param . name ) , value ) ;
} else if ( Array . isArray ( value ) ) {
topics . push ( value . map ( ( value ) => encodeTopic ( param , value ) ) ) ;
} else {
topics . push ( encodeTopic ( param , value ) ) ;
}
} ) ;
}
* /
// Create the filter for the event with search criteria (e.g. for eth_filterLog)
2023-01-27 17:29:49 -05:00
encodeFilterTopics ( fragment , values ) {
if ( typeof ( fragment ) === "string" ) {
const f = this . getEvent ( fragment ) ;
( 0 , index _js _3 . assertArgument ) ( f , "unknown event" , "eventFragment" , fragment ) ;
fragment = f ;
2022-09-05 16:57:11 -04:00
}
2023-01-27 17:29:49 -05:00
( 0 , index _js _3 . assert ) ( values . length <= fragment . inputs . length , ` too many arguments for ${ fragment . format ( ) } ` , "UNEXPECTED_ARGUMENT" , { count : values . length , expectedCount : fragment . inputs . length } ) ;
2022-09-05 16:57:11 -04:00
const topics = [ ] ;
2023-01-27 17:29:49 -05:00
if ( ! fragment . anonymous ) {
topics . push ( fragment . topicHash ) ;
2022-09-05 16:57:11 -04:00
}
// @TODO: Use the coders for this; to properly support tuples, etc.
const encodeTopic = ( param , value ) => {
if ( param . type === "string" ) {
return ( 0 , index _js _2 . id ) ( value ) ;
}
else if ( param . type === "bytes" ) {
2022-09-15 22:58:45 -04:00
return ( 0 , index _js _1 . keccak256 ) ( ( 0 , index _js _3 . hexlify ) ( value ) ) ;
2022-09-05 16:57:11 -04:00
}
if ( param . type === "bool" && typeof ( value ) === "boolean" ) {
value = ( value ? "0x01" : "0x00" ) ;
}
if ( param . type . match ( /^u?int/ ) ) {
2022-12-09 18:24:58 -05:00
value = ( 0 , index _js _3 . toBeHex ) ( value ) ;
2022-09-05 16:57:11 -04:00
}
// Check addresses are valid
if ( param . type === "address" ) {
this . # abiCoder . encode ( [ "address" ] , [ value ] ) ;
}
2022-09-15 22:58:45 -04:00
return ( 0 , index _js _3 . zeroPadValue ) ( ( 0 , index _js _3 . hexlify ) ( value ) , 32 ) ;
2022-09-05 16:57:11 -04:00
//@TOOD should probably be return toHex(value, 32)
} ;
values . forEach ( ( value , index ) => {
2023-01-27 17:29:49 -05:00
const param = fragment . inputs [ index ] ;
2022-09-05 16:57:11 -04:00
if ( ! param . indexed ) {
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( value == null , "cannot filter non-indexed parameters; must be null" , ( "contract." + param . name ) , value ) ;
2022-09-05 16:57:11 -04:00
return ;
}
if ( value == null ) {
topics . push ( null ) ;
}
else if ( param . baseType === "array" || param . baseType === "tuple" ) {
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( false , "filtering with tuples or arrays not supported" , ( "contract." + param . name ) , value ) ;
2022-09-05 16:57:11 -04:00
}
else if ( Array . isArray ( value ) ) {
topics . push ( value . map ( ( value ) => encodeTopic ( param , value ) ) ) ;
}
else {
topics . push ( encodeTopic ( param , value ) ) ;
}
} ) ;
// Trim off trailing nulls
while ( topics . length && topics [ topics . length - 1 ] === null ) {
topics . pop ( ) ;
}
return topics ;
}
2023-01-27 17:29:49 -05:00
encodeEventLog ( fragment , values ) {
if ( typeof ( fragment ) === "string" ) {
const f = this . getEvent ( fragment ) ;
( 0 , index _js _3 . assertArgument ) ( f , "unknown event" , "eventFragment" , fragment ) ;
fragment = f ;
2022-09-05 16:57:11 -04:00
}
const topics = [ ] ;
const dataTypes = [ ] ;
const dataValues = [ ] ;
2023-01-27 17:29:49 -05:00
if ( ! fragment . anonymous ) {
topics . push ( fragment . topicHash ) ;
2022-09-05 16:57:11 -04:00
}
2023-01-27 17:29:49 -05:00
( 0 , index _js _3 . assertArgument ) ( values . length === fragment . inputs . length , "event arguments/values mismatch" , "values" , values ) ;
fragment . inputs . forEach ( ( param , index ) => {
2022-09-05 16:57:11 -04:00
const value = values [ index ] ;
if ( param . indexed ) {
if ( param . type === "string" ) {
topics . push ( ( 0 , index _js _2 . id ) ( value ) ) ;
}
else if ( param . type === "bytes" ) {
topics . push ( ( 0 , index _js _1 . keccak256 ) ( value ) ) ;
}
else if ( param . baseType === "tuple" || param . baseType === "array" ) {
// @TODO
throw new Error ( "not implemented" ) ;
}
else {
topics . push ( this . # abiCoder . encode ( [ param . type ] , [ value ] ) ) ;
}
}
else {
dataTypes . push ( param ) ;
dataValues . push ( value ) ;
}
} ) ;
return {
data : this . # abiCoder . encode ( dataTypes , dataValues ) ,
topics : topics
} ;
}
// Decode a filter for the event and the search criteria
2023-01-27 17:29:49 -05:00
decodeEventLog ( fragment , data , topics ) {
if ( typeof ( fragment ) === "string" ) {
const f = this . getEvent ( fragment ) ;
( 0 , index _js _3 . assertArgument ) ( f , "unknown event" , "eventFragment" , fragment ) ;
fragment = f ;
2022-09-05 16:57:11 -04:00
}
2023-01-27 17:29:49 -05:00
if ( topics != null && ! fragment . anonymous ) {
const eventTopic = fragment . topicHash ;
2022-11-09 02:57:02 -05:00
( 0 , index _js _3 . assertArgument ) ( ( 0 , index _js _3 . isHexString ) ( topics [ 0 ] , 32 ) && topics [ 0 ] . toLowerCase ( ) === eventTopic , "fragment/topic mismatch" , "topics[0]" , topics [ 0 ] ) ;
2022-09-05 16:57:11 -04:00
topics = topics . slice ( 1 ) ;
}
const indexed = [ ] ;
const nonIndexed = [ ] ;
const dynamic = [ ] ;
2023-01-27 17:29:49 -05:00
fragment . inputs . forEach ( ( param , index ) => {
2022-09-05 16:57:11 -04:00
if ( param . indexed ) {
if ( param . type === "string" || param . type === "bytes" || param . baseType === "tuple" || param . baseType === "array" ) {
2022-10-01 01:34:06 -04:00
indexed . push ( fragments _js _1 . ParamType . from ( { type : "bytes32" , name : param . name } ) ) ;
2022-09-05 16:57:11 -04:00
dynamic . push ( true ) ;
}
else {
indexed . push ( param ) ;
dynamic . push ( false ) ;
}
}
else {
nonIndexed . push ( param ) ;
dynamic . push ( false ) ;
}
} ) ;
2022-09-15 22:58:45 -04:00
const resultIndexed = ( topics != null ) ? this . # abiCoder . decode ( indexed , ( 0 , index _js _3 . concat ) ( topics ) ) : null ;
2022-09-05 16:57:11 -04:00
const resultNonIndexed = this . # abiCoder . decode ( nonIndexed , data , true ) ;
//const result: (Array<any> & { [ key: string ]: any }) = [ ];
const values = [ ] ;
const keys = [ ] ;
let nonIndexedIndex = 0 , indexedIndex = 0 ;
2023-01-27 17:29:49 -05:00
fragment . inputs . forEach ( ( param , index ) => {
2022-09-05 16:57:11 -04:00
let value = null ;
if ( param . indexed ) {
if ( resultIndexed == null ) {
value = new Indexed ( null ) ;
}
else if ( dynamic [ index ] ) {
value = new Indexed ( resultIndexed [ indexedIndex ++ ] ) ;
}
else {
try {
value = resultIndexed [ indexedIndex ++ ] ;
}
catch ( error ) {
value = error ;
}
}
}
else {
try {
value = resultNonIndexed [ nonIndexedIndex ++ ] ;
}
catch ( error ) {
value = error ;
}
}
values . push ( value ) ;
keys . push ( param . name || null ) ;
} ) ;
return abstract _coder _js _1 . Result . fromItems ( values , keys ) ;
}
2022-09-15 22:58:45 -04:00
/ * *
* Parses a transaction , finding the matching function and extracts
* the parameter values along with other useful function details .
*
* If the matching function cannot be found , return null .
* /
2022-09-05 16:57:11 -04:00
parseTransaction ( tx ) {
2022-09-15 22:58:45 -04:00
const data = ( 0 , index _js _3 . getBytes ) ( tx . data , "tx.data" ) ;
const value = ( 0 , index _js _3 . getBigInt ) ( ( tx . value != null ) ? tx . value : 0 , "tx.value" ) ;
const fragment = this . getFunction ( ( 0 , index _js _3 . hexlify ) ( data . slice ( 0 , 4 ) ) ) ;
2022-09-05 16:57:11 -04:00
if ( ! fragment ) {
return null ;
}
const args = this . # abiCoder . decode ( fragment . inputs , data . slice ( 4 ) ) ;
2022-09-15 22:58:45 -04:00
return new TransactionDescription ( fragment , fragment . selector , args , value ) ;
2022-09-05 16:57:11 -04:00
}
2022-09-15 22:58:45 -04:00
parseCallResult ( data ) {
throw new Error ( "@TODO" ) ;
}
/ * *
* Parses a receipt log , finding the matching event and extracts
* the parameter values along with other useful event details .
*
* If the matching event cannot be found , returns null .
* /
2022-09-05 16:57:11 -04:00
parseLog ( log ) {
const fragment = this . getEvent ( log . topics [ 0 ] ) ;
if ( ! fragment || fragment . anonymous ) {
return null ;
}
// @TODO: If anonymous, and the only method, and the input count matches, should we parse?
// Probably not, because just because it is the only event in the ABI does
// not mean we have the full ABI; maybe just a fragment?
2022-09-15 22:58:45 -04:00
return new LogDescription ( fragment , fragment . topicHash , this . decodeEventLog ( fragment , log . data , log . topics ) ) ;
}
/ * *
* Parses a revert data , finding the matching error and extracts
* the parameter values along with other useful error details .
*
* If the matching event cannot be found , returns null .
* /
2022-09-05 16:57:11 -04:00
parseError ( data ) {
2022-09-15 22:58:45 -04:00
const hexData = ( 0 , index _js _3 . hexlify ) ( data ) ;
const fragment = this . getError ( ( 0 , index _js _3 . dataSlice ) ( hexData , 0 , 4 ) ) ;
2022-09-05 16:57:11 -04:00
if ( ! fragment ) {
return null ;
}
2022-09-15 22:58:45 -04:00
const args = this . # abiCoder . decode ( fragment . inputs , ( 0 , index _js _3 . dataSlice ) ( hexData , 4 ) ) ;
return new ErrorDescription ( fragment , fragment . selector , args ) ;
2022-09-05 16:57:11 -04:00
}
2022-09-15 22:58:45 -04:00
/ * *
* Creates a new [ [ Interface ] ] from the ABI % % value % % .
*
* The % % value % % may be provided as an existing [ [ Interface ] ] object ,
* a JSON - encoded ABI or any Human - Readable ABI format .
* /
2022-09-05 16:57:11 -04:00
static from ( value ) {
// Already an Interface, which is immutable
if ( value instanceof Interface ) {
return value ;
}
// JSON
if ( typeof ( value ) === "string" ) {
return new Interface ( JSON . parse ( value ) ) ;
}
// Maybe an interface from an older version, or from a symlinked copy
if ( typeof ( value . format ) === "function" ) {
2022-09-15 22:58:45 -04:00
return new Interface ( value . format ( "json" ) ) ;
2022-09-05 16:57:11 -04:00
}
// Array of fragments
return new Interface ( value ) ;
}
}
exports . Interface = Interface ;
//# sourceMappingURL=interface.js.map