docs: added more jsdocs

This commit is contained in:
Richard Moore 2022-09-15 22:30:27 -04:00
parent 12a13c6d56
commit edcba76366
4 changed files with 238 additions and 178 deletions

View File

@ -180,6 +180,9 @@ export class Network implements Freezable<Network> {
return gas;
}
/**
* Returns a new Network for the %%network%% name or chainId.
*/
static from(network?: Networkish): Network {
// Default network
if (network == null) { return Network.from("homestead"); }
@ -226,6 +229,10 @@ export class Network implements Freezable<Network> {
return throwArgumentError("invalid network", "network", network);
}
/**
* Register %%nameOrChainId%% with a function which returns
* an instance of a Network representing that chain.
*/
static register(nameOrChainId: string | number | bigint, networkFunc: () => Network): void {
if (typeof(nameOrChainId) === "number") { nameOrChainId = BigInt(nameOrChainId); }
const existing = Networks.get(nameOrChainId);

View File

@ -4,7 +4,7 @@
// https://playground.open-rpc.org/?schemaUrl=https://raw.githubusercontent.com/ethereum/eth1.0-apis/assembled-spec/openrpc.json&uiSchema%5BappBar%5D%5Bui:splitView%5D=true&uiSchema%5BappBar%5D%5Bui:input%5D=false&uiSchema%5BappBar%5D%5Bui:examplesDropdown%5D=false
import { resolveAddress } from "../address/index.js";
import { TypedDataEncoder } from "../hash/typed-data.js";
import { TypedDataEncoder } from "../hash/index.js";
import { accessListify } from "../transaction/index.js";
import {
defineProperties, getBigInt, hexlify, toQuantity, toUtf8Bytes,
@ -26,10 +26,6 @@ import type { Provider, TransactionRequest, TransactionResponse } from "./provid
import type { Signer } from "./signer.js";
//function copy<T = any>(value: T): T {
// return JSON.parse(JSON.stringify(value));
//}
const Primitive = "bigint,boolean,function,number,string,symbol".split(/,/g);
//const Methods = "getAddress,then".split(/,/g);
function deepCopy<T = any>(value: T): T {
@ -67,6 +63,9 @@ function isPollable(value: any): value is Pollable {
return (value && typeof(value.pollingInterval) === "number");
}
/**
* A JSON-RPC payload, which are sent to a JSON-RPC server.
*/
export type JsonRpcPayload = {
id: number;
method: string;
@ -74,11 +73,17 @@ export type JsonRpcPayload = {
jsonrpc: "2.0";
};
/**
* A JSON-RPC result, which are returned on success from a JSON-RPC server.
*/
export type JsonRpcResult = {
id: number;
result: any;
};
/**
* A JSON-RPC error, which are returned on failure from a JSON-RPC server.
*/
export type JsonRpcError = {
id: number;
error: {
@ -88,23 +93,60 @@ export type JsonRpcError = {
}
};
export type JsonRpcOptions = {
// Whether to immediately fallback onto useing the polling strategy; otherwise
// attempt to use filters first, falling back onto polling if filter returns failure
export type DebugEventJsonRpcApiProvider = {
action: "sendRpcPayload",
payload: JsonRpcPayload | Array<JsonRpcPayload>
} | {
action: "receiveRpcResult",
result: Array<JsonRpcResult | JsonRpcError>
} | {
action: "receiveRpcError",
error: Error
};
/**
* Options for configuring a [[JsonRpcApiProvider]]. Much of this
* is targetted towards sub-classes, which often will not expose
* any of these options to their consumers.
*
* _property: options.polling? => boolean
* If true, the polling strategy is used immediately for events.
* Otherwise, an attempt to use filters is made and on failure
* polling is used for that and all future events. (default: ``false``)
*
* _property: options.staticNetwork => [[Network]]
* If this is set, then there are no requests made for the chainId.
* (default: ``null``)
*
* _warning:
* This should **ONLY** be used if it is **certain** that the network
* cannot change, such as when using INFURA (since the URL dictates the
* network). If the network is assumed static and it does change, this
* can have tragic consequences. For example, this **CANNOT** be used
* with MetaMask, since the used can select a new network from the
* drop-down at any time.
*
* _property: option.batchStallTime? => number
* The amount of time (in ms) to wait, allowing requests to be batched,
* before making the request. If ``0``, then batching will only occur
* within the same event loop. If the batchSize is ``1``, then this is
* ignored. (default: ``10``)
*
* _property: options.batchMaxSize? => number
* The target maximum size (in bytes) to allow a payload within a single
* batch. At least one request will be made per request, which may
* violate this constraint if it is set too small or a large request is
* present. (default: 1Mb)
*
* _property: options.bstchMaxCount? => number
* The maximum number of payloads to allow in a single batch. Set this to
* ``1`` to disable batching entirely. (default: ``100``)
*/
export type JsonRpcApiProviderOptions = {
polling?: boolean;
// Whether to check the network on each call; only set this to true when a backend
// **cannot** change otherwise catastrophic errors can occur
staticNetwork?: null | Network;
// How long to wait before draining the payload queue
batchStallTime?: number;
// Maximum estimated size (in bytes) to allow in a batch
batchMaxSize?: number;
// Maximum number of payloads to send per batch; if set to 1, non-batching requests
// are made.
batchMaxCount?: number;
};
@ -161,26 +203,6 @@ export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
return await this.populateCall(tx);
}
//async getNetwork(): Promise<Frozen<Network>> {
// return await this.provider.getNetwork();
//}
//async estimateGas(tx: TransactionRequest): Promise<bigint> {
// return await this.provider.estimateGas(tx);
//}
//async call(tx: TransactionRequest): Promise<string> {
// return await this.provider.call(tx);
//}
//async resolveName(name: string | Addressable): Promise<null | string> {
// return await this.provider.resolveName(name);
//}
//async getNonce(blockTag?: BlockTag): Promise<number> {
// return await this.provider.getTransactionCountOf(this.address);
//}
// Returns just the hash of the transaction after sent, which is what
// the bare JSON-RPC API does;
async sendUncheckedTransaction(_tx: TransactionRequest): Promise<string> {
@ -315,15 +337,21 @@ type RejectFunc = (error: Error) => void;
type Payload = { payload: JsonRpcPayload, resolve: ResolveFunc, reject: RejectFunc };
/**
* The JsonRpcApiProvider is an abstract class and **MUST** be
* sub-classed.
*
* It provides the base for all JSON-RPC-based Provider interaction.
*/
export class JsonRpcApiProvider extends AbstractProvider {
#options: Required<JsonRpcOptions>;
#options: Required<JsonRpcApiProviderOptions>;
#nextId: number;
#payloads: Array<Payload>;
#drainTimer: null | NodeJS.Timer;
constructor(network?: Networkish, options?: JsonRpcOptions) {
constructor(network?: Networkish, options?: JsonRpcApiProviderOptions) {
super(network);
this.#nextId = 1;
@ -339,26 +367,21 @@ export class JsonRpcApiProvider extends AbstractProvider {
}
}
_getOption<K extends keyof JsonRpcOptions>(key: K): JsonRpcOptions[K] {
/**
* Returns the value associated with the option %%key%%.
*
* Sub-classes can use this to inquire about configuration options.
*/
_getOption<K extends keyof JsonRpcApiProviderOptions>(key: K): JsonRpcApiProviderOptions[K] {
return this.#options[key];
}
// @TODO: Merge this into send
//prepareRequest(method: string, params: Array<any>): JsonRpcPayload {
// return {
// method, params, id: (this.#nextId++), jsonrpc: "2.0"
// };
//}
/*
async send<T = any>(method: string, params: Array<any>): Promise<T> {
// @TODO: This should construct and queue the payload
throw new Error("sub-class must implement this");
}
*/
#scheduleDrain(): void {
if (this.#drainTimer) { return; }
// If we aren't using batching, no hard in sending it immeidately
const stallTime = (this._getOption("batchMaxCount") === 1) ? 0: this._getOption("batchStallTime");
this.#drainTimer = setTimeout(() => {
this.#drainTimer = null;
@ -420,10 +443,23 @@ export class JsonRpcApiProvider extends AbstractProvider {
}
})();
}
}, this.#options.batchStallTime);
}, stallTime);
}
// Sub-classes should **NOT** override this
/**
* Requests the %%method%% with %%params%% via the JSON-RPC protocol
* over the underlying channel. This can be used to call methods
* on the backend that do not have a high-level API within the Provider
* API.
*
* This method queues requests according to the batch constraints
* in the options, assigns the request a unique ID.
*
* **Do NOT override** this method in sub-classes; instead
* override [[_send]] or force the options values in the
* call to the constructor to modify this method's behavior.
*/
send(method: string, params: Array<any> | Record<string, any>): Promise<any> {
// @TODO: cache chainId?? purge on switch_networks
@ -441,13 +477,29 @@ export class JsonRpcApiProvider extends AbstractProvider {
return <Promise<JsonRpcResult>>promise;
}
// Sub-classes MUST override this
/**
* Sends a JSON-RPC %%payload%% (or a batch) to the underlying channel.
*
* Sub-classes **MUST** override this.
*/
_send(payload: JsonRpcPayload | Array<JsonRpcPayload>): Promise<Array<JsonRpcResult | JsonRpcError>> {
return throwError("sub-classes must override _send", "UNSUPPORTED_OPERATION", {
operation: "jsonRpcApiProvider._send"
});
}
/**
* Resolves to the [[Signer]] account for %%address%% managed by
* the client.
*
* If the %%address%% is a number, it is used as an index in the
* the accounts from [[listAccounts]].
*
* This can only be used on clients which manage accounts (such as
* Geth with imported account or MetaMask).
*
* Throws if the account doesn't exist.
*/
async getSigner(address: number | string = 0): Promise<JsonRpcSigner> {
const accountsPromise = this.send("eth_accounts", [ ]);
@ -482,6 +534,12 @@ export class JsonRpcApiProvider extends AbstractProvider {
return Network.from(getBigInt(await this._perform({ method: "chainId" })));
}
/**
* Return a Subscriber that will manage the %%sub%%.
*
* Sub-classes can override this to modify the behavior of
* subscription management.
*/
_getSubscriber(sub: Subscription): Subscriber {
// Pending Filters aren't availble via polling
if (sub.type === "pending") { return new FilterIdPendingSubscriber(this); }
@ -499,7 +557,11 @@ export class JsonRpcApiProvider extends AbstractProvider {
return super._getSubscriber(sub);
}
// Normalize a JSON-RPC transaction
/**
* Returns %%tx%% as a normalized JSON-RPC transaction request,
* which has all values hexlified and any numeric values converted
* to Quantity values.
*/
getRpcTransaction(tx: TransactionRequest): JsonRpcTransactionRequest {
const result: JsonRpcTransactionRequest = {};
@ -525,7 +587,10 @@ export class JsonRpcApiProvider extends AbstractProvider {
return result;
}
// Get the necessary paramters for making a JSON-RPC request
/**
* Returns the request method and arguments required to perform
* %%req%%.
*/
getRpcRequest(req: PerformActionRequest): null | { method: string, args: Array<any> } {
switch (req.method) {
case "chainId":
@ -624,6 +689,10 @@ export class JsonRpcApiProvider extends AbstractProvider {
return null;
}
/**
* Returns an ethers-style Error for the given JSON-RPC error
* %%payload%%.
*/
getRpcError(payload: JsonRpcPayload, error: JsonRpcError): Error {
console.log("getRpcError", payload, error);
return new Error(`JSON-RPC badness; @TODO: ${ error }`);
@ -686,6 +755,12 @@ export class JsonRpcApiProvider extends AbstractProvider {
*/
}
/**
* Resolves to the non-normalized value by performing %%req%%.
*
* Sub-classes may override this to modify behavior of actions,
* and should generally call ``super._perform`` as a fallback.
*/
async _perform(req: PerformActionRequest): Promise<any> {
// Legacy networks do not like the type field being passed along (which
// is fair), so we delete type if it is 0 and a non-EIP-1559 network
@ -709,33 +784,26 @@ export class JsonRpcApiProvider extends AbstractProvider {
if (request != null) {
return await this.send(request.method, request.args);
/*
@TODO: Add debug output to send
this.emit("debug", { type: "sendRequest", request });
try {
const result =
//console.log("RR", result);
this.emit("debug", { type: "getResponse", result });
return result;
} catch (error) {
this.emit("debug", { type: "getError", error });
throw error;
//throw this.getRpcError(request.method, request.args, <Error>error);
}
*/
}
return super._perform(req);
}
}
/**
* The JsonRpcProvider is one of the most common Providers,
* which performs all operations over HTTP (or HTTPS) requests.
*
* Events are processed by polling the backend for the current block
* number; when it advances, all block-base events are then checked
* for updates.
*/
export class JsonRpcProvider extends JsonRpcApiProvider {
#connect: FetchRequest;
#pollingInterval: number;
constructor(url?: string | FetchRequest, network?: Networkish, options?: JsonRpcOptions) {
constructor(url?: string | FetchRequest, network?: Networkish, options?: JsonRpcApiProviderOptions) {
if (url == null) { url = "http:/\/localhost:8545"; }
super(network, options);
@ -762,6 +830,9 @@ export class JsonRpcProvider extends JsonRpcApiProvider {
return resp;
}
/**
* The polling interval (default: 4000 ms)
*/
get pollingInterval(): number { return this.#pollingInterval; }
set pollingInterval(value: number) {
if (!Number.isInteger(value) || value < 0) { throw new Error("invalid interval"); }
@ -774,24 +845,6 @@ export class JsonRpcProvider extends JsonRpcApiProvider {
}
}
// This class should only be used when it is not possible for the
// underlying network to change, such as with INFURA. If you are
// using MetaMask or some other client which allows users to change
// their network DO NOT USE THIS. Bad things will happen.
/*
export class StaticJsonRpcProvider extends JsonRpcProvider {
readonly network!: Network;
constructor(url: string | ConnectionInfo, network?: Network, options?: JsonRpcOptions) {
super(url, network, options);
defineProperties<StaticJsonRpcProvider>(this, { network });
}
async _detectNetwork(): Promise<Network> {
return this.network;
}
}
*/
/*
function spelunkData(value: any): null | { message: string, data: string } {
if (value == null) { return null; }

View File

@ -64,6 +64,7 @@ export interface Signer extends Addressable, ContractRunner, NameResolver {
* - if ``from`` is specified , check that it matches this Signer
* - populates ``nonce`` via ``signer.getNonce("pending")``
* - populates ``gasLimit`` via ``signer.estimateGas(tx)``
* - populates ``chainId`` via ``signer.provider.getNetwork()``
* - populates ``type`` and relevant fee data for that type (``gasPrice``
* for legacy transactions, ``maxFeePerGas`` for EIP-1559, etc)
*
@ -109,7 +110,7 @@ export interface Signer extends Addressable, ContractRunner, NameResolver {
call(tx: CallRequest): Promise<string>;
/**
* Resolves an [[Address]], ENS Name or [[Addressable]] to an [[Address]].
* Resolves an [[Address]] or ENS Name to an [[Address]].
*/
resolveName(name: string): Promise<null | string>;
@ -118,15 +119,15 @@ export interface Signer extends Addressable, ContractRunner, NameResolver {
// Signing
/**
* Signs %%tx%%, returning the fully signed transaction. This does not populate
* any additional properties within the transaction.
* Signs %%tx%%, returning the fully signed transaction. This does not
* populate any additional properties within the transaction.
*/
signTransaction(tx: TransactionRequest): Promise<string>;
/**
* Sends %%tx%% to the Network. The ``signer.populateTransaction(tx)`` is
* called first to ensure all necessary properties for the transaction to be
* valid have been popualted dirst.
* Sends %%tx%% to the Network. The ``signer.populateTransaction(tx)``
* is called first to ensure all necessary properties for the
* transaction to be valid have been popualted first.
*/
sendTransaction(tx: TransactionRequest): Promise<TransactionResponse>;

View File

@ -1,17 +1,13 @@
//export type TransactionReceipt {
//}
import { version } from "../_version.js";
import { defineReadOnly } from "./properties.js";
export type ErrorSignature = {
r: string;
s: string;
yParity: 0 | 1;
networkV: bigint;
};
import type {
TransactionRequest, TransactionReceipt, TransactionResponse
} from "../providers/index.js";
import type { FetchRequest, FetchResponse } from "./fetch.js";
export type ErrorAccessList = Array<{ address: string, storageKeys: Array<string> }>;
export type ErrorInfo<T> = Omit<T, "code" | "name" | "message">;
@ -20,61 +16,17 @@ const ErrorConstructors: Record<string, { new (...args: Array<any>): Error }> =
ErrorConstructors.INVALID_ARGUMENT = TypeError;
ErrorConstructors.NUMERIC_FAULT = RangeError;
ErrorConstructors.BUFFER_OVERRUN = RangeError;
/*
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<Uint8Array>;
}
export interface ErrorFetchRequest {
url: string;
method: string;
headers: Readonly<Record<string, string>>;
getHeader(key: string): string;
body: null | Readonly<Uint8Array>;
hasBody(): this is ErrorFetchRequestWithBody;
}
export interface ErrorFetchResponseWithBody extends ErrorFetchResponse {
body: Readonly<Uint8Array>;
}
export interface ErrorFetchResponse {
statusCode: number;
statusMessage: string;
headers: Readonly<Record<string, string>>;
getHeader(key: string): string;
body: null | Readonly<Uint8Array>;
hasBody(): this is ErrorFetchResponseWithBody;
}
/**
* All errors emitted by ethers have an **ErrorCode** to help
* identify and coalesce errors to simplfy programatic analysis.
*
* _property: ``"UNKNOWN_ERROR"``
* This is a general puspose fallback when no other error makes sense
* or the error wasn't expected
*
* _property: ``"NOT_IMPLEMENTED"``
*/
export type ErrorCode =
// Generic Errors
@ -125,14 +77,14 @@ export interface NetworkError extends EthersError<"NETWORK_ERROR"> {
}
export interface ServerError extends EthersError<"SERVER_ERROR"> {
request: ErrorFetchRequest | string;
response?: ErrorFetchResponse;
request: FetchRequest | string;
response?: FetchResponse;
}
export interface TimeoutError extends EthersError<"TIMEOUT"> {
operation: string;
reason: string;
request?: ErrorFetchRequest;
request?: FetchRequest;
}
export interface BadDataError extends EthersError<"BAD_DATA"> {
@ -176,11 +128,6 @@ export interface UnexpectedArgumentError extends EthersError<"UNEXPECTED_ARGUMEN
expectedCount: number;
}
//export interface ValueMismatchError extends EthersError<ErrorCode.UNEXPECTED_ARGUMENT> {
// count: number;
// expectedCount: number;
//}
// Blockchain Errors
@ -209,28 +156,28 @@ export interface CallExceptionError extends EthersError<"CALL_EXCEPTION"> {
//}
export interface InsufficientFundsError extends EthersError<"INSUFFICIENT_FUNDS"> {
transaction: any;//ErrorTransaction;
transaction: TransactionRequest;
}
export interface NonceExpiredError extends EthersError<"NONCE_EXPIRED"> {
transaction: any; //ErrorTransaction;
transaction: TransactionRequest;
}
export interface OffchainFaultError extends EthersError<"OFFCHAIN_FAULT"> {
transaction?: any;
transaction?: TransactionRequest;
reason: string;
}
export interface ReplacementUnderpricedError extends EthersError<"REPLACEMENT_UNDERPRICED"> {
transaction: any; //ErrorTransaction;
transaction: TransactionRequest;
}
export interface TransactionReplacedError extends EthersError<"TRANSACTION_REPLACED"> {
cancelled: boolean;
reason: "repriced" | "cancelled" | "replaced";
hash: string;
replacement: any; //TransactionResponse;
receipt: any; //TransactionReceipt;
replacement: TransactionResponse;
receipt: TransactionReceipt;
}
export interface UnconfiguredNameError extends EthersError<"UNCONFIGURED_NAME"> {
@ -238,7 +185,7 @@ export interface UnconfiguredNameError extends EthersError<"UNCONFIGURED_NAME">
}
export interface UnpredictableGasLimitError extends EthersError<"UNPREDICTABLE_GAS_LIMIT"> {
transaction: any; //ErrorTransaction;
transaction: TransactionRequest;
}
export interface ActionRejectedError extends EthersError<"ACTION_REJECTED"> {
@ -286,10 +233,19 @@ export type CodedEthersError<T> =
/**
* Returns true if the %%error%% matches an error thrown by ethers
* that matches the error %%code%%.
*
* In TypeScript envornoments, this can be used to check that %%error%%
* matches an EthersError type, which means the expected properties will
* be set.
*
* @See [ErrorCodes](api:ErrorCode)
* @example
* try {
* // code....
* } catch (e) {
* if (isError(e, errors.CALL_EXCEPTION)) {
* if (isError(e, "CALL_EXCEPTION")) {
* console.log(e.data);
* }
* }
@ -298,14 +254,30 @@ export function isError<K extends ErrorCode, T extends CodedEthersError<K>>(erro
return (error && (<EthersError>error).code === code);
}
/**
* Returns true if %%error%% is a [CALL_EXCEPTION](api:CallExceptionError).
*/
export function isCallException(error: any): error is CallExceptionError {
return isError(error, "CALL_EXCEPTION");
}
/**
* Returns a new Error configured to the format ethers emits errors, with
* the %%message%%, [[api:ErrorCode]] %%code%% and additioanl properties
* for the corresponding EthersError.
*
* Each error in ethers includes the version of ethers, a
* machine-readable [[ErrorCode]], and depneding on %%code%%, additional
* required properties. The error message will also include the %%meeage%%,
* ethers version, %%code%% and all aditional properties, serialized.
*/
export function makeError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): T {
{
const details: Array<string> = [];
if (info) {
if ("message" in info || "code" in info || "name" in info) {
throw new Error(`value will overwrite populated values: ${ JSON.stringify(info) }`);
}
for (const key in info) {
const value = <any>(info[<keyof ErrorInfo<T>>key]);
try {
@ -326,18 +298,30 @@ export function makeError<K extends ErrorCode, T extends CodedEthersError<K>>(me
const create = ErrorConstructors[code] || Error;
const error = <T>(new create(message));
defineReadOnly(error, "code", code);
if (info) {
for (const key in info) {
defineReadOnly(error, <keyof T>key, <any>(info[<keyof ErrorInfo<T>>key]));
}
}
return <T>error;
}
/**
* Throws an EthersError with %%message%%, %%code%% and additional error
* info.
*
* @see [[api:makeError]]
*/
export function throwError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): never {
throw makeError(message, code, info);
}
/**
* Throws an [[api:ArgumentError]] with %%message%% for the parameter with
* %%name%% and the %%value%%.
*/
export function throwArgumentError(message: string, name: string, value: any): never {
return throwError(message, "INVALID_ARGUMENT", {
argument: name,
@ -345,11 +329,17 @@ export function throwArgumentError(message: string, name: string, value: any): n
});
}
/**
* A simple helper to simply ensuring provided arguments match expected
* constraints, throwing if not.
*
* In TypeScript environments, the %%check%% has been asserted true, so
* any further code does not need additional compile-time checks.
*/
export function assertArgument(check: unknown, message: string, name: string, value: unknown): asserts check {
if (!check) { throwArgumentError(message, name, value); }
}
export function assertArgumentCount(count: number, expectedCount: number, message: string = ""): void {
if (message) { message = ": " + message; }
@ -389,6 +379,9 @@ const _normalizeForms = ["NFD", "NFC", "NFKD", "NFKC"].reduce((accum, form) => {
return accum;
}, <Array<string>>[]);
/**
* Throws if the normalization %%form%% is not supported.
*/
export function assertNormalize(form: string): void {
if (_normalizeForms.indexOf(form) === -1) {
throwError("platform missing String.prototype.normalize", "UNSUPPORTED_OPERATION", {
@ -397,6 +390,12 @@ export function assertNormalize(form: string): void {
}
}
/**
* Many classes use file-scoped values to guard the constructor,
* making it effectively private. This facilitates that pattern
* by ensuring the %%givenGaurd%% matches the file-scoped %%guard%%,
* throwing if not, indicating the %%className%% if provided.
*/
export function assertPrivate(givenGuard: any, guard: any, className: string = ""): void {
if (givenGuard !== guard) {
let method = className, operation = "new";