UNPKG

@0xobelisk/rooch-client

Version:
299 lines (281 loc) 8.07 kB
import { Args, Bytes, CallFunctionArgs, ModuleABIView, RoochClient, Secp256k1Keypair, Transaction, TypeArgs, TypeTag, NetworkType, GetStatesParams, ObjectStateView, ListStatesParams, PaginatedStateKVViews, ExecuteTransactionResponseView, address, GetEventsByEventHandleParams, PaginatedEventViews, } from '@roochnetwork/rooch-sdk'; import { delay } from './util'; /** * `RoochTransaction` is used to send transaction with a given gas coin. * It always uses the gas coin to pay for the gas, * and update the gas coin after the transaction. */ export class RoochInteractor { public readonly clients: RoochClient[]; public currentClient: RoochClient; public readonly fullNodes: string[]; public currentFullNode: string; public network?: NetworkType; constructor(fullNodeUrls: string[], network?: NetworkType) { if (fullNodeUrls.length === 0) throw new Error('fullNodeUrls must not be empty'); this.clients = fullNodeUrls.map((url) => new RoochClient({ url })); this.currentClient = this.clients[0]; this.fullNodes = fullNodeUrls; this.currentFullNode = fullNodeUrls[0]; this.network = network; } switchToNextProvider() { const currentClientIdx = this.clients.indexOf(this.currentClient); this.currentClient = this.clients[(currentClientIdx + 1) % this.clients.length]; this.currentFullNode = this.fullNodes[(currentClientIdx + 1) % this.clients.length]; } async createSession( sessionArgs: { appName: string; appUrl: string; scopes: string[]; }, signer: Secp256k1Keypair ) { for (const client of this.clients) { try { const session = await client.createSession({ sessionArgs, signer, }); return session; } catch (err) { console.warn(`Failed to create session: ${err}`); await delay(2000); } } throw new Error('Failed to create session with all fullnodes'); } async signAndExecuteTransaction( transaction: Transaction | Bytes, signer: Secp256k1Keypair, option: { withOutput: boolean; } ): Promise<any> { for (const client of this.clients) { try { const txnResponse = await client.signAndExecuteTransaction({ transaction, signer, option, }); return txnResponse; } catch (err) { console.warn(`Failed to send transaction: ${err}`); await delay(2000); } } throw new Error('Failed to send transaction with all fullnodes'); } async executeViewFunction( contractAddress: string, moduleName: string, funcName: string, typeArguments: TypeTag[] = [], args: Args[] = [] ) { for (const client of this.clients) { try { const input: CallFunctionArgs = { address: contractAddress, module: moduleName, function: funcName, typeArgs: typeArguments, args, }; const result = await client.executeViewFunction(input); return result; } catch (err) { await delay(2000); console.warn(`Failed to execute view function: ${err}`); } } throw new Error('Failed to execute view function with all fullnodes'); } async getModuleAbi( accountAddress: string, moduleName: string ): Promise<ModuleABIView> { for (const client of this.clients) { try { const result = await client.getModuleAbi({ moduleAddr: accountAddress, moduleName, }); return result; } catch (err) { await delay(2000); console.warn( `Failed to get ModuleAbi ${accountAddress} ${moduleName}: ${err}` ); } } throw new Error( `Failed to get ModuleAbi ${accountAddress} ${moduleName} with all fullnodes` ); } async getModuleAbis( accountAddress: string, modules: string[] ): Promise<ModuleABIView[]> { for (const client of this.clients) { try { const result: ModuleABIView[] = []; for (const moduleName of modules) { const moduleAbi = await client.getModuleAbi({ moduleAddr: accountAddress, moduleName, }); result.push(moduleAbi); } return result; } catch (err) { await delay(2000); console.warn( `Failed to get ModuleAbi ${accountAddress} ${modules.join( ',' )}: ${err}` ); } } throw new Error( `Failed to get ModuleAbi ${accountAddress} ${modules.join( ',' )} with all fullnodes` ); } async getBalance(address: string, coinType: string) { for (const client of this.clients) { try { const result = await client.getBalance({ owner: address, coinType, }); return result; } catch (err) { await delay(2000); console.warn(`Failed to get balance: ${err}`); } } throw new Error(`Failed to get balance with all fullnodes`); } async getRpcApiVersion(): Promise<string | undefined> { for (const client of this.clients) { try { const result = await client.getRpcApiVersion(); return result; } catch (err) { await delay(2000); console.warn(`Failed to get RPC API version: ${err}`); } } throw new Error('Failed to get RPC API version with all fullnodes'); } async getChainId(): Promise<bigint> { for (const client of this.clients) { try { const result = await client.getChainId(); return result; } catch (err) { await delay(2000); console.warn(`Failed to get chain ID: ${err}`); } } throw new Error('Failed to get chain ID with all fullnodes'); } async getStates(params: GetStatesParams): Promise<ObjectStateView[]> { for (const client of this.clients) { try { const result = await client.getStates(params); return result; } catch (err) { await delay(2000); console.warn(`Failed to get states: ${err}`); } } throw new Error('Failed to get states with all fullnodes'); } async listStates(params: ListStatesParams): Promise<PaginatedStateKVViews> { for (const client of this.clients) { try { const result = await client.listStates(params); return result; } catch (err) { await delay(2000); console.warn(`Failed to list states: ${err}`); } } throw new Error('Failed to list states with all fullnodes'); } async getEvents( input: GetEventsByEventHandleParams ): Promise<PaginatedEventViews> { for (const client of this.clients) { try { const result = await client.getEvents(input); return result; } catch (err) { await delay(2000); console.warn(`Failed to get events: ${err}`); } } throw new Error('Failed to get events with all fullnodes'); } async transfer(input: { signer: Secp256k1Keypair; recipient: address; amount: number | bigint; coinType: TypeArgs; }): Promise<ExecuteTransactionResponseView> { for (const client of this.clients) { try { const result = await client.transfer(input); return result; } catch (err) { await delay(2000); console.warn(`Failed to transfer: ${err}`); } } throw new Error('Failed to transfer with all fullnodes'); } async transferObject(input: { signer: Secp256k1Keypair; recipient: address; objectId: string; objectType: TypeArgs; }): Promise<ExecuteTransactionResponseView> { for (const client of this.clients) { try { const result = await client.transferObject(input); return result; } catch (err) { await delay(2000); console.warn(`Failed to transfer object: ${err}`); } } throw new Error('Failed to transfer object with all fullnodes'); } }