Skip to content
This repository has been archived by the owner on Apr 27, 2022. It is now read-only.

Verify xDai deployments on BlockScout #340

Closed
nlordell opened this issue Jan 13, 2021 · 12 comments
Closed

Verify xDai deployments on BlockScout #340

nlordell opened this issue Jan 13, 2021 · 12 comments
Labels
on hold Waiting for alignment of planets

Comments

@nlordell
Copy link
Contributor

☝️

@fedgiac
Copy link
Contributor

fedgiac commented Mar 2, 2021

A description of my attempts to get our contracts verified on Blockscout.

Unlike Etherscan, Blockscout does not accept full Solc compilation input for contract verification (issue). This means that the source code of the verified contracts must be flattened (which requires minor changes to the contract code to remove circular dependencies).

However, in our project we compile simultaneously contracts that use abicoder v2 and other contracts that don't. Since pragma abicoder v2 can only be set at a file level, it means that the entire file would be treated as if compiled with abicoder v2, which makes the compiled bytecode differ from the deployed one. This is also the case if we prepend pragma abicoder v2 to all the contracts in our repo (should we do this anyway by the way?).

Blockscout is also integrated with Sourcify, a project that aims to make contract source verification less centralized (example of a contract verified with Sourcify on Blockscout).
According to my testing, a contract that is verified on Sourcify is also (after a while, ≈1h?) verified on Blockscout. Blockscout also provides this integration on its interface: "Verify & Publish" -> "Verification via sources and metadata JSON file" appears to be a wrapper around Sourcify verification (except that verification on Blockscout is immediate). To verify manually, it's (normally) enough to upload the json file with the contract name that can be found on deployments/xdai/. This is in principle good because hardhat-deploy supports Sourcify out of the box with the task hardhat sourcify --network xdai.

However, among other things, immutables are not supported (issue). (There is some work in progress! 🎉 )

I found the most helpful error messages when trying to verify a contract manually on Sourcify with the unstable official website. Again, the JSON file with the name of the contract to verify in deployments/xdai/, generated by hardhat deploy, should be enough for verification.

To me it looks like we won't be able to verify our contract until any of the two issues above is fixed, both issues are nontrivial.

I say we should not verify our contract on Blockscout/Sourcify for now. Since we use deterministic deployments, and our contracts are verified on Etherscan, you can check that the code is correct by checking the contract code on Etherscan mainnet at the same address.

The remaining use case for contract verification would be the read/write contract feature. I wonder if we might be able to somehow take our contract interface and implement each function by injecting the compiled bytecode into the source. However, this seems quite complicated and not worth the effort.

I think it would also be nice to verify on Sourcify our mainnet/Rinkeby contracts, since it already almost comes for free with hardhat deploy.

Edit: after more testing, a contract verified with Sourcify doesn't seem to be automatically verified on Blockscout. However, hardhat sourcify supports a --endpoint flag which might help using this tool with Blockscout.

@fleupold
Copy link
Contributor

fleupold commented Mar 2, 2021

Very nice 🕵️ work. Agree that it would be nice to verify everything on Sourcify and not rely on specific block explorers.

Regarding blockscout only accepting flattened contracts, I have been seeing this interface which also allows me to chose

  1. Verification through raw source files and standard JSON file(s) with metadata from the Solidity contract compilation process.
    [...]
    Drop all Solidity contract source files and JSON metadata file(s) created during contract compilation into the drop zone.

I'm not at all sure if we have access to these files (and if this option already works via their API) but since it wasn't mentioned in your analysis, I thought I'd bring it up.

@nlordell
Copy link
Contributor Author

nlordell commented Mar 3, 2021

Regarding blockscout only accepting flattened contracts

I think it only accepts flattened contracts or Sourcify. As @fedgiac mentioned:

"Verification via sources and metadata JSON file" appears to be a wrapper around Sourcify verification (except that verification on Blockscout is immediate)

So this would also suffer from the issue where immutables are not supported (which we make use of).

I say we should not verify our contract on Blockscout/Sourcify for now.

I agree with this conclusion.

@nlordell nlordell added the on hold Waiting for alignment of planets label Mar 3, 2021
@fedgiac
Copy link
Contributor

fedgiac commented Mar 3, 2021

and if this option already works via their API

I didn't find this option in theirBlockscout's documentation. I saw Sourcify mentioned as a premium feature, but I think it was just referring to the manual verification on their website.

edit: clarified which API was not found

@FabijanC
Copy link

Just to mention that Sourcify offers both a UI and an API. Also, Sourcify runs a monitoring service that, upon detecing a new contract created, attempts to fetch its sources and do the process of verification automatically. This is possible only if the author publishes the sources (to IPFS, this is something offered by e.g. Remix IDE).

Support for contracts with immutable variables is in progress and should be featured in the weeks to come.

@fedgiac
Copy link
Contributor

fedgiac commented Aug 20, 2021

Update on this issue: I still wasn't able to verify GPv2Settlement. The error is "deployed and recompiled bytecode don't match" and not about immutables this time.

$ npx hardhat sourcify --network xdai
verifying GPv2AllowListAuthentication (0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE on chain 100) ...
 => contract GPv2AllowListAuthentication is now verified
verifying GPv2AllowListAuthentication_Implementation (0x9E7Ae8Bdba9AA346739792d219a808884996Db67 on chain 100) ...
 => contract GPv2AllowListAuthentication_Implementation is now verified
already verified: GPv2AllowListAuthentication_Proxy (0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE), skipping.
verifying GPv2Settlement (0x9008D19f58AAbD9eD0D60971565AA8510560ab41 on chain 100) ...
{"error":"Contract name: GPv2Settlement. The deployed and recompiled bytecode don't match."}

The error message is the same if I use the Blockscout interface or the Sourcify interface.

The good news is that GPv2AllowListAuthentication was immediately verified on Blockscout after running the command, which means that if we manage to verify on Sourcify then the tooling to instantly verify on Blockscout is already there.

@helderjnpinto
Copy link

this approach with sourcify excludes all private ethereum compatible blockchains that sourcify don't supports.

@fedgiac
Copy link
Contributor

fedgiac commented Feb 1, 2022

As of today, the settlement contract still fails verification of Sourcify. The authenticator however was successfully verified.

I made another unsuccessful attempt to verify the settlement contract using the npm package @nomiclabs/hardhat-etherscan, which, despite the name, supports Blockscout verification on xDai.
Unfortunately it also didn't work, the (shortened) output was:

Successfully submitted source code for contract
src/contracts/GPv2Settlement.sol:GPv2Settlement at 0x9008D19f58AAbD9eD0D60971565AA8510560ab41
for verification on the block explorer. Waiting for verification result...

Error in plugin @nomiclabs/hardhat-etherscan: The contract verification failed.
Here is the (bulk of the) code used to verify the contract.
yarn add @nomiclabs/hardhat-etherscan

Add import "@nomiclabs/hardhat-etherscan"; to hardhat.config.ts and to the exported object the entry etherscan: { apiKey: { xdai: "any nonempty string" } }. Then add the following task to the task list:

import { task } from "hardhat/config";
import type { HardhatRuntimeEnvironment } from "hardhat/types";

interface Args {
  settlementContractAddress: string;
}

const setupVerifyContractCodeTask: () => void = () => {
  task(
    "verify-contract-code",
    "Verify the contract code on the network's block explorer.",
  )
    .addPositionalParam("settlementContractAddress", "")
    .setAction(verifyContractCode);
};
export { setupVerifyContractCodeTask };

async function verifyContractCode(
  { settlementContractAddress }: Args,
  hre: HardhatRuntimeEnvironment,
) {
  const settlement = await hre.ethers.getContractAt(
    "GPv2Settlement",
    settlementContractAddress,
  );

  const [authenticatorAddress, vaultAddress] = await Promise.all([
    settlement.authenticator(),
    settlement.vaultRelayer(),
  ]);

  await hre.run("verify:verify", {
    address: settlementContractAddress,
    constructorArguments: [authenticatorAddress, vaultAddress],
  });
}

Run with:

npx hardhat verify-contract-code --network xdai 0x9008D19f58AAbD9eD0D60971565AA8510560ab41

@FabijanC
Copy link

FabijanC commented Feb 1, 2022

@kuzdogan

@kuzdogan
Copy link

kuzdogan commented Feb 9, 2022

Hey there. I just took a deeper look into what's going on. In the case of immutable variables what Sourcify currently does is this:

  • Find the transaction that created the contract through scraping from the block explorer i.e. Blockscout
  • Get the transaction input data via the RPC
  • Compare tx input to recompiled creation bytecode

In the case of GPv2Settlement I see that the recompiled creation bytecode (0x6101006...) vastly differs from the tx input (0x4d61747...). This means the creation transaction of the contract is not a contract create tx but a call to a contract that creates the contract.

The contract GPv2Settlement at 0x9008D19f58AAbD9eD0D60971565AA8510560ab41 was created at the tx 0x9ddc538f89cd8433f4a19bc4de0de27e7c68a1d04a14b327185e4bba9af87133 and the transaction is a call to the contract 0x4e59b44847b379578588920ca78fbf26c0b4956c. Is 0x4e59b44847b379578588920ca78fbf26c0b4956c a factory contract?

The current workaround described above, unfortunately, cannot handle this case when the tx that creates the contract is not a create tx (i.e. not to address null) + the contract has immutables. However, we can at least show a more informative message by looking at the to: field of the tx if it is not null.

There's also an ongoing implementation ethereum/sourcify#507 to gather all creation bytecodes by running a modified geth and verify using the creation bytecode search, but this is currently planned for the Ethereum networks only as we can't run a client for all networks we support, and will take some more time.

@fedgiac
Copy link
Contributor

fedgiac commented Feb 9, 2022

Thanks for looking into the issue @kuzdogan!

I think you are right: I tried to deploy the settlement contract with a deploy transaction on Rinkeby (here) and I was able to verify it on Sourcify (here).

0x4e59b44847b379578588920ca78fbf26c0b4956c is indeed a factory contract, you can find more info here if needed. In practice, it's a small wrapper around a call to CREATE2. The reason we do this is to enable deterministic deployments, so that we can have the same contract address on multiple networks without having to use the same EOA deployer.

Looking forward to the implementation with the modified node. For us specifically, we rely on Sourcify to verify contracts on the xDAI network, as it seems that the local block explorer delegates the verification of "non-flattenable" smart contracts to Sourcify, but I definitely understand that running nodes on multiple networks would take a lot of maintainance.

Note: weirdly, to verify the contract deployed above I had to go to the Sourcify website, as npx hardhat sourcify --network rinkeby was failing verification with {"error":"Every promise rejected"}. However, this is likely not a Sourcify issue.

@kuzdogan
Copy link

kuzdogan commented Feb 9, 2022

I see, then this upcoming issue/feature ethereum/sourcify#619 would be related to this. This is also a WIP but nice that we have an awaiting use case for it :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
on hold Waiting for alignment of planets
Projects
None yet
Development

No branches or pull requests

6 participants