openzeppelin-contracts icon indicating copy to clipboard operation
openzeppelin-contracts copied to clipboard

Add a chain detection library

Open CodeSandwich opened this issue 2 years ago • 2 comments
trafficstars

🧐 Motivation Some contracts need to act differently depending on the chain they're deployed on. E.g. the ecosystem may have different addresses. If you don't want to outsource all these differences to a deployment script, you can always look up block.chainid, but that's fragile with a new magic value per blockchain.

📝 Details It'd be great to have a library for detecting chains. Just a bunch of constants like ETHEREUM = 1 would be a good bare minimum to avoid magic numbers. On top of that there may or may not be convenience functions like isEthereum() returns (bool). There may or may not be constants with string chain names, it could be useful for dynamic generation of URLs and if unused, shouldn't bloat the bytecode. There may or may not be a function chainName() returns (string memory) to streamline names handling, but it may unavoidably bloat the bytecode with all the available names.

CodeSandwich avatar Apr 18 '23 13:04 CodeSandwich

Hey @CodeSandwich, do you have a specific use case in which block.chainid doesn't serve the purpose you're looking for? I know some chains may report a different CHAINID inside their virtual machine implementation to the returned via eth_chainId JSON-RPC call so this may also become a liability to deal with in the future because it'll require support.

Having an example in which is clearly better to use the proposed chainName() could help to the discussion.

ernestognw avatar Apr 22 '23 12:04 ernestognw

Sure! Just to be clear, the core of this proposal are the constants with chain IDs, the rest like chainName are nice extras which may or may not be worth adding.

Use case for constants with chain IDs

The real world use case I have is an integration with Chainlink, but other multi chain protocols will benefit similarly. On each chain the Link token has a different address. In order to pick the correct one I have this section in the constructor:

if (block.chainid == 1) _linkToken = 0x514910771AF9Ca656af840dff83E8264EcF986CA;
else if (block.chainid == 5) _linkToken = 0x326C977E6efc84E512bB9C30f76E30c160eD06FB;
else revert("Unsupported chain");

In order to review the code one needs to look up the chain IDs of the mainnet (1) and Goerli (5). Sure, 1 and 5 can be stored as nicely named constants, but then one needs to trust these constants. The perfect solution would be to have them in OpenZeppelin, something along these lines:

import {ChainIds} from "openzeppelin-contracts/utils/ChainIds.sol";
...
if (block.chainid == ChainIds.Ethereum) _linkToken = 0x514910771AF9Ca656af840dff83E8264EcF986CA;
else if (block.chainid == ChainIds.Goerli) _linkToken = 0x326C977E6efc84E512bB9C30f76E30c160eD06FB;
else revert("Unsupported chain");

This may be further cleaned up if we have helper functions (a nice-to-have extra):

import {ChainIds} from "openzeppelin-contracts/utils/ChainIds.sol";
...
if (ChainIds.isEthereum()) _linkToken = 0x514910771AF9Ca656af840dff83E8264EcF986CA;
else if (ChainIds.isGoerli()) _linkToken = 0x326C977E6efc84E512bB9C30f76E30c160eD06FB;
else revert("Unsupported chain");

Use case for chain names

I need to build URLs on-chain for off-chain resources. In my particular case these are paths for retrieving data by a Chainlink oracle:

sring memory chainName;
if (block.chainid == 1) chainName = "ethereum;
else if (block.chainid == 5) chainName = "goerli"
else revert("Unsupported chain");
return string.concat("drips,", chainName, ",ownedBy");

A perfect solution would be to have something like this:

import {ChainIds} from "openzeppelin-contracts/utils/ChainIds.sol";
...
return string.concat("drips,", ChainIds.chainName(), ",ownedBy");

Other off-chain integrations like NFT's tokenURI may need the chain name to cleanly differentiate resources and chainName would allow some code cleaning up. This is a nice-to-have extra, I can't stress enough how the constants with chain IDs are the core of this proposal.

CodeSandwich avatar Apr 22 '23 21:04 CodeSandwich

Hello @CodeSandwich

There are currently 300 chains listed here and the number is continuously growing. While maintaining an up to date list in a "solidity friendly" format might have some interest, I don't feel it falls in the scope of our contracts.

That could be an interesting side project, compile such a list from the file linked above, and distribute it automatically.

Amxx avatar May 23 '23 09:05 Amxx