DEV Community

Chigozie Oduah
Chigozie Oduah

Posted on

Simple Ways to Compile and Deploy Solidity Contracts

Introduction

Solidity is a contract-oriented language used to develop on-chain programs ( smart contracts ) on the ethereum network and compiling the contract is especially stressful when you’re setting up your local node to use for deployment and compilation, so these processes are usually skipped in some tutorials out there to prevent them from being bulky. In this tutorial we will show you three ways you can compile and two ways you can deploy your contract.

How to compile

In this section we'll talk about compiling your contract. We will start with using Remix IDE then we’ll talk about using VS Code and the solidity extension.

Remix IDE

This is an online development environment used to create and deploy smart contracts in the browser. It doesn’t need anyone to register before using and all the contracts that are created are stored in the browser’s local storage so your progress would not be lost whenever you exit the site unless you cleared the site’s data in your browser.

To compile your contract using this IDE we start by navigating to the site: https://remix.ethereum.org/

When the site is loaded it should look something like this

Image description

But don’t worry if it doesn’t, it means they have modified the user-interface by the time you are reading this article. It should still have the same basic navigation so you’ll be fine reading the article.

Now, In the Remix IDE, click on the contracts folder and select any of the available contracts. If there are no available contracts there, create a new file in the folder named Contract.sol and copy the following code into it.

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.11;

contract Contract {
  function greet() public view returns (string memory) {
      return "hello";
  }
}
Enter fullscreen mode Exit fullscreen mode

Then, we navigate to the SOLIDITY COMPILER tab and click on the** Compile <contract name>.sol** button.

Image description

And our code is compiled. If you want to extract the ABI or the BYTECODE of the contract we click on Compilation Details and click on the copy icon beside ABI or any other entry that we want to copy.

Image description

VisualStudio Code

Now we’ll talk about using VisualStudio Code to compile our contract. We get started by opening the folder that our contract is in, in VS Code. If we don’t have a contract file created yet, we will open any directory that we want our contract in and create a new file Contract.sol and fill it with the contract code below.

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.11;

contract Contract {
  function greet() public view returns (string memory) {
      return "hello";
  }
}
Enter fullscreen mode Exit fullscreen mode

Then we go to the extensions tab and install the solidity extension.

Image description

Once installed, we click on the contract file to open it.

Image description

After that, we right click inside the file and a menu will appear with a list of options to do with your contract. In this menu, click on Solidity: Download compiler and set workspace local path.

Image description

This makes a list of versions appear above. Then we select the version that our contract needs, ( in our case it is 0.8.11, specified by the pragma solidity ^0.8.11; line ).

Image description

When it is done downloading the compiler, you’ll see a newly created JavaScript file in your project directory. And if you don’t see it, you should try downloading it again, check your network or check if the extension had an error while it was installing.

Now, right click in the contract file again and this time select Solidity: Compile with configured local solc file. After compiling the contract, you should see a new bin folder like the following:

Image description

If you don’t see the bin folder, it means that VS Code did not detect the compiler and it will try downloading the compiler again, so you should wait till it is done. And then, click on the Solidity: Compile with configured local solc file again and this time it should be working.

How to deploy

There are three ways we can deploy a smart contract to the ethereum network and they are

  • Remix IDE
  • Web3
  • EtherJS

Remix IDE

Deploying our contract using the Remix IDE is really straightforward and doesn’t need you to write any deployment script whatsoever. But to deploy our contract to the ethereum network we need to have metamask installed in the browser we are using it in. To deploy the contract, you navigate to the DEPLOY & RUN TRANSACTIONS tab and click on the Deploy button.

Image description

This deployment is only limited to our browser, it is used for testing before deploying our contract to the public ethereum network. It is really helpful because we can test the contract’s interface before deploying to the network. It is already well known that deploying a contract to the ethereum network can cost a lot of money depending on how big the contract is, so the fact that we can test out the contract’s interface before deploying it is really a huge benefit.

To deploy our contract to the public network all we do is change the environment option from JavaScript VM to Injected Web3.

Image description

This triggers a Metamask window prompting you to connect your wallet. Click on connect wallet to connect and then hit the Deploy button.

After deployment, you will see the contract interface appear under the Deployed contracts dropdown.

Image description

We use this interface to interact with our deployed contract. And we can also copy the address of the deployed contract by clicking the copy icon on the top of the interface.

Web3JS

To deploy our contract using this method we start by creating a project folder ( we can call it web3-deployment ) then we install the web3 package and the package for our wallet provider. With the following commands:

npm init -y
npm i web3 wallet-provider
Enter fullscreen mode Exit fullscreen mode

In our terminal/command-prompt in our web3-deployment folder. Also, replace the wallet-provider with the wallet provider of your choice.

Next, we create an index.js file in the web3-deployment folder and begin by copying the following code into it

