Socket
Socket
Sign inDemoInstall

near-api-js

Package Overview
Dependencies
Maintainers
4
Versions
77
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

near-api-js - npm Package Compare versions

Comparing version 0.36.3 to 0.37.0

lib/browser-connect.d.ts

8

lib/account.d.ts

@@ -27,10 +27,4 @@ /// <reference types="node" />

readonly accountId: string;
private _state;
private _ready;
protected get ready(): Promise<void>;
constructor(connection: Connection, accountId: string);
/**
* Helper function when getting the state of a NEAR account
* @returns Promise<void>
*/
fetchState(): Promise<void>;

@@ -125,3 +119,3 @@ /**

/**
* See https://docs.near.org/docs/api/rpc#view-contract-state
* See https://docs.near.org/docs/develop/front-end/rpc#view-contract-state
*

@@ -128,0 +122,0 @@ * Returns the state (key value pairs) of this account's contract based on the key prefix.

@@ -8,2 +8,3 @@ 'use strict';

const bn_js_1 = __importDefault(require("bn.js"));
const depd_1 = __importDefault(require("depd"));
const transaction_1 = require("./transaction");

@@ -25,8 +26,6 @@ const providers_1 = require("./providers");

const TX_NONCE_RETRY_NUMBER = 12;
// Default number of retries before giving up on a transaction.
const TX_STATUS_RETRY_NUMBER = 12;
// Default wait until next retry in millis.
const TX_STATUS_RETRY_WAIT = 500;
const TX_NONCE_RETRY_WAIT = 500;
// Exponential back off for waiting to retry.
const TX_STATUS_RETRY_WAIT_BACKOFF = 1.5;
const TX_NONCE_RETRY_WAIT_BACKOFF = 1.5;
function parseJsonFromRawResponse(response) {

@@ -45,10 +44,9 @@ return JSON.parse(Buffer.from(response).toString());

get ready() {
return this._ready || (this._ready = Promise.resolve(this.fetchState()));
const deprecate = depd_1.default('Account.ready()');
deprecate('not needed anymore, always ready');
return Promise.resolve();
}
/**
* Helper function when getting the state of a NEAR account
* @returns Promise<void>
*/
async fetchState() {
this._state = await this.connection.provider.query(`account/${this.accountId}`, '');
const deprecate = depd_1.default('Account.fetchState()');
deprecate('use `Account.state()` instead');
}

@@ -60,4 +58,3 @@ /**

async state() {
await this.ready;
return this._state;
return await this.connection.provider.query(`account/${this.accountId}`, '');
}

@@ -79,3 +76,2 @@ printLogsAndFailures(contractId, results) {

async signTransaction(receiverId, actions) {
await this.ready;
const accessKeyInfo = await this.findAccessKey(receiverId, actions);

@@ -97,30 +93,12 @@ if (!accessKeyInfo) {

async signAndSendTransaction(receiverId, actions) {
await this.ready;
let txHash, signedTx;
// TODO: TX_NONCE (different constants for different uses of exponentialBackoff?)
const result = await exponential_backoff_1.default(TX_STATUS_RETRY_WAIT, TX_NONCE_RETRY_NUMBER, TX_STATUS_RETRY_WAIT_BACKOFF, async () => {
const result = await exponential_backoff_1.default(TX_NONCE_RETRY_WAIT, TX_NONCE_RETRY_NUMBER, TX_NONCE_RETRY_WAIT_BACKOFF, async () => {
[txHash, signedTx] = await this.signTransaction(receiverId, actions);
const publicKey = signedTx.transaction.publicKey;
try {
const result = await exponential_backoff_1.default(TX_STATUS_RETRY_WAIT, TX_STATUS_RETRY_NUMBER, TX_STATUS_RETRY_WAIT_BACKOFF, async () => {
try {
return await this.connection.provider.sendTransaction(signedTx);
}
catch (error) {
// TODO: Somehow getting still:
// Error: send_tx_commit has timed out.
if (error.type === 'TimeoutError') {
console.warn(`Retrying transaction ${receiverId}:${borsh_1.baseEncode(txHash)} as it has timed out`);
return null;
}
throw error;
}
});
if (!result) {
throw new providers_1.TypedError(`Exceeded ${TX_STATUS_RETRY_NUMBER} attempts for transaction ${borsh_1.baseEncode(txHash)}.`, 'RetriesExceeded', new providers_1.ErrorContext(borsh_1.baseEncode(txHash)));
}
return result;
return await this.connection.provider.sendTransaction(signedTx);
}
catch (error) {
if (error.message.match(/Transaction nonce \d+ must be larger than nonce of the used access key \d+/)) {
if (error.type === 'InvalidNonce') {
console.warn(`Retrying transaction ${receiverId}:${borsh_1.baseEncode(txHash)} with new nonce.`);

@@ -179,4 +157,3 @@ delete this.accessKeyByPublicKeyCache[publicKey.toString()];

catch (e) {
// TODO: Check based on .type when nearcore starts returning query errors in structured format
if (e.message.includes('does not exist while viewing')) {
if (e.type == 'AccessKeyDoesNotExist') {
return null;

@@ -308,3 +285,3 @@ }

/**
* See https://docs.near.org/docs/api/rpc#view-contract-state
* See https://docs.near.org/docs/develop/front-end/rpc#view-contract-state
*

@@ -311,0 +288,0 @@ * Returns the state (key value pairs) of this account's contract based on the key prefix.

export * as keyStores from './key_stores/browser-index';
export * from './common-index';
export * from './browser-connect';
import 'error-polyfill';

@@ -27,2 +27,3 @@ "use strict";

__exportStar(require("./common-index"), exports);
__exportStar(require("./browser-connect"), exports);
require("error-polyfill");

@@ -12,4 +12,4 @@ import * as providers from './providers';

import { KeyPair } from './utils/key_pair';
import { connect, Near } from './near';
import { Near } from './near';
import { WalletAccount, WalletConnection } from './wallet-account';
export { accountCreator, providers, utils, transactions, validators, multisig, Account, Connection, Contract, InMemorySigner, Signer, KeyPair, connect, Near, WalletAccount, WalletConnection };
export { accountCreator, providers, utils, transactions, validators, multisig, Account, Connection, Contract, InMemorySigner, Signer, KeyPair, Near, WalletAccount, WalletConnection };

@@ -22,3 +22,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.WalletConnection = exports.WalletAccount = exports.Near = exports.connect = exports.KeyPair = exports.Signer = exports.InMemorySigner = exports.Contract = exports.Connection = exports.Account = exports.multisig = exports.validators = exports.transactions = exports.utils = exports.providers = exports.accountCreator = void 0;
exports.WalletConnection = exports.WalletAccount = exports.Near = exports.KeyPair = exports.Signer = exports.InMemorySigner = exports.Contract = exports.Connection = exports.Account = exports.multisig = exports.validators = exports.transactions = exports.utils = exports.providers = exports.accountCreator = void 0;
const providers = __importStar(require("./providers"));

@@ -48,3 +48,2 @@ exports.providers = providers;

const near_1 = require("./near");
Object.defineProperty(exports, "connect", { enumerable: true, get: function () { return near_1.connect; } });
Object.defineProperty(exports, "Near", { enumerable: true, get: function () { return near_1.Near; } });

@@ -51,0 +50,0 @@ // TODO: Deprecate and remove WalletAccount

export * as keyStores from './key_stores/index';
export * from './common-index';
export * from './connect';

@@ -27,1 +27,2 @@ "use strict";

__exportStar(require("./common-index"), exports);
__exportStar(require("./connect"), exports);

@@ -9,3 +9,3 @@ import BN from 'bn.js';

import { KeyStore } from './key_stores';
declare type NearConfig = {
export declare type NearConfig = {
keyStore?: KeyStore;

@@ -57,9 +57,1 @@ signer?: Signer;

}
declare type ConnectConfig = NearConfig & {
keyPath?: string;
};
/**
* Initialize connection to Near network.
*/
export declare function connect(config: ConnectConfig): Promise<Near>;
export {};

@@ -6,3 +6,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.connect = exports.Near = void 0;
exports.Near = void 0;
const bn_js_1 = __importDefault(require("bn.js"));

@@ -12,5 +12,3 @@ const account_1 = require("./account");

