64

Given the (Solidity) source code of a smart contract, is there a way to deterministically compile the code and compare it with the code on the blockchain? I want to verify that the contract does what the source code claims to do and the author hasn't tampered with it.

J-B
  • 8,941
  • 16
  • 46
  • 77

7 Answers7

41

AFAIK the best way to do this at the moment is to compile the source code again with the exact same compiler version the author used (so this is something that needs to be disclosed) and to compare the bytecode.

So the match you should check is the compiled bytecode against the data of the contract creation tx.

kenorb
  • 1,171
  • 1
  • 12
  • 28
Thomas Bertani
  • 2,647
  • 18
  • 13
  • Not 100%, still problematic https://github.com/trufflesuite/truffle-compile/issues/77 – Ender Oct 19 '20 at 09:13
  • Thank you so much! The contract was built on v5.17.0, but I chose v5.0.0 to verify the contract code, so it threw errors. Finally, I change the version to be same with built compiler v5.17.0. – M.Bonjour Sep 08 '21 at 08:10
22

To add to @thomas-bertani's answer, today etherchain.org released a verification tool for Ethereum contracts

Here's the text from the page:

Source code verification provides transparency for users interacting with smart contracts. By uploading the source code, Etherscan will match the compiled code with that on the blockchain. Just like contracts, a "smart contract" should provide end users with more information on what they are "digitally signing" for and give users an opportunity to audit the code to independently verify that it actually does what it is supposed to do.

dodgy_coder
  • 103
  • 4
makevoid
  • 2,471
  • 1
  • 13
  • 23
14

Currently the workflow is quite annoying. You need to compile the contract with the same compiler version and the same setting (look out for the "optimization=true" flag).

Now please note that the resulting bytecode does NOT match with the bytecode that is stored on the address. The reason for that is that the compiled contract does contain an initialization part that is ran only once when the contract is submitted to the chain. So the byte code stored on the blockchain is the code without the initialization part.

To verify the code you have two options:

  1. Submit the compiled code to a (virtual) blockchain and than check with the getCode command the resulting code.
  2. Compare the compiled code with the payload of the transaction that created the contract.

Etherchain helps to do this process.

In principal pattern matching techniques could be applied to identify a contact even if not exactly the same compiler is used. A project that is doing this and in general linking high level contract (Serpent/Solidity) to Ethereum adresses is: Etherscrape

mKoeppelmann
  • 7,616
  • 8
  • 36
  • 48
8

https://etherscan.io/verifyContract is a verification tool. By providing the Solidity Source Code it checks if the generated Bytecode matches to the contract Bytecode (under the given address). user should choose the same compiler and to enable or disable the optimimsation.

Badr Bellaj
  • 18,780
  • 4
  • 58
  • 75
5

Another approach would be to decompile the bytecode and compare it with the source.

There is a tool called Porosity that does just that.

emx
  • 151
  • 1
  • 3
2

Recommend to use the open-sourced command line tool ConsenSys just released, bytecode-verifier, respective npm package

Bytecode Verifier is a handy commandline tool for verifying locally compiled bytecode of a target Solidity contract against its actual bytecode stored in Etheruem Blockchain provided its contract address.

  • integrity/correctness of bytecode: what's actually being stored on chain is correctly compiled from particular contract, which might be helpful in case of non-trivial potential high-value holder contract deployment(e.g. MultiSig Wallet), especially the contract is deployed through a third party platform.

  • Minimimal effort, simple to use: solidity compiler envolves overtime with minor and some major changes, which complicates the verification of bytecode. (as recurring "bytecode doesn't match" questions being asked on Ethereum Stack Exchange). Bytecode Verifier has been tested against latest version all the way back to some of the oldest deployed contracts.

  • Testnet friendly: most projects launch on testnet before deploying the contract system to mainnet, this tool supports Rinkeby, Kovan and Ropsten Testnet, which constitute three active, well-maintained testnets that most ethereum developers use.

Hope it helps!

Alex Xiong
  • 181
  • 4
0

This is how I do it in a web3 script.

First, compile the code.

const solc = require('solc');

//contract sources
const contractPath = "../contracts/";

const input = {
  "ContractName.sol" : fs.readFileSync(contractPath + 'contractName.sol', 'utf8'),
}

let solcOutput = await solc.compile({ sources: input }, 1);

now compare byteCode

let blockCode = await web3.eth.getCode(contractAddress);
let solcCode = '0x' + (solcOutput.contracts["contractName.sol:contracName"].runtimeBytecode);}
Ilan Dshare
  • 512
  • 5
  • 12
  • This does not work, you are missing constructor parameters and auxdata – mdv Aug 23 '18 at 21:50
  • How did u test it? it works for me on all of kyber network contracts. – Ilan Dshare Oct 04 '18 at 10:12
  • @mdv Do you need to have matching constructor parameters? I'm seeing conflicting responses, but my guess is no, since the constructor is designed to put values in storage, not determine the existence of functions or state vars. – Garen Vartanian Oct 05 '18 at 04:08