const provider = require(/* your provider */);
const Web3 = require('web3');
const web3 = new Web3(provider.provider());
Enter fullscreen mode Exit fullscreen mode

Also replacing the /* your provider */ part with the name of your wallet provider.

Then, add the following snippet

let abi = JSON.parse(`[
  {
    "inputs": [],
    "name": "greet",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]`);
Enter fullscreen mode Exit fullscreen mode

The contents of the JSON.parse() method above is the ABI of the contract we compiled earlier. So you should change it to the abi of the contract you are compiling if you are deploying a different contract.

After that, we add the below to our index.js file

let bytecode = JSON.parse(`{
  "functionDebugData": {},
  "generatedSources": [],
  "linkReferences": {},
  "object": "608060405234801561001057600080fd5b5061017c806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063cfae321714610030575b600080fd5b61003861004e565b6040516100459190610124565b60405180910390f35b60606040518060400160405280600581526020017f68656c6c6f000000000000000000000000000000000000000000000000000000815250905090565b600081519050919050565b600082825260208201905092915050565b60005b838110156100c55780820151818401526020810190506100aa565b838111156100d4576000848401525b50505050565b6000601f19601f8301169050919050565b60006100f68261008b565b6101008185610096565b93506101108185602086016100a7565b610119816100da565b840191505092915050565b6000602082019050818103600083015261013e81846100eb565b90509291505056fea26469706673582212206a88e5fc2cbb31aca036100317594eef00ab7e3975c29b02a81d4ed4674ed35a64736f6c634300080c0033",
  "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x17C DUP1 PUSH2 0x20 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x2B JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xCFAE3217 EQ PUSH2 0x30 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x38 PUSH2 0x4E JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x45 SWAP2 SWAP1 PUSH2 0x124 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x60 PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x5 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x68656C6C6F000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP3 DUP3 MSTORE PUSH1 0x20 DUP3 ADD SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xC5 JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0xAA JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0xD4 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x1F NOT PUSH1 0x1F DUP4 ADD AND SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0xF6 DUP3 PUSH2 0x8B JUMP JUMPDEST PUSH2 0x100 DUP2 DUP6 PUSH2 0x96 JUMP JUMPDEST SWAP4 POP PUSH2 0x110 DUP2 DUP6 PUSH1 0x20 DUP7 ADD PUSH2 0xA7 JUMP JUMPDEST PUSH2 0x119 DUP2 PUSH2 0xDA JUMP JUMPDEST DUP5 ADD SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH1 0x0 DUP4 ADD MSTORE PUSH2 0x13E DUP2 DUP5 PUSH2 0xEB JUMP JUMPDEST SWAP1 POP SWAP3 SWAP2 POP POP JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 PUSH11 0x88E5FC2CBB31ACA0361003 OR MSIZE 0x4E 0xEF STOP 0xAB PUSH31 0x3975C29B02A81D4ED4674ED35A64736F6C634300080C003300000000000000 ",
  "sourceMap": "67:108:0:-:0;;;;;;;;;;;;;;;;;;;"
}`);
Enter fullscreen mode Exit fullscreen mode

This is the compiled bytecode we got from our contract. And again, should be changed when you are deploying a different contract.

Now that we have the bytecode and ABI in our deployment script, we add this to our file.

web3.eth.getAccounts()
  .then(accounts => {
    return new web3.eth.Contract(abi)
      .deploy({ data: bytecode.object }).send({ from: accounts[0], gas: '1000000' });
  })
  .then(contract => {
    console.log('Contract deployed at ', contract.options.address);
  })
  .catch(error => {
    console.error(error);
  });
Enter fullscreen mode Exit fullscreen mode

This is what deploys our contract to the ethereum network and how it works is that:

  1. The 1st line gets the accounts that are provided by our wallet provider,
  2. In the 2nd line we call a .then() method and pass an anonymous function that initializes our contract to it,
  3. Then the 3rd - 4th line creates an instance of Contract created with its ABI and then it deploys the contract using the .deploy() method. This method takes in an object with the data key containing the bytecode object and an optional arguments key that contains an array of the arguments that passed to the contract on deployment. The deploy method initializes a transaction; it is not started until the .send() method signs the transaction. It specifies the owner of this transaction with the from key and the limit of ethers it can spend deploying the contract with the gas key and returns a promise.
  4. On the 6th line we call another .then() method so we can display the contract’s address from the contract object passed from the previous .then() into the console, and,
  5. Finally, we catch any errors during the contract’s deployment using the .catch() method and display it in the console.

We can now test our code in the console:

> node index.js
Contract deployed at  0x844D……………………18
Enter fullscreen mode Exit fullscreen mode

If you see something like this, then it means your contract was successfully deployed, If not then you’ll have to do some bit of debugging :)

EthersJS

Deployment using EthersJS is done in almost the same way it is as Web3JS.

  1. We start with a new folder,
  2. Then, we initialize the folder as a node project,
  3. Next, we install ethers and our wallet provider,
  4. After that, we create an index.js file,
  5. In the index.js file we import ethers and our wallet provider then include the ABI and bytecode. The index.js file should look like the following in the beginning:
const provider = require('ganache-cli');
const ethers = require('ethers');

const abi = JSON.parse(`[
  {
    "inputs": [],
    "name": "greet",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]`);

const bytecode = JSON.parse(`{
  "functionDebugData": {},
  "generatedSources": [],
  "linkReferences": {},
  "object": "608060405234801561001057600080fd5b5061017c806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063cfae321714610030575b600080fd5b61003861004e565b6040516100459190610124565b60405180910390f35b60606040518060400160405280600581526020017f68656c6c6f000000000000000000000000000000000000000000000000000000815250905090565b600081519050919050565b600082825260208201905092915050565b60005b838110156100c55780820151818401526020810190506100aa565b838111156100d4576000848401525b50505050565b6000601f19601f8301169050919050565b60006100f68261008b565b6101008185610096565b93506101108185602086016100a7565b610119816100da565b840191505092915050565b6000602082019050818103600083015261013e81846100eb565b90509291505056fea26469706673582212206a88e5fc2cbb31aca036100317594eef00ab7e3975c29b02a81d4ed4674ed35a64736f6c634300080c0033",
  "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x17C DUP1 PUSH2 0x20 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x2B JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xCFAE3217 EQ PUSH2 0x30 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x38 PUSH2 0x4E JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x45 SWAP2 SWAP1 PUSH2 0x124 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x60 PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x5 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x68656C6C6F000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP3 DUP3 MSTORE PUSH1 0x20 DUP3 ADD SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xC5 JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0xAA JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0xD4 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x1F NOT PUSH1 0x1F DUP4 ADD AND SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0xF6 DUP3 PUSH2 0x8B JUMP JUMPDEST PUSH2 0x100 DUP2 DUP6 PUSH2 0x96 JUMP JUMPDEST SWAP4 POP PUSH2 0x110 DUP2 DUP6 PUSH1 0x20 DUP7 ADD PUSH2 0xA7 JUMP JUMPDEST PUSH2 0x119 DUP2 PUSH2 0xDA JUMP JUMPDEST DUP5 ADD SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH1 0x0 DUP4 ADD MSTORE PUSH2 0x13E DUP2 DUP5 PUSH2 0xEB JUMP JUMPDEST SWAP1 POP SWAP3 SWAP2 POP POP JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 PUSH11 0x88E5FC2CBB31ACA0361003 OR MSIZE 0x4E 0xEF STOP 0xAB PUSH31 0x3975C29B02A81D4ED4674ED35A64736F6C634300080C003300000000000000 ",
  "sourceMap": "67:108:0:-:0;;;;;;;;;;;;;;;;;;;"
}`);
Enter fullscreen mode Exit fullscreen mode

After starting off with the index.js file, we create our signer:

const signer = (new ethers.providers.Web3Provider( provider.provider() ) ).getSigner();
Enter fullscreen mode Exit fullscreen mode

This is basically a class instance that represents the accounts and is used to sign transactions in ethers.js.

Then we create a factory:

const factory = new ethers.ContractFactory(abi, bytecode.object, signer);
Enter fullscreen mode Exit fullscreen mode

The ContractFactory sends a transaction to initialize the contract using the ABI and bytecode and then sign the transaction using the signer. The contract isn’t deployed until we call the factory.deploy() method

factory.deploy()
  .then(contract => {
    console.log("Contract address is ", contract.address);
    return contract.deployed();
  })
  .then(() => {
    console.log("Contract is deployed");
  })
  .catch((err) => {
    console.err(err);
  });
Enter fullscreen mode Exit fullscreen mode

This returns a promise with the contract instance. The contract object is obtained before the contract is deployed ( that is when the transaction is initialized ). At the 3rd line of this snippet, we get access to the contract’s address before we use the contract. We have to wait for the contract to be deployed using the contract.deployed(); method. This returns a promise that gets resolved when the contract is deployed so we add another .then() method. Finally, we did some error handling using the .catch() method to help with debugging our code.

After running the index.js we should get something like:

Contract address is  0x134027014b698b8A2F6DCEb51B576cDb3f42E550
Contract is deployed
Enter fullscreen mode Exit fullscreen mode

If you got something else, It means there is an error and with the help of our error handling, it should be easier to debug than starting from scratch.

Conclusion

Easy ways to compile and deploy solidity contracts aren’t always talked about in a lot of tutorials. So this article serves as something to read and get you familiar with some of the ways you can compile your contract. And it is my greatest wish that this article did that perfectly.

Happy coding ;)

Top comments (1)

Collapse
 
shegz profile image
Bobate Olusegun

This write up is simple, enriched and awesome. @ghoulkingr am considering blockchain development.. Nice one fam