protofire / eth-cli

CLI swiss army knife for Ethereum developers
https://www.npmjs.com/package/eth-cli
MIT License
239 stars 40 forks source link

Make it possible to use repl getting the contract's abi from etherscan when is possible #72

Open nicosampler opened 5 years ago

nicosampler commented 5 years ago

There are some cases where the contract source code have been verified in Etherscan, for example this one dai, in those cases would be great if there is an option to start repl mode without passing the abi explicitly. Like how is it doing for ERC20 tokens.

Perhaps it could be something like: eth repl etherscanAbi@contractAddress

fvictorio commented 5 years ago

Some notes for whomever implements this (including maybe my future self) after a failed attempt at doing it.

Interface

I think the most ergonomic interface is:

eth repl --mainnet https://etherscan.io/token/0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359

You could argue that the --mainnet is redundant, since the network could be inferred from the etherscan URL, but let's just not go there. Note that the token in the URL could also be address and the result should be pretty much the same.

Also, I have no idea what name should be used for the loaded contract.

Detecting URLs as arguments

Here's a working RegExp:

const etherscanUrlPattern = new RegExp('^https?://etherscan.io/(?:address|token)/((?:0x)?\\w{40})')

And you can use it like this to extract the address:

    const etherscanMatch = arg.match(etherscanUrlPattern)
    if (etherscanMatch) {
      const address = etherscanMatch[1]
    }

Obtaining the ABI

After obtaining the address, you can use this endpoint for getting the ABI:

https://api.etherscan.io/api?module=contract&action=getabi&address=${address}

This might be an unauthorized use of the Etherscan API, I don't know. If that's the case, we could require an Etherscan API Key, although that would make this feature a lot less useful. Alternatively, we could bundle an API Key with eth-cli, if that's allowed.

Where to fetch the ABI

This is the part where I stumbled. I tried to do it inside loadABI, but that means converting it to an async function, and that caused a lot of other dependent functions to be converted too. I think we should do a big refactor and make a function that receives the raw arg and returns an object with the name, address and ABI. This function should be completely tested, since it would implement a logic that will be used in a lot of places.