diff --git a/dist/core/ChainId.d.ts b/dist/core/ChainId.d.ts new file mode 100644 index 0000000..0eeb1c7 --- /dev/null +++ b/dist/core/ChainId.d.ts @@ -0,0 +1,4 @@ +/** @export ChainId */ +export declare enum ChainId { + MAINNET = "1" +} diff --git a/dist/core/actions.d.ts b/dist/core/actions.d.ts new file mode 100644 index 0000000..8278c12 --- /dev/null +++ b/dist/core/actions.d.ts @@ -0,0 +1,71 @@ +import { PrivateTxState, PrivateTxStatus } from './privateTransaction'; +import { ChainId } from './ChainId'; +/** + * @export + * @interface SerializableTransactionReceipt + */ +export interface SerializableTransactionReceipt { + to: string; + from: string; + contractAddress: string; + transactionIndex: number; + blockHash: string; + transactionHash: string; + blockNumber: number; + status?: number; +} +export declare const addTransaction: import("@reduxjs/toolkit").ActionCreatorWithOptionalPayload<{ + chainId: ChainId; + hash: string; + from: string; + approval?: { + tokenAddress: string; + spender: string; + }; + claim?: { + recipient: string; + }; + summary?: string; +}, string>; +export declare const clearAllTransactions: import("@reduxjs/toolkit").ActionCreatorWithOptionalPayload<{ + chainId: ChainId; +}, string>; +export declare const finalizeTransaction: import("@reduxjs/toolkit").ActionCreatorWithOptionalPayload<{ + chainId: ChainId; + hash: string; + receipt: SerializableTransactionReceipt; +}, string>; +export declare const checkedTransaction: import("@reduxjs/toolkit").ActionCreatorWithOptionalPayload<{ + chainId: ChainId; + hash: string; + blockNumber: number; +}, string>; +export declare const updatePrivateTxStatus: import("@reduxjs/toolkit").ActionCreatorWithOptionalPayload<{ + chainId: ChainId; + hash: string; + status: PrivateTxStatus; +}, string>; +/** + * @export + * @interface TransactionDetails + */ +export interface TransactionDetails { + hash: string; + approval?: { + tokenAddress: string; + spender: string; + }; + summary?: string; + claim?: { + recipient: string; + }; + receipt?: SerializableTransactionReceipt; + lastCheckedBlockNumber?: number; + addedTime: number; + confirmedTime?: number; + from: string; + privateTx?: { + state: PrivateTxState; + status?: PrivateTxStatus; + }; +} diff --git a/dist/core/index.d.ts b/dist/core/index.d.ts new file mode 100644 index 0000000..aada4ef --- /dev/null +++ b/dist/core/index.d.ts @@ -0,0 +1,39 @@ +export * from './ChainId'; +export * from './actions'; +export * from './isTransactionState'; +export * from './privateTransaction'; +import * as Reducer from './reducer'; +export { Reducer }; +export * from './transaction'; +/** + +TODO + +import * as ChainId from './ChainId'; +import { + addTransaction, + checkedTransaction, + clearAllTransactions, + finalizeTransaction, + SerializableTransactionReceipt, + updatePrivateTxStatus, +} from './actions'; + +import * as Actions from './actions'; +import * as PrivateTransaction from './privateTransaction'; +import * as Reducer from './reducer'; +import * as Transaction from './transaction'; +export { + ChainId, + Actions, + PrivateTransaction, + Reducer, + Transaction, + addTransaction, + checkedTransaction, + clearAllTransactions, + finalizeTransaction, + SerializableTransactionReceipt, + updatePrivateTxStatus, +}; + */ diff --git a/dist/core/isTransactionState.d.ts b/dist/core/isTransactionState.d.ts new file mode 100644 index 0000000..57246d7 --- /dev/null +++ b/dist/core/isTransactionState.d.ts @@ -0,0 +1,55 @@ +/** + * + * @class PrivateTransaction + * @license GPL-3.0-Only + * @see {@link https://docs.manifoldfinance.com} + * @since 2022.03 + * @version 0.1.0 + * + */ +import { TransactionDetails } from './reducer'; +/** + * @summary + * Basic explanation of the tx state types: + * UNCHECKED -> Tx status has not been checked and there's no information about it. + * PROCESSING -> Tx checks are in place until a resolution happens: OK, INDETERMINATE, ERROR. + * OK -> Relay received the Tx && all downstream miners accepted without complains && tx mined successfully + * INDETERMINATE -> Relay received correctly the Tx && at least one miner accepted the TX && TX potentially mineable + * ERROR -> Relay haven't received the TX || none of the miners accepted the Tx || Tx was not mined successfully + */ +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +export declare function isTxPending(tx?: TransactionDetails): boolean; +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +export declare function isTxSuccessful(tx?: TransactionDetails): boolean; +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +export declare function isTxIndeterminate(tx?: TransactionDetails): boolean; +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {number} + */ +export declare function txMinutesPending(tx?: TransactionDetails): number; +/** + * + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +export declare function isTxExpired(tx?: TransactionDetails): boolean; diff --git a/dist/core/privateTransaction.d.ts b/dist/core/privateTransaction.d.ts new file mode 100644 index 0000000..e52e009 --- /dev/null +++ b/dist/core/privateTransaction.d.ts @@ -0,0 +1,58 @@ +import { JsonRpcResponse } from '../jsonrpc'; +/** + * @enum PrivateTxState + * @interface PrivateTxStatus + * @interface RelayResponse + * @description Transaction State Types + * + * - UNCHECKED -> Tx status has not been checked and there's no information about it. + * - PROCESSING -> Tx checks are in place until a resolution happens: OK, INDETERMINATE, ERROR. + * - OK -> Relay received the Tx && all downstream miners accepted without complains && tx mined successfully + * - INDETERMINATE -> Relay received correctly the Tx && at least one miner accepted the TX && TX potentially mineable + * - ERROR -> Relay haven't received the TX || none of the miners accepted the Tx || Tx was not mined successfully + * +/** + * + * + * @export + * @enum {number} + */ +export declare enum PrivateTxState { + UNCHECKED = "UNCHECKED", + PROCESSING = "PROCESSING", + OK = "OK", + INDETERMINATE = "INDETERMINATE", + ERROR = "ERROR" +} +/** @type RelayResponses */ +export declare type RelayResponses = Record; +/** + * + * @export + * @interface RelayResponse + */ +export interface RelayResponse { + response: JsonRpcResponse; + error?: string; +} +/** + * + * @export + * @interface PrivateTxStatus + */ +export interface PrivateTxStatus { + transactionHash: string; + receivedAt: string; + relayedAt?: string; + minedAt?: string; + relayFailure?: boolean; + relayResponses?: RelayResponses; +} +/** + * + * + * @export + * @param {*} privateTx + * @return {*} + */ +export declare function privateTx(privateTx: any): any; diff --git a/dist/core/reducer.d.ts b/dist/core/reducer.d.ts new file mode 100644 index 0000000..b085a00 --- /dev/null +++ b/dist/core/reducer.d.ts @@ -0,0 +1,35 @@ +/** + * + * @filename Redux Reducer + * + */ +import { ChainId } from './ChainId'; +import { PrivateTxState, PrivateTxStatus } from './privateTransaction'; +import { SerializableTransactionReceipt } from './actions'; +export interface TransactionDetails { + hash: string; + approval?: { + tokenAddress: string; + spender: string; + }; + summary?: string; + claim?: { + recipient: string; + }; + receipt?: SerializableTransactionReceipt; + lastCheckedBlockNumber?: number; + addedTime: number; + confirmedTime?: number; + from: string; + privateTx?: { + state: PrivateTxState; + status?: PrivateTxStatus; + }; +} +declare type txHash = string; +export declare type TransactionState = { + [key in ChainId]?: Record; +}; +export declare const initialState: TransactionState; +declare const _default: import("@reduxjs/toolkit/dist/createReducer").ReducerWithInitialState; +export default _default; diff --git a/dist/core/transaction.d.ts b/dist/core/transaction.d.ts new file mode 100644 index 0000000..f708cf3 --- /dev/null +++ b/dist/core/transaction.d.ts @@ -0,0 +1,13 @@ +/** + * @package OpenMev Transaction + */ +/** + * @exports PrivateTransaction + */ +import * as PrivateTransaction from './privateTransaction'; +export { PrivateTransaction }; +/** + * @exports isTxState + */ +import { isTxIndeterminate, isTxPending, isTxSuccessful, txMinutesPending } from './isTransactionState'; +export { isTxIndeterminate, isTxPending, isTxSuccessful, txMinutesPending }; diff --git a/dist/errors/index.d.ts b/dist/errors/index.d.ts new file mode 100644 index 0000000..dd14465 --- /dev/null +++ b/dist/errors/index.d.ts @@ -0,0 +1,2 @@ +export * from './rpc'; +export * from './transaction'; diff --git a/dist/errors/rpc.d.ts b/dist/errors/rpc.d.ts new file mode 100644 index 0000000..5a0ddbf --- /dev/null +++ b/dist/errors/rpc.d.ts @@ -0,0 +1,72 @@ +/** + * Error subclass implementing JSON RPC 2.0 errors and Ethereum RPC errors per EIP-1474. + * @see https://eips.ethereum.org/EIPS/eip-1474 + */ +export declare class RpcError extends Error { + readonly code: number; + readonly data?: T; + readonly internal?: unknown; + constructor( + /** Number error code */ + code: number, + /** Human-readable string */ + message: string, + /** Low-level error */ + internal?: unknown, + /** Other useful information about error */ + data?: T); +} +/** + * Error subclass implementing Ethereum Provider errors per EIP-1193. + * @see https://eips.ethereum.org/EIPS/eip-1193 + */ +export declare class ProviderRpcError extends RpcError { + /** + * Create an Ethereum Provider JSON-RPC error. + * `code` must be an integer in the 1000 <= 4999 range. + */ + constructor( + /** + * Number error code + * @see https://eips.ethereum.org/EIPS/eip-1193#error-standards + */ + code: 4001 | 4100 | 4200 | 4900 | 4901 | 4902, + /** Human-readable string */ + message: string, + /** Low-level error */ + internal?: unknown, + /** Other useful information about error */ + data?: T); +} +export declare class AddChainError extends Error { + name: string; + message: string; +} +export declare class ChainNotConfiguredError extends Error { + name: string; + message: string; +} +export declare class ConnectorAlreadyConnectedError extends Error { + name: string; + message: string; +} +export declare class ConnectorNotFoundError extends Error { + name: string; + message: string; +} +export declare class SwitchChainError extends ProviderRpcError { + name: string; + constructor(error: unknown); +} +export declare class SwitchChainNotSupportedError extends Error { + name: string; + message: string; +} +export declare class UserRejectedRequestError extends ProviderRpcError { + name: string; + constructor(error: unknown); +} +export declare class ResourceUnavailableError extends RpcError { + name: string; + constructor(error: unknown); +} diff --git a/dist/errors/stdErrors.d.ts b/dist/errors/stdErrors.d.ts new file mode 100644 index 0000000..ba7a4ed --- /dev/null +++ b/dist/errors/stdErrors.d.ts @@ -0,0 +1,38 @@ +/** +@export stderrors +@note github.com/WalletConnect/walletconnect-utils/blob/master/jsonrpc/utils/src/constants.ts +*/ +export declare const PARSE_ERROR = "PARSE_ERROR"; +export declare const INVALID_REQUEST = "INVALID_REQUEST"; +export declare const METHOD_NOT_FOUND = "METHOD_NOT_FOUND"; +export declare const INVALID_PARAMS = "INVALID_PARAMS"; +export declare const INTERNAL_ERROR = "INTERNAL_ERROR"; +export declare const SERVER_ERROR = "SERVER_ERROR"; +export declare const RESERVED_ERROR_CODES: number[]; +export declare const SERVER_ERROR_CODE_RANGE: number[]; +export declare const STANDARD_ERROR_MAP: { + PARSE_ERROR: { + code: number; + message: string; + }; + INVALID_REQUEST: { + code: number; + message: string; + }; + METHOD_NOT_FOUND: { + code: number; + message: string; + }; + INVALID_PARAMS: { + code: number; + message: string; + }; + INTERNAL_ERROR: { + code: number; + message: string; + }; + SERVER_ERROR: { + code: number; + message: string; + }; +}; diff --git a/dist/errors/transaction.d.ts b/dist/errors/transaction.d.ts new file mode 100644 index 0000000..8a47c08 --- /dev/null +++ b/dist/errors/transaction.d.ts @@ -0,0 +1,175 @@ +import { Provider, TransactionReceipt } from '@ethersproject/providers'; +import { TransactionResponse } from '@ethersproject/abstract-provider'; +export declare type ErrorSignature = { + r: string; + s: string; + yParity: 0 | 1; + networkV: bigint; +}; +export declare type ErrorAccessList = Array<{ + address: string; + storageKeys: Array; +}>; +export interface ErrorTransaction { + type?: number; + to?: string; + from?: string; + nonce?: number; + gasLimit?: bigint; + gasPrice?: bigint; + maxPriorityFeePerGas?: bigint; + maxFeePerGas?: bigint; + data?: string; + value?: bigint; + chainId?: bigint; + hash?: string; + signature?: ErrorSignature; + accessList?: ErrorAccessList; +} +export interface ErrorFetchRequestWithBody extends ErrorFetchRequest { + body: Readonly; +} +export interface ErrorFetchRequest { + url: string; + method: string; + headers: Readonly>; + getHeader(key: string): string; + body: null | Readonly; + hasBody(): this is ErrorFetchRequestWithBody; +} +export interface ErrorFetchResponseWithBody extends ErrorFetchResponse { + body: Readonly; +} +export interface ErrorFetchResponse { + statusCode: number; + statusMessage: string; + headers: Readonly>; + getHeader(key: string): string; + body: null | Readonly; + hasBody(): this is ErrorFetchResponseWithBody; +} +/** + * @export ErrorCode + * @summary EthersJs ErrorCode + */ +export declare type ErrorCode = 'UNKNOWN_ERROR' | 'NOT_IMPLEMENTED' | 'UNSUPPORTED_OPERATION' | 'NETWORK_ERROR' | 'SERVER_ERROR' | 'TIMEOUT' | 'BAD_DATA' | 'BUFFER_OVERRUN' | 'NUMERIC_FAULT' | 'INVALID_ARGUMENT' | 'MISSING_ARGUMENT' | 'UNEXPECTED_ARGUMENT' | 'VALUE_MISMATCH' | 'CALL_EXCEPTION' | 'INSUFFICIENT_FUNDS' | 'NONCE_EXPIRED' | 'REPLACEMENT_UNDERPRICED' | 'TRANSACTION_REPLACED' | 'UNPREDICTABLE_GAS_LIMIT' | 'UNCONFIGURED_NAME' | 'OFFCHAIN_FAULT'; +export interface EthersError extends Error { + code: ErrorCode; + info?: Record; + error?: Error; +} +export interface UnknownError extends EthersError<'UNKNOWN_ERROR'> { + [key: string]: any; +} +export interface NotImplementedError extends EthersError<'NOT_IMPLEMENTED'> { + operation: string; +} +export interface UnsupportedOperationError extends EthersError<'UNSUPPORTED_OPERATION'> { + operation: string; +} +export interface NetworkError extends EthersError<'NETWORK_ERROR'> { + event: string; +} +export interface ServerError extends EthersError<'SERVER_ERROR'> { + request: ErrorFetchRequest | string; + response?: ErrorFetchResponse; +} +export interface TimeoutError extends EthersError<'TIMEOUT'> { + operation: string; + reason: string; + request?: ErrorFetchRequest; +} +export interface BadDataError extends EthersError<'BAD_DATA'> { + value: any; +} +export interface BufferOverrunError extends EthersError<'BUFFER_OVERRUN'> { + buffer: Uint8Array; + length: number; + offset: number; +} +export interface NumericFaultError extends EthersError<'NUMERIC_FAULT'> { + operation: string; + fault: string; + value: any; +} +export interface InvalidArgumentError extends EthersError<'INVALID_ARGUMENT'> { + argument: string; + value: any; + info?: Record; +} +export interface MissingArgumentError extends EthersError<'MISSING_ARGUMENT'> { + count: number; + expectedCount: number; +} +export interface UnexpectedArgumentError extends EthersError<'UNEXPECTED_ARGUMENT'> { + count: number; + expectedCount: number; +} +export interface CallExceptionError extends EthersError<'CALL_EXCEPTION'> { + data: string; + transaction?: any; + method?: string; + signature?: string; + args?: ReadonlyArray; + errorSignature?: string; + errorName?: string; + errorArgs?: ReadonlyArray; + reason?: string; +} +export interface InsufficientFundsError extends EthersError<'INSUFFICIENT_FUNDS'> { + transaction: any; +} +export interface NonceExpiredError extends EthersError<'NONCE_EXPIRED'> { + transaction: any; +} +export interface OffchainFaultError extends EthersError<'OFFCHAIN_FAULT'> { + transaction?: any; + reason: string; +} +export interface ReplacementUnderpricedError extends EthersError<'REPLACEMENT_UNDERPRICED'> { + transaction: any; +} +export interface TransactionReplacedError extends EthersError<'TRANSACTION_REPLACED'> { + cancelled: boolean; + reason: 'repriced' | 'cancelled' | 'replaced'; + hash: string; + replacement: any; + receipt: any; +} +export interface UnconfiguredNameError extends EthersError<'UNCONFIGURED_NAME'> { + value: string; +} +export interface UnpredictableGasLimitError extends EthersError<'UNPREDICTABLE_GAS_LIMIT'> { + transaction: any; +} +/** + * @export CodedEthersError + */ +export declare type CodedEthersError = T extends "UNKNOWN_ERROR" ? UnknownError : T extends "NOT_IMPLEMENTED" ? NotImplementedError : T extends "UNSUPPORTED_OPERATION" ? UnsupportedOperationError : T extends "NETWORK_ERROR" ? NetworkError : T extends "SERVER_ERROR" ? ServerError : T extends "TIMEOUT" ? TimeoutError : T extends "BAD_DATA" ? BadDataError : T extends "BUFFER_OVERRUN" ? BufferOverrunError : T extends "NUMERIC_FAULT" ? NumericFaultError : T extends "INVALID_ARGUMENT" ? InvalidArgumentError : T extends "MISSING_ARGUMENT" ? MissingArgumentError : T extends "UNEXPECTED_ARGUMENT" ? UnexpectedArgumentError : T extends "CALL_EXCEPTION" ? CallExceptionError : T extends "INSUFFICIENT_FUNDS" ? InsufficientFundsError : T extends "NONCE_EXPIRED" ? NonceExpiredError : T extends "OFFCHAIN_FAULT" ? OffchainFaultError : T extends "REPLACEMENT_UNDERPRICED" ? ReplacementUnderpricedError : T extends "TRANSACTION_REPLACED" ? TransactionReplacedError : T extends "UNCONFIGURED_NAME" ? UnconfiguredNameError : T extends "UNPREDICTABLE_GAS_LIMIT" ? UnpredictableGasLimitError : never; +/** + * #isError + * @param error + * @param code + * @returns + */ +export declare function isError>(error: any, code: K): error is T; +/** + * #isCallException + * @param error + * @returns + */ +export declare function isCallException(error: any): error is CallExceptionError; +/** + * #getTransactionError + * @param tx + * @param receipt + * @param provider + * @returns + */ +export declare const getTransactionError: (tx: TransactionResponse, receipt: TransactionReceipt, provider: Provider) => Promise; +/** + * @export parseReasonCode + * @param messageData + * @returns + */ +export declare const parseReasonCode: (messageData: string) => string; diff --git a/dist/index.cjs b/dist/index.cjs new file mode 100644 index 0000000..6b20550 --- /dev/null +++ b/dist/index.cjs @@ -0,0 +1,539 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var toolkit = require('@reduxjs/toolkit'); +var strings = require('@ethersproject/strings'); + +/** @export ChainId */ +exports.ChainId = void 0; +(function (ChainId) { + ChainId["MAINNET"] = "1"; +})(exports.ChainId || (exports.ChainId = {})); + +/** + * @filename Redux Action + * @version 0.2.0 + */ +const addTransaction = toolkit.createAction('transactions/addTransaction'); +const clearAllTransactions = toolkit.createAction('transactions/clearAllTransactions'); +const finalizeTransaction = toolkit.createAction('transactions/finalizeTransaction'); +const checkedTransaction = toolkit.createAction('transactions/checkedTransaction'); +const updatePrivateTxStatus = toolkit.createAction('transactions/updatePrivateTxStatus'); + +/** + * @enum PrivateTxState + * @interface PrivateTxStatus + * @interface RelayResponse + * @description Transaction State Types + * + * - UNCHECKED -> Tx status has not been checked and there's no information about it. + * - PROCESSING -> Tx checks are in place until a resolution happens: OK, INDETERMINATE, ERROR. + * - OK -> Relay received the Tx && all downstream miners accepted without complains && tx mined successfully + * - INDETERMINATE -> Relay received correctly the Tx && at least one miner accepted the TX && TX potentially mineable + * - ERROR -> Relay haven't received the TX || none of the miners accepted the Tx || Tx was not mined successfully + * +/** + * + * + * @export + * @enum {number} + */ +exports.PrivateTxState = void 0; +(function (PrivateTxState) { + PrivateTxState["UNCHECKED"] = "UNCHECKED"; + PrivateTxState["PROCESSING"] = "PROCESSING"; + PrivateTxState["OK"] = "OK"; + PrivateTxState["INDETERMINATE"] = "INDETERMINATE"; + PrivateTxState["ERROR"] = "ERROR"; +})(exports.PrivateTxState || (exports.PrivateTxState = {})); +/** + * + * + * @export + * @param {*} privateTx + * @return {*} + */ +function privateTx(privateTx) { + throw new Error('[#sushiguard]: Function Error.'); +} + +var privateTransaction = /*#__PURE__*/Object.freeze({ + __proto__: null, + get PrivateTxState () { return exports.PrivateTxState; }, + privateTx: privateTx +}); + +/** + * + * @class PrivateTransaction + * @license GPL-3.0-Only + * @see {@link https://docs.manifoldfinance.com} + * @since 2022.03 + * @version 0.1.0 + * + */ +/** + * @summary + * Basic explanation of the tx state types: + * UNCHECKED -> Tx status has not been checked and there's no information about it. + * PROCESSING -> Tx checks are in place until a resolution happens: OK, INDETERMINATE, ERROR. + * OK -> Relay received the Tx && all downstream miners accepted without complains && tx mined successfully + * INDETERMINATE -> Relay received correctly the Tx && at least one miner accepted the TX && TX potentially mineable + * ERROR -> Relay haven't received the TX || none of the miners accepted the Tx || Tx was not mined successfully + */ +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +function isTxPending(tx) { + if (!tx?.privateTx) + return !tx?.receipt; + return tx?.privateTx?.state === exports.PrivateTxState.UNCHECKED || tx?.privateTx?.state === exports.PrivateTxState.PROCESSING; +} +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +function isTxSuccessful(tx) { + if (!tx?.privateTx) + return !!tx && (tx.receipt?.status === 1 || typeof tx.receipt?.status === 'undefined'); + return (tx?.privateTx?.state === exports.PrivateTxState.OK && + !!tx && + (tx.receipt?.status === 1 || typeof tx.receipt?.status === 'undefined')); +} +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +function isTxIndeterminate(tx) { + if (!tx?.privateTx) + return false; + return tx?.privateTx?.state === exports.PrivateTxState.INDETERMINATE; +} +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {number} + */ +function txMinutesPending(tx) { + if (!tx) + return 0; + return (new Date().getTime() - tx.addedTime) / 1000 / 60; +} +/** + * + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +function isTxExpired(tx) { + if (!tx) + return false; + return txMinutesPending(tx) > 60; +} + +/** + * + * @filename Redux Reducer + * + */ +const now = () => new Date().getTime(); +const initialState = {}; +var reducer = toolkit.createReducer(initialState, (builder) => builder + .addCase(addTransaction, +// @ts-expect-error +(transactions, { payload: { chainId, from, hash, approval, summary, claim, privateTx = false } }) => { + if (transactions[chainId]?.[hash]) { + throw Error('Attempted to add existing transaction.'); + } + const txs = transactions[chainId] ?? {}; + txs[hash] = { + hash, + approval, + summary, + claim, + from, + addedTime: now(), + ...(privateTx ? { privateTx: { state: exports.PrivateTxState.UNCHECKED, status: undefined } } : {}), + }; + transactions[chainId] = txs; +}) + .addCase(clearAllTransactions, (transactions, { payload: { chainId } }) => { + if (!transactions[chainId]) + return; + transactions[chainId] = {}; +}) + .addCase(checkedTransaction, (transactions, { payload: { chainId, hash, blockNumber } }) => { + const tx = transactions[chainId]?.[hash]; + if (!tx) { + return; + } + if (!tx.lastCheckedBlockNumber) { + tx.lastCheckedBlockNumber = blockNumber; + } + else { + tx.lastCheckedBlockNumber = Math.max(blockNumber, tx.lastCheckedBlockNumber); + } +}) + .addCase(finalizeTransaction, (transactions, { payload: { hash, chainId, receipt } }) => { + const tx = transactions[chainId]?.[hash]; + if (!tx) { + return; + } + tx.receipt = receipt; + tx.confirmedTime = now(); +}) + .addCase(updatePrivateTxStatus, (transactions, { payload: { chainId, hash, status } }) => { + const tx = transactions[chainId]?.[hash]; + if (!tx) + return; + if (!tx.privateTx) + throw new Error('Invalid update private tx call to a non private tx'); + const prevState = tx.privateTx?.state; + tx.privateTx?.status; + const minutesElapsed = txMinutesPending(tx); + // If previous state was a definitive one, we skip processing new events + if (prevState && + (prevState === exports.PrivateTxState.ERROR || + prevState === exports.PrivateTxState.INDETERMINATE || + prevState === exports.PrivateTxState.OK)) + return; + // derive new private tx state from latest received status + let state = exports.PrivateTxState.PROCESSING; + // OK - Relay received the Tx && all downstream miners accepted without complains && tx mined successfully + if (status.receivedAt && status.relayedAt && !status.relayFailure && status.minedAt) + state = exports.PrivateTxState.OK; + // ERROR + if (status.receivedAt && + status.relayFailure && + status.relayResponses && + Object.values(status.relayResponses).reduceRight((prev, current) => { + if (prev) + return prev; + if (current.error || current.response.error) + return true; + return false; + }, false)) + state = exports.PrivateTxState.ERROR; + // INDETERMINATE + if (status.receivedAt && status.relayedAt && status.relayFailure && status.minedAt) + state = exports.PrivateTxState.INDETERMINATE; + // If more than 20 minutes has passed, better to mark this TX as indeterminate + if (minutesElapsed > 3) + state = exports.PrivateTxState.INDETERMINATE; + // update new state + tx.privateTx.state = state ?? exports.PrivateTxState.UNCHECKED; + tx.privateTx.status = status; +})); + +var reducer$1 = /*#__PURE__*/Object.freeze({ + __proto__: null, + initialState: initialState, + 'default': reducer +}); + +/** + * @file JsonRpc + * @version 0.3.0 + * @license Apache-2.0 + * + */ +/** + * @export + * @class HttpJsonRpcError + * @extends {Error} + */ +class HttpJsonRpcError extends Error { + constructor(message, req, res) { + super(message); + this.req = req; + this.res = res; + } +} +/** + * @export + * @template T + * @param {string} url + * @param {Partial} { + * @return {(Promise>)} + */ +function fetchJsonRpc(url, { jsonrpc = '2.0', id = new Date().getTime(), method = '', params = [] }) { + return fetch(url, { + headers: { 'Content-Type': 'application/json' }, + method: 'POST', + body: JSON.stringify({ jsonrpc, id, method, params }), + }).then((res) => { + // handle http errors (anything not 200) + if (res.status !== 200) + throw new HttpJsonRpcError(res.statusText, { jsonrpc, id, method, params }, res); + // handle successful response + return res.json(); + }); +} +function validateJsonRpcResponse(response) { + if (response.jsonrpc !== '2.0' || + (typeof response.id !== 'string' && typeof response.id !== 'number' && response.id !== null) || + ('result' in response && 'error' in response) || + (!('result' in response) && !('error' in response)) || + (response.error && typeof response.error.code !== 'number') || + (response.error && typeof response.error.message !== 'string')) + throw new Error(`Expected JSON-RPC response, received something else.\n${JSON.stringify(response)}`); + return true; +} +function isJsonRpcSuccess(response) { + return !!response.result && !response.error; +} +function isJsonRpcError(response) { + return !!response.error && !response.result; +} + +const BURN_ADDRESS = '0x000000000000000000000000000000000000dead'; + +const AddressZero = '0x0000000000000000000000000000000000000000'; + +const EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = `\x19\x01`; + +// @note this is also the old OVM_ETH address on Optimism +const DeadAddress = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'; + +/** + * Error subclass implementing JSON RPC 2.0 errors and Ethereum RPC errors per EIP-1474. + * @see https://eips.ethereum.org/EIPS/eip-1474 + */ +class RpcError extends Error { + constructor( + /** Number error code */ + code, + /** Human-readable string */ + message, + /** Low-level error */ + internal, + /** Other useful information about error */ + data) { + if (!Number.isInteger(code)) + throw new Error('"code" must be an integer.'); + if (!message || typeof message !== 'string') + throw new Error('"message" must be a nonempty string.'); + super(message); + this.code = code; + this.data = data; + this.internal = internal; + } +} +/** + * Error subclass implementing Ethereum Provider errors per EIP-1193. + * @see https://eips.ethereum.org/EIPS/eip-1193 + */ +class ProviderRpcError extends RpcError { + /** + * Create an Ethereum Provider JSON-RPC error. + * `code` must be an integer in the 1000 <= 4999 range. + */ + constructor( + /** + * Number error code + * @see https://eips.ethereum.org/EIPS/eip-1193#error-standards + */ + code, + /** Human-readable string */ + message, + /** Low-level error */ + internal, + /** Other useful information about error */ + data) { + if (!(Number.isInteger(code) && code >= 1000 && code <= 4999)) + throw new Error('"code" must be an integer such that: 1000 <= code <= 4999'); + super(code, message, internal, data); + } +} +class AddChainError extends Error { + constructor() { + super(...arguments); + this.name = 'AddChainError'; + this.message = 'Error adding chain'; + } +} +class ChainNotConfiguredError extends Error { + constructor() { + super(...arguments); + this.name = 'ChainNotConfigured'; + this.message = 'Chain not configured'; + } +} +class ConnectorAlreadyConnectedError extends Error { + constructor() { + super(...arguments); + this.name = 'ConnectorAlreadyConnectedError'; + this.message = 'Connector already connected'; + } +} +class ConnectorNotFoundError extends Error { + constructor() { + super(...arguments); + this.name = 'ConnectorNotFoundError'; + this.message = 'Connector not found'; + } +} +class SwitchChainError extends ProviderRpcError { + constructor(error) { + super(4902, 'Error switching chain', error); + this.name = 'SwitchChainError'; + } +} +class SwitchChainNotSupportedError extends Error { + constructor() { + super(...arguments); + this.name = 'SwitchChainNotSupportedError'; + this.message = 'Switch chain not supported by connector'; + } +} +class UserRejectedRequestError extends ProviderRpcError { + constructor(error) { + super(4001, 'User rejected request', error); + this.name = 'UserRejectedRequestError'; + } +} +class ResourceUnavailableError extends RpcError { + constructor(error) { + super(-32002, 'Resource unavailable', error); + this.name = 'ResourceUnavailable'; + } +} + +/** + * #isError + * @param error + * @param code + * @returns + */ +function isError(error, code) { + return error && error.code === code; +} +/** + * #isCallException + * @param error + * @returns + */ +function isCallException(error) { + return isError(error, 'CALL_EXCEPTION'); +} +/** + * #getTransactionError + * @param tx + * @param receipt + * @param provider + * @returns + */ +const getTransactionError = async (tx, receipt, provider) => { + if (typeof tx !== 'object') { + throw TypeError(`tx argument ${tx} must be a transaction object`); + } + if (typeof receipt !== 'object') { + throw TypeError(`receipt argument ${receipt} must be a transaction receipt object`); + } + if (receipt.status) { + throw TypeError('Transaction did not fail. Can only read the revert reason from failed transactions'); + } + if (!receipt.transactionHash) { + throw TypeError(`There is no transaction hash on the receipt object`); + } + if (receipt.gasUsed === tx.gasLimit) { + throw Error('Transaction failed as it ran out of gas.'); + } + // TODO: check type + let rawMessageData; + try { + const result = await provider.call({ + ...tx, + }, receipt.blockNumber); + // @dev Trim the 0x prefix + rawMessageData = result.slice(2); + } + catch (e) { + if (e.message.startsWith('Node error: ')) { + // @dev Trim "Node error: " + const errorObjectStr = e.message.slice(12); + // @dev Parse the error object + const errorObject = JSON.parse(errorObjectStr); + if (!errorObject.data) { + throw Error('Failed to parse data field error object:' + errorObjectStr); + } + if (errorObject.data.startsWith('Reverted 0x')) { + // Trim "Reverted 0x" from the data field + rawMessageData = errorObject.data.slice(11); + } + else if (errorObject.data.startsWith('0x')) { + // Trim "0x" from the data field + rawMessageData = errorObject.data.slice(2); + } + else { + throw Error('Failed to parse data field of error object:' + errorObjectStr); + } + } + else { + throw Error('Failed to parse error message from Ethereum call: ' + e.message); + } + } + return parseReasonCode(rawMessageData); +}; +/** + * @export parseReasonCode + * @param messageData + * @returns + */ +const parseReasonCode = (messageData) => { + // Get the length of the revert reason + const strLen = parseInt(messageData.slice(8 + 64, 8 + 128), 16); + // Using the length and known offset, extract and convert the revert reason + const reasonCodeHex = messageData.slice(8 + 128, 8 + 128 + strLen * 2); + // Convert reason from hex to string + const reason = strings.toUtf8String('0x' + reasonCodeHex); + return reason; +}; + +exports.AddChainError = AddChainError; +exports.AddressZero = AddressZero; +exports.BURN_ADDRESS = BURN_ADDRESS; +exports.ChainNotConfiguredError = ChainNotConfiguredError; +exports.ConnectorAlreadyConnectedError = ConnectorAlreadyConnectedError; +exports.ConnectorNotFoundError = ConnectorNotFoundError; +exports.DeadAddress = DeadAddress; +exports.EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA; +exports.HttpJsonRpcError = HttpJsonRpcError; +exports.PrivateTransaction = privateTransaction; +exports.ProviderRpcError = ProviderRpcError; +exports.Reducer = reducer$1; +exports.ResourceUnavailableError = ResourceUnavailableError; +exports.RpcError = RpcError; +exports.SwitchChainError = SwitchChainError; +exports.SwitchChainNotSupportedError = SwitchChainNotSupportedError; +exports.UserRejectedRequestError = UserRejectedRequestError; +exports.addTransaction = addTransaction; +exports.checkedTransaction = checkedTransaction; +exports.clearAllTransactions = clearAllTransactions; +exports.fetchJsonRpc = fetchJsonRpc; +exports.finalizeTransaction = finalizeTransaction; +exports.getTransactionError = getTransactionError; +exports.isCallException = isCallException; +exports.isError = isError; +exports.isJsonRpcError = isJsonRpcError; +exports.isJsonRpcSuccess = isJsonRpcSuccess; +exports.isTxExpired = isTxExpired; +exports.isTxIndeterminate = isTxIndeterminate; +exports.isTxPending = isTxPending; +exports.isTxSuccessful = isTxSuccessful; +exports.parseReasonCode = parseReasonCode; +exports.privateTx = privateTx; +exports.txMinutesPending = txMinutesPending; +exports.updatePrivateTxStatus = updatePrivateTxStatus; +exports.validateJsonRpcResponse = validateJsonRpcResponse; +//# sourceMappingURL=index.cjs.map diff --git a/dist/index.cjs.map b/dist/index.cjs.map new file mode 100644 index 0000000..5e985a0 --- /dev/null +++ b/dist/index.cjs.map @@ -0,0 +1 @@ +{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..e50c7b7 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,596 @@ +import * as _reduxjs_toolkit from '@reduxjs/toolkit'; +import * as _reduxjs_toolkit_dist_createReducer from '@reduxjs/toolkit/dist/createReducer'; +import { TransactionReceipt, Provider } from '@ethersproject/providers'; +import { TransactionResponse } from '@ethersproject/abstract-provider'; + +/** @export ChainId */ +declare enum ChainId { + MAINNET = "1" +} + +/** + * @file JsonRpc + * @version 0.3.0 + * @license Apache-2.0 + * + */ +/** + * JsonRpcRequest + * @export + * @interface JsonRpcRequest + */ +interface JsonRpcRequest { + jsonrpc: '2.0'; + id: number | string | null; + method: string; + params?: unknown[] | unknown; +} +/** + * @export + * @interface JsonRpcError + */ +interface JsonRpcError { + code: number; + message: string; + data?: unknown; +} +/** + * @export + * @interface JsonRpcResponse + * @template T + */ +interface JsonRpcResponse { + jsonrpc: '2.0'; + id?: number | string | null; + result?: T; + error?: JsonRpcError; +} +/** + * @export + * @interface JsonRpcPayload + */ +interface JsonRpcPayload { + jsonrpc: string; + method: string; + params?: any[]; + id?: string | number; +} +/** + * @export + * @class HttpJsonRpcError + * @extends {Error} + */ +declare class HttpJsonRpcError extends Error { + req?: JsonRpcRequest; + res?: Response; + constructor(message: string, req?: JsonRpcRequest, res?: Response); +} +/** + * @export + * @template T + * @param {string} url + * @param {Partial} { + * @return {(Promise>)} + */ +declare function fetchJsonRpc(url: string, { jsonrpc, id, method, params }: Partial): Promise>; +declare type JsonRpcMethod = 'eth_accounts' | 'eth_blockNumber' | 'eth_call' | 'eth_chainId' | 'eth_coinbase' | 'eth_estimateGas' | 'eth_gasPrice' | 'eth_getBalance' | 'eth_getBlockByHash' | 'eth_getBlockByNumber' | 'eth_getBlockTransactionCountByHash' | 'eth_getBlockTransactionCountByNumber' | 'eth_getCode' | 'eth_getLogs' | 'eth_getProof' | 'eth_getStorageAt' | 'eth_getTransactionByBlockHashAndIndex' | 'eth_getTransactionByBlockNumberAndIndex' | 'eth_getTransactionByHash' | 'eth_getTransactionCount' | 'eth_getTransactionReceipt' | 'eth_getUncleByBlockHashAndIndex' | 'eth_getUncleByBlockNumberAndIndex' | 'eth_getUncleCountByBlockHash' | 'eth_getUncleCountByBlockNumber' | 'eth_protocolVersion' | 'eth_sendRawTransaction' | 'eth_sendTransaction' | 'eth_sign' | 'eth_signTransaction' | 'eth_signTypedData' | 'eth_syncing'; +interface IJsonRpcRequest> { + readonly jsonrpc: '2.0'; + readonly id: string | number | null; + readonly method: TMethod; + readonly params: TParams; +} +interface IJsonRpcSuccess { + readonly jsonrpc: '2.0'; + readonly id: string | number | null; + readonly result: TResult; +} +interface IJsonRpcError { + readonly jsonrpc: '2.0'; + readonly id: string | number | null; + readonly error: { + readonly code: number; + readonly message: string; + readonly data?: unknown; + }; +} +declare type IJsonRpcResponse = IJsonRpcSuccess | IJsonRpcError; +declare function validateJsonRpcResponse(response: any): response is IJsonRpcResponse; +declare function isJsonRpcSuccess(response: IJsonRpcResponse): response is IJsonRpcSuccess; +declare function isJsonRpcError(response: IJsonRpcResponse): response is IJsonRpcError; + +/** + * @enum PrivateTxState + * @interface PrivateTxStatus + * @interface RelayResponse + * @description Transaction State Types + * + * - UNCHECKED -> Tx status has not been checked and there's no information about it. + * - PROCESSING -> Tx checks are in place until a resolution happens: OK, INDETERMINATE, ERROR. + * - OK -> Relay received the Tx && all downstream miners accepted without complains && tx mined successfully + * - INDETERMINATE -> Relay received correctly the Tx && at least one miner accepted the TX && TX potentially mineable + * - ERROR -> Relay haven't received the TX || none of the miners accepted the Tx || Tx was not mined successfully + * +/** + * + * + * @export + * @enum {number} + */ +declare enum PrivateTxState { + UNCHECKED = "UNCHECKED", + PROCESSING = "PROCESSING", + OK = "OK", + INDETERMINATE = "INDETERMINATE", + ERROR = "ERROR" +} +/** @type RelayResponses */ +declare type RelayResponses = Record; +/** + * + * @export + * @interface RelayResponse + */ +interface RelayResponse { + response: JsonRpcResponse; + error?: string; +} +/** + * + * @export + * @interface PrivateTxStatus + */ +interface PrivateTxStatus { + transactionHash: string; + receivedAt: string; + relayedAt?: string; + minedAt?: string; + relayFailure?: boolean; + relayResponses?: RelayResponses; +} +/** + * + * + * @export + * @param {*} privateTx + * @return {*} + */ +declare function privateTx(privateTx: any): any; + +type privateTransaction_PrivateTxState = PrivateTxState; +declare const privateTransaction_PrivateTxState: typeof PrivateTxState; +type privateTransaction_RelayResponses = RelayResponses; +type privateTransaction_RelayResponse = RelayResponse; +type privateTransaction_PrivateTxStatus = PrivateTxStatus; +declare const privateTransaction_privateTx: typeof privateTx; +declare namespace privateTransaction { + export { + privateTransaction_PrivateTxState as PrivateTxState, + privateTransaction_RelayResponses as RelayResponses, + privateTransaction_RelayResponse as RelayResponse, + privateTransaction_PrivateTxStatus as PrivateTxStatus, + privateTransaction_privateTx as privateTx, + }; +} + +/** + * @export + * @interface SerializableTransactionReceipt + */ +interface SerializableTransactionReceipt { + to: string; + from: string; + contractAddress: string; + transactionIndex: number; + blockHash: string; + transactionHash: string; + blockNumber: number; + status?: number; +} +declare const addTransaction: _reduxjs_toolkit.ActionCreatorWithOptionalPayload<{ + chainId: ChainId; + hash: string; + from: string; + approval?: { + tokenAddress: string; + spender: string; + }; + claim?: { + recipient: string; + }; + summary?: string; +}, string>; +declare const clearAllTransactions: _reduxjs_toolkit.ActionCreatorWithOptionalPayload<{ + chainId: ChainId; +}, string>; +declare const finalizeTransaction: _reduxjs_toolkit.ActionCreatorWithOptionalPayload<{ + chainId: ChainId; + hash: string; + receipt: SerializableTransactionReceipt; +}, string>; +declare const checkedTransaction: _reduxjs_toolkit.ActionCreatorWithOptionalPayload<{ + chainId: ChainId; + hash: string; + blockNumber: number; +}, string>; +declare const updatePrivateTxStatus: _reduxjs_toolkit.ActionCreatorWithOptionalPayload<{ + chainId: ChainId; + hash: string; + status: PrivateTxStatus; +}, string>; +/** + * @export + * @interface TransactionDetails + */ +interface TransactionDetails$1 { + hash: string; + approval?: { + tokenAddress: string; + spender: string; + }; + summary?: string; + claim?: { + recipient: string; + }; + receipt?: SerializableTransactionReceipt; + lastCheckedBlockNumber?: number; + addedTime: number; + confirmedTime?: number; + from: string; + privateTx?: { + state: PrivateTxState; + status?: PrivateTxStatus; + }; +} + +interface TransactionDetails { + hash: string; + approval?: { + tokenAddress: string; + spender: string; + }; + summary?: string; + claim?: { + recipient: string; + }; + receipt?: SerializableTransactionReceipt; + lastCheckedBlockNumber?: number; + addedTime: number; + confirmedTime?: number; + from: string; + privateTx?: { + state: PrivateTxState; + status?: PrivateTxStatus; + }; +} +declare type txHash = string; +declare type TransactionState = { + [key in ChainId]?: Record; +}; +declare const initialState: TransactionState; +declare const _default: _reduxjs_toolkit_dist_createReducer.ReducerWithInitialState; + +type reducer_TransactionDetails = TransactionDetails; +type reducer_TransactionState = TransactionState; +declare const reducer_initialState: typeof initialState; +declare namespace reducer { + export { + _default as default, + reducer_TransactionDetails as TransactionDetails, + reducer_TransactionState as TransactionState, + reducer_initialState as initialState, + }; +} + +/** + * + * @class PrivateTransaction + * @license GPL-3.0-Only + * @see {@link https://docs.manifoldfinance.com} + * @since 2022.03 + * @version 0.1.0 + * + */ + +/** + * @summary + * Basic explanation of the tx state types: + * UNCHECKED -> Tx status has not been checked and there's no information about it. + * PROCESSING -> Tx checks are in place until a resolution happens: OK, INDETERMINATE, ERROR. + * OK -> Relay received the Tx && all downstream miners accepted without complains && tx mined successfully + * INDETERMINATE -> Relay received correctly the Tx && at least one miner accepted the TX && TX potentially mineable + * ERROR -> Relay haven't received the TX || none of the miners accepted the Tx || Tx was not mined successfully + */ +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +declare function isTxPending(tx?: TransactionDetails): boolean; +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +declare function isTxSuccessful(tx?: TransactionDetails): boolean; +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +declare function isTxIndeterminate(tx?: TransactionDetails): boolean; +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {number} + */ +declare function txMinutesPending(tx?: TransactionDetails): number; +/** + * + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +declare function isTxExpired(tx?: TransactionDetails): boolean; + +declare const BURN_ADDRESS = "0x000000000000000000000000000000000000dead"; + +declare const AddressZero = "0x0000000000000000000000000000000000000000"; + +declare const EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = "\u0019\u0001"; + +declare const DeadAddress = "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000"; + +/** + * Error subclass implementing JSON RPC 2.0 errors and Ethereum RPC errors per EIP-1474. + * @see https://eips.ethereum.org/EIPS/eip-1474 + */ +declare class RpcError extends Error { + readonly code: number; + readonly data?: T; + readonly internal?: unknown; + constructor( + /** Number error code */ + code: number, + /** Human-readable string */ + message: string, + /** Low-level error */ + internal?: unknown, + /** Other useful information about error */ + data?: T); +} +/** + * Error subclass implementing Ethereum Provider errors per EIP-1193. + * @see https://eips.ethereum.org/EIPS/eip-1193 + */ +declare class ProviderRpcError extends RpcError { + /** + * Create an Ethereum Provider JSON-RPC error. + * `code` must be an integer in the 1000 <= 4999 range. + */ + constructor( + /** + * Number error code + * @see https://eips.ethereum.org/EIPS/eip-1193#error-standards + */ + code: 4001 | 4100 | 4200 | 4900 | 4901 | 4902, + /** Human-readable string */ + message: string, + /** Low-level error */ + internal?: unknown, + /** Other useful information about error */ + data?: T); +} +declare class AddChainError extends Error { + name: string; + message: string; +} +declare class ChainNotConfiguredError extends Error { + name: string; + message: string; +} +declare class ConnectorAlreadyConnectedError extends Error { + name: string; + message: string; +} +declare class ConnectorNotFoundError extends Error { + name: string; + message: string; +} +declare class SwitchChainError extends ProviderRpcError { + name: string; + constructor(error: unknown); +} +declare class SwitchChainNotSupportedError extends Error { + name: string; + message: string; +} +declare class UserRejectedRequestError extends ProviderRpcError { + name: string; + constructor(error: unknown); +} +declare class ResourceUnavailableError extends RpcError { + name: string; + constructor(error: unknown); +} + +declare type ErrorSignature = { + r: string; + s: string; + yParity: 0 | 1; + networkV: bigint; +}; +declare type ErrorAccessList = Array<{ + address: string; + storageKeys: Array; +}>; +interface ErrorTransaction { + type?: number; + to?: string; + from?: string; + nonce?: number; + gasLimit?: bigint; + gasPrice?: bigint; + maxPriorityFeePerGas?: bigint; + maxFeePerGas?: bigint; + data?: string; + value?: bigint; + chainId?: bigint; + hash?: string; + signature?: ErrorSignature; + accessList?: ErrorAccessList; +} +interface ErrorFetchRequestWithBody extends ErrorFetchRequest { + body: Readonly; +} +interface ErrorFetchRequest { + url: string; + method: string; + headers: Readonly>; + getHeader(key: string): string; + body: null | Readonly; + hasBody(): this is ErrorFetchRequestWithBody; +} +interface ErrorFetchResponseWithBody extends ErrorFetchResponse { + body: Readonly; +} +interface ErrorFetchResponse { + statusCode: number; + statusMessage: string; + headers: Readonly>; + getHeader(key: string): string; + body: null | Readonly; + hasBody(): this is ErrorFetchResponseWithBody; +} +/** + * @export ErrorCode + * @summary EthersJs ErrorCode + */ +declare type ErrorCode = 'UNKNOWN_ERROR' | 'NOT_IMPLEMENTED' | 'UNSUPPORTED_OPERATION' | 'NETWORK_ERROR' | 'SERVER_ERROR' | 'TIMEOUT' | 'BAD_DATA' | 'BUFFER_OVERRUN' | 'NUMERIC_FAULT' | 'INVALID_ARGUMENT' | 'MISSING_ARGUMENT' | 'UNEXPECTED_ARGUMENT' | 'VALUE_MISMATCH' | 'CALL_EXCEPTION' | 'INSUFFICIENT_FUNDS' | 'NONCE_EXPIRED' | 'REPLACEMENT_UNDERPRICED' | 'TRANSACTION_REPLACED' | 'UNPREDICTABLE_GAS_LIMIT' | 'UNCONFIGURED_NAME' | 'OFFCHAIN_FAULT'; +interface EthersError extends Error { + code: ErrorCode; + info?: Record; + error?: Error; +} +interface UnknownError extends EthersError<'UNKNOWN_ERROR'> { + [key: string]: any; +} +interface NotImplementedError extends EthersError<'NOT_IMPLEMENTED'> { + operation: string; +} +interface UnsupportedOperationError extends EthersError<'UNSUPPORTED_OPERATION'> { + operation: string; +} +interface NetworkError extends EthersError<'NETWORK_ERROR'> { + event: string; +} +interface ServerError extends EthersError<'SERVER_ERROR'> { + request: ErrorFetchRequest | string; + response?: ErrorFetchResponse; +} +interface TimeoutError extends EthersError<'TIMEOUT'> { + operation: string; + reason: string; + request?: ErrorFetchRequest; +} +interface BadDataError extends EthersError<'BAD_DATA'> { + value: any; +} +interface BufferOverrunError extends EthersError<'BUFFER_OVERRUN'> { + buffer: Uint8Array; + length: number; + offset: number; +} +interface NumericFaultError extends EthersError<'NUMERIC_FAULT'> { + operation: string; + fault: string; + value: any; +} +interface InvalidArgumentError extends EthersError<'INVALID_ARGUMENT'> { + argument: string; + value: any; + info?: Record; +} +interface MissingArgumentError extends EthersError<'MISSING_ARGUMENT'> { + count: number; + expectedCount: number; +} +interface UnexpectedArgumentError extends EthersError<'UNEXPECTED_ARGUMENT'> { + count: number; + expectedCount: number; +} +interface CallExceptionError extends EthersError<'CALL_EXCEPTION'> { + data: string; + transaction?: any; + method?: string; + signature?: string; + args?: ReadonlyArray; + errorSignature?: string; + errorName?: string; + errorArgs?: ReadonlyArray; + reason?: string; +} +interface InsufficientFundsError extends EthersError<'INSUFFICIENT_FUNDS'> { + transaction: any; +} +interface NonceExpiredError extends EthersError<'NONCE_EXPIRED'> { + transaction: any; +} +interface OffchainFaultError extends EthersError<'OFFCHAIN_FAULT'> { + transaction?: any; + reason: string; +} +interface ReplacementUnderpricedError extends EthersError<'REPLACEMENT_UNDERPRICED'> { + transaction: any; +} +interface TransactionReplacedError extends EthersError<'TRANSACTION_REPLACED'> { + cancelled: boolean; + reason: 'repriced' | 'cancelled' | 'replaced'; + hash: string; + replacement: any; + receipt: any; +} +interface UnconfiguredNameError extends EthersError<'UNCONFIGURED_NAME'> { + value: string; +} +interface UnpredictableGasLimitError extends EthersError<'UNPREDICTABLE_GAS_LIMIT'> { + transaction: any; +} +/** + * @export CodedEthersError + */ +declare type CodedEthersError = T extends "UNKNOWN_ERROR" ? UnknownError : T extends "NOT_IMPLEMENTED" ? NotImplementedError : T extends "UNSUPPORTED_OPERATION" ? UnsupportedOperationError : T extends "NETWORK_ERROR" ? NetworkError : T extends "SERVER_ERROR" ? ServerError : T extends "TIMEOUT" ? TimeoutError : T extends "BAD_DATA" ? BadDataError : T extends "BUFFER_OVERRUN" ? BufferOverrunError : T extends "NUMERIC_FAULT" ? NumericFaultError : T extends "INVALID_ARGUMENT" ? InvalidArgumentError : T extends "MISSING_ARGUMENT" ? MissingArgumentError : T extends "UNEXPECTED_ARGUMENT" ? UnexpectedArgumentError : T extends "CALL_EXCEPTION" ? CallExceptionError : T extends "INSUFFICIENT_FUNDS" ? InsufficientFundsError : T extends "NONCE_EXPIRED" ? NonceExpiredError : T extends "OFFCHAIN_FAULT" ? OffchainFaultError : T extends "REPLACEMENT_UNDERPRICED" ? ReplacementUnderpricedError : T extends "TRANSACTION_REPLACED" ? TransactionReplacedError : T extends "UNCONFIGURED_NAME" ? UnconfiguredNameError : T extends "UNPREDICTABLE_GAS_LIMIT" ? UnpredictableGasLimitError : never; +/** + * #isError + * @param error + * @param code + * @returns + */ +declare function isError>(error: any, code: K): error is T; +/** + * #isCallException + * @param error + * @returns + */ +declare function isCallException(error: any): error is CallExceptionError; +/** + * #getTransactionError + * @param tx + * @param receipt + * @param provider + * @returns + */ +declare const getTransactionError: (tx: TransactionResponse, receipt: TransactionReceipt, provider: Provider) => Promise; +/** + * @export parseReasonCode + * @param messageData + * @returns + */ +declare const parseReasonCode: (messageData: string) => string; + +export { AddChainError, AddressZero, BURN_ADDRESS, BadDataError, BufferOverrunError, CallExceptionError, ChainId, ChainNotConfiguredError, CodedEthersError, ConnectorAlreadyConnectedError, ConnectorNotFoundError, DeadAddress, EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA, ErrorAccessList, ErrorCode, ErrorFetchRequest, ErrorFetchRequestWithBody, ErrorFetchResponse, ErrorFetchResponseWithBody, ErrorSignature, ErrorTransaction, EthersError, HttpJsonRpcError, IJsonRpcError, IJsonRpcRequest, IJsonRpcResponse, IJsonRpcSuccess, InsufficientFundsError, InvalidArgumentError, JsonRpcError, JsonRpcMethod, JsonRpcPayload, JsonRpcRequest, JsonRpcResponse, MissingArgumentError, NetworkError, NonceExpiredError, NotImplementedError, NumericFaultError, OffchainFaultError, privateTransaction as PrivateTransaction, PrivateTxState, PrivateTxStatus, ProviderRpcError, reducer as Reducer, RelayResponse, RelayResponses, ReplacementUnderpricedError, ResourceUnavailableError, RpcError, SerializableTransactionReceipt, ServerError, SwitchChainError, SwitchChainNotSupportedError, TimeoutError, TransactionDetails$1 as TransactionDetails, TransactionReplacedError, UnconfiguredNameError, UnexpectedArgumentError, UnknownError, UnpredictableGasLimitError, UnsupportedOperationError, UserRejectedRequestError, addTransaction, checkedTransaction, clearAllTransactions, fetchJsonRpc, finalizeTransaction, getTransactionError, isCallException, isError, isJsonRpcError, isJsonRpcSuccess, isTxExpired, isTxIndeterminate, isTxPending, isTxSuccessful, parseReasonCode, privateTx, txMinutesPending, updatePrivateTxStatus, validateJsonRpcResponse }; diff --git a/dist/index.mjs b/dist/index.mjs new file mode 100644 index 0000000..a11517f --- /dev/null +++ b/dist/index.mjs @@ -0,0 +1,500 @@ +import { createAction, createReducer } from '@reduxjs/toolkit'; +import { toUtf8String } from '@ethersproject/strings'; + +/** @export ChainId */ +var ChainId; +(function (ChainId) { + ChainId["MAINNET"] = "1"; +})(ChainId || (ChainId = {})); + +/** + * @filename Redux Action + * @version 0.2.0 + */ +const addTransaction = createAction('transactions/addTransaction'); +const clearAllTransactions = createAction('transactions/clearAllTransactions'); +const finalizeTransaction = createAction('transactions/finalizeTransaction'); +const checkedTransaction = createAction('transactions/checkedTransaction'); +const updatePrivateTxStatus = createAction('transactions/updatePrivateTxStatus'); + +/** + * @enum PrivateTxState + * @interface PrivateTxStatus + * @interface RelayResponse + * @description Transaction State Types + * + * - UNCHECKED -> Tx status has not been checked and there's no information about it. + * - PROCESSING -> Tx checks are in place until a resolution happens: OK, INDETERMINATE, ERROR. + * - OK -> Relay received the Tx && all downstream miners accepted without complains && tx mined successfully + * - INDETERMINATE -> Relay received correctly the Tx && at least one miner accepted the TX && TX potentially mineable + * - ERROR -> Relay haven't received the TX || none of the miners accepted the Tx || Tx was not mined successfully + * +/** + * + * + * @export + * @enum {number} + */ +var PrivateTxState; +(function (PrivateTxState) { + PrivateTxState["UNCHECKED"] = "UNCHECKED"; + PrivateTxState["PROCESSING"] = "PROCESSING"; + PrivateTxState["OK"] = "OK"; + PrivateTxState["INDETERMINATE"] = "INDETERMINATE"; + PrivateTxState["ERROR"] = "ERROR"; +})(PrivateTxState || (PrivateTxState = {})); +/** + * + * + * @export + * @param {*} privateTx + * @return {*} + */ +function privateTx(privateTx) { + throw new Error('[#sushiguard]: Function Error.'); +} + +var privateTransaction = /*#__PURE__*/Object.freeze({ + __proto__: null, + get PrivateTxState () { return PrivateTxState; }, + privateTx: privateTx +}); + +/** + * + * @class PrivateTransaction + * @license GPL-3.0-Only + * @see {@link https://docs.manifoldfinance.com} + * @since 2022.03 + * @version 0.1.0 + * + */ +/** + * @summary + * Basic explanation of the tx state types: + * UNCHECKED -> Tx status has not been checked and there's no information about it. + * PROCESSING -> Tx checks are in place until a resolution happens: OK, INDETERMINATE, ERROR. + * OK -> Relay received the Tx && all downstream miners accepted without complains && tx mined successfully + * INDETERMINATE -> Relay received correctly the Tx && at least one miner accepted the TX && TX potentially mineable + * ERROR -> Relay haven't received the TX || none of the miners accepted the Tx || Tx was not mined successfully + */ +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +function isTxPending(tx) { + if (!tx?.privateTx) + return !tx?.receipt; + return tx?.privateTx?.state === PrivateTxState.UNCHECKED || tx?.privateTx?.state === PrivateTxState.PROCESSING; +} +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +function isTxSuccessful(tx) { + if (!tx?.privateTx) + return !!tx && (tx.receipt?.status === 1 || typeof tx.receipt?.status === 'undefined'); + return (tx?.privateTx?.state === PrivateTxState.OK && + !!tx && + (tx.receipt?.status === 1 || typeof tx.receipt?.status === 'undefined')); +} +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +function isTxIndeterminate(tx) { + if (!tx?.privateTx) + return false; + return tx?.privateTx?.state === PrivateTxState.INDETERMINATE; +} +/** + * + * @export + * @param {TransactionDetails} [tx] + * @return {number} + */ +function txMinutesPending(tx) { + if (!tx) + return 0; + return (new Date().getTime() - tx.addedTime) / 1000 / 60; +} +/** + * + * + * @export + * @param {TransactionDetails} [tx] + * @return {boolean} + */ +function isTxExpired(tx) { + if (!tx) + return false; + return txMinutesPending(tx) > 60; +} + +/** + * + * @filename Redux Reducer + * + */ +const now = () => new Date().getTime(); +const initialState = {}; +var reducer = createReducer(initialState, (builder) => builder + .addCase(addTransaction, +// @ts-expect-error +(transactions, { payload: { chainId, from, hash, approval, summary, claim, privateTx = false } }) => { + if (transactions[chainId]?.[hash]) { + throw Error('Attempted to add existing transaction.'); + } + const txs = transactions[chainId] ?? {}; + txs[hash] = { + hash, + approval, + summary, + claim, + from, + addedTime: now(), + ...(privateTx ? { privateTx: { state: PrivateTxState.UNCHECKED, status: undefined } } : {}), + }; + transactions[chainId] = txs; +}) + .addCase(clearAllTransactions, (transactions, { payload: { chainId } }) => { + if (!transactions[chainId]) + return; + transactions[chainId] = {}; +}) + .addCase(checkedTransaction, (transactions, { payload: { chainId, hash, blockNumber } }) => { + const tx = transactions[chainId]?.[hash]; + if (!tx) { + return; + } + if (!tx.lastCheckedBlockNumber) { + tx.lastCheckedBlockNumber = blockNumber; + } + else { + tx.lastCheckedBlockNumber = Math.max(blockNumber, tx.lastCheckedBlockNumber); + } +}) + .addCase(finalizeTransaction, (transactions, { payload: { hash, chainId, receipt } }) => { + const tx = transactions[chainId]?.[hash]; + if (!tx) { + return; + } + tx.receipt = receipt; + tx.confirmedTime = now(); +}) + .addCase(updatePrivateTxStatus, (transactions, { payload: { chainId, hash, status } }) => { + const tx = transactions[chainId]?.[hash]; + if (!tx) + return; + if (!tx.privateTx) + throw new Error('Invalid update private tx call to a non private tx'); + const prevState = tx.privateTx?.state; + tx.privateTx?.status; + const minutesElapsed = txMinutesPending(tx); + // If previous state was a definitive one, we skip processing new events + if (prevState && + (prevState === PrivateTxState.ERROR || + prevState === PrivateTxState.INDETERMINATE || + prevState === PrivateTxState.OK)) + return; + // derive new private tx state from latest received status + let state = PrivateTxState.PROCESSING; + // OK - Relay received the Tx && all downstream miners accepted without complains && tx mined successfully + if (status.receivedAt && status.relayedAt && !status.relayFailure && status.minedAt) + state = PrivateTxState.OK; + // ERROR + if (status.receivedAt && + status.relayFailure && + status.relayResponses && + Object.values(status.relayResponses).reduceRight((prev, current) => { + if (prev) + return prev; + if (current.error || current.response.error) + return true; + return false; + }, false)) + state = PrivateTxState.ERROR; + // INDETERMINATE + if (status.receivedAt && status.relayedAt && status.relayFailure && status.minedAt) + state = PrivateTxState.INDETERMINATE; + // If more than 20 minutes has passed, better to mark this TX as indeterminate + if (minutesElapsed > 3) + state = PrivateTxState.INDETERMINATE; + // update new state + tx.privateTx.state = state ?? PrivateTxState.UNCHECKED; + tx.privateTx.status = status; +})); + +var reducer$1 = /*#__PURE__*/Object.freeze({ + __proto__: null, + initialState: initialState, + 'default': reducer +}); + +/** + * @file JsonRpc + * @version 0.3.0 + * @license Apache-2.0 + * + */ +/** + * @export + * @class HttpJsonRpcError + * @extends {Error} + */ +class HttpJsonRpcError extends Error { + constructor(message, req, res) { + super(message); + this.req = req; + this.res = res; + } +} +/** + * @export + * @template T + * @param {string} url + * @param {Partial} { + * @return {(Promise>)} + */ +function fetchJsonRpc(url, { jsonrpc = '2.0', id = new Date().getTime(), method = '', params = [] }) { + return fetch(url, { + headers: { 'Content-Type': 'application/json' }, + method: 'POST', + body: JSON.stringify({ jsonrpc, id, method, params }), + }).then((res) => { + // handle http errors (anything not 200) + if (res.status !== 200) + throw new HttpJsonRpcError(res.statusText, { jsonrpc, id, method, params }, res); + // handle successful response + return res.json(); + }); +} +function validateJsonRpcResponse(response) { + if (response.jsonrpc !== '2.0' || + (typeof response.id !== 'string' && typeof response.id !== 'number' && response.id !== null) || + ('result' in response && 'error' in response) || + (!('result' in response) && !('error' in response)) || + (response.error && typeof response.error.code !== 'number') || + (response.error && typeof response.error.message !== 'string')) + throw new Error(`Expected JSON-RPC response, received something else.\n${JSON.stringify(response)}`); + return true; +} +function isJsonRpcSuccess(response) { + return !!response.result && !response.error; +} +function isJsonRpcError(response) { + return !!response.error && !response.result; +} + +const BURN_ADDRESS = '0x000000000000000000000000000000000000dead'; + +const AddressZero = '0x0000000000000000000000000000000000000000'; + +const EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = `\x19\x01`; + +// @note this is also the old OVM_ETH address on Optimism +const DeadAddress = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'; + +/** + * Error subclass implementing JSON RPC 2.0 errors and Ethereum RPC errors per EIP-1474. + * @see https://eips.ethereum.org/EIPS/eip-1474 + */ +class RpcError extends Error { + constructor( + /** Number error code */ + code, + /** Human-readable string */ + message, + /** Low-level error */ + internal, + /** Other useful information about error */ + data) { + if (!Number.isInteger(code)) + throw new Error('"code" must be an integer.'); + if (!message || typeof message !== 'string') + throw new Error('"message" must be a nonempty string.'); + super(message); + this.code = code; + this.data = data; + this.internal = internal; + } +} +/** + * Error subclass implementing Ethereum Provider errors per EIP-1193. + * @see https://eips.ethereum.org/EIPS/eip-1193 + */ +class ProviderRpcError extends RpcError { + /** + * Create an Ethereum Provider JSON-RPC error. + * `code` must be an integer in the 1000 <= 4999 range. + */ + constructor( + /** + * Number error code + * @see https://eips.ethereum.org/EIPS/eip-1193#error-standards + */ + code, + /** Human-readable string */ + message, + /** Low-level error */ + internal, + /** Other useful information about error */ + data) { + if (!(Number.isInteger(code) && code >= 1000 && code <= 4999)) + throw new Error('"code" must be an integer such that: 1000 <= code <= 4999'); + super(code, message, internal, data); + } +} +class AddChainError extends Error { + constructor() { + super(...arguments); + this.name = 'AddChainError'; + this.message = 'Error adding chain'; + } +} +class ChainNotConfiguredError extends Error { + constructor() { + super(...arguments); + this.name = 'ChainNotConfigured'; + this.message = 'Chain not configured'; + } +} +class ConnectorAlreadyConnectedError extends Error { + constructor() { + super(...arguments); + this.name = 'ConnectorAlreadyConnectedError'; + this.message = 'Connector already connected'; + } +} +class ConnectorNotFoundError extends Error { + constructor() { + super(...arguments); + this.name = 'ConnectorNotFoundError'; + this.message = 'Connector not found'; + } +} +class SwitchChainError extends ProviderRpcError { + constructor(error) { + super(4902, 'Error switching chain', error); + this.name = 'SwitchChainError'; + } +} +class SwitchChainNotSupportedError extends Error { + constructor() { + super(...arguments); + this.name = 'SwitchChainNotSupportedError'; + this.message = 'Switch chain not supported by connector'; + } +} +class UserRejectedRequestError extends ProviderRpcError { + constructor(error) { + super(4001, 'User rejected request', error); + this.name = 'UserRejectedRequestError'; + } +} +class ResourceUnavailableError extends RpcError { + constructor(error) { + super(-32002, 'Resource unavailable', error); + this.name = 'ResourceUnavailable'; + } +} + +/** + * #isError + * @param error + * @param code + * @returns + */ +function isError(error, code) { + return error && error.code === code; +} +/** + * #isCallException + * @param error + * @returns + */ +function isCallException(error) { + return isError(error, 'CALL_EXCEPTION'); +} +/** + * #getTransactionError + * @param tx + * @param receipt + * @param provider + * @returns + */ +const getTransactionError = async (tx, receipt, provider) => { + if (typeof tx !== 'object') { + throw TypeError(`tx argument ${tx} must be a transaction object`); + } + if (typeof receipt !== 'object') { + throw TypeError(`receipt argument ${receipt} must be a transaction receipt object`); + } + if (receipt.status) { + throw TypeError('Transaction did not fail. Can only read the revert reason from failed transactions'); + } + if (!receipt.transactionHash) { + throw TypeError(`There is no transaction hash on the receipt object`); + } + if (receipt.gasUsed === tx.gasLimit) { + throw Error('Transaction failed as it ran out of gas.'); + } + // TODO: check type + let rawMessageData; + try { + const result = await provider.call({ + ...tx, + }, receipt.blockNumber); + // @dev Trim the 0x prefix + rawMessageData = result.slice(2); + } + catch (e) { + if (e.message.startsWith('Node error: ')) { + // @dev Trim "Node error: " + const errorObjectStr = e.message.slice(12); + // @dev Parse the error object + const errorObject = JSON.parse(errorObjectStr); + if (!errorObject.data) { + throw Error('Failed to parse data field error object:' + errorObjectStr); + } + if (errorObject.data.startsWith('Reverted 0x')) { + // Trim "Reverted 0x" from the data field + rawMessageData = errorObject.data.slice(11); + } + else if (errorObject.data.startsWith('0x')) { + // Trim "0x" from the data field + rawMessageData = errorObject.data.slice(2); + } + else { + throw Error('Failed to parse data field of error object:' + errorObjectStr); + } + } + else { + throw Error('Failed to parse error message from Ethereum call: ' + e.message); + } + } + return parseReasonCode(rawMessageData); +}; +/** + * @export parseReasonCode + * @param messageData + * @returns + */ +const parseReasonCode = (messageData) => { + // Get the length of the revert reason + const strLen = parseInt(messageData.slice(8 + 64, 8 + 128), 16); + // Using the length and known offset, extract and convert the revert reason + const reasonCodeHex = messageData.slice(8 + 128, 8 + 128 + strLen * 2); + // Convert reason from hex to string + const reason = toUtf8String('0x' + reasonCodeHex); + return reason; +}; + +export { AddChainError, AddressZero, BURN_ADDRESS, ChainId, ChainNotConfiguredError, ConnectorAlreadyConnectedError, ConnectorNotFoundError, DeadAddress, EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA, HttpJsonRpcError, privateTransaction as PrivateTransaction, PrivateTxState, ProviderRpcError, reducer$1 as Reducer, ResourceUnavailableError, RpcError, SwitchChainError, SwitchChainNotSupportedError, UserRejectedRequestError, addTransaction, checkedTransaction, clearAllTransactions, fetchJsonRpc, finalizeTransaction, getTransactionError, isCallException, isError, isJsonRpcError, isJsonRpcSuccess, isTxExpired, isTxIndeterminate, isTxPending, isTxSuccessful, parseReasonCode, privateTx, txMinutesPending, updatePrivateTxStatus, validateJsonRpcResponse }; +//# sourceMappingURL=index.mjs.map diff --git a/dist/index.mjs.map b/dist/index.mjs.map new file mode 100644 index 0000000..67e17da --- /dev/null +++ b/dist/index.mjs.map @@ -0,0 +1 @@ +{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/dist/jsonrpc/index.d.ts b/dist/jsonrpc/index.d.ts new file mode 100644 index 0000000..32cec81 --- /dev/null +++ b/dist/jsonrpc/index.d.ts @@ -0,0 +1,90 @@ +/** + * @file JsonRpc + * @version 0.3.0 + * @license Apache-2.0 + * + */ +/** + * JsonRpcRequest + * @export + * @interface JsonRpcRequest + */ +export interface JsonRpcRequest { + jsonrpc: '2.0'; + id: number | string | null; + method: string; + params?: unknown[] | unknown; +} +/** + * @export + * @interface JsonRpcError + */ +export interface JsonRpcError { + code: number; + message: string; + data?: unknown; +} +/** + * @export + * @interface JsonRpcResponse + * @template T + */ +export interface JsonRpcResponse { + jsonrpc: '2.0'; + id?: number | string | null; + result?: T; + error?: JsonRpcError; +} +/** + * @export + * @interface JsonRpcPayload + */ +export interface JsonRpcPayload { + jsonrpc: string; + method: string; + params?: any[]; + id?: string | number; +} +/** + * @export + * @class HttpJsonRpcError + * @extends {Error} + */ +export declare class HttpJsonRpcError extends Error { + req?: JsonRpcRequest; + res?: Response; + constructor(message: string, req?: JsonRpcRequest, res?: Response); +} +/** + * @export + * @template T + * @param {string} url + * @param {Partial} { + * @return {(Promise>)} + */ +export declare function fetchJsonRpc(url: string, { jsonrpc, id, method, params }: Partial): Promise>; +export declare type JsonRpcMethod = 'eth_accounts' | 'eth_blockNumber' | 'eth_call' | 'eth_chainId' | 'eth_coinbase' | 'eth_estimateGas' | 'eth_gasPrice' | 'eth_getBalance' | 'eth_getBlockByHash' | 'eth_getBlockByNumber' | 'eth_getBlockTransactionCountByHash' | 'eth_getBlockTransactionCountByNumber' | 'eth_getCode' | 'eth_getLogs' | 'eth_getProof' | 'eth_getStorageAt' | 'eth_getTransactionByBlockHashAndIndex' | 'eth_getTransactionByBlockNumberAndIndex' | 'eth_getTransactionByHash' | 'eth_getTransactionCount' | 'eth_getTransactionReceipt' | 'eth_getUncleByBlockHashAndIndex' | 'eth_getUncleByBlockNumberAndIndex' | 'eth_getUncleCountByBlockHash' | 'eth_getUncleCountByBlockNumber' | 'eth_protocolVersion' | 'eth_sendRawTransaction' | 'eth_sendTransaction' | 'eth_sign' | 'eth_signTransaction' | 'eth_signTypedData' | 'eth_syncing'; +export interface IJsonRpcRequest> { + readonly jsonrpc: '2.0'; + readonly id: string | number | null; + readonly method: TMethod; + readonly params: TParams; +} +export interface IJsonRpcSuccess { + readonly jsonrpc: '2.0'; + readonly id: string | number | null; + readonly result: TResult; +} +export interface IJsonRpcError { + readonly jsonrpc: '2.0'; + readonly id: string | number | null; + readonly error: { + readonly code: number; + readonly message: string; + readonly data?: unknown; + }; +} +export declare type IJsonRpcResponse = IJsonRpcSuccess | IJsonRpcError; +export declare function validateJsonRpcResponse(response: any): response is IJsonRpcResponse; +export declare function isJsonRpcSuccess(response: IJsonRpcResponse): response is IJsonRpcSuccess; +export declare function isJsonRpcError(response: IJsonRpcResponse): response is IJsonRpcError; diff --git a/dist/values/AddressBurn.d.ts b/dist/values/AddressBurn.d.ts new file mode 100644 index 0000000..77039dd --- /dev/null +++ b/dist/values/AddressBurn.d.ts @@ -0,0 +1 @@ +export declare const BURN_ADDRESS = "0x000000000000000000000000000000000000dead"; diff --git a/dist/values/AddressDead.d.ts b/dist/values/AddressDead.d.ts new file mode 100644 index 0000000..33266dc --- /dev/null +++ b/dist/values/AddressDead.d.ts @@ -0,0 +1 @@ +export declare const DeadAddress = "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000"; diff --git a/dist/values/AddressZero.d.ts b/dist/values/AddressZero.d.ts new file mode 100644 index 0000000..ef889ae --- /dev/null +++ b/dist/values/AddressZero.d.ts @@ -0,0 +1 @@ +export declare const AddressZero = "0x0000000000000000000000000000000000000000"; diff --git a/dist/values/EIP191.d.ts b/dist/values/EIP191.d.ts new file mode 100644 index 0000000..441b289 --- /dev/null +++ b/dist/values/EIP191.d.ts @@ -0,0 +1 @@ +export declare const EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = "\u0019\u0001"; diff --git a/dist/values/index.d.ts b/dist/values/index.d.ts new file mode 100644 index 0000000..84a0c3e --- /dev/null +++ b/dist/values/index.d.ts @@ -0,0 +1,4 @@ +export * from './AddressBurn'; +export * from './AddressZero'; +export * from './EIP191'; +export * from './AddressDead';