Skip to content

Instantly share code, notes, and snippets.

@gosuto-inzasheru
Last active June 27, 2022 12:45
Show Gist options
  • Save gosuto-inzasheru/f1be00d6b487f4faa585b00d23f805f1 to your computer and use it in GitHub Desktop.
Save gosuto-inzasheru/f1be00d6b487f4faa585b00d23f805f1 to your computer and use it in GitHub Desktop.
generates a clean .sol interface file for any solidity contract address verified on etherscan
import os
import re
import requests
import sys
from dotenv import load_dotenv
# https://etherscan.io/contract-license-types
# https://spdx.org/licenses/
ETHERSCAN_TO_SPDX= {
'Unlicense': 'Unlicense',
'MIT': 'MIT',
'GNU GPLv2': 'GPL-2.0',
'GNU GPLv3': 'GPL-3.0',
'GNU LGPLv2.1': 'LGPL-2.1',
'GNU LGPLv3': 'LGPL-3.0',
'BSD-2-Clause': 'BSD-2-Clause',
'BSD-3-Clause': 'BSD-3-Clause',
'MPL-2.0': 'MPL-2.0',
'OSL-3.0': 'OSL-3.0',
'Apache-2.0': 'Apache-2.0',
'GNU AGPLv3': 'AGPL-3.0',
'BSL 1.1': 'BUSL-1.1',
}
def get_from_etherscan(address):
r = requests.get('https://api.etherscan.io/api', params={
'module': 'contract',
'action': 'getsourcecode',
'address': address,
'apikey': os.getenv('ETHERSCAN_TOKEN'),
}).json()
if r['status'] != '1':
raise Exception(r['result'])
result = r['result'][0]
if result['Proxy'] != '0':
return get_from_etherscan(result['Implementation'])
contract = {}
contract['name'] = result['ContractName']
try:
contract['license'] = ETHERSCAN_TO_SPDX[result['LicenseType']]
except KeyError:
contract['license'] = None
contract['version'] = re.findall(
r'v(\d+\.\d+\.\d+)\+', result['CompilerVersion']
)[0]
contract['abi'] = result['ABI']
return contract
def main(address):
load_dotenv()
dump_dir = 'interfaces/autogenerated/'
os.makedirs(dump_dir, exist_ok=True)
contract = get_from_etherscan(address)
dump_tmp = f'{dump_dir}I{contract["name"]}.tmp'
with open(dump_tmp, 'w') as f:
f.write(contract['abi'])
command = f'cat {dump_tmp} | abi-to-sol --validate -S -A'
if contract['license']:
command += f' -L={contract["license"]}'
if contract['version']:
command += f' -V=^{contract["version"]}'
command += f' I{contract["name"]} > {dump_dir}I{contract["name"]}.sol'
print(command)
os.system(command)
os.remove(dump_tmp)
if __name__ == '__main__':
main(sys.argv[1])
@gosuto-inzasheru
Copy link
Author

INSTALLATION

  • copypasta generate_interface.py to your brownie dir
  • install the excellent abi-to-sol:
npm install abi-to-sol
  • make sure to have installed prettier and its solidity plugin alongside abi-to-sol:
npm install --save-dev prettier prettier-plugin-solidity

USAGE

python generate_interface.py 0xb2Bf1d48F2C2132913278672e6924efda3385de2

it will generate a clean .sol interface file in interfaces/autogenerated/.

TODO

  • support vyper contracts (eg 0x1Ba86c33509013c937344f6e231DA2E63ea45197)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment