2022-09-05 16:57:11 -04:00
"use strict" ;
2022-11-30 15:44:23 -05:00
/ * *
* About Subclassing the Provider ...
*
* @ _section : api / providers / abstract - provider : Subclassing Provider [ abstract - provider ]
* /
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
exports . AbstractProvider = exports . UnmanagedSubscriber = void 0 ;
2022-09-05 16:57:11 -04:00
// @TODO
// Event coalescence
// When we register an event with an async value (e.g. address is a Signer
// or ENS name), we need to add it immeidately for the Event API, but also
// need time to resolve the address. Upon resolving the address, we need to
// migrate the listener to the static event. We also need to maintain a map
// of Signer/ENS name to address so we can sync respond to listenerCount.
const index _js _1 = require ( "../address/index.js" ) ;
2023-02-02 04:05:47 -05:00
const index _js _2 = require ( "../constants/index.js" ) ;
const index _js _3 = require ( "../contract/index.js" ) ;
const index _js _4 = require ( "../hash/index.js" ) ;
const index _js _5 = require ( "../transaction/index.js" ) ;
const index _js _6 = require ( "../utils/index.js" ) ;
2022-09-05 16:57:11 -04:00
const ens _resolver _js _1 = require ( "./ens-resolver.js" ) ;
2022-09-27 03:45:27 -04:00
const format _js _1 = require ( "./format.js" ) ;
2022-09-05 16:57:11 -04:00
const network _js _1 = require ( "./network.js" ) ;
const provider _js _1 = require ( "./provider.js" ) ;
const subscriber _polling _js _1 = require ( "./subscriber-polling.js" ) ;
// Constants
const BN _2 = BigInt ( 2 ) ;
const MAX _CCIP _REDIRECTS = 10 ;
2022-09-27 03:45:27 -04:00
function isPromise ( value ) {
return ( value && typeof ( value . then ) === "function" ) ;
}
2022-09-05 16:57:11 -04:00
function getTag ( prefix , value ) {
return prefix + ":" + JSON . stringify ( value , ( k , v ) => {
2022-11-09 02:57:02 -05:00
if ( v == null ) {
return "null" ;
}
2022-09-05 16:57:11 -04:00
if ( typeof ( v ) === "bigint" ) {
return ` bigint: ${ v . toString ( ) } ` ;
}
if ( typeof ( v ) === "string" ) {
return v . toLowerCase ( ) ;
}
// Sort object keys
if ( typeof ( v ) === "object" && ! Array . isArray ( v ) ) {
const keys = Object . keys ( v ) ;
keys . sort ( ) ;
return keys . reduce ( ( accum , key ) => {
accum [ key ] = v [ key ] ;
return accum ;
} , { } ) ;
}
return v ;
} ) ;
}
class UnmanagedSubscriber {
name ;
2023-02-02 04:05:47 -05:00
constructor ( name ) { ( 0 , index _js _6 . defineProperties ) ( this , { name } ) ; }
2022-09-05 16:57:11 -04:00
start ( ) { }
stop ( ) { }
pause ( dropWhilePaused ) { }
resume ( ) { }
}
exports . UnmanagedSubscriber = UnmanagedSubscriber ;
function copy ( value ) {
return JSON . parse ( JSON . stringify ( value ) ) ;
}
function concisify ( items ) {
items = Array . from ( ( new Set ( items ) ) . values ( ) ) ;
items . sort ( ) ;
return items ;
}
async function getSubscription ( _event , provider ) {
if ( _event == null ) {
throw new Error ( "invalid event" ) ;
}
// Normalize topic array info an EventFilter
if ( Array . isArray ( _event ) ) {
_event = { topics : _event } ;
}
if ( typeof ( _event ) === "string" ) {
switch ( _event ) {
case "block" :
case "pending" :
case "debug" :
case "network" : {
return { type : _event , tag : _event } ;
}
}
}
2023-02-02 04:05:47 -05:00
if ( ( 0 , index _js _6 . isHexString ) ( _event , 32 ) ) {
2022-09-05 16:57:11 -04:00
const hash = _event . toLowerCase ( ) ;
return { type : "transaction" , tag : getTag ( "tx" , { hash } ) , hash } ;
}
if ( _event . orphan ) {
const event = _event ;
// @TODO: Should lowercase and whatnot things here instead of copy...
return { type : "orphan" , tag : getTag ( "orphan" , event ) , filter : copy ( event ) } ;
}
if ( ( _event . address || _event . topics ) ) {
const event = _event ;
const filter = {
topics : ( ( event . topics || [ ] ) . map ( ( t ) => {
if ( t == null ) {
return null ;
}
if ( Array . isArray ( t ) ) {
return concisify ( t . map ( ( t ) => t . toLowerCase ( ) ) ) ;
}
return t . toLowerCase ( ) ;
} ) )
} ;
if ( event . address ) {
const addresses = [ ] ;
const promises = [ ] ;
const addAddress = ( addr ) => {
2023-02-02 04:05:47 -05:00
if ( ( 0 , index _js _6 . isHexString ) ( addr ) ) {
2022-09-05 16:57:11 -04:00
addresses . push ( addr ) ;
}
else {
promises . push ( ( async ( ) => {
addresses . push ( await ( 0 , index _js _1 . resolveAddress ) ( addr , provider ) ) ;
} ) ( ) ) ;
}
} ;
if ( Array . isArray ( event . address ) ) {
event . address . forEach ( addAddress ) ;
}
else {
addAddress ( event . address ) ;
}
if ( promises . length ) {
await Promise . all ( promises ) ;
}
filter . address = concisify ( addresses . map ( ( a ) => a . toLowerCase ( ) ) ) ;
}
return { filter , tag : getTag ( "event" , filter ) , type : "event" } ;
}
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assertArgument ) ( false , "unknown ProviderEvent" , "event" , _event ) ;
2022-09-05 16:57:11 -04:00
}
function getTime ( ) { return ( new Date ( ) ) . getTime ( ) ; }
class AbstractProvider {
# subs ;
# plugins ;
// null=unpaused, true=paused+dropWhilePaused, false=paused
# pausedState ;
# networkPromise ;
# anyNetwork ;
# performCache ;
2022-09-27 03:45:27 -04:00
// The most recent block number if running an event or -1 if no "block" event
# lastBlockNumber ;
2022-09-05 16:57:11 -04:00
# nextTimer ;
# timers ;
# disableCcipRead ;
// @TODO: This should be a () => Promise<Network> so network can be
// done when needed; or rely entirely on _detectNetwork?
constructor ( _network ) {
if ( _network === "any" ) {
this . # anyNetwork = true ;
this . # networkPromise = null ;
}
else if ( _network ) {
const network = network _js _1 . Network . from ( _network ) ;
this . # anyNetwork = false ;
this . # networkPromise = Promise . resolve ( network ) ;
setTimeout ( ( ) => { this . emit ( "network" , network , null ) ; } , 0 ) ;
}
else {
this . # anyNetwork = false ;
this . # networkPromise = null ;
}
2022-09-27 03:45:27 -04:00
this . # lastBlockNumber = - 1 ;
2022-09-05 16:57:11 -04:00
this . # performCache = new Map ( ) ;
this . # subs = new Map ( ) ;
this . # plugins = new Map ( ) ;
this . # pausedState = null ;
2023-02-02 04:05:47 -05:00
this . # nextTimer = 1 ;
2022-09-05 16:57:11 -04:00
this . # timers = new Map ( ) ;
this . # disableCcipRead = false ;
}
get provider ( ) { return this ; }
get plugins ( ) {
return Array . from ( this . # plugins . values ( ) ) ;
}
attachPlugin ( plugin ) {
if ( this . # plugins . get ( plugin . name ) ) {
throw new Error ( ` cannot replace existing plugin: ${ plugin . name } ` ) ;
}
2022-11-09 02:57:02 -05:00
this . # plugins . set ( plugin . name , plugin . connect ( this ) ) ;
2022-09-05 16:57:11 -04:00
return this ;
}
getPlugin ( name ) {
return ( this . # plugins . get ( name ) ) || null ;
}
get disableCcipRead ( ) { return this . # disableCcipRead ; }
2022-11-30 15:44:23 -05:00
set disableCcipRead ( value ) { this . # disableCcipRead = ! ! value ; }
2022-09-05 16:57:11 -04:00
// Shares multiple identical requests made during the same 250ms
async # perform ( req ) {
// Create a tag
const tag = getTag ( req . method , req ) ;
let perform = this . # performCache . get ( tag ) ;
if ( ! perform ) {
perform = this . _perform ( req ) ;
this . # performCache . set ( tag , perform ) ;
setTimeout ( ( ) => {
if ( this . # performCache . get ( tag ) === perform ) {
this . # performCache . delete ( tag ) ;
}
} , 250 ) ;
}
return await perform ;
}
async ccipReadFetch ( tx , calldata , urls ) {
if ( this . disableCcipRead || urls . length === 0 || tx . to == null ) {
return null ;
}
const sender = tx . to . toLowerCase ( ) ;
const data = calldata . toLowerCase ( ) ;
const errorMessages = [ ] ;
for ( let i = 0 ; i < urls . length ; i ++ ) {
const url = urls [ i ] ;
// URL expansion
const href = url . replace ( "{sender}" , sender ) . replace ( "{data}" , data ) ;
// If no {data} is present, use POST; otherwise GET
//const json: string | null = (url.indexOf("{data}") >= 0) ? null: JSON.stringify({ data, sender });
//const result = await fetchJson({ url: href, errorPassThrough: true }, json, (value, response) => {
// value.status = response.statusCode;
// return value;
//});
2023-02-02 04:05:47 -05:00
const request = new index _js _6 . FetchRequest ( href ) ;
2022-09-05 16:57:11 -04:00
if ( url . indexOf ( "{data}" ) === - 1 ) {
request . body = { data , sender } ;
}
2022-11-09 02:57:02 -05:00
this . emit ( "debug" , { action : "sendCcipReadFetchRequest" , request , index : i , urls } ) ;
2022-09-05 16:57:11 -04:00
let errorMessage = "unknown error" ;
const resp = await request . send ( ) ;
try {
const result = resp . bodyJson ;
if ( result . data ) {
2022-11-09 02:57:02 -05:00
this . emit ( "debug" , { action : "receiveCcipReadFetchResult" , request , result } ) ;
2022-09-05 16:57:11 -04:00
return result . data ;
}
if ( result . message ) {
errorMessage = result . message ;
}
2022-11-09 02:57:02 -05:00
this . emit ( "debug" , { action : "receiveCcipReadFetchError" , request , result } ) ;
2022-09-05 16:57:11 -04:00
}
catch ( error ) { }
// 4xx indicates the result is not present; stop
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( resp . statusCode < 400 || resp . statusCode >= 500 , ` response not found during CCIP fetch: ${ errorMessage } ` , "OFFCHAIN_FAULT" , { reason : "404_MISSING_RESOURCE" , transaction : tx , info : { url , errorMessage } } ) ;
2022-09-05 16:57:11 -04:00
// 5xx indicates server issue; try the next url
errorMessages . push ( errorMessage ) ;
}
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( false , ` error encountered during CCIP fetch: ${ errorMessages . map ( ( m ) => JSON . stringify ( m ) ) . join ( ", " ) } ` , "OFFCHAIN_FAULT" , {
2022-09-05 16:57:11 -04:00
reason : "500_SERVER_ERROR" ,
transaction : tx , info : { urls , errorMessages }
} ) ;
}
2022-09-27 03:45:27 -04:00
_wrapBlock ( value , network ) {
return new provider _js _1 . Block ( ( 0 , format _js _1 . formatBlock ) ( value ) , this ) ;
}
_wrapLog ( value , network ) {
return new provider _js _1 . Log ( ( 0 , format _js _1 . formatLog ) ( value ) , this ) ;
}
_wrapTransactionReceipt ( value , network ) {
return new provider _js _1 . TransactionReceipt ( ( 0 , format _js _1 . formatTransactionReceipt ) ( value ) , this ) ;
}
_wrapTransactionResponse ( tx , network ) {
2023-03-20 12:53:37 -04:00
return new provider _js _1 . TransactionResponse ( ( 0 , format _js _1 . formatTransactionResponse ) ( tx ) , this ) ;
2022-09-05 16:57:11 -04:00
}
_detectNetwork ( ) {
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( false , "sub-classes must implement this" , "UNSUPPORTED_OPERATION" , {
2022-09-05 16:57:11 -04:00
operation : "_detectNetwork"
} ) ;
}
// Sub-classes should override this and handle PerformActionRequest requests, calling
// the super for any unhandled actions.
async _perform ( req ) {
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( false , ` unsupported method: ${ req . method } ` , "UNSUPPORTED_OPERATION" , {
2022-09-05 16:57:11 -04:00
operation : req . method ,
info : req
} ) ;
}
// State
async getBlockNumber ( ) {
2023-02-02 04:05:47 -05:00
const blockNumber = ( 0 , index _js _6 . getNumber ) ( await this . # perform ( { method : "getBlockNumber" } ) , "%response" ) ;
2022-09-27 03:45:27 -04:00
if ( this . # lastBlockNumber >= 0 ) {
this . # lastBlockNumber = blockNumber ;
}
return blockNumber ;
2022-09-05 16:57:11 -04:00
}
_getAddress ( address ) {
return ( 0 , index _js _1 . resolveAddress ) ( address , this ) ;
}
_getBlockTag ( blockTag ) {
if ( blockTag == null ) {
return "latest" ;
}
switch ( blockTag ) {
case "earliest" :
return "0x0" ;
case "latest" :
case "pending" :
case "safe" :
case "finalized" :
return blockTag ;
}
2023-02-02 04:05:47 -05:00
if ( ( 0 , index _js _6 . isHexString ) ( blockTag ) ) {
if ( ( 0 , index _js _6 . isHexString ) ( blockTag , 32 ) ) {
2022-09-05 16:57:11 -04:00
return blockTag ;
}
2023-02-02 04:05:47 -05:00
return ( 0 , index _js _6 . toQuantity ) ( blockTag ) ;
2022-09-05 16:57:11 -04:00
}
2023-03-03 18:25:07 -07:00
if ( typeof ( blockTag ) === "bigint" ) {
blockTag = ( 0 , index _js _6 . getNumber ) ( blockTag , "blockTag" ) ;
}
2022-09-05 16:57:11 -04:00
if ( typeof ( blockTag ) === "number" ) {
if ( blockTag >= 0 ) {
2023-02-02 04:05:47 -05:00
return ( 0 , index _js _6 . toQuantity ) ( blockTag ) ;
2022-09-05 16:57:11 -04:00
}
2022-09-27 03:45:27 -04:00
if ( this . # lastBlockNumber >= 0 ) {
2023-02-02 04:05:47 -05:00
return ( 0 , index _js _6 . toQuantity ) ( this . # lastBlockNumber + blockTag ) ;
2022-09-27 03:45:27 -04:00
}
2023-02-02 04:05:47 -05:00
return this . getBlockNumber ( ) . then ( ( b ) => ( 0 , index _js _6 . toQuantity ) ( b + blockTag ) ) ;
2022-09-05 16:57:11 -04:00
}
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assertArgument ) ( false , "invalid blockTag" , "blockTag" , blockTag ) ;
2022-09-05 16:57:11 -04:00
}
2022-09-27 03:45:27 -04:00
_getFilter ( filter ) {
// Create a canonical representation of the topics
const topics = ( filter . topics || [ ] ) . map ( ( t ) => {
if ( t == null ) {
return null ;
}
if ( Array . isArray ( t ) ) {
return concisify ( t . map ( ( t ) => t . toLowerCase ( ) ) ) ;
}
return t . toLowerCase ( ) ;
} ) ;
const blockHash = ( "blockHash" in filter ) ? filter . blockHash : undefined ;
const resolve = ( _address , fromBlock , toBlock ) => {
let address = undefined ;
switch ( _address . length ) {
case 0 : break ;
case 1 :
address = _address [ 0 ] ;
break ;
default :
_address . sort ( ) ;
address = _address ;
}
if ( blockHash ) {
if ( fromBlock != null || toBlock != null ) {
throw new Error ( "invalid filter" ) ;
}
}
const filter = { } ;
if ( address ) {
filter . address = address ;
}
if ( topics . length ) {
filter . topics = topics ;
}
if ( fromBlock ) {
filter . fromBlock = fromBlock ;
}
if ( toBlock ) {
filter . toBlock = toBlock ;
}
if ( blockHash ) {
filter . blockHash = blockHash ;
}
return filter ;
} ;
// Addresses could be async (ENS names or Addressables)
let address = [ ] ;
if ( filter . address ) {
if ( Array . isArray ( filter . address ) ) {
for ( const addr of filter . address ) {
address . push ( this . _getAddress ( addr ) ) ;
}
}
else {
address . push ( this . _getAddress ( filter . address ) ) ;
}
}
let fromBlock = undefined ;
if ( "fromBlock" in filter ) {
fromBlock = this . _getBlockTag ( filter . fromBlock ) ;
}
let toBlock = undefined ;
if ( "toBlock" in filter ) {
toBlock = this . _getBlockTag ( filter . toBlock ) ;
}
if ( address . filter ( ( a ) => ( typeof ( a ) !== "string" ) ) . length ||
( fromBlock != null && typeof ( fromBlock ) !== "string" ) ||
( toBlock != null && typeof ( toBlock ) !== "string" ) ) {
return Promise . all ( [ Promise . all ( address ) , fromBlock , toBlock ] ) . then ( ( result ) => {
return resolve ( result [ 0 ] , result [ 1 ] , result [ 2 ] ) ;
} ) ;
}
return resolve ( address , fromBlock , toBlock ) ;
}
_getTransactionRequest ( _request ) {
const request = ( 0 , provider _js _1 . copyRequest ) ( _request ) ;
const promises = [ ] ;
[ "to" , "from" ] . forEach ( ( key ) => {
if ( request [ key ] == null ) {
return ;
}
const addr = ( 0 , index _js _1 . resolveAddress ) ( request [ key ] ) ;
if ( isPromise ( addr ) ) {
promises . push ( ( async function ( ) { request [ key ] = await addr ; } ) ( ) ) ;
}
else {
request [ key ] = addr ;
}
} ) ;
if ( request . blockTag != null ) {
const blockTag = this . _getBlockTag ( request . blockTag ) ;
if ( isPromise ( blockTag ) ) {
promises . push ( ( async function ( ) { request . blockTag = await blockTag ; } ) ( ) ) ;
}
else {
request . blockTag = blockTag ;
}
}
if ( promises . length ) {
return ( async function ( ) {
await Promise . all ( promises ) ;
return request ;
} ) ( ) ;
}
return request ;
}
2022-09-05 16:57:11 -04:00
async getNetwork ( ) {
// No explicit network was set and this is our first time
if ( this . # networkPromise == null ) {
// Detect the current network (shared with all calls)
const detectNetwork = this . _detectNetwork ( ) . then ( ( network ) => {
this . emit ( "network" , network , null ) ;
return network ;
} , ( error ) => {
// Reset the networkPromise on failure, so we will try again
if ( this . # networkPromise === detectNetwork ) {
this . # networkPromise = null ;
}
throw error ;
} ) ;
this . # networkPromise = detectNetwork ;
2022-09-27 03:45:27 -04:00
return ( await detectNetwork ) . clone ( ) ;
2022-09-05 16:57:11 -04:00
}
const networkPromise = this . # networkPromise ;
const [ expected , actual ] = await Promise . all ( [
networkPromise ,
this . _detectNetwork ( ) // The actual connected network
] ) ;
if ( expected . chainId !== actual . chainId ) {
if ( this . # anyNetwork ) {
// The "any" network can change, so notify listeners
this . emit ( "network" , actual , expected ) ;
// Update the network if something else hasn't already changed it
if ( this . # networkPromise === networkPromise ) {
this . # networkPromise = Promise . resolve ( actual ) ;
}
}
else {
// Otherwise, we do not allow changes to the underlying network
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( false , ` network changed: ${ expected . chainId } => ${ actual . chainId } ` , "NETWORK_ERROR" , {
2022-09-05 16:57:11 -04:00
event : "changed"
} ) ;
}
}
2022-09-27 03:45:27 -04:00
return expected . clone ( ) ;
2022-09-05 16:57:11 -04:00
}
async getFeeData ( ) {
2023-02-02 04:05:47 -05:00
const { block , gasPrice } = await ( 0 , index _js _6 . resolveProperties ) ( {
2022-09-05 16:57:11 -04:00
block : this . getBlock ( "latest" ) ,
gasPrice : ( ( async ( ) => {
try {
const gasPrice = await this . # perform ( { method : "getGasPrice" } ) ;
2023-02-02 04:05:47 -05:00
return ( 0 , index _js _6 . getBigInt ) ( gasPrice , "%response" ) ;
2022-09-05 16:57:11 -04:00
}
catch ( error ) { }
return null ;
} ) ( ) )
} ) ;
let maxFeePerGas = null , maxPriorityFeePerGas = null ;
if ( block && block . baseFeePerGas ) {
// We may want to compute this more accurately in the future,
// using the formula "check if the base fee is correct".
// See: https://eips.ethereum.org/EIPS/eip-1559
2023-02-02 04:05:47 -05:00
maxPriorityFeePerGas = BigInt ( "1000000000" ) ;
2022-09-05 16:57:11 -04:00
// Allow a network to override their maximum priority fee per gas
//const priorityFeePlugin = (await this.getNetwork()).getPlugin<MaxPriorityFeePlugin>("org.ethers.plugins.max-priority-fee");
//if (priorityFeePlugin) {
// maxPriorityFeePerGas = await priorityFeePlugin.getPriorityFee(this);
//}
maxFeePerGas = ( block . baseFeePerGas * BN _2 ) + maxPriorityFeePerGas ;
}
return new provider _js _1 . FeeData ( gasPrice , maxFeePerGas , maxPriorityFeePerGas ) ;
}
async estimateGas ( _tx ) {
2022-09-27 03:45:27 -04:00
let tx = this . _getTransactionRequest ( _tx ) ;
if ( isPromise ( tx ) ) {
tx = await tx ;
}
2023-02-02 04:05:47 -05:00
return ( 0 , index _js _6 . getBigInt ) ( await this . # perform ( {
2022-09-27 03:45:27 -04:00
method : "estimateGas" , transaction : tx
2022-09-05 16:57:11 -04:00
} ) , "%response" ) ;
}
async # call ( tx , blockTag , attempt ) {
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( attempt < MAX _CCIP _REDIRECTS , "CCIP read exceeded maximum redirections" , "OFFCHAIN_FAULT" , {
2022-11-09 02:57:02 -05:00
reason : "TOO_MANY_REDIRECTS" ,
transaction : Object . assign ( { } , tx , { blockTag , enableCcipRead : true } )
} ) ;
2022-09-27 03:45:27 -04:00
// This came in as a PerformActionTransaction, so to/from are safe; we can cast
const transaction = ( 0 , provider _js _1 . copyRequest ) ( tx ) ;
2022-09-05 16:57:11 -04:00
try {
2023-02-02 04:05:47 -05:00
return ( 0 , index _js _6 . hexlify ) ( await this . _perform ( { method : "call" , transaction , blockTag } ) ) ;
2022-09-05 16:57:11 -04:00
}
catch ( error ) {
// CCIP Read OffchainLookup
2023-02-02 04:05:47 -05:00
if ( ! this . disableCcipRead && ( 0 , index _js _6 . isCallException ) ( error ) && error . data && attempt >= 0 && blockTag === "latest" && transaction . to != null && ( 0 , index _js _6 . dataSlice ) ( error . data , 0 , 4 ) === "0x556f1830" ) {
2022-09-05 16:57:11 -04:00
const data = error . data ;
const txSender = await ( 0 , index _js _1 . resolveAddress ) ( transaction . to , this ) ;
// Parse the CCIP Read Arguments
let ccipArgs ;
try {
2023-02-02 04:05:47 -05:00
ccipArgs = parseOffchainLookup ( ( 0 , index _js _6 . dataSlice ) ( error . data , 4 ) ) ;
2022-09-05 16:57:11 -04:00
}
catch ( error ) {
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( false , error . message , "OFFCHAIN_FAULT" , {
2022-11-09 02:57:02 -05:00
reason : "BAD_DATA" , transaction , info : { data }
2022-09-05 16:57:11 -04:00
} ) ;
}
// Check the sender of the OffchainLookup matches the transaction
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( ccipArgs . sender . toLowerCase ( ) === txSender . toLowerCase ( ) , "CCIP Read sender mismatch" , "CALL_EXCEPTION" , {
2022-11-09 02:57:02 -05:00
action : "call" ,
data ,
reason : "OffchainLookup" ,
transaction : transaction ,
invocation : null ,
revert : {
signature : "OffchainLookup(address,string[],bytes,bytes4,bytes)" ,
name : "OffchainLookup" ,
args : ccipArgs . errorArgs
}
} ) ;
2022-09-05 16:57:11 -04:00
const ccipResult = await this . ccipReadFetch ( transaction , ccipArgs . calldata , ccipArgs . urls ) ;
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( ccipResult != null , "CCIP Read failed to fetch data" , "OFFCHAIN_FAULT" , {
2022-11-09 02:57:02 -05:00
reason : "FETCH_FAILED" , transaction , info : { data : error . data , errorArgs : ccipArgs . errorArgs }
} ) ;
const tx = {
2022-09-05 16:57:11 -04:00
to : txSender ,
2023-02-02 04:05:47 -05:00
data : ( 0 , index _js _6 . concat ) ( [ ccipArgs . selector , encodeBytes ( [ ccipResult , ccipArgs . extraData ] ) ] )
2022-11-09 02:57:02 -05:00
} ;
this . emit ( "debug" , { action : "sendCcipReadCall" , transaction : tx } ) ;
try {
const result = await this . # call ( tx , blockTag , attempt + 1 ) ;
this . emit ( "debug" , { action : "receiveCcipReadCallResult" , transaction : Object . assign ( { } , tx ) , result } ) ;
return result ;
}
catch ( error ) {
this . emit ( "debug" , { action : "receiveCcipReadCallError" , transaction : Object . assign ( { } , tx ) , error } ) ;
throw error ;
}
2022-09-05 16:57:11 -04:00
}
throw error ;
}
}
2022-09-27 03:45:27 -04:00
async # checkNetwork ( promise ) {
2023-02-02 04:05:47 -05:00
const { value } = await ( 0 , index _js _6 . resolveProperties ) ( {
2022-09-27 03:45:27 -04:00
network : this . getNetwork ( ) ,
value : promise
} ) ;
return value ;
}
2022-09-05 16:57:11 -04:00
async call ( _tx ) {
2023-02-02 04:05:47 -05:00
const { tx , blockTag } = await ( 0 , index _js _6 . resolveProperties ) ( {
2022-09-27 03:45:27 -04:00
tx : this . _getTransactionRequest ( _tx ) ,
blockTag : this . _getBlockTag ( _tx . blockTag )
} ) ;
return await this . # checkNetwork ( this . # call ( tx , blockTag , _tx . enableCcipRead ? 0 : - 1 ) ) ;
2022-09-05 16:57:11 -04:00
}
// Account
async # getAccountValue ( request , _address , _blockTag ) {
let address = this . _getAddress ( _address ) ;
let blockTag = this . _getBlockTag ( _blockTag ) ;
if ( typeof ( address ) !== "string" || typeof ( blockTag ) !== "string" ) {
[ address , blockTag ] = await Promise . all ( [ address , blockTag ] ) ;
}
2022-09-27 03:45:27 -04:00
return await this . # checkNetwork ( this . # perform ( Object . assign ( request , { address , blockTag } ) ) ) ;
2022-09-05 16:57:11 -04:00
}
async getBalance ( address , blockTag ) {
2023-02-02 04:05:47 -05:00
return ( 0 , index _js _6 . getBigInt ) ( await this . # getAccountValue ( { method : "getBalance" } , address , blockTag ) , "%response" ) ;
2022-09-05 16:57:11 -04:00
}
async getTransactionCount ( address , blockTag ) {
2023-02-02 04:05:47 -05:00
return ( 0 , index _js _6 . getNumber ) ( await this . # getAccountValue ( { method : "getTransactionCount" } , address , blockTag ) , "%response" ) ;
2022-09-05 16:57:11 -04:00
}
async getCode ( address , blockTag ) {
2023-02-02 04:05:47 -05:00
return ( 0 , index _js _6 . hexlify ) ( await this . # getAccountValue ( { method : "getCode" } , address , blockTag ) ) ;
2022-09-05 16:57:11 -04:00
}
2022-09-29 22:57:27 -04:00
async getStorage ( address , _position , blockTag ) {
2023-02-02 04:05:47 -05:00
const position = ( 0 , index _js _6 . getBigInt ) ( _position , "position" ) ;
return ( 0 , index _js _6 . hexlify ) ( await this . # getAccountValue ( { method : "getStorage" , position } , address , blockTag ) ) ;
2022-09-05 16:57:11 -04:00
}
// Write
async broadcastTransaction ( signedTx ) {
2023-02-02 04:05:47 -05:00
const { blockNumber , hash , network } = await ( 0 , index _js _6 . resolveProperties ) ( {
2022-10-20 05:03:32 -04:00
blockNumber : this . getBlockNumber ( ) ,
hash : this . _perform ( {
method : "broadcastTransaction" ,
signedTransaction : signedTx
} ) ,
network : this . getNetwork ( )
} ) ;
2023-02-02 04:05:47 -05:00
const tx = index _js _5 . Transaction . from ( signedTx ) ;
2022-10-20 05:03:32 -04:00
if ( tx . hash !== hash ) {
throw new Error ( "@TODO: the returned hash did not match" ) ;
}
return this . _wrapTransactionResponse ( tx , network ) . replaceableTransaction ( blockNumber ) ;
2022-09-05 16:57:11 -04:00
}
async # getBlock ( block , includeTransactions ) {
2022-09-27 03:45:27 -04:00
// @TODO: Add CustomBlockPlugin check
2023-02-02 04:05:47 -05:00
if ( ( 0 , index _js _6 . isHexString ) ( block , 32 ) ) {
2022-09-05 16:57:11 -04:00
return await this . # perform ( {
method : "getBlock" , blockHash : block , includeTransactions
} ) ;
}
let blockTag = this . _getBlockTag ( block ) ;
if ( typeof ( blockTag ) !== "string" ) {
blockTag = await blockTag ;
}
return await this . # perform ( {
method : "getBlock" , blockTag , includeTransactions
} ) ;
}
// Queries
2022-11-30 15:44:23 -05:00
async getBlock ( block , prefetchTxs ) {
2023-02-02 04:05:47 -05:00
const { network , params } = await ( 0 , index _js _6 . resolveProperties ) ( {
2022-09-27 03:45:27 -04:00
network : this . getNetwork ( ) ,
2022-11-30 15:44:23 -05:00
params : this . # getBlock ( block , ! ! prefetchTxs )
2022-09-27 03:45:27 -04:00
} ) ;
2022-09-05 16:57:11 -04:00
if ( params == null ) {
return null ;
}
2023-03-20 12:53:37 -04:00
return this . _wrapBlock ( params , network ) ;
2022-09-05 16:57:11 -04:00
}
async getTransaction ( hash ) {
2023-02-02 04:05:47 -05:00
const { network , params } = await ( 0 , index _js _6 . resolveProperties ) ( {
2022-09-27 03:45:27 -04:00
network : this . getNetwork ( ) ,
params : this . # perform ( { method : "getTransaction" , hash } )
} ) ;
if ( params == null ) {
return null ;
}
2023-03-20 12:53:37 -04:00
return this . _wrapTransactionResponse ( params , network ) ;
2022-09-05 16:57:11 -04:00
}
async getTransactionReceipt ( hash ) {
2023-02-02 04:05:47 -05:00
const { network , params } = await ( 0 , index _js _6 . resolveProperties ) ( {
2022-09-27 03:45:27 -04:00
network : this . getNetwork ( ) ,
params : this . # perform ( { method : "getTransactionReceipt" , hash } )
} ) ;
if ( params == null ) {
2022-09-05 16:57:11 -04:00
return null ;
}
// Some backends did not backfill the effectiveGasPrice into old transactions
// in the receipt, so we look it up manually and inject it.
2022-09-27 03:45:27 -04:00
if ( params . gasPrice == null && params . effectiveGasPrice == null ) {
2022-09-05 16:57:11 -04:00
const tx = await this . # perform ( { method : "getTransaction" , hash } ) ;
2022-09-27 03:45:27 -04:00
if ( tx == null ) {
throw new Error ( "report this; could not find tx or effectiveGasPrice" ) ;
}
params . effectiveGasPrice = tx . gasPrice ;
2022-09-05 16:57:11 -04:00
}
2023-03-20 12:53:37 -04:00
return this . _wrapTransactionReceipt ( params , network ) ;
2022-09-05 16:57:11 -04:00
}
async getTransactionResult ( hash ) {
2023-02-02 04:05:47 -05:00
const { result } = await ( 0 , index _js _6 . resolveProperties ) ( {
2022-09-27 03:45:27 -04:00
network : this . getNetwork ( ) ,
result : this . # perform ( { method : "getTransactionResult" , hash } )
} ) ;
2022-09-05 16:57:11 -04:00
if ( result == null ) {
return null ;
}
2023-02-02 04:05:47 -05:00
return ( 0 , index _js _6 . hexlify ) ( result ) ;
2022-09-05 16:57:11 -04:00
}
// Bloom-filter Queries
async getLogs ( _filter ) {
2022-09-27 03:45:27 -04:00
let filter = this . _getFilter ( _filter ) ;
if ( isPromise ( filter ) ) {
filter = await filter ;
}
2023-02-02 04:05:47 -05:00
const { network , params } = await ( 0 , index _js _6 . resolveProperties ) ( {
2022-09-05 16:57:11 -04:00
network : this . getNetwork ( ) ,
2022-09-27 03:45:27 -04:00
params : this . # perform ( { method : "getLogs" , filter } )
2022-09-05 16:57:11 -04:00
} ) ;
2023-03-20 12:53:37 -04:00
return params . map ( ( p ) => this . _wrapLog ( p , network ) ) ;
2022-09-05 16:57:11 -04:00
}
// ENS
_getProvider ( chainId ) {
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( false , "provider cannot connect to target network" , "UNSUPPORTED_OPERATION" , {
2022-09-05 16:57:11 -04:00
operation : "_getProvider()"
} ) ;
}
async getResolver ( name ) {
return await ens _resolver _js _1 . EnsResolver . fromName ( this , name ) ;
}
async getAvatar ( name ) {
const resolver = await this . getResolver ( name ) ;
if ( resolver ) {
return await resolver . getAvatar ( ) ;
}
return null ;
}
async resolveName ( name ) {
const resolver = await this . getResolver ( name ) ;
if ( resolver ) {
return await resolver . getAddress ( ) ;
}
return null ;
}
async lookupAddress ( address ) {
2023-02-02 04:05:47 -05:00
address = ( 0 , index _js _1 . getAddress ) ( address ) ;
const node = ( 0 , index _js _4 . namehash ) ( address . substring ( 2 ) . toLowerCase ( ) + ".addr.reverse" ) ;
try {
const ensAddr = await ens _resolver _js _1 . EnsResolver . getEnsAddress ( this ) ;
const ensContract = new index _js _3 . Contract ( ensAddr , [
"function resolver(bytes32) view returns (address)"
] , this ) ;
const resolver = await ensContract . resolver ( node ) ;
if ( resolver == null || resolver === index _js _2 . ZeroHash ) {
return null ;
}
const resolverContract = new index _js _3 . Contract ( resolver , [
"function name(bytes32) view returns (string)"
] , this ) ;
const name = await resolverContract . name ( node ) ;
2023-02-16 08:19:59 -05:00
// Failed forward resolution
2023-02-02 04:05:47 -05:00
const check = await this . resolveName ( name ) ;
if ( check !== address ) {
2023-02-16 08:19:59 -05:00
return null ;
2023-02-02 04:05:47 -05:00
}
return name ;
}
catch ( error ) {
2023-02-16 08:19:59 -05:00
// No data was returned from the resolver
if ( ( 0 , index _js _6 . isError ) ( error , "BAD_DATA" ) && error . value === "0x" ) {
return null ;
}
// Something reerted
if ( ( 0 , index _js _6 . isError ) ( error , "CALL_EXCEPTION" ) ) {
return null ;
}
throw error ;
2023-02-02 04:05:47 -05:00
}
return null ;
2022-09-05 16:57:11 -04:00
}
2022-11-09 02:57:02 -05:00
async waitForTransaction ( hash , _confirms , timeout ) {
const confirms = ( _confirms != null ) ? _confirms : 1 ;
2022-09-05 16:57:11 -04:00
if ( confirms === 0 ) {
return this . getTransactionReceipt ( hash ) ;
}
return new Promise ( async ( resolve , reject ) => {
let timer = null ;
const listener = ( async ( blockNumber ) => {
try {
const receipt = await this . getTransactionReceipt ( hash ) ;
if ( receipt != null ) {
if ( blockNumber - receipt . blockNumber + 1 >= confirms ) {
resolve ( receipt ) ;
2022-11-09 02:57:02 -05:00
//this.off("block", listener);
2022-09-05 16:57:11 -04:00
if ( timer ) {
clearTimeout ( timer ) ;
timer = null ;
}
return ;
}
}
}
catch ( error ) {
console . log ( "EEE" , error ) ;
}
this . once ( "block" , listener ) ;
} ) ;
if ( timeout != null ) {
timer = setTimeout ( ( ) => {
if ( timer == null ) {
return ;
}
timer = null ;
this . off ( "block" , listener ) ;
2023-02-02 04:05:47 -05:00
reject ( ( 0 , index _js _6 . makeError ) ( "timeout" , "TIMEOUT" , { reason : "timeout" } ) ) ;
2022-09-05 16:57:11 -04:00
} , timeout ) ;
}
listener ( await this . getBlockNumber ( ) ) ;
} ) ;
}
async waitForBlock ( blockTag ) {
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( false , "not implemented yet" , "NOT_IMPLEMENTED" , {
operation : "waitForBlock"
} ) ;
2022-09-05 16:57:11 -04:00
}
_clearTimeout ( timerId ) {
const timer = this . # timers . get ( timerId ) ;
if ( ! timer ) {
return ;
}
if ( timer . timer ) {
clearTimeout ( timer . timer ) ;
}
this . # timers . delete ( timerId ) ;
}
2022-11-30 15:44:23 -05:00
_setTimeout ( _func , timeout ) {
if ( timeout == null ) {
timeout = 0 ;
}
2022-09-05 16:57:11 -04:00
const timerId = this . # nextTimer ++ ;
const func = ( ) => {
this . # timers . delete ( timerId ) ;
_func ( ) ;
} ;
if ( this . paused ) {
this . # timers . set ( timerId , { timer : null , func , time : timeout } ) ;
}
else {
const timer = setTimeout ( func , timeout ) ;
this . # timers . set ( timerId , { timer , func , time : getTime ( ) } ) ;
}
return timerId ;
}
_forEachSubscriber ( func ) {
for ( const sub of this . # subs . values ( ) ) {
func ( sub . subscriber ) ;
}
}
// Event API; sub-classes should override this; any supported
// event filter will have been munged into an EventFilter
_getSubscriber ( sub ) {
switch ( sub . type ) {
case "debug" :
case "network" :
return new UnmanagedSubscriber ( sub . type ) ;
case "block" :
return new subscriber _polling _js _1 . PollingBlockSubscriber ( this ) ;
case "event" :
return new subscriber _polling _js _1 . PollingEventSubscriber ( this , sub . filter ) ;
case "transaction" :
return new subscriber _polling _js _1 . PollingTransactionSubscriber ( this , sub . hash ) ;
case "orphan" :
return new subscriber _polling _js _1 . PollingOrphanSubscriber ( this , sub . filter ) ;
}
throw new Error ( ` unsupported event: ${ sub . type } ` ) ;
}
_recoverSubscriber ( oldSub , newSub ) {
for ( const sub of this . # subs . values ( ) ) {
if ( sub . subscriber === oldSub ) {
if ( sub . started ) {
sub . subscriber . stop ( ) ;
}
sub . subscriber = newSub ;
if ( sub . started ) {
newSub . start ( ) ;
}
if ( this . # pausedState != null ) {
newSub . pause ( this . # pausedState ) ;
}
break ;
}
}
}
async # hasSub ( event , emitArgs ) {
let sub = await getSubscription ( event , this ) ;
// This is a log that is removing an existing log; we actually want
// to emit an orphan event for the removed log
if ( sub . type === "event" && emitArgs && emitArgs . length > 0 && emitArgs [ 0 ] . removed === true ) {
sub = await getSubscription ( { orphan : "drop-log" , log : emitArgs [ 0 ] } , this ) ;
}
return this . # subs . get ( sub . tag ) || null ;
}
async # getSub ( event ) {
const subscription = await getSubscription ( event , this ) ;
// Prevent tampering with our tag in any subclass' _getSubscriber
const tag = subscription . tag ;
let sub = this . # subs . get ( tag ) ;
if ( ! sub ) {
const subscriber = this . _getSubscriber ( subscription ) ;
const addressableMap = new WeakMap ( ) ;
const nameMap = new Map ( ) ;
sub = { subscriber , tag , addressableMap , nameMap , started : false , listeners : [ ] } ;
this . # subs . set ( tag , sub ) ;
}
return sub ;
}
async on ( event , listener ) {
const sub = await this . # getSub ( event ) ;
sub . listeners . push ( { listener , once : false } ) ;
if ( ! sub . started ) {
sub . subscriber . start ( ) ;
sub . started = true ;
if ( this . # pausedState != null ) {
sub . subscriber . pause ( this . # pausedState ) ;
}
}
return this ;
}
async once ( event , listener ) {
const sub = await this . # getSub ( event ) ;
sub . listeners . push ( { listener , once : true } ) ;
if ( ! sub . started ) {
sub . subscriber . start ( ) ;
sub . started = true ;
if ( this . # pausedState != null ) {
sub . subscriber . pause ( this . # pausedState ) ;
}
}
return this ;
}
async emit ( event , ... args ) {
const sub = await this . # hasSub ( event , args ) ;
2023-02-02 04:05:47 -05:00
// If there is not subscription or if a recent emit removed
// the last of them (which also deleted the sub) do nothing
if ( ! sub || sub . listeners . length === 0 ) {
2022-09-05 16:57:11 -04:00
return false ;
}
;
const count = sub . listeners . length ;
sub . listeners = sub . listeners . filter ( ( { listener , once } ) => {
2023-02-02 04:05:47 -05:00
const payload = new index _js _6 . EventPayload ( this , ( once ? null : listener ) , event ) ;
2022-09-05 16:57:11 -04:00
try {
listener . call ( this , ... args , payload ) ;
}
catch ( error ) { }
return ! once ;
} ) ;
2022-11-09 02:57:02 -05:00
if ( sub . listeners . length === 0 ) {
if ( sub . started ) {
sub . subscriber . stop ( ) ;
}
this . # subs . delete ( sub . tag ) ;
}
2022-09-05 16:57:11 -04:00
return ( count > 0 ) ;
}
async listenerCount ( event ) {
if ( event ) {
const sub = await this . # hasSub ( event ) ;
if ( ! sub ) {
return 0 ;
}
return sub . listeners . length ;
}
let total = 0 ;
for ( const { listeners } of this . # subs . values ( ) ) {
total += listeners . length ;
}
return total ;
}
async listeners ( event ) {
if ( event ) {
const sub = await this . # hasSub ( event ) ;
if ( ! sub ) {
return [ ] ;
}
return sub . listeners . map ( ( { listener } ) => listener ) ;
}
let result = [ ] ;
for ( const { listeners } of this . # subs . values ( ) ) {
result = result . concat ( listeners . map ( ( { listener } ) => listener ) ) ;
}
return result ;
}
async off ( event , listener ) {
const sub = await this . # hasSub ( event ) ;
if ( ! sub ) {
return this ;
}
if ( listener ) {
const index = sub . listeners . map ( ( { listener } ) => listener ) . indexOf ( listener ) ;
if ( index >= 0 ) {
sub . listeners . splice ( index , 1 ) ;
}
}
if ( ! listener || sub . listeners . length === 0 ) {
if ( sub . started ) {
sub . subscriber . stop ( ) ;
}
this . # subs . delete ( sub . tag ) ;
}
return this ;
}
async removeAllListeners ( event ) {
if ( event ) {
const { tag , started , subscriber } = await this . # getSub ( event ) ;
if ( started ) {
subscriber . stop ( ) ;
}
this . # subs . delete ( tag ) ;
}
else {
for ( const [ tag , { started , subscriber } ] of this . # subs ) {
if ( started ) {
subscriber . stop ( ) ;
}
this . # subs . delete ( tag ) ;
}
}
return this ;
}
// Alias for "on"
async addListener ( event , listener ) {
return await this . on ( event , listener ) ;
}
// Alias for "off"
async removeListener ( event , listener ) {
return this . off ( event , listener ) ;
}
// Sub-classes should override this to shutdown any sockets, etc.
// but MUST call this super.shutdown.
2022-12-30 16:35:04 -05:00
destroy ( ) {
2022-09-05 16:57:11 -04:00
// Stop all listeners
this . removeAllListeners ( ) ;
// Shut down all tiemrs
for ( const timerId of this . # timers . keys ( ) ) {
this . _clearTimeout ( timerId ) ;
}
}
get paused ( ) { return ( this . # pausedState != null ) ; }
set paused ( pause ) {
if ( ! ! pause === this . paused ) {
return ;
}
if ( this . paused ) {
this . resume ( ) ;
}
else {
this . pause ( false ) ;
}
}
pause ( dropWhilePaused ) {
2022-09-27 03:45:27 -04:00
this . # lastBlockNumber = - 1 ;
2022-09-05 16:57:11 -04:00
if ( this . # pausedState != null ) {
if ( this . # pausedState == ! ! dropWhilePaused ) {
return ;
}
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( false , "cannot change pause type; resume first" , "UNSUPPORTED_OPERATION" , {
2022-09-05 16:57:11 -04:00
operation : "pause"
} ) ;
}
this . _forEachSubscriber ( ( s ) => s . pause ( dropWhilePaused ) ) ;
this . # pausedState = ! ! dropWhilePaused ;
for ( const timer of this . # timers . values ( ) ) {
// Clear the timer
if ( timer . timer ) {
clearTimeout ( timer . timer ) ;
}
// Remaining time needed for when we become unpaused
timer . time = getTime ( ) - timer . time ;
}
}
resume ( ) {
if ( this . # pausedState == null ) {
return ;
}
this . _forEachSubscriber ( ( s ) => s . resume ( ) ) ;
this . # pausedState = null ;
for ( const timer of this . # timers . values ( ) ) {
// Remaining time when we were paused
let timeout = timer . time ;
if ( timeout < 0 ) {
timeout = 0 ;
}
// Start time (in cause paused, so we con compute remaininf time)
timer . time = getTime ( ) ;
// Start the timer
setTimeout ( timer . func , timeout ) ;
}
}
}
exports . AbstractProvider = AbstractProvider ;
function _parseString ( result , start ) {
try {
const bytes = _parseBytes ( result , start ) ;
if ( bytes ) {
2023-02-02 04:05:47 -05:00
return ( 0 , index _js _6 . toUtf8String ) ( bytes ) ;
2022-09-05 16:57:11 -04:00
}
}
catch ( error ) { }
return null ;
}
function _parseBytes ( result , start ) {
if ( result === "0x" ) {
return null ;
}
try {
2023-02-02 04:05:47 -05:00
const offset = ( 0 , index _js _6 . getNumber ) ( ( 0 , index _js _6 . dataSlice ) ( result , start , start + 32 ) ) ;
const length = ( 0 , index _js _6 . getNumber ) ( ( 0 , index _js _6 . dataSlice ) ( result , offset , offset + 32 ) ) ;
return ( 0 , index _js _6 . dataSlice ) ( result , offset + 32 , offset + 32 + length ) ;
2022-09-05 16:57:11 -04:00
}
catch ( error ) { }
return null ;
}
function numPad ( value ) {
2023-02-02 04:05:47 -05:00
const result = ( 0 , index _js _6 . toBeArray ) ( value ) ;
2022-09-05 16:57:11 -04:00
if ( result . length > 32 ) {
throw new Error ( "internal; should not happen" ) ;
}
const padded = new Uint8Array ( 32 ) ;
padded . set ( result , 32 - result . length ) ;
return padded ;
}
function bytesPad ( value ) {
if ( ( value . length % 32 ) === 0 ) {
return value ;
}
const result = new Uint8Array ( Math . ceil ( value . length / 32 ) * 32 ) ;
result . set ( value ) ;
return result ;
}
const empty = new Uint8Array ( [ ] ) ;
// ABI Encodes a series of (bytes, bytes, ...)
function encodeBytes ( datas ) {
const result = [ ] ;
let byteCount = 0 ;
// Add place-holders for pointers as we add items
for ( let i = 0 ; i < datas . length ; i ++ ) {
result . push ( empty ) ;
byteCount += 32 ;
}
for ( let i = 0 ; i < datas . length ; i ++ ) {
2023-02-02 04:05:47 -05:00
const data = ( 0 , index _js _6 . getBytes ) ( datas [ i ] ) ;
2022-09-05 16:57:11 -04:00
// Update the bytes offset
result [ i ] = numPad ( byteCount ) ;
// The length and padded value of data
result . push ( numPad ( data . length ) ) ;
result . push ( bytesPad ( data ) ) ;
byteCount += 32 + Math . ceil ( data . length / 32 ) * 32 ;
}
2023-02-02 04:05:47 -05:00
return ( 0 , index _js _6 . concat ) ( result ) ;
2022-09-05 16:57:11 -04:00
}
const zeros = "0x0000000000000000000000000000000000000000000000000000000000000000" ;
function parseOffchainLookup ( data ) {
const result = {
sender : "" , urls : [ ] , calldata : "" , selector : "" , extraData : "" , errorArgs : [ ]
} ;
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( ( 0 , index _js _6 . dataLength ) ( data ) >= 5 * 32 , "insufficient OffchainLookup data" , "OFFCHAIN_FAULT" , {
2023-01-28 01:53:29 -05:00
reason : "insufficient OffchainLookup data"
} ) ;
2023-02-02 04:05:47 -05:00
const sender = ( 0 , index _js _6 . dataSlice ) ( data , 0 , 32 ) ;
( 0 , index _js _6 . assert ) ( ( 0 , index _js _6 . dataSlice ) ( sender , 0 , 12 ) === ( 0 , index _js _6 . dataSlice ) ( zeros , 0 , 12 ) , "corrupt OffchainLookup sender" , "OFFCHAIN_FAULT" , {
2023-01-28 01:53:29 -05:00
reason : "corrupt OffchainLookup sender"
} ) ;
2023-02-02 04:05:47 -05:00
result . sender = ( 0 , index _js _6 . dataSlice ) ( sender , 12 ) ;
2022-09-05 16:57:11 -04:00
// Read the URLs from the response
try {
const urls = [ ] ;
2023-02-02 04:05:47 -05:00
const urlsOffset = ( 0 , index _js _6 . getNumber ) ( ( 0 , index _js _6 . dataSlice ) ( data , 32 , 64 ) ) ;
const urlsLength = ( 0 , index _js _6 . getNumber ) ( ( 0 , index _js _6 . dataSlice ) ( data , urlsOffset , urlsOffset + 32 ) ) ;
const urlsData = ( 0 , index _js _6 . dataSlice ) ( data , urlsOffset + 32 ) ;
2022-09-05 16:57:11 -04:00
for ( let u = 0 ; u < urlsLength ; u ++ ) {
const url = _parseString ( urlsData , u * 32 ) ;
if ( url == null ) {
throw new Error ( "abort" ) ;
}
urls . push ( url ) ;
}
result . urls = urls ;
}
catch ( error ) {
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( false , "corrupt OffchainLookup urls" , "OFFCHAIN_FAULT" , {
2023-01-28 01:53:29 -05:00
reason : "corrupt OffchainLookup urls"
} ) ;
2022-09-05 16:57:11 -04:00
}
// Get the CCIP calldata to forward
try {
const calldata = _parseBytes ( data , 64 ) ;
if ( calldata == null ) {
throw new Error ( "abort" ) ;
}
result . calldata = calldata ;
}
catch ( error ) {
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( false , "corrupt OffchainLookup calldata" , "OFFCHAIN_FAULT" , {
2023-01-28 01:53:29 -05:00
reason : "corrupt OffchainLookup calldata"
} ) ;
2022-09-05 16:57:11 -04:00
}
// Get the callbackSelector (bytes4)
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( ( 0 , index _js _6 . dataSlice ) ( data , 100 , 128 ) === ( 0 , index _js _6 . dataSlice ) ( zeros , 0 , 28 ) , "corrupt OffchainLookup callbaackSelector" , "OFFCHAIN_FAULT" , {
2023-01-28 01:53:29 -05:00
reason : "corrupt OffchainLookup callbaackSelector"
} ) ;
2023-02-02 04:05:47 -05:00
result . selector = ( 0 , index _js _6 . dataSlice ) ( data , 96 , 100 ) ;
2022-09-05 16:57:11 -04:00
// Get the extra data to send back to the contract as context
try {
const extraData = _parseBytes ( data , 128 ) ;
if ( extraData == null ) {
throw new Error ( "abort" ) ;
}
result . extraData = extraData ;
}
catch ( error ) {
2023-02-02 04:05:47 -05:00
( 0 , index _js _6 . assert ) ( false , "corrupt OffchainLookup extraData" , "OFFCHAIN_FAULT" , {
2023-01-28 01:53:29 -05:00
reason : "corrupt OffchainLookup extraData"
} ) ;
2022-09-05 16:57:11 -04:00
}
result . errorArgs = "sender,urls,calldata,selector,extraData" . split ( /,/ ) . map ( ( k ) => result [ k ] ) ;
return result ;
}
//# sourceMappingURL=abstract-provider.js.map