{"id":25963381,"url":"https://github.com/neuroborus/ethers-tools","last_synced_at":"2025-03-04T20:30:03.843Z","repository":{"id":278231356,"uuid":"934849570","full_name":"neuroborus/ethers-tools","owner":"neuroborus","description":"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.","archived":false,"fork":false,"pushed_at":"2025-03-01T10:09:21.000Z","size":66,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-01T11:20:37.364Z","etag":null,"topics":["abi","blockchain","dapp","dapp-development","decode","ethereum","ethers","ethersjs","javascript","jsonrpc","multicall","node","smart-contracts","typescript","web3","zero-dependency"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/neuroborus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-18T14:01:12.000Z","updated_at":"2025-02-24T22:00:07.000Z","dependencies_parsed_at":null,"dependency_job_id":"20b1bc95-1001-43ee-8beb-a3acc15fe3a1","html_url":"https://github.com/neuroborus/ethers-tools","commit_stats":null,"previous_names":["neuroborus/ethers-tools"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuroborus%2Fethers-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuroborus%2Fethers-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuroborus%2Fethers-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuroborus%2Fethers-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neuroborus","download_url":"https://codeload.github.com/neuroborus/ethers-tools/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241827098,"owners_count":20026600,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["abi","blockchain","dapp","dapp-development","decode","ethereum","ethers","ethersjs","javascript","jsonrpc","multicall","node","smart-contracts","typescript","web3","zero-dependency"],"created_at":"2025-03-04T20:30:03.310Z","updated_at":"2025-03-04T20:30:03.818Z","avatar_url":"https://github.com/neuroborus.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ethers-tools\n\n[![npm version](https://badge.fury.io/js/ethers-tools.svg)](https://badge.fury.io/js/ethers-tools)\n\n## Description\n\n**ethers-tools** is a lightweight zero-dependency JavaScript/TypeScript library built on top of [ethers.js](https://github.com/ethers-io/ethers.js)\ndesigned to simplify **smart contract** interactions and [multicall3](https://www.multicall3.com/) aggregation\non the Ethereum blockchain and other EVM-compatible networks.  \nAll of these tools are compatible with TypeScript and pure JavaScript.  \nJSDoc is provided.\n\n### Installation\n\nFirst, you will need **ethers**. Then, you can install:\n\n`npm i ethers-tools`  \n`yarn add ethers-tools`  \n`pnpm add ethers-tools`\n\n## Quickstart\n\n```typescript\nimport { ethers } from 'ethers';\nimport { Contract, ContractCall, MulticallUnit } from 'ethers-tools';\n\nconst RPC_URL = 'https://eth.llamarpc.com';\nconst PROVIDER = new ethers.JsonRpcProvider(RPC_URL);\n\nconst RegistryAbi = '\u003cabi\u003e';\nclass RegistryContract extends Contract {\n  constructor() {\n    super(RegistryAbi, '0xbaA999AC55EAce41CcAE355c77809e68Bb345170', PROVIDER);\n  }\n\n  getAddressesProvidersListCall(): ContractCall {\n    return this.getCall('getAddressesProvidersList');\n  }\n\n  owner(): Promise\u003cstring\u003e {\n    return this.call\u003cstring\u003e('owner');\n  }\n\n  getOwnerCall(): ContractCall {\n    return this.getCall('owner');\n  }\n}\n\n// ....\n\nconst registry = new RegistryContract(PROVIDER);\nconst unit = new MulticallUnit(PROVIDER); // Unit-of-Work - like\n\nconst listCallTag = 'listCall';\nunit.add(listCallTag, registry.getAddressesProvidersListCall());\n\nconst ownerCallTag = 'ownerCall';\nunit.add(ownerCallTag, registry.getOwnerCall());\n\nconst result: boolean = await unit.run();\n\nconst list = unit.getArray\u003cstring[]\u003e(listCallTag);\nconst owner = unit.getSingle\u003cstring\u003e(ownerCallTag);\nconst directOwner = await registry.owner();\n\nconsole.log(result);\nconsole.log(owner === directOwner);\nconsole.log(JSON.stringify(list));\n```\n\n#### Expected output\n\n```\ntrue\ntrue\n[\"0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e\",\"0xcfBf336fe147D643B9Cb705648500e101504B16d\",\"0xeBa440B438Ad808101d1c451C1C5322c90BEFCdA\"]\n```\n\n## Contract\n\n### Description\n\n**Contract** is a parent class for contract classes that includes basic state getters and methods for calling the contract\ndirectly or obtaining a `ContractCall` for use in **MulticallUnit**. These methods can be parameterized.\n\n### Driver\n\nThe driver is either a `signer` or a `provider`. The contract's ability to make calls depends on it.\nAn error will occur if you try to call the contract without it, especially when making a non-static call without\nproviding an ethers `Signer` (e.g, `Wallet`) as the driver.\n\n### Fields\n\n- `.address` // Address of contract.\n- `.callable` // Flag that indicates whether calls (static or non-static) can be made.\n- `.readonly` // Flag that indicates whether only static calls are allowed (false if non-static calls are possible).\n- `.interface` // Ethers contract interface.\n- `.contract` // 'Bare' ethers Contract.\n- `.provider` // Ethers Provider.\n- `.signer` // Ethers Signer.\n\n### Methods\n\n```\nconstructor(\n  abi: Interface | InterfaceAbi, // ABI of the contract\n  address?: string, // Address of the contract\n  driver?: Signer | Provider,\n  callsOptions?: CallOptions, // Default call options for each call.\n);\n```\n\n- `call\u003cT = unknown\u003e(methodName: string, args?: any[], options?: CallOptions): Promise\u003cT\u003e` // Performs a single on-chain call for the contract. Throws an error if unable to execute.\n- `getCall(methodName: string, args?: any[], callData?: Partial\u003cContractCall\u003e): ContractCall` // Creates a `ContractCall` for `MulticallUnit`. Throws an error if unable to create. You can do force replacement with a `callData` parameter.\n\n#### CallOptions\n\n```typescript\nexport interface CallOptions {\n  forceMutability?: CallMutability; // By default, Contract/MulticallUnit automatically detects the mutability of the method(s). You can force it.\n  highPriorityTx?: boolean; // If activated, calls as \"high priority tx\": multiply gasPrice and gasLimit by multiplier. It takes additional requests to get them.\n  priorityOptions?: PriorityCallOptions; // Only matters if `highPriorityTx` is activated\n}\nexport interface PriorityCallOptions {\n  asynchronous?: boolean; // Can be a little faster if provider allows (simultaneously getting gasPrice \u0026 gasLimit).\n  chainId?: bigint; // Manually set. (Prevents replay attacks by ensuring the transaction is valid only for the intended blockchain network)\n  provideChainId?: boolean; // Automatic - additional async request. (Prevents replay attacks by ensuring the transaction is valid only for the intended blockchain network)\n  multiplier?: number; // Multiplier for gasPrise and gasLimit values.\n}\n```\n\n#### ContractCall\n\n```typescript\nexport type ContractCall = {\n  method: string; // Name of the method.\n  target: string; // Address of contract.\n  allowFailure: boolean; // Failure allowance - false by default (*).\n  callData: string; // Encoded function data - uses in multicall.\n  stateMutability: StateMutability; // Shows mutability of the method.\n  contractInterface: ethers.Interface; // Interface of the callable contract. Uses for answer decoding.\n};\nexport declare enum StateMutability {\n  View = 'view',\n  Pure = 'pure',\n  NonPayable = 'nonpayable',\n  Payable = 'payable',\n}\n```\n\n## MulticallUnit\n\n### Description\n\n**MulticallUnit** is a tool that takes a list of calls (`ContractCall`). When the `run()` method is invoked,\nit splits the stored calls into mutable and static, prioritizing mutable calls. It then processes them by stacks.\nThe size of the concurrently processed call stack for mutable and static calls can be adjusted separately via\n`MulticallOptions`, along with other parameters.\n\n### Tags\n\nTags serve as unique references for your specific calls.\nThey support [single values, arrays, and records](/types/entities/multicall-tags.d.ts).  \nThis can be useful for complex calls.\n\n```typescript\ntype Keyable = string | number | symbol;\ntype Tagable = Keyable | bigint;\n\nexport type MulticallTags = Tagable | Tagable[] | Record\u003cKeyable, Tagable\u003e;\n```\n\n### Fields\n\n- `.tags` // Array of provided tags.\n- `.calls` // Array of provided calls.\n- `.response` // Array of whole response.\n- `.success` // Flag that indicates whether all calls were successful.\n- `.static` // Flag that indicates whether all calls are static (view-only).\n- `.executing` // Flag that indicates if `run()` executing at the moment.\n\n### Methods\n\n```\nconstructor(\n  driver: Signer | Provider,\n  options?: MulticallOptions, // Default options for the each run.\n  multicallAddress?: string, // You can use any address. Useful for less popular networks.\n);\n```\n\n- `run(options?: MulticallOptions): void` // Completely clears the Unit for reuse.\n- `add(tags: MulticallTags, contractCall: ContractCall): MulticallTags` // Add new call.\n- `run(): Promise\u003cboolean\u003e` // Executes the multicall operation.\n- `getSingle\u003cT\u003e(tags: MulticallTags): T | undefined` // Get single primitive value as result.\n- `getArray\u003cT\u003e(tags: MulticallTags, deep?: boolean): T | undefined` // Get array as result.\n- `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.\n- `isSuccess(tags: MulticallTags): boolean | undefined` // Check if call finished successfully.\n\n#### MulticallOptions\n\n```typescript\nexport interface MulticallOptions {\n  maxStaticCallsStack?: number; // The maximum size of one static execution. If it overfills, the multicall performs additional executions. DEFAULT: 50\n  maxMutableCallsStack?: number; // The maximum size of one mutable execution. If it overfills, the multicall performs additional executions. DEFAULT: 10\n  forceMutability?: CallMutability; // Allows to force mutability. It will try to call as static or mutable if you want to.\n  waitForTxs?: boolean; // Wait for every transaction. Turned on by default for nonce safety. DEFAULT: true\n  highPriorityTxs?: boolean; // You can make priority transaction when it is necessary. Requires more calls, but will be processed more quickly.\n  priorityOptions?: PriorityCallOptions; // Only matters if `highPriorityTxs` is turned on.\n}\nexport enum CallMutability {\n  Static = 'STATIC',\n  Mutable = 'MUTABLE',\n}\n```\n\n#### Warning\n\nSince in the case of a **mutable call**, the result is not returned but rather **a transaction or a receipt**,\n`getRaw` for a single **call stack** will provide the same information.\nAs a result, using `allowFailure` will lead to inconsistent results.\nWhen using `allowFailure`, _make sure that you do not need to track the outcome of a specific execution_.\n\n## Other\n\n#### Helpers\n\n```typescript\nexport declare const priorityCall: (\n  // Function that allows making custom priority calls\n  provider: Provider,\n  signer: Signer,\n  contract: Contract,\n  method: string,\n  args: any[],\n  options: PriorityCallOptions\n) =\u003e Promise\u003cTransactionResponse\u003e;\n```\n\n```typescript\nexport declare const waitForAddressTxs: (\n  // Function that waits for the end of all users transactions\n  address: string,\n  provider: Provider,\n  delayMs?: number\n) =\u003e Promise\u003cvoid\u003e;\n```\n\n```typescript\nexport declare const isStaticMethod: (\n  // Accepts mutability and says if method is static\n  state: StateMutability | string\n) =\u003e boolean;\n```\n\n```typescript\nexport declare const isStaticArray: (calls: ContractCall[]) =\u003e boolean; // Accepts array of ContractCalls and says if all methods are static\n```\n\n#### Entities\n\n```typescript\nexport enum Chain { // Contains more than 250 different chains. Supports JS as struct. All of these chains right now supports multicall3.\n  Mainnet = 1,\n  Kovan = 42,\n  Rinkeby = 4,\n  // And other 250+ chains...\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneuroborus%2Fethers-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneuroborus%2Fethers-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneuroborus%2Fethers-tools/lists"}