const contract_1 = require("./contract");
const unencrypted_file_system_keystore_1 = require("./key_stores/unencrypted_file_system_keystore");
const account_creator_1 = require("./account_creator");
const key_stores_1 = require("./key_stores");
class Near {

@@ -43,3 +41,2 @@ constructor(config) {

const account = new account_1.Account(this.connection, accountId);
await account.state();
return account;

@@ -82,28 +79,1 @@ }

exports.Near = Near;
/**
* Initialize connection to Near network.
*/
async function connect(config) {
// Try to find extra key in `KeyPath` if provided.
if (config.keyPath && config.deps && config.deps.keyStore) {
try {
const accountKeyFile = await unencrypted_file_system_keystore_1.readKeyFile(config.keyPath);
if (accountKeyFile[0]) {
// TODO: Only load key if network ID matches
const keyPair = accountKeyFile[1];
const keyPathStore = new key_stores_1.InMemoryKeyStore();
await keyPathStore.setKey(config.networkId, accountKeyFile[0], keyPair);
if (!config.masterAccount) {
config.masterAccount = accountKeyFile[0];
}
config.deps.keyStore = new key_stores_1.MergeKeyStore([config.deps.keyStore, keyPathStore]);
console.log(`Loaded master account ${accountKeyFile[0]} key from ${config.keyPath} with public key = ${keyPair.getPublicKey()}`);
}
}
catch (error) {
console.warn(`Failed to load master account key from ${config.keyPath}: ${error}`);
}
}
return new Near(config);
}
exports.connect = connect;

@@ -14,3 +14,10 @@ "use strict";

const borsh_1 = require("borsh");
const exponential_backoff_1 = __importDefault(require("../utils/exponential-backoff"));
const rpc_errors_1 = require("../utils/rpc_errors");
// Default number of retries before giving up on a request.
const REQUEST_RETRY_NUMBER = 12;
// Default wait until next retry in millis.
const REQUEST_RETRY_WAIT = 500;
// Exponential back off for waiting to retry.
const REQUEST_RETRY_WAIT_BACKOFF = 1.5;
/// Keep ids unique across all connections.

@@ -74,3 +81,3 @@ let _nextId = 123;

if (result && result.error) {
throw new Error(`Querying ${args} failed: ${result.error}.\n${JSON.stringify(result, null, 2)}`);
throw new errors_1.TypedError(`Querying ${args} failed: ${result.error}.\n${JSON.stringify(result, null, 2)}`, rpc_errors_1.getErrorTypeFromErrorMessage(result.error));
}

@@ -140,34 +147,46 @@ return result;

async sendJsonRpc(method, params) {
const request = {
method,
params,
id: (_nextId++),
jsonrpc: '2.0'
};
const response = await web_1.fetchJson(this.connection, JSON.stringify(request));
if (response.error) {
if (typeof response.error.data === 'object') {
if (typeof response.error.data.error_message === 'string' && typeof response.error.data.error_type === 'string') {
// if error data has error_message and error_type properties, we consider that node returned an error in the old format
throw new errors_1.TypedError(response.error.data.error_message, response.error.data.error_type);
const result = await exponential_backoff_1.default(REQUEST_RETRY_WAIT, REQUEST_RETRY_NUMBER, REQUEST_RETRY_WAIT_BACKOFF, async () => {
try {
const request = {
method,
params,
id: (_nextId++),
jsonrpc: '2.0'
};
const response = await web_1.fetchJson(this.connection, JSON.stringify(request));
if (response.error) {
if (typeof response.error.data === 'object') {
if (typeof response.error.data.error_message === 'string' && typeof response.error.data.error_type === 'string') {
// if error data has error_message and error_type properties, we consider that node returned an error in the old format
throw new errors_1.TypedError(response.error.data.error_message, response.error.data.error_type);
}
throw rpc_errors_1.parseRpcError(response.error.data);
}
else {
const errorMessage = `[${response.error.code}] ${response.error.message}: ${response.error.data}`;
// NOTE: All this hackery is happening because structured errors not implemented
// TODO: Fix when https://github.com/nearprotocol/nearcore/issues/1839 gets resolved
if (response.error.data === 'Timeout' || errorMessage.includes('Timeout error')
|| errorMessage.includes('query has timed out')) {
throw new errors_1.TypedError(errorMessage, 'TimeoutError');
}
throw new errors_1.TypedError(errorMessage, rpc_errors_1.getErrorTypeFromErrorMessage(response.error.data));
}
}
else {
throw rpc_errors_1.parseRpcError(response.error.data);
}
return response.result;
}
else {
const errorMessage = `[${response.error.code}] ${response.error.message}: ${response.error.data}`;
// NOTE: All this hackery is happening because structured errors not implemented
// TODO: Fix when https://github.com/nearprotocol/nearcore/issues/1839 gets resolved
if (response.error.data === 'Timeout' || errorMessage.includes('Timeout error')) {
throw new errors_1.TypedError('send_tx_commit has timed out.', 'TimeoutError');
catch (error) {
if (error.type === 'TimeoutError') {
console.warn(`Retrying request to ${method} as it has timed out`, params);
return null;
}
else {
throw new errors_1.TypedError(errorMessage);
}
throw error;
}
});
if (!result) {
throw new errors_1.TypedError(`Exceeded ${REQUEST_RETRY_NUMBER} attempts for request to ${method}.`, 'RetriesExceeded');
}
return response.result;
return result;
}
}
exports.JsonRpcProvider = JsonRpcProvider;
import { Signature, KeyPair, PublicKey } from './utils/key_pair';
import { KeyStore } from './key_stores';
import { KeyStore } from './key_stores/keystore';
/**

@@ -4,0 +4,0 @@ * General signing interface, can be used for in memory signing, RPC singing, external wallet, HSM, etc.

@@ -9,3 +9,3 @@ "use strict";

const key_pair_1 = require("./utils/key_pair");
const key_stores_1 = require("./key_stores");
const in_memory_key_store_1 = require("./key_stores/in_memory_key_store");
/**

@@ -35,3 +35,3 @@ * General signing interface, can be used for in memory signing, RPC singing, external wallet, HSM, etc.

static async fromKeyPair(networkId, accountId, keyPair) {
const keyStore = new key_stores_1.InMemoryKeyStore();
const keyStore = new in_memory_key_store_1.InMemoryKeyStore();
await keyStore.setKey(networkId, accountId, keyPair);

@@ -38,0 +38,0 @@ return new InMemorySigner(keyStore);

@@ -9,1 +9,2 @@ import { ServerError } from '../generated/rpc_error_types';

export declare function formatError(errorClassName: string, errorData: any): string;
export declare function getErrorTypeFromErrorMessage(errorMessage: any): "UntypedError" | "CodeDoesNotExist" | "AccountDoesNotExist" | "InvalidNonce" | "AccessKeyDoesNotExist";

@@ -28,3 +28,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.formatError = exports.parseResultError = exports.parseRpcError = void 0;
exports.getErrorTypeFromErrorMessage = exports.formatError = exports.parseResultError = exports.parseRpcError = void 0;
const mustache_1 = __importDefault(require("mustache"));

@@ -106,2 +106,20 @@ const rpc_error_schema_json_1 = __importDefault(require("../generated/rpc_error_schema.json"));

}
function getErrorTypeFromErrorMessage(errorMessage) {
// This function should be removed when JSON RPC starts returning typed errors.
switch (true) {
case /^account .*? does not exist while viewing$/.test(errorMessage):
return 'AccountDoesNotExist';
case /^Account .*? doesn't exist$/.test(errorMessage):
return 'AccountDoesNotExist';
case /^access key .*? does not exist while viewing$/.test(errorMessage):
return 'AccessKeyDoesNotExist';
case /wasm execution failed with error: FunctionCallError\(CompilationError\(CodeDoesNotExist/.test(errorMessage):
return 'CodeDoesNotExist';
case /Transaction nonce \d+ must be larger than nonce of the used access key \d+/.test(errorMessage):
return 'InvalidNonce';
default:
return 'UntypedError';
}
}
exports.getErrorTypeFromErrorMessage = getErrorTypeFromErrorMessage;
/**

@@ -108,0 +126,0 @@ * Helper function determining if the argument is an object

@@ -152,3 +152,2 @@ "use strict";

async signAndSendTransaction(receiverId, actions) {
await this.ready;
const localKey = await this.connection.signer.getPublicKey(this.accountId, this.connection.networkId);

@@ -164,4 +163,3 @@ let accessKey = await this.accessKeyForTransaction(receiverId, actions, localKey);

catch (e) {
// TODO: Use TypedError when available
if (e.message.includes('does not have enough balance')) {
if (e.type === 'NotEnoughBalance') {
accessKey = await this.accessKeyForTransaction(receiverId, actions);

@@ -168,0 +166,0 @@ }

{
"name": "near-api-js",
"description": "JavaScript library to interact with NEAR Protocol via RPC API",
"version": "0.36.3",
"version": "0.37.0",
"repository": {

@@ -14,3 +14,3 @@ "type": "git",

"dependencies": {
"@types/bn.js": "^4.11.5",
"@types/bn.js": "^5.1.0",
"bn.js": "^5.0.0",

@@ -41,3 +41,3 @@ "borsh": "^0.3.1",

"semver": "^7.1.1",
"ts-morph": "^8.1.0",
"ts-morph": "^10.0.0",
"typedoc": "^0.19.2",

@@ -44,0 +44,0 @@ "typescript": "^3.5.1",

'use strict';
import BN from 'bn.js';
import depd from 'depd';
import {

@@ -42,10 +43,7 @@ transfer,

// Default number of retries before giving up on a transaction.
const TX_STATUS_RETRY_NUMBER = 12;
// Default wait until next retry in millis.
const TX_STATUS_RETRY_WAIT = 500;
const TX_NONCE_RETRY_WAIT = 500;
// Exponential back off for waiting to retry.
const TX_STATUS_RETRY_WAIT_BACKOFF = 1.5;
const TX_NONCE_RETRY_WAIT_BACKOFF = 1.5;

@@ -82,7 +80,7 @@ export interface AccountState {

readonly accountId: string;
private _state: AccountState;
private _ready: Promise<void>;
protected get ready(): Promise<void> {
return this._ready || (this._ready = Promise.resolve(this.fetchState()));
const deprecate = depd('Account.ready()');
deprecate('not needed anymore, always ready');
return Promise.resolve();
}

@@ -95,8 +93,5 @@

/**
* Helper function when getting the state of a NEAR account
* @returns Promise<void>
*/
async fetchState(): Promise<void> {
this._state = await this.connection.provider.query(`account/${this.accountId}`, '');
const deprecate = depd('Account.fetchState()');
deprecate('use `Account.state()` instead');
}

@@ -109,4 +104,3 @@

async state(): Promise<AccountState> {
await this.ready;
return this._state;
return await this.connection.provider.query(`account/${this.accountId}`, '');
}

@@ -131,4 +125,2 @@

protected async signTransaction(receiverId: string, actions: Action[]): Promise<[Uint8Array, SignedTransaction]> {
await this.ready;
const accessKeyInfo = await this.findAccessKey(receiverId, actions);

@@ -155,7 +147,5 @@ if (!accessKeyInfo) {

protected async signAndSendTransaction(receiverId: string, actions: Action[]): Promise<FinalExecutionOutcome> {
await this.ready;
let txHash, signedTx;
// TODO: TX_NONCE (different constants for different uses of exponentialBackoff?)
const result = await exponentialBackoff(TX_STATUS_RETRY_WAIT, TX_NONCE_RETRY_NUMBER, TX_STATUS_RETRY_WAIT_BACKOFF, async () => {
const result = await exponentialBackoff(TX_NONCE_RETRY_WAIT, TX_NONCE_RETRY_NUMBER, TX_NONCE_RETRY_WAIT_BACKOFF, async () => {
[txHash, signedTx] = await this.signTransaction(receiverId, actions);

@@ -165,25 +155,5 @@ const publicKey = signedTx.transaction.publicKey;

try {
const result = await exponentialBackoff(TX_STATUS_RETRY_WAIT, TX_STATUS_RETRY_NUMBER, TX_STATUS_RETRY_WAIT_BACKOFF, async () => {
try {
return await this.connection.provider.sendTransaction(signedTx);
} catch (error) {
// TODO: Somehow getting still:
// Error: send_tx_commit has timed out.
if (error.type === 'TimeoutError') {
console.warn(`Retrying transaction ${receiverId}:${baseEncode(txHash)} as it has timed out`);
return null;
}
throw error;
}
});
if (!result) {
throw new TypedError(
`Exceeded ${TX_STATUS_RETRY_NUMBER} attempts for transaction ${baseEncode(txHash)}.`,
'RetriesExceeded',
new ErrorContext(baseEncode(txHash)));
}
return result;
return await this.connection.provider.sendTransaction(signedTx);
} catch (error) {
if (error.message.match(/Transaction nonce \d+ must be larger than nonce of the used access key \d+/)) {
if (error.type === 'InvalidNonce') {
console.warn(`Retrying transaction ${receiverId}:${baseEncode(txHash)} with new nonce.`);

@@ -248,4 +218,3 @@ delete this.accessKeyByPublicKeyCache[publicKey.toString()];

} catch (e) {
// TODO: Check based on .type when nearcore starts returning query errors in structured format
if (e.message.includes('does not exist while viewing')) {
if (e.type == 'AccessKeyDoesNotExist') {
return null;

@@ -395,3 +364,3 @@ }

/**
* See https://docs.near.org/docs/api/rpc#view-contract-state
* See https://docs.near.org/docs/develop/front-end/rpc#view-contract-state
*

@@ -398,0 +367,0 @@ * Returns the state (key value pairs) of this account's contract based on the key prefix.

export * as keyStores from './key_stores/browser-index';
export * from './common-index';
export * from './browser-connect';
import 'error-polyfill';

@@ -13,3 +13,3 @@ import * as providers from './providers';

import { KeyPair } from './utils/key_pair';
import { connect, Near } from './near';
import { Near } from './near';

@@ -34,3 +34,2 @@ // TODO: Deprecate and remove WalletAccount

connect,
Near,

@@ -37,0 +36,0 @@

export * as keyStores from './key_stores/index';
export * from './common-index';
export * from './common-index';
export * from './connect';

@@ -1,2 +0,1 @@

import BN from 'bn.js';

@@ -7,8 +6,7 @@ import { Account } from './account';

import { Contract } from './contract';
import { readKeyFile } from './key_stores/unencrypted_file_system_keystore';
import { PublicKey } from './utils/key_pair';
import { AccountCreator, LocalAccountCreator, UrlAccountCreator } from './account_creator';
import { InMemoryKeyStore, KeyStore, MergeKeyStore } from './key_stores';
import { KeyStore } from './key_stores';
type NearConfig = {
export type NearConfig = {
keyStore?: KeyStore;

@@ -55,3 +53,2 @@ signer?: Signer;

const account = new Account(this.connection, accountId);
await account.state();
return account;

@@ -96,31 +93,1 @@ }

}
type ConnectConfig = NearConfig & {
keyPath?: string;
}
/**
* Initialize connection to Near network.
*/
export async function connect(config: ConnectConfig): Promise<Near> {
// Try to find extra key in `KeyPath` if provided.
if (config.keyPath && config.deps && config.deps.keyStore) {
try {
const accountKeyFile = await readKeyFile(config.keyPath);
if (accountKeyFile[0]) {
// TODO: Only load key if network ID matches
const keyPair = accountKeyFile[1];
const keyPathStore = new InMemoryKeyStore();
await keyPathStore.setKey(config.networkId, accountKeyFile[0], keyPair);
if (!config.masterAccount) {
config.masterAccount = accountKeyFile[0];
}
config.deps.keyStore = new MergeKeyStore([config.deps.keyStore, keyPathStore]);
console.log(`Loaded master account ${accountKeyFile[0]} key from ${config.keyPath} with public key = ${keyPair.getPublicKey()}`);
}
} catch (error) {
console.warn(`Failed to load master account key from ${config.keyPath}: ${error}`);
}
}
return new Near(config);
}

@@ -11,3 +11,4 @@ import depd from 'depd';

import { baseEncode } from 'borsh';
import { parseRpcError } from '../utils/rpc_errors';
import exponentialBackoff from '../utils/exponential-backoff';
import { parseRpcError, getErrorTypeFromErrorMessage } from '../utils/rpc_errors';
import { SignedTransaction } from '../transaction';

@@ -17,2 +18,11 @@

// Default number of retries before giving up on a request.
const REQUEST_RETRY_NUMBER = 12;
// Default wait until next retry in millis.
const REQUEST_RETRY_WAIT = 500;
// Exponential back off for waiting to retry.
const REQUEST_RETRY_WAIT_BACKOFF = 1.5;
/// Keep ids unique across all connections.

@@ -83,3 +93,5 @@ let _nextId = 123;

if (result && result.error) {
throw new Error(`Querying ${args} failed: ${result.error}.\n${JSON.stringify(result, null, 2)}`);
throw new TypedError(
`Querying ${args} failed: ${result.error}.\n${JSON.stringify(result, null, 2)}`,
getErrorTypeFromErrorMessage(result.error));
}

@@ -158,30 +170,47 @@ return result;

async sendJsonRpc(method: string, params: object): Promise<any> {
const request = {
method,
params,
id: (_nextId++),
jsonrpc: '2.0'
};
const response = await fetchJson(this.connection, JSON.stringify(request));
if (response.error) {
if (typeof response.error.data === 'object') {
if (typeof response.error.data.error_message === 'string' && typeof response.error.data.error_type === 'string') {
// if error data has error_message and error_type properties, we consider that node returned an error in the old format
throw new TypedError(response.error.data.error_message, response.error.data.error_type);
} else {
throw parseRpcError(response.error.data);
const result = await exponentialBackoff(REQUEST_RETRY_WAIT, REQUEST_RETRY_NUMBER, REQUEST_RETRY_WAIT_BACKOFF, async () => {
try {
const request = {
method,
params,
id: (_nextId++),
jsonrpc: '2.0'
};
const response = await fetchJson(this.connection, JSON.stringify(request));
if (response.error) {
if (typeof response.error.data === 'object') {
if (typeof response.error.data.error_message === 'string' && typeof response.error.data.error_type === 'string') {
// if error data has error_message and error_type properties, we consider that node returned an error in the old format
throw new TypedError(response.error.data.error_message, response.error.data.error_type);
}
throw parseRpcError(response.error.data);
} else {
const errorMessage = `[${response.error.code}] ${response.error.message}: ${response.error.data}`;
// NOTE: All this hackery is happening because structured errors not implemented
// TODO: Fix when https://github.com/nearprotocol/nearcore/issues/1839 gets resolved
if (response.error.data === 'Timeout' || errorMessage.includes('Timeout error')
|| errorMessage.includes('query has timed out')) {
throw new TypedError(errorMessage, 'TimeoutError');
}
throw new TypedError(errorMessage, getErrorTypeFromErrorMessage(response.error.data));
}
}
} else {
const errorMessage = `[${response.error.code}] ${response.error.message}: ${response.error.data}`;
// NOTE: All this hackery is happening because structured errors not implemented
// TODO: Fix when https://github.com/nearprotocol/nearcore/issues/1839 gets resolved
if (response.error.data === 'Timeout' || errorMessage.includes('Timeout error')) {
throw new TypedError('send_tx_commit has timed out.', 'TimeoutError');
} else {
throw new TypedError(errorMessage);
return response.result;
} catch (error) {
if (error.type === 'TimeoutError') {
console.warn(`Retrying request to ${method} as it has timed out`, params);
return null;
}
throw error;
}
});
if (!result) {
throw new TypedError(
`Exceeded ${REQUEST_RETRY_NUMBER} attempts for request to ${method}.`, 'RetriesExceeded');
}
return response.result;
return result;
}
}
import sha256 from 'js-sha256';
import { Signature, KeyPair, PublicKey } from './utils/key_pair';
import { KeyStore, InMemoryKeyStore } from './key_stores';
import { KeyStore } from './key_stores/keystore';
import { InMemoryKeyStore } from './key_stores/in_memory_key_store';

@@ -5,0 +6,0 @@ /**

@@ -80,2 +80,20 @@

export function getErrorTypeFromErrorMessage(errorMessage) {
// This function should be removed when JSON RPC starts returning typed errors.
switch (true) {
case /^account .*? does not exist while viewing$/.test(errorMessage):
return 'AccountDoesNotExist';
case /^Account .*? doesn't exist$/.test(errorMessage):
return 'AccountDoesNotExist';
case /^access key .*? does not exist while viewing$/.test(errorMessage):
return 'AccessKeyDoesNotExist';
case /wasm execution failed with error: FunctionCallError\(CompilationError\(CodeDoesNotExist/.test(errorMessage):
return 'CodeDoesNotExist';
case /Transaction nonce \d+ must be larger than nonce of the used access key \d+/.test(errorMessage):
return 'InvalidNonce';
default:
return 'UntypedError';
}
}
/**

@@ -82,0 +100,0 @@ * Helper function determining if the argument is an object

@@ -181,4 +181,2 @@ import { Account } from './account';

protected async signAndSendTransaction(receiverId: string, actions: Action[]): Promise<FinalExecutionOutcome> {
await this.ready;
const localKey = await this.connection.signer.getPublicKey(this.accountId, this.connection.networkId);

@@ -194,4 +192,3 @@ let accessKey = await this.accessKeyForTransaction(receiverId, actions, localKey);

} catch (e) {
// TODO: Use TypedError when available
if (e.message.includes('does not have enough balance')) {
if (e.type === 'NotEnoughBalance') {
accessKey = await this.accessKeyForTransaction(receiverId, actions);

@@ -198,0 +195,0 @@ } else {

@@ -116,3 +116,2 @@ /* global BigInt */

await sender.sendMoney(receiver.accountId, new BN(parseNearAmount('1')));
await receiver.fetchState();
const state = await receiver.state();

@@ -119,0 +118,0 @@ expect(BigInt(state.amount)).toBeGreaterThanOrEqual(BigInt(new BN(receiverAmount).add(new BN(parseNearAmount('0.9'))).toString()));

const nearApi = require('../lib/index');
const { Account, Contract, providers } = require('../lib/index');
const testUtils = require('./test-utils');

@@ -38,3 +38,3 @@ const fs = require('fs');

await workingAccount.createAccount(newAccountName, newAccountPublicKey, newAmount);
const newAccount = new nearApi.Account(nearjs.connection, newAccountName);
const newAccount = new Account(nearjs.connection, newAccountName);
const state = await newAccount.state();

@@ -49,4 +49,2 @@ expect(state.amount).toEqual(newAmount.toString());

await sender.sendMoney(receiver.accountId, new BN(10000));
await receiver.fetchState();
// TODO: Why `.state()` is not fetching state?
const state = await receiver.state();

@@ -60,6 +58,16 @@ expect(state.amount).toEqual(new BN(receiverAmount).add(new BN(10000)).toString());

await sender.deleteAccount(receiver.accountId);
const reloaded = new nearApi.Account(sender.connection, sender);
const reloaded = new Account(sender.connection, sender);
await expect(reloaded.state()).rejects.toThrow();
});
test('multiple parallel transactions', async () => {
const PARALLEL_NUMBER = 5;
await Promise.all([...Array(PARALLEL_NUMBER).keys()].map(async (_, i) => {
const account = new Account(workingAccount.connection, workingAccount.accountId);
// NOTE: Need to have different transactions outside of nonce, or they all succeed by being identical
// TODO: Check if randomization of exponential back off helps to do more transactions without exceeding retries
await account.sendMoney(account.accountId, new BN(i));
}));
});
describe('errors', () => {

@@ -103,3 +111,3 @@ let oldLog;

await workingAccount.createAndDeployContract(contractId, newPublicKey, data, HELLO_WASM_BALANCE);
contract = new nearApi.Contract(workingAccount, contractId, {
contract = new Contract(workingAccount, contractId, {
viewMethods: ['hello', 'getValue', 'returnHiWithLogs'],

@@ -145,3 +153,3 @@ changeMethods: ['setValue', 'generateLogs', 'triggerAssert', 'testSetRemove', 'crossContract']

const result2 = await workingAccount.functionCall(contractId, 'setValue', { value: setCallValue });
expect(nearApi.providers.getTransactionLastResult(result2)).toEqual(setCallValue);
expect(providers.getTransactionLastResult(result2)).toEqual(setCallValue);
expect(await workingAccount.viewFunction(contractId, 'getValue', {})).toEqual(setCallValue);

@@ -227,3 +235,3 @@ });

test('can have view methods only', async () => {
const contract = new nearApi.Contract(workingAccount, contractId, {
const contract = new Contract(workingAccount, contractId, {
viewMethods: ['hello'],

@@ -235,3 +243,3 @@ });

test('can have change methods only', async () => {
const contract = new nearApi.Contract(workingAccount, contractId, {
const contract = new Contract(workingAccount, contractId, {
changeMethods: ['hello'],

@@ -238,0 +246,0 @@ });

@@ -14,3 +14,4 @@ const nearApi = require('../../lib/index');

GasLimitExceeded,
formatError
formatError,
getErrorTypeFromErrorMessage,
} = nearApi.utils.rpc_errors;

@@ -111,2 +112,17 @@ describe('rpc-errors', () => {

test('test getErrorTypeFromErrorMessage', () => {
const err1 = 'account random.near does not exist while viewing';
const err2 = 'Account random2.testnet doesn\'t exist';
const err3 = 'access key ed25519:DvXowCpBHKdbD2qutgfhG6jvBMaXyUh7DxrDSjkLxMHp does not exist while viewing';
const err4 = 'wasm execution failed with error: FunctionCallError(CompilationError(CodeDoesNotExist { account_id: "random.testnet" }))';
const err5 = '[-32000] Server error: Invalid transaction: Transaction nonce 1 must be larger than nonce of the used access key 1';
expect(getErrorTypeFromErrorMessage(err1)).toEqual('AccountDoesNotExist');
expect(getErrorTypeFromErrorMessage(err2)).toEqual('AccountDoesNotExist');
expect(getErrorTypeFromErrorMessage(err3)).toEqual('AccessKeyDoesNotExist');
expect(getErrorTypeFromErrorMessage(err4)).toEqual('CodeDoesNotExist');
expect(getErrorTypeFromErrorMessage(err5)).toEqual('InvalidNonce');
expect(getErrorTypeFromErrorMessage('random string')).toEqual('UntypedError');
expect(getErrorTypeFromErrorMessage(undefined)).toEqual('UntypedError');
expect(getErrorTypeFromErrorMessage('')).toEqual('UntypedError');
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc