ethereum: token verification instructions

commit-id:7c346ae8
This commit is contained in:
Csongor Kiss 2022-12-01 17:03:54 +00:00 committed by Csongor Kiss
parent 4fcd5ffcca
commit 523a30140f
1 changed files with 147 additions and 0 deletions

View File

@ -0,0 +1,147 @@
# Token contract verification on Etherscan
This document explains how to perform verification of the wrapped asset
contracts deployed by the Portal token bridge on Etherscan and similar explorer
services. The purpose of contract verification is to provide the source code of
the contract so that users have better transparency into the programs they
interact with (whether this makes a difference in practice is beyond the scope
of this document).
Verification requires uploading the source code and supplying the compiler
version and arguments that the deployed bytecode was compiled with. Etherscan
will then recompile the source code on their servers and match the result
against the deployed bytecode.
We will use the flattened source file, as it's easier to upload. Flattened just
means that the whole contract, including its dependencies, are inlined into a
single source file.
Wormhole's flattened source files can be downloaded from [Github
Actions](https://github.com/wormhole-foundation/wormhole/actions/workflows/evm-flattened-contracts.yml).
This page includes a version of the contracts for each ethereum contract
deployment. The deployed token contract tends not to change very often (if at
all), so it should be safe to just pick the latest run and download the
artifacts from there (download `flattened-contracts` at the bottom of the page
after selecting the run).
The file needed for token verification is `token/Token.sol`.
For our running example, we'll use the wrapped WETH contract deployed on
Moonbeam:
https://moonscan.io/address/0xab3f0245b83feb11d15aaffefd7ad465a59817ed
First, we verify that this contract is a proxy. This step can be done by
visiting the https://moonbeam.moonscan.io/proxycontractchecker page, and pasting
in the contract address. For ethereum, the site to use would be
https://etherscan.io/proxycontractchecker, and other chain explorers have
similar pages too.
This will present a popup with the following text:
> The proxy contract verification completed with the message:
> The proxy's (0xab3f0245b83feb11d15aaffefd7ad465a59817ed) implementation contract is found at: 0xb1731c586ca89a23809861c6103f0b96b3f57d92
Click save.
Next, we'll verify the actual source code. Head over to
https://moonscan.io/verifyContract and paste in contract address, in our case
`0xab3f0245b83feb11d15aaffefd7ad465a59817ed`. Fill in the rest of the form with
the following values, then continue.
| Field | Value |
| ---------------- | ------------------------- |
| Compiler type | Solidity (Single file) |
| Compiler version | v0.8.4+commit.c7e474f2 |
| License type | Apache-2 |
On the next page, select "optimizations: yes", and paste the contents of
`token/Token.sol` from before into the source file textaera.
In the misc settings, enter 200 for optimization runs, and leave the rest as
default.
## ABI-encoded constructor arguments
The last missing piece is the ABI-encoded constructor arguments field. These
are the arguments that the contract was instantiated with, and it will be
different for each wrapped contract.
There are two ways to proceed. The first method is easier, but does not
work on all explorers (it does on moonscan), the second method is more involved,
but will always work. Try the first, and if it didn't work, then try the second.
## Constructor arguments, method #1
Leave the constructor arguments field empty, and just proceed to verification.
This step will fail, because the deployed bytecode will actually include the
constructor arguments, and the result of compiling the source file doesn't.
At this point, some explorers will just return a generic error message saying
the bytecodes didn't match, without any additional information. If this is the
case, go to method #2.
If the page shows what the *expected* bytecode was, and lists out the *actual*
bytecodes it found in the source file, then we may proceed here. The *expected*
bytecode will be the same as the `BridgeToken` bytecode with the constructor
arguments appended to the end. This means that the `BridgeToken` bytecode is a
proper prefix of the expected bytecode. Just copy the rest of the bytes of the
expected bytecode (for example in your favourite text editor), i.e. the suffix
that comes after the `BridgeToken` prefix. Go back to the previous page, and use
these bytes as the constructor arguments. This time, verification should succeed.
## Constructor arguments, method #2
If the explorer page does not show the expected and actual bytecodes, then we
need to compute the arguments ourselves. For this, we will need the `forge` tool
(install from https://getfoundry.sh/), and a local checkout of the wormhole repository
```sh
$ git clone https://github.com/wormhole-foundation/wormhole.git
```
First, install the dependencies by running the `make dependencies` in the
`ethereum` folder:
```sh
wormhole/ethereum $ make dependencies
```
Next, we will run a `forge` script to compute the constructor arguments. For
this, we will need two pieces of data. First, the address of the Portal token
bridge contract on the chain we're performing verification on. This can be found
in
https://github.com/wormhole-foundation/wormhole/blob/main/sdk/js/src/utils/consts.ts
under the MAINNET section (or TESTNET if you're verifying a testnet contract).
For our example, the mainnet moonbeam token bridge contract is
`0xb1731c586ca89a23809861c6103f0b96b3f57d92`.
Next, we'll need the VAA (the signed wormhole message) that was sent to the
token bridge contract to create the wrapped asset. This can be found by finding
the transaction that created this contract. On the contract's page
https://moonscan.io/address/0xab3f0245b83feb11d15aaffefd7ad465a59817ed, the
"Content creator" field has a link to the "at txn ...". In our case, this is
https://moonscan.io/tx/0x9f6db0a0749558e8ef5bf24c1be148498fb3c451d040198b7362c2ce32469e67
Expand the details, which shows a call to `createWrapped` in the "Input data"
section. Click "Decode input data" which will show the hex value of the
`encodedVM` argument. In our case it's
```
0x01000000020d00aa6b30da219a0573e1a2ff47b4e51b4768ff671ac99b4ca851b69a5c756c495f5e5416b1bacd1e65e01085184a0ea167bb8160db15621e39b079b7d8cae26e71000207a7e7d1053e143dffa3c3023ca7ca8816bcfa62d264112d3b51ca4eadde5cb8615673252063c9bc327ba5eaeeef37fa8e08064822b6de8746065606de2749b4010349718c3a2ed771b885b972d01ee36e9267b142945e8d4af06c7b6d43f12830f5745f17e70eb368f510520cd5386a44dd8d5c6f875f8e28c40f8ff8e559400358000418b99fc0b8090b4ec7c6cde6c43f82dc9f1c15a7610624833287c963bf776c7641b1a8410acb4f1b927c3784dd9290aaa50fca818c728d33e42de9b16b3d3dba0005fb5fce6005369257755550e4e6f7b1023fab3f83e4e70ec822ade40571fb712b26e537b7394278151055048d85553c73c1c7dbb65a956c05ded272b7c480d0c001066732b0cd475f74d2afacee7ce175a44648f2cc0ffc88f07b29edd7bd6497b9c728bd7e2df8f4bd926e0faa2820874d2a9006e7b8bb7fefd4876ba7acebfb4271000738db4897b6c4054c4c724254d02c6dfe2486379d4ee8ff3ccc4e180395d798784ca1d35a219e34c31ae3defadc0765aca0e81b047f5748663164cf2060e33465010c03b1fd13f924d56238344d6a9de1d650120b106e93f5638b2eb23fa7706b9ecb1e2fa10c805e6ec4f24742c7e43fb815084dcb18720fb6eae90d59c1824acf64010d13c022cfea6df258340a44b7b5667da9f6c739d92b2f77351eeb0217faf244a84d50be71579b65850f92397deaa133e267f224ea2537c223a7c9966417843917000fdc31f1540f66fa5d2991b52af617be24eaa66f41ad5542ac0b4f972b0afafcec3e57f52e4e71b933fad4ec9cf69a4c4bdbbb1a2a9b44f07a287be493dcb1fdb50010904167e5728f1405aceaacb67832e23ebe374f6bda35f75e9bb79c21acbda8e50ad864f24a9fd26f0f6c1a4eba02506db0669a8cd9829245b40c4510aa0bd74f001104877f08d3917e176ac487b25e03d123121171716387a391b56053eaed9364b42becc817ef9973fdeb117e75dd665a7b22a7641c60fdb8786a50082a463702760112739bc4983ac0408cbc13969b7ba6715dfef337324d39b36f8120e883584f51726ea0f07a4e08d66dd5f1144d7dbb49720cd0547834ee58d5b918d242e956eb720163396ad38785000000020000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa5850000000000014c530102000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200021257455448000000000000000000000000000000000000000000000000000000005772617070656420457468657200000000000000000000000000000000000000
```
We copy this field and go back to our terminal. Run the following
```
wormhole/ethereum $ forge script scripts/TokenABI.s.sol -s "token_constructor_args(bytes, address)" <VAA-BYTES> <CONTRACT-ADDRESS>
```
where in place of `<VAA-BYTES>`, substitute the hex sequence we just copied from
the explorer, and in place of `<CONTRACT-ADDRESS>`, the token bridge's address
from before (`0xb1731c586ca89a23809861c6103f0b96b3f57d92` for moonbeam).
Running that command prints the following:
```
0x000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d9200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000164c71f461500000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000014c53000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d920000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000d57726170706564204574686572000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004574554480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
```
Copy the hex *excluding* the 0x at the front, and paste that into the
constructor arguments field, then hit verify. The contract should now be verified.