Giter VIP home page Giter VIP logo

hardhat-abi-exporter's Introduction

Hardhat ABI Exporter

Export Ethereum smart contract ABIs on compilation via Hardhat.

Versions of this plugin prior to 2.0.0 were released as buidler-abi-exporter.

Installation

npm install --save-dev hardhat-abi-exporter
# or
yarn add --dev hardhat-abi-exporter

Usage

Load plugin in Hardhat config:

require('hardhat-abi-exporter');

Add configuration under the abiExporter key:

option description default
path path to ABI export directory (relative to Hardhat root) './abi'
runOnCompile whether to automatically export ABIs during compilation false
clear whether to delete old ABI files in path on compilation false
flat whether to flatten output directory (may cause name collisions) false
only Array of String matchers used to select included contracts, defaults to all contracts if length is 0 []
except Array of String matchers used to exclude contracts []
spacing number of spaces per indentation level of formatted output 2
pretty whether to use interface-style formatting of output for better readability false
format format type ("json", "minimal", "fullName"). Alternative to pretty json
filter Function with signature (abiElement: any, index: number, abi: any, fullyQualifiedName: string) => boolean used to filter elements from each exported ABI () => true
rename Function with signature (sourceName: string, contractName: string) => string used to rename an exported ABI (incompatible with flat option) undefined

Note that the configuration formatted as either a single Object, or an Array of objects. An Array may be used to specify multiple outputs.

abiExporter: {
  path: './data/abi',
  runOnCompile: true,
  clear: true,
  flat: true,
  only: [':ERC20$'],
  spacing: 2,
  pretty: true,
  format: "minimal",
}

// or

abiExporter: [
  {
    path: './abi/pretty',
    pretty: true,
  },
  {
    path: './abi/ugly',
    pretty: false,
  },
]

// or

abiExporter: [
  {
    path: './abi/json',
    format: "json",
  },
  {
    path: './abi/minimal',
    format: "minimal",
  },
  {
    path: './abi/fullName',
    format: "fullName",
  },
]

The included Hardhat tasks may be run manually:

npx hardhat export-abi
npx hardhat clear-abi
# or
yarn run hardhat export-abi
yarn run hardhat clear-abi

By default, the hardhat compile task is run before exporting ABIs. This behavior can be disabled with the --no-compile flag:

npx hardhat export-abi --no-compile
# or
yarn run hardhat export-abi --no-compile

The path directory will be created if it does not exist.

The clear option is set to false by default because it represents a destructive action, but should be set to true in most cases.

ABIs files are saved in the format [CONTRACT_NAME].json.

hardhat-abi-exporter's People

Contributors

6str avatar cruzdanilo avatar dependabot[bot] avatar itsnickbarry avatar juztamau5 avatar mrtenz avatar phated avatar thelostone-mc avatar will-holley avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

hardhat-abi-exporter's Issues

Export lightweight ABIs

Hi there, thanks for this plugin!

Would be great to have the option to export only some functions and events to have lighter ABIs...
Is this feature would makes sense on this plugin? What do you recommend to implement it?
It'd be happy to contribute on this one.

Best regards,
Luca

Contract ABI format

Hi, I am getting this ABI output from running yarn run hardhat export-abi. It does not look like a valid contract ABI format.

[
  "constructor(string,string,uint256)",
  "event Approval(address indexed,address indexed,uint256)",
  "event Transfer(address indexed,address indexed,uint256)",
  "function allowance(address,address) view returns (uint256)",
  "function approve(address,uint256) returns (bool)",
  "function balanceOf(address) view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function decreaseAllowance(address,uint256) returns (bool)",
  "function increaseAllowance(address,uint256) returns (bool)",
  "function name() view returns (string)",
  "function symbol() view returns (string)",
  "function totalSupply() view returns (uint256)",
  "function transfer(address,uint256) returns (bool)",
  "function transferFrom(address,address,uint256) returns (bool)"
]

contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract ERC20Contract is ERC20 {
    constructor(
        string memory name,
        string memory symbol,
        uint256 supply
    ) public ERC20(name, symbol) {
        _mint(msg.sender, supply);
    }
}

packages

"hardhat": "2.2.1",
"hardhat-abi-exporter": "^2.6.1",

node version

node --version 
v16.13.0

[suggestion] add bin-exporter

Hello, author! I have a suggestion: Maybe, the plugin could be added a function: export .bin file, Why?

Becouse .abi + .bin could generate .go/.java/.objc abi-object-file by abigen(thus hardhat-abi-exporter plugin will be more useful, not only for ethers or web3js), eg:

[^ plus]: .bin file content is bytecode without 0x in raw Oracle.json, like this:

{
  // ...
  "bytecode": "0x60806040523480156200001157600080fd5b5060405162001ac638038062001...",
  "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100a9576000...",
  "linkReferences": {},
  "deployedLinkReferences": {}
}
                                          โ†“โ†“โ†“โ†“
60806040523480156200001157600080fd5b50604051620031d3380380620031d383398181016040528101...

( :: output File name suffix is not important, it's up to you, but maybe .bin for bytecode and .abi for abi are more accurate)
'

'

'
abigen target file like this:

abigen --bin Oracle.bin --abi Oracle.abi --pkg oracle -o oracle.go
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.

package oracle

import (
	"errors"
	"math/big"
	"strings"

	ethereum "github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/event"
)

// Reference imports to suppress errors if they are not otherwise used.
var (
	_ = errors.New
	_ = big.NewInt
	_ = strings.NewReader
	_ = ethereum.NotFound
	_ = bind.Bind
	_ = common.Big1
	_ = types.BloomLookup
	_ = event.NewSubscription
)

// OracleMetaData contains all meta data concerning the Oracle contract.
var OracleMetaData = &bind.MetaData{
	ABI: "[{\"inputs\":[],\"name\":\"ETH\",\"outputs\":...",
}

// OracleABI is the input ABI used to generate the binding from.
// Deprecated: Use OracleMetaData.ABI instead.
var OracleABI = OracleMetaData.ABI

// Oracle is an auto generated Go binding around an Ethereum contract.
type Oracle struct {
	OracleCaller     // Read-only binding to the contract
	OracleTransactor // Write-only binding to the contract
	OracleFilterer   // Log filterer for contract events
}
// has more...

salute!

Support excluding contracts that match a pattern or are in a specific directory?

Thanks for this tool, it's super helpful. One feature I wish it supported is passing in a regex pattern and/or specifying specific subfolders to exclude in the except array.

For example if I had a file structure like:
contracts
L interfaces
..L IERC20.sol
..L IERC721.sol
MyContract.sol
OtherContract.sol

It would be great if I had a way to exclude all of the contracts in the interfaces directory without specifying each of the files individually. Would you consider adding support for this feature?

hardhat-abi-exporter: duplicate output destination:

I am trying to deploy a contract, and each version has the same error message, deleting the ABI folder does nothing, deleting all cache folders and other compile time folders also doesn't work.

Error in plugin hardhat-abi-exporter: duplicate output destination: /Users/computer/folder/testCoin-4/abis/Ownable.json

I have tried running clear & also trying a fresh install. I have also changed folder names, and moved their destination, starting from a fresh starter also doesn't help.

abiExporter: { path: "./abis", runOnCompile: true, clear: true, flat: true, only: [], spacing: 2, pretty: true, },

Include bytecode files in export

Hi, I was wondering would it be possible to also have a flag to also generate files with bytecode for the contract? From what I understand they already exist in the artifacts.

Such a feature would save some time when generating abi files to be used in for example bindings for golang

`hardhat clean` doesn't remove abis

I would expect the hardhat clean command to remove the generated abis, the same way that typechain hooks into the clean command and removes the code that it generates. Would be helpful when you've borked something and want to confirm that the state is fresh.

Error: ENOTEMPTY: directory not empty, rmdir

When there are files in the output directory the plugin fails, even though I have clear set to true in config.

Full error:

{ Error: ENOTEMPTY: directory not empty, rmdir '/Users/solar/dev/eth/tug-of-war/solidity/../dapp/src/abi'
    at Object.rmdirSync (fs.js:684:3)
    at OverriddenTaskDefinition._action (/Users/solar/dev/eth/tug-of-war/solidity/node_modules/hardhat-abi-exporter/index.js:31:8)
  errno: -66,
  syscall: 'rmdir',
  code: 'ENOTEMPTY',
  path: '/Users/solar/dev/eth/tug-of-war/solidity/../dapp/src/abi' }

to support `.ts` extension

Hi! ๐Ÿ‘‹

Firstly, thanks for your work on this project! ๐Ÿ™‚

Today I used patch-package to patch [email protected] for the project I'm working on.

Here is the diff that solved my problem:

diff --git a/node_modules/hardhat-abi-exporter/index.d.ts b/node_modules/hardhat-abi-exporter/index.d.ts
index 7b44cdf..baeb105 100644
--- a/node_modules/hardhat-abi-exporter/index.d.ts
+++ b/node_modules/hardhat-abi-exporter/index.d.ts
@@ -12,6 +12,8 @@ interface AbiExporterUserConfig {
   format?: string,
   filter?: (abiElement: any, index: number, abi: any, fullyQualifiedName: string) => boolean,
   rename?: (sourceName: string, contractName: string) => string,
+  fileExtension?: '.json' | '.ts',
+  renameABI?: (name: string) => string,
 }
 
 declare module 'hardhat/types/config' {
@@ -32,6 +34,8 @@ declare module 'hardhat/types/config' {
       format?: string,
       filter: (abiElement: any, index: number, abi: any, fullyQualifiedName: string) => boolean,
       rename: (sourceName: string, contractName: string) => string,
+      fileExtension?: '.json' | '.ts',
+      renameABI?: (name: string) => string,
     }[]
   }
 }
diff --git a/node_modules/hardhat-abi-exporter/tasks/export_abi.js b/node_modules/hardhat-abi-exporter/tasks/export_abi.js
index d0c6ccd..9fdaa4c 100644
--- a/node_modules/hardhat-abi-exporter/tasks/export_abi.js
+++ b/node_modules/hardhat-abi-exporter/tasks/export_abi.js
@@ -61,9 +61,9 @@ subtask(
     const destination = path.resolve(
       outputDirectory,
       config.rename(sourceName, contractName)
-    ) + '.json';
+    ) + config.fileExtension || '.json';
 
-    outputData.push({ abi, destination });
+    outputData.push({ abi, destination, contractName });
   }));
 
   outputData.reduce(function (acc, { destination }) {
@@ -79,8 +79,15 @@ subtask(
     await hre.run('clear-abi-group', { path: config.path });
   }
 
-  await Promise.all(outputData.map(async function ({ abi, destination }) {
+  await Promise.all(outputData.map(async function ({ abi, destination, contractName }) {
     await fs.promises.mkdir(path.dirname(destination), { recursive: true });
-    await fs.promises.writeFile(destination, `${JSON.stringify(abi, null, config.spacing)}\n`, { flag: 'w' });
+    let fileContent = '';
+    if (config.fileExtension === '.ts') {
+      const name = config.renameABI ? config.renameABI(contractName) : `ABI_${contractName}`;
+      fileContent = `const ${name} = ${JSON.stringify(abi, null, config.spacing)} as const;\nexport default ${name};\n`;
+    } else {
+      fileContent = `${JSON.stringify(abi, null, config.spacing)}\n`;
+    }
+    await fs.promises.writeFile(destination, fileContent, { flag: 'w' });
   }));
 });

This issue body was partially generated by patch-package.

Feature Request: add feature to combine all ABIs into one file

Hi
Thanks for such a great library!
I was wondering if there would be a feature to put all flattened ABIs into one file.
reasons:

  1. currently events and errors are not getting into ABI if they are imported from a library; so we can combine all ABIs to cover all events and errors.
  2. If you are using the Diamond EIP, it is really helpful to use one ABI for all the facets.

Duplicate ABI error thrown for unknown reason

throw new HardhatPluginError(`duplicate output destination: ${ destination }`);

This line throws when I compile a combination of Uniswap v3 core and periphery contract libraries. I get:

Error in plugin hardhat-abi-exporter: duplicate output destination: .../uniswap/v3-core/abi/IUniswapV3Factory.json

when compiling, despite there only being one interface in the whole repo named IUniswapV3Factory.

Disabling this line throws no error.

Perhaps the error is unnecessary since a set is used anyway, so duplicate abi's will just be ignored anyway? or perhaps the abi's should be diffed instead (e.g. using lodash.isEqual) and if the diff does not match, then the error thrown.

Will this work for vyper?

The description explicitly mentions solidity but isn't ABI generation only dependent on the bytecode?
Will it work for vyper too?

DeprecationWarning

Seeing this warning on the latest LTS version of node (16.13.0):

(node:21035) [DEP0147] DeprecationWarning: In future versions of Node.js, fs.rmdir(path, { recursive: true }) will be removed. Use fs.rm(path, { recursive: true }) instead

Should be a small fix. If possible!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.