An open API service indexing awesome lists of open source software.

https://github.com/neuroborus/ethers-tools

ethers-tools is a zero-dependencies lightweight JavaScript/TypeScript library built on top of ethers.js designed to simplify smart contract interactions and multicall3 aggregation on the Ethereum blockchain and compatible EVM networks.
https://github.com/neuroborus/ethers-tools

abi blockchain dapp dapp-development decode ethereum ethers ethersjs javascript jsonrpc multicall node smart-contracts typescript web3 zero-dependency

Last synced: over 1 year ago
JSON representation

ethers-tools is a zero-dependencies lightweight JavaScript/TypeScript library built on top of ethers.js designed to simplify smart contract interactions and multicall3 aggregation on the Ethereum blockchain and compatible EVM networks.

Awesome Lists containing this project

README

          

# ethers-tools

[![npm version](https://badge.fury.io/js/ethers-tools.svg)](https://badge.fury.io/js/ethers-tools)

## Description

**ethers-tools** is a lightweight zero-dependency JavaScript/TypeScript library built on top of [ethers.js](https://github.com/ethers-io/ethers.js)
designed to simplify **smart contract** interactions and [multicall3](https://www.multicall3.com/) aggregation
on the Ethereum blockchain and other EVM-compatible networks.
All of these tools are compatible with TypeScript and pure JavaScript.
JSDoc is provided.

### Installation

First, you will need **ethers**. Then, you can install:

`npm i ethers-tools`
`yarn add ethers-tools`
`pnpm add ethers-tools`

## Quickstart

```typescript
import { ethers } from 'ethers';
import { Contract, ContractCall, MulticallUnit } from 'ethers-tools';

const RPC_URL = 'https://eth.llamarpc.com';
const PROVIDER = new ethers.JsonRpcProvider(RPC_URL);

const RegistryAbi = '';
class RegistryContract extends Contract {
constructor() {
super(RegistryAbi, '0xbaA999AC55EAce41CcAE355c77809e68Bb345170', PROVIDER);
}

getAddressesProvidersListCall(): ContractCall {
return this.getCall('getAddressesProvidersList');
}

owner(): Promise {
return this.call('owner');
}

getOwnerCall(): ContractCall {
return this.getCall('owner');
}
}

// ....

const registry = new RegistryContract(PROVIDER);
const unit = new MulticallUnit(PROVIDER); // Unit-of-Work - like

const listCallTag = 'listCall';
unit.add(listCallTag, registry.getAddressesProvidersListCall());

const ownerCallTag = 'ownerCall';
unit.add(ownerCallTag, registry.getOwnerCall());

const result: boolean = await unit.run();

const list = unit.getArray(listCallTag);
const owner = unit.getSingle(ownerCallTag);
const directOwner = await registry.owner();

console.log(result);
console.log(owner === directOwner);
console.log(JSON.stringify(list));
```

#### Expected output

```
true
true
["0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e","0xcfBf336fe147D643B9Cb705648500e101504B16d","0xeBa440B438Ad808101d1c451C1C5322c90BEFCdA"]
```

## Contract

### Description

**Contract** is a parent class for contract classes that includes basic state getters and methods for calling the contract
directly or obtaining a `ContractCall` for use in **MulticallUnit**. These methods can be parameterized.

### Driver

The driver is either a `signer` or a `provider`. The contract's ability to make calls depends on it.
An error will occur if you try to call the contract without it, especially when making a non-static call without
providing an ethers `Signer` (e.g, `Wallet`) as the driver.

### Fields

- `.address` // Address of contract.
- `.callable` // Flag that indicates whether calls (static or non-static) can be made.
- `.readonly` // Flag that indicates whether only static calls are allowed (false if non-static calls are possible).
- `.interface` // Ethers contract interface.
- `.contract` // 'Bare' ethers Contract.
- `.provider` // Ethers Provider.
- `.signer` // Ethers Signer.

### Methods

```
constructor(
abi: Interface | InterfaceAbi, // ABI of the contract
address?: string, // Address of the contract
driver?: Signer | Provider,
callsOptions?: CallOptions, // Default call options for each call.
);
```

- `call(methodName: string, args?: any[], options?: CallOptions): Promise` // Performs a single on-chain call for the contract. Throws an error if unable to execute.
- `getCall(methodName: string, args?: any[], callData?: Partial): ContractCall` // Creates a `ContractCall` for `MulticallUnit`. Throws an error if unable to create. You can do force replacement with a `callData` parameter.

#### CallOptions

```typescript
export interface CallOptions {
forceMutability?: CallMutability; // By default, Contract/MulticallUnit automatically detects the mutability of the method(s). You can force it.
highPriorityTx?: boolean; // If activated, calls as "high priority tx": multiply gasPrice and gasLimit by multiplier. It takes additional requests to get them.
priorityOptions?: PriorityCallOptions; // Only matters if `highPriorityTx` is activated
}
export interface PriorityCallOptions {
asynchronous?: boolean; // Can be a little faster if provider allows (simultaneously getting gasPrice & gasLimit).
chainId?: bigint; // Manually set. (Prevents replay attacks by ensuring the transaction is valid only for the intended blockchain network)
provideChainId?: boolean; // Automatic - additional async request. (Prevents replay attacks by ensuring the transaction is valid only for the intended blockchain network)
multiplier?: number; // Multiplier for gasPrise and gasLimit values.
}
```

#### ContractCall

```typescript
export type ContractCall = {
method: string; // Name of the method.
target: string; // Address of contract.
allowFailure: boolean; // Failure allowance - false by default (*).
callData: string; // Encoded function data - uses in multicall.
stateMutability: StateMutability; // Shows mutability of the method.
contractInterface: ethers.Interface; // Interface of the callable contract. Uses for answer decoding.
};
export declare enum StateMutability {
View = 'view',
Pure = 'pure',
NonPayable = 'nonpayable',
Payable = 'payable',
}
```

## MulticallUnit

### Description

**MulticallUnit** is a tool that takes a list of calls (`ContractCall`). When the `run()` method is invoked,
it splits the stored calls into mutable and static, prioritizing mutable calls. It then processes them by stacks.
The size of the concurrently processed call stack for mutable and static calls can be adjusted separately via
`MulticallOptions`, along with other parameters.

### Tags

Tags serve as unique references for your specific calls.
They support [single values, arrays, and records](/types/entities/multicall-tags.d.ts).
This can be useful for complex calls.

```typescript
type Keyable = string | number | symbol;
type Tagable = Keyable | bigint;

export type MulticallTags = Tagable | Tagable[] | Record;
```

### Fields

- `.tags` // Array of provided tags.
- `.calls` // Array of provided calls.
- `.response` // Array of whole response.
- `.success` // Flag that indicates whether all calls were successful.
- `.static` // Flag that indicates whether all calls are static (view-only).
- `.executing` // Flag that indicates if `run()` executing at the moment.

### Methods

```
constructor(
driver: Signer | Provider,
options?: MulticallOptions, // Default options for the each run.
multicallAddress?: string, // You can use any address. Useful for less popular networks.
);
```

- `run(options?: MulticallOptions): void` // Completely clears the Unit for reuse.
- `add(tags: MulticallTags, contractCall: ContractCall): MulticallTags` // Add new call.
- `run(): Promise` // Executes the multicall operation.
- `getSingle(tags: MulticallTags): T | undefined` // Get single primitive value as result.
- `getArray(tags: MulticallTags, deep?: boolean): T | undefined` // Get array as result.
- `getRaw(tags: MulticallTags): string | TransactionResponse | TransactionReceipt | undefined;` // Get the raw multicall result. Returns TransactionResponse if a mutable call has been processed. Returns TransactionReceipt if the `waitForTxs` flag was turned on.
- `isSuccess(tags: MulticallTags): boolean | undefined` // Check if call finished successfully.

#### MulticallOptions

```typescript
export interface MulticallOptions {
maxStaticCallsStack?: number; // The maximum size of one static execution. If it overfills, the multicall performs additional executions. DEFAULT: 50
maxMutableCallsStack?: number; // The maximum size of one mutable execution. If it overfills, the multicall performs additional executions. DEFAULT: 10
forceMutability?: CallMutability; // Allows to force mutability. It will try to call as static or mutable if you want to.
waitForTxs?: boolean; // Wait for every transaction. Turned on by default for nonce safety. DEFAULT: true
highPriorityTxs?: boolean; // You can make priority transaction when it is necessary. Requires more calls, but will be processed more quickly.
priorityOptions?: PriorityCallOptions; // Only matters if `highPriorityTxs` is turned on.
}
export enum CallMutability {
Static = 'STATIC',
Mutable = 'MUTABLE',
}
```

#### Warning

Since in the case of a **mutable call**, the result is not returned but rather **a transaction or a receipt**,
`getRaw` for a single **call stack** will provide the same information.
As a result, using `allowFailure` will lead to inconsistent results.
When using `allowFailure`, _make sure that you do not need to track the outcome of a specific execution_.

## Other

#### Helpers

```typescript
export declare const priorityCall: (
// Function that allows making custom priority calls
provider: Provider,
signer: Signer,
contract: Contract,
method: string,
args: any[],
options: PriorityCallOptions
) => Promise;
```

```typescript
export declare const waitForAddressTxs: (
// Function that waits for the end of all users transactions
address: string,
provider: Provider,
delayMs?: number
) => Promise;
```

```typescript
export declare const isStaticMethod: (
// Accepts mutability and says if method is static
state: StateMutability | string
) => boolean;
```

```typescript
export declare const isStaticArray: (calls: ContractCall[]) => boolean; // Accepts array of ContractCalls and says if all methods are static
```

#### Entities

```typescript
export enum Chain { // Contains more than 250 different chains. Supports JS as struct. All of these chains right now supports multicall3.
Mainnet = 1,
Kovan = 42,
Rinkeby = 4,
// And other 250+ chains...
}
```