chedder
Version:
166 lines (146 loc) • 5.35 kB
text/typescript
const fetch = require('node-fetch');
import * as naclUtil from "../tweetnacl/util.js";
let rpcUrl: string = "https://rpc.mainnet.near.org/"
export function setRpcUrl(newUrl: string) {
rpcUrl = newUrl;
}
const fetchHeaders: Record<string, string> = { 'Content-type': 'application/json; charset=utf-8' }
export function addHeader(name: string, value: string) {
fetchHeaders[name] = value
}
export function getHeaders() {
return fetchHeaders;
}
export function ytonFull(str: string): string {
let pre="";
if (str.startsWith("-")) {
pre="-"
str= str.slice(1);
}
let result = (str + "").padStart(25, "0")
result = result.slice(0, -24) + "." + result.slice(-24)
return pre + result;
}
export function formatJSONErr(obj: any): any {
let text = JSON.stringify(obj)
text = text.replace(/{/g, " ")
text = text.replace(/}/g, " ")
text = text.replace(/"/g, "")
//---------
//try some enhancements
//---------
//convert yoctoNEAR to near
const largeNumbersFound = text.match(/\d{14,50}/g)
if (largeNumbersFound) {
for (const matches of largeNumbersFound) {
const parts = matches.split(" ")
const yoctoString = parts.pop() || ""
if (yoctoString.length >= 20) {
// convert to NEAR
text = text.replace(new RegExp(yoctoString, "g"), ytonFull(yoctoString))
}
}
}
//if panicked-at: show relevant info only
console.error(text); //show info in the console before removing extra info
const KEY = "panicked at "
const kl = KEY.length
let n = text.indexOf(KEY)
if (n > 0 && n < text.length - kl - 5) {
const i = text.indexOf("'", n + kl + 4)
const cut = text.slice(n + kl, i)
if (cut.trim().length > 5) {
console.error(text.slice(n, i + 80)) //show info in the console before removing extra info
text = "panicked at: " + cut;
}
}
return text
}
let id = 0
export async function jsonRpcInternal(payload: Record<string, any>): Promise<any> {
try {
const rpcOptions = {
body: JSON.stringify(payload),
method: "POST",
headers: { 'Content-type': 'application/json; charset=utf-8' }
}
let timeoutRetries = 0;
while (true) {
let fetchResult = await fetch(rpcUrl, rpcOptions);
let response = await fetchResult.json()
if (!fetchResult.ok) throw new Error(rpcUrl + " " + fetchResult.status + " " + fetchResult.statusText)
let error = response.error
if (!error && response.result && response.result.error) {
if (response.result.logs && response.result.logs.length) {
console.log("response.result.logs:", response.result.logs);
}
error = {
message: response.result.error
}
}
if (error) {
const errorMessage = formatJSONErr(error);
if (error.data === 'Timeout' || errorMessage.indexOf('Timeout error') != -1) {
const err = new Error('jsonRpc has timed out')
if (timeoutRetries<3){
timeoutRetries++;
console.error(err.message,"RETRY #",timeoutRetries);
continue;
}
err.name = 'TimeoutError'
throw err;
}
else {
throw new Error("Error: " + errorMessage);
}
}
if (!response.result) {
console.log("response.result=",response.result)
}
return response.result;
}
}
catch (ex) {
//add rpc url to err info
throw new Error(ex.message + " (" + rpcUrl + ")")
}
}
// if (!response.ok) {
// if (response.status === 503) {
// console.warn(`Retrying HTTP request for ${url} as it's not available now`);
// return null;
// }
// throw createError(response.status, await response.text());
// }
// return response;
// } catch (error) {
// if (error.toString().includes('FetchError')) {
// console.warn(`Retrying HTTP request for ${url} because of error: ${error}`);
// return null;
// }
// throw error;
// }
/**
* makes a jsonRpc call with {method}
* @param method jsonRpc method to call
* @param jsonRpcParams string[] with parameters
*/
export async function jsonRpc(method: string, jsonRpcParams: any): Promise<any> {
const payload = {
method: method,
params: jsonRpcParams,
id: ++id,
jsonrpc: "2.0"
}
return jsonRpcInternal(payload);
}
/**
* makes a jsonRpc "query" call
* @param {string} queryWhat : account/xx | call/contract/method
* @param {any} params : { amount:"2020202202212"}
*/
export async function jsonRpcQuery(queryWhat: string, params?: any): Promise<any> {
if (typeof params == "object" && Object.keys(params).length == 0) { params = undefined }
let queryParams = [queryWhat, params || ""] //params for the fn call - something - the jsonrpc call fail if there's a single item in the array
return await jsonRpc("query", queryParams);
}