hardhat-zksync icon indicating copy to clipboard operation
hardhat-zksync copied to clipboard

Cannot verify the account contract

Open ChiHaoLu opened this issue 10 months ago • 9 comments

📝 Description

It cannot verify the account contract with zkSync hardhat.

🔄 Reproduction Steps

  if (hre.network.config.verifyURL) {
    console.log(`Requesting contract verification...`);
    for (let i = 0; i < 50; i++) {
      console.log(i);
      try {
        await verifyContract({
          address: accountAddress,
          contract: fullContractSource,
          constructorArguments: constructorArgs,
          bytecode: aaArtifact.bytecode,
        });
        break;
      } catch (e) {
        console.log(e)
        await timeout(3000);
      }
    }
  }

The factory is:

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

import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol";
import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol";

contract AAFactory {
    bytes32 public aaBytecodeHash;

    constructor(bytes32 _aaBytecodeHash) {
        aaBytecodeHash = _aaBytecodeHash;
    }

    function deployAccount(
        bytes32 salt,
        address owner
    ) external returns (address accountAddress) {
        (bool success, bytes memory returnData) = SystemContractsCaller
            .systemCallWithReturndata(
                uint32(gasleft()),
                address(DEPLOYER_SYSTEM_CONTRACT),
                uint128(0),
                abi.encodeCall(
                    DEPLOYER_SYSTEM_CONTRACT.create2Account,
                    (
                        salt,
                        aaBytecodeHash,
                        abi.encode(owner),
                        IContractDeployer.AccountAbstractionVersion.Version1
                    )
                )
            );
        require(success, "Deployment failed");

        (accountAddress) = abi.decode(returnData, (address));
    }
}

🤔 Expected Behavior

Expect it to verify successfully.

😯 Current Behavior

ZkSyncVerifyPluginError: The address 0x7d9Cc156be13a4690eCcC840179c2771670E9AF4 has no bytecode. Is the contract deployed to this network?
  The selected network is zkSyncSepoliaTestnet.
    at retrieveContractBytecode (/Users/chihaolu/Desktop/imToken/zkSync-Payment-Mininal-Demo/node_modules/@matterlabs/hardhat-zksync-verify/src/utils.ts:75:15)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async OverriddenTaskDefinition.verifyContract [as _action] (/Users/chihaolu/Desktop/imToken/zkSync-Payment-Mininal-Demo/node_modules/@matterlabs/hardhat-zksync-verify/src/task-actions.ts:163:33)
    at async Environment._runTaskDefinition (/Users/chihaolu/Desktop/imToken/zkSync-Payment-Mininal-Demo/node_modules/hardhat/src/internal/core/runtime-environment.ts:359:14)
    at async Object.Environment.run (/Users/chihaolu/Desktop/imToken/zkSync-Payment-Mininal-Demo/node_modules/hardhat/src/internal/core/runtime-environment.ts:192:14)
Done!

🖥️ Environment

networks: {
    zkSyncSepoliaTestnet: {
      url: "https://sepolia.era.zksync.dev",
      ethNetwork: "sepolia",
      zksync: true,
      verifyURL:
        "https://explorer.sepolia.era.zksync.dev/contract_verification",
    }
  },

ChiHaoLu avatar Apr 10 '24 09:04 ChiHaoLu

Hello @ChiHaoLu are you sure you are verifying the right address? It seems that you are working with your wallet address.

Please check exactly what is accountAddress you are passing to the verification.

Use this as an example, in order to see how to deploy account via factory contract.

nikola-bozin-txfusion avatar Apr 12 '24 13:04 nikola-bozin-txfusion

Hello @ChiHaoLu are you sure you are verifying the right address? It seems that you are working with your wallet address.

Please check exactly what is accountAddress you are passing to the verification.

Use this as an example, in order to see how to deploy account via factory contract.

Thanks for your reply, I am sure this account address is my deployed account contract. Won't the account contract show as an Account instead of Contract in zkSync explorer?

Is there any successfully verified account contract I can refer to?

ChiHaoLu avatar Apr 12 '24 13:04 ChiHaoLu

@ChiHaoLu, could you send us your full deployment process instead of just a part of it?

nikola-bozin-txfusion avatar Apr 12 '24 13:04 nikola-bozin-txfusion

I found I should use await aaFactory.aaBytecodeHash() instead of aaArtifact.bytecode in my deploy script when calculating the create2 address. It's my fault.

But I get another error when verifying the account contract:

yarn execute:eraSepolia deployAccount.ts
yarn run v1.22.19
warning ../../../package.json: No license field
$ hardhat compile & hardhat deploy-zksync --network zkSyncSepoliaTestnet --script deployAccount.ts
Nothing to compile
AA factory address: 0xF330C22ac63237802B7DBe4e8d4B0d730589bCA5
0x010006793e0d648a9353cc8874da3e4f55d925dd92b7162f6dacd8b09909c4ad
Account deployed on address 0x864EE4b9010AcA123De5e10602766B59cAE5c054
Funding smart contract account with some ETH
Requesting contract verification...
0
ZkSyncVerifyPluginError: The address provided as argument contains a contract, but its bytecode doesn't match any of your local contracts.

      Possible causes are:
        - Contract code changed after the deployment was executed. This includes code for seemingly unrelated contracts.
        - A solidity file was added, moved, deleted or renamed after the deployment was executed. This includes files for seemingly unrelated contracts.
        - Solidity compiler settings were modified after the deployment was executed (like the optimizer, target EVM, etc.).
        - The given address is wrong.
        - The selected network is wrong.
    at OverriddenTaskDefinition.getContractInfo [as _action] (/Users/chihaolu/Desktop/imToken/zkSync-Payment-Mininal-Demo/node_modules/@matterlabs/hardhat-zksync-verify/src/task-actions.ts:286:19)
    at async Environment._runTaskDefinition (/Users/chihaolu/Desktop/imToken/zkSync-Payment-Mininal-Demo/node_modules/hardhat/src/internal/core/runtime-environment.ts:359:14)
    at async Environment.run (/Users/chihaolu/Desktop/imToken/zkSync-Payment-Mininal-Demo/node_modules/hardhat/src/internal/core/runtime-environment.ts:192:14)
    at async OverriddenTaskDefinition.verifyContract [as _action] (/Users/chihaolu/Desktop/imToken/zkSync-Payment-Mininal-Demo/node_modules/@matterlabs/hardhat-zksync-verify/src/task-actions.ts:172:54)
    at async Environment._runTaskDefinition (/Users/chihaolu/Desktop/imToken/zkSync-Payment-Mininal-Demo/node_modules/hardhat/src/internal/core/runtime-environment.ts:359:14)
    at async Object.Environment.run (/Users/chihaolu/Desktop/imToken/zkSync-Payment-Mininal-Demo/node_modules/hardhat/src/internal/core/runtime-environment.ts:192:14)
Done!
✨  Done in 8.47s.

My deploy script is:

// load env file
import dotenv from "dotenv"
import * as ethers from "ethers"
import { HardhatRuntimeEnvironment } from "hardhat/types"
import { utils } from "zksync-ethers"
import { getDeployer, getWallet, verifyContract } from "./utils"

dotenv.config()
export default async function (hre: HardhatRuntimeEnvironment) {
    // Load the factory
    const wallet = getWallet()
    const deployer = getDeployer()
    const factoryArtifact = await deployer.loadArtifact("AAFactory")
    const aaArtifact = await deployer.loadArtifact("Account")
    const vaultAddress = process.env.VAULT_ADDRESS
    const factoryAddress = process.env.ACCOUNT_FACTORY_ADDRESS
    console.log(`AA factory address: ${factoryAddress}`)
    const aaFactory = new ethers.Contract(
        factoryAddress,
        factoryArtifact.abi,
        wallet
    )

    // Deploy account with factory
    const ownerAddress = wallet.address
    const salt = ethers.randomBytes(32)
    const tx = await aaFactory.deployAccount(salt, ownerAddress)
    await tx.wait()

    const abiCoder = new ethers.AbiCoder()
    const constructorArgs = abiCoder.encode(
        ["address", "address"],
        [ownerAddress, vaultAddress]
    )
    const accountAddress = utils.create2Address(
        factoryAddress,
        await aaFactory.aaBytecodeHash(),
        salt,
        constructorArgs
    )

    console.log(`Account deployed on address ${accountAddress}`)

    // Funding account with ETH
    console.log("Funding smart contract account with some ETH")
    await (
        await wallet.sendTransaction({
            to: accountAddress,
            value: ethers.parseEther("0.00001")
        })
    ).wait()

    // Verify the account
    const fullContractSource = `${aaArtifact.sourceName}:${aaArtifact.contractName}`
    if (hre.network.config.verifyURL) {
        const retryTime = 1
        console.log(`Requesting contract verification...`)
        for (let i = 0; i < retryTime; i++) {
            console.log(i)
            try {
                await verifyContract({
                    address: accountAddress,
                    contract: fullContractSource,
                    constructorArguments: constructorArgs,
                    bytecode: aaArtifact.bytecode
                })
                break
            } catch (e) {
                console.log(e)
                await timeout(3000)
            }
        }
    }
    console.log(`Done!`)
}

function timeout(ms: number) {
    return new Promise((resolve) => setTimeout(resolve, ms))
}

My deploy transaction: link

ChiHaoLu avatar Apr 12 '24 14:04 ChiHaoLu

I also tried below code and failed too:

await verifyContract({
    address: accountAddress,
    contract: fullContractSource,
    constructorArguments: [ownerAddress, vaultAddress],
    bytecode: aaArtifact.bytecode
})

And the command method is failed too:

$ yarn hardhat verify --network zkSyncSepoliaTestnet 0x864EE4b9010AcA123De5e10602766B59cAE5c054 0x8Fc8ecf8A75877E51aa595Bb1a02CF3804b24613 0x305A6E5796d41774c21BdC2c0474628B1Bf2f86E
> 
Error in plugin @matterlabs/hardhat-zksync-verify: The address provided as argument contains a contract, but its bytecode doesn't match any of your local contracts.

      Possible causes are:
        - Contract code changed after the deployment was executed. This includes code for seemingly unrelated contracts.
        - A solidity file was added, moved, deleted or renamed after the deployment was executed. This includes files for seemingly unrelated contracts.
        - Solidity compiler settings were modified after the deployment was executed (like the optimizer, target EVM, etc.).
        - The given address is wrong.
        - The selected network is wrong.

ChiHaoLu avatar Apr 12 '24 14:04 ChiHaoLu

Could you provide the address of your deployed AAFactory?

nikola-bozin-txfusion avatar Apr 12 '24 14:04 nikola-bozin-txfusion

Could you provide the address of your deployed AAFactory?

Thanks, my factory address

ChiHaoLu avatar Apr 12 '24 14:04 ChiHaoLu

Hello, we are unable to reproduce the error with the code you provided. Therefore, I suggest reviewing the script we created for you and testing the deployment process with script that works at our side.

import * as zk from 'zksync-ethers';
import * as hre from 'hardhat';
import { ZeroHash, AbiCoder, parseEther } from 'ethers';

async function main() {
  const vault = '0x305A6E5796d41774c21BdC2c0474628B1Bf2f86E' // YOUR VAULT ADDRESS

  const aaArtifact = await hre.deployer.loadArtifact("Account");
  const bytecodeHash = zk.utils.hashBytecode(aaArtifact.bytecode);
  const factory = await hre.deployer.deploy("AAFactory", [bytecodeHash, vault], undefined, [
    aaArtifact.bytecode,
  ]);
  const factoryAddress = await factory.getAddress();

  console.log(`AA factory address: ${factoryAddress}`);

  const owner = await hre.deployer.getWallet();
  const salt = ZeroHash; // Salt is zero for simplicity

  // deploy account
  const tx = await factory.deployAccount(salt, owner.address);
  await tx.wait();

  const abiCoder = new AbiCoder();
  const accountAddress = zk.utils.create2Address(
    factoryAddress,
    await factory.aaBytecodeHash(),
    salt,
    abiCoder.encode(["address", "address"], [owner.address, vault])
  );
  console.log(`Account deployed on address ${accountAddress}`);

  console.log("Funding smart contract account with some ETH")
  await (
      await owner.sendTransaction({
          to: accountAddress,
          value: parseEther("0.00001")
      })
  ).wait()

  await hre.run('verify', {
    address: accountAddress,
    contract: 'contracts/Account.sol:Account',
    constructorArgsParams: [owner.address, vault],
    bytecode: aaArtifact.bytecode,
  });
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

kiriyaga-txfusion avatar Apr 15 '24 09:04 kiriyaga-txfusion

Thanks a lot! I will try it and give the feedback!

ChiHaoLu avatar May 07 '24 04:05 ChiHaoLu