import { rpc , u , wallet } from "@cityofzion/neon-core" ; export interface PastTransaction { txid : string ; blockHeight : number ; change : { [ assetSymbol ] : u . Fixed8 ; } ; } export interface Provider { name : string ; getRPCEndpoint ( noCache ? ) : Promise < string > ; getBalance ( address ) : Promise < wallet . Balance > ; getClaims ( address ) : Promise < wallet . Claims > ; getMaxClaimAmount ( address ) : Promise < u . Fixed8 > ; getHeight ( ) : Promise < number > ; getTransactionHistory ( address ) : Promise < PastTransaction [ ] > ; } export interface DataProvider extends Provider { getAPIEndpoint ( net ) : string ; } export interface RpcNode { height : number ; url : string ; } export function filterHttpsOnly ( nodes ) { return nodes . filter ( ( n ) => n . url . includes ( "https://" ) ) ; } export async function raceToSuccess < T > ( promises ) { try { const errors = await Promise . all ( promises . map ( ( p ) => p . then ( ( val ) => Promise . reject ( val ) , ( err ) => err ) ) ) ; return await Promise . reject ( errors ) ; } catch ( success ) { return success ; } } export async function getBestUrl ( rpcs ) { const clients = rpcs . map ( ( r ) => new rpc . RPCClient ( r . url ) ) ; return await raceToSuccess ( clients . map ( ( c ) => c . ping ( ) . then ( ( _ ) => c . net ) ) ) ; } export function findGoodNodesFromHeight ( nodes , tolerance = 1 ) { if ( nodes . length === 0 ) { throw new Error ( "No eligible nodes found!" ) ; } const sortedNodes = nodes . slice ( ) . sort ( ( n1 , n2 ) => n2 . height - n1 . height ) ; const bestHeight = sortedNodes [ 0 ] . height ; const threshold = bestHeight - tolerance ; return sortedNodes . filter ( ( n ) => n . height >= threshold ) ; }