import { assertType , ErrorWithCode , Logger , nullLogger , pack , RenJSError , RenNetwork , RenNetworkString , RenVMShard , utils , } from "@renproject/utils" ; import { ParamsQueryBlock , ParamsQueryBlocks , ParamsQueryTxs , ParamsSubmitGateway , ParamsSubmitTx , ResponseQueryBlock , ResponseQueryBlocks , ResponseQueryConfig , ResponseQueryTx , ResponseSubmitGateway , ResponseSubmitTx , RPCMethod , RPCParams , RPCResponses , SubmitGatewayInput , submitGatewayType , } from "./methods" ; import { BlockState } from "./methods/ren_queryBlockState" ; import { HttpProvider , Provider } from "./rpc/jsonRpc" ; import { renRpcUrls } from "./rpcUrls" ; import { RenVMCrossChainTransaction , RenVMTransaction , RenVMTransactionWithStatus , unmarshalRenVMTransaction , } from "./unmarshal" ; export class RenVMProvider extends HttpProvider < RPCParams , RPCResponses > { public readonly logger : Logger ; public constructor ( endpointOrProvider , logger = nullLogger ) { super ( typeof endpointOrProvider !== "string" ? endpointOrProvider : renRpcUrls [ endpointOrProvider ] || endpointOrProvider ) ; this . logger = logger ; } public queryBlock = async ( blockHeight , retry ? ) : Promise < ResponseQueryBlock > => ( await this . sendMessage < RPCMethod . QueryBlock > ( RPCMethod . QueryBlock , { blockHeight } , retry ) ) . block ; public queryBlocks = async ( blockHeight , n , retry ? ) : Promise < ResponseQueryBlocks > => ( await this . sendMessage < RPCMethod . QueryBlocks > ( RPCMethod . QueryBlocks , { blockHeight , n } , retry ) ) . blocks ; public submitGateway = async ( gateway , tx , retry ? ) : Promise < ResponseSubmitGateway > => this . sendMessage < RPCMethod . SubmitGateway > ( RPCMethod . SubmitGateway , { gateway , tx } , retry ) ; public submitTx = async ( tx , retry ? ) : Promise < ResponseSubmitTx > => this . sendMessage < RPCMethod . SubmitTx > ( RPCMethod . SubmitTx , { tx } as ParamsSubmitTx , retry ) ; public queryTxs = async ( tags , page ? , pageSize ? , txStatus ? , retry ? ) : Promise < RenVMTransaction [ ] > => ( await this . sendMessage < RPCMethod . QueryTxs > ( RPCMethod . QueryTxs , { tags , page : ( page || 0 ) . toString ( ) , pageSize : ( pageSize || 0 ) . toString ( ) , txStatus , } , retry ) ) . txs . map ( ( tx ) => unmarshalRenVMTransaction ( tx ) ) ; public queryConfig = async ( retry ? ) : Promise < ResponseQueryConfig > => this . sendMessage < RPCMethod . QueryConfig > ( RPCMethod . QueryConfig , { } , retry ) ; public queryBlockState = utils . memoize ( async ( contract , retry ? ) : Promise < BlockState > => { const { state } = await this . sendMessage < RPCMethod . QueryBlockState > ( RPCMethod . QueryBlockState , { contract } , retry ) ; return pack . unmarshal . unmarshalTypedPackValue ( state ) ; } ) ; public submitGatewayDetails = async ( gateway , params , retries ? ) : Promise < string > => { const { selector , gHash , gPubKey , nHash , nonce , payload , pHash , to } = params ; assertType < Buffer > ( "Buffer" , { gHash , gPubKey , nHash , nonce , payload , pHash , } ) ; assertType < string > ( "string" , { to } ) ; const txIn = { t : submitGatewayType , v : { ghash : utils . toURLBase64 ( gHash ) , gpubkey : utils . toURLBase64 ( gPubKey ) , nhash : utils . toURLBase64 ( nHash ) , nonce : utils . toURLBase64 ( nonce ) , payload : utils . toURLBase64 ( payload ) , phash : utils . toURLBase64 ( pHash ) , to , } , } ; const tx = { selector : selector , version : "1" , in : txIn as unknown as SubmitGatewayInput [ "in" ] , } ; await this . submitGateway ( gateway , tx , retries ) ; return gateway ; } ; param txHash public readonly queryTx = async < T extends RenVMTransactionWithStatus = RenVMTransactionWithStatus < RenVMCrossChainTransaction > > ( txHash , retries ? ) : Promise < T > => { assertType < string > ( "string" , { txHash } ) ; let response ; try { response = await this . sendMessage < RPCMethod . QueryTx > ( RPCMethod . QueryTx , { txHash } , retries ) ; } catch ( error ) { if ( error . message . match ( /^invalid params: / ) ) { throw ErrorWithCode . from ( error , RenJSError . PARAMETER_ERROR ) ; } else if ( error . message . match ( /not found$/ ) ) { throw ErrorWithCode . from ( error , RenJSError . TRANSACTION_NOT_FOUND ) ; } else { throw ErrorWithCode . from ( error , RenJSError . UNKNOWN_ERROR ) ; } } try { return { tx : unmarshalRenVMTransaction ( response . tx ) , txStatus : response . txStatus , } as T ; } catch ( error ) { throw ErrorWithCode . from ( error , RenJSError . INTERNAL_ERROR ) ; } } ; /**
     * selectShard fetches the public key for the RenVM shard handling
     * the provided contract.
     */ public readonly selectShard = async ( asset ) : Promise < RenVMShard > => { let blockState ; try { blockState = await this . queryBlockState ( asset , 5 ) ; } catch ( error ) { throw ErrorWithCode . from ( new Error ( `Error fetching RenVM shards: ${ String ( error . message ) }` ) , RenJSError . NETWORK_ERROR ) ; } if ( ! blockState [ asset ] ) { throw new Error ( `No RenVM block state found for ${ asset }.` ) ; } const pubKey = blockState [ asset ] . shards [ 0 ] . pubKey ; if ( ! pubKey || pubKey . length === 0 ) { throw new Error ( `Unable to fetch RenVM public key for ${ asset }.` ) ; } assertType < Buffer > ( "Buffer" , { pubKey } ) ; return { gPubKey : utils . toURLBase64 ( pubKey ) , } ; } ; public getNetwork = async ( ) : Promise < string > => ( await this . queryConfig ( ) ) . network ; public getConfirmationTarget = async ( chainName ) : Promise < number > => { const renVMConfig = await this . sendMessage ( RPCMethod . QueryConfig , { } ) ; return parseInt ( renVMConfig . confirmations [ chainName ] , 10 ) ; } ; }