In this tutorial, I will discuss how to compile using Solc 0.5 in Solidity and above.
Staying up to date with the latest syntax, code, methods, and techniques can be quite challenging when it comes to beginners in a programming language. Moreover, it is not so easy to be a beginner when it comes to Solidity.
Although Solidity is a powerful programming language, it only has a handful of tutors online to teach newbies. When these courses are outdated, it becomes difficult for beginners to stay up to date with the latest modifications.
Students are forced to rely upon and stick to the older versions provided by these courses. Well, whatsoever it may be we are interested in learning today how to compile using Solidity code using the Solc 0.5 version and above.
So, let us get started.
Creating a Solidity Smart Contract
To learn how to compile Solidity code using Solc 0.5 version and above, we first must have a contract at hand. Below is a sample crowdfunding project smart contract I wish to use for this tutorial.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract Inbox {
string public message;
constructor(string memory initialMessage) {
message = initialMessage;
}
function setMessage(string memory newMessage) public {
message = newMessage;
}
}
Let us now proceed with learning how to compile with the newer versions of Solc.
Compiling Solidity Code
Before we look into the new syntax and everything for our compile script, let us first see what the older code looked like. This would give us a better idea of what has changed and how.
The old compile script:
const path = require('path');
const fs = require('fs');
const solc = require('solc');
const inboxPath = path.resolve(__dirname, 'contracts', 'Inbox.sol');
const source = fs.readFileSync(inboxPath, 'UTF-8');
module.exports = solc.compile(source, 1).contracts[':Inbox'];
Explaining the code:
So, what is actually happening in here. What do we understand with all those lines of code up there? Well, let me explain in a step-by-step manner. We’re beginners we do get off the track sometimes. This breather should get you back on it!
- Firstly, we are importing the required modules: fs, path, and solc.
- Next, we are taking the file path of the Inbox.sol smart contract.
- We are then reading the file contents and marking it as source so we can pass it into the compiler for compiling. On the second argument, we are also saying readFileSync that the contents are utf-8 encoded.
- The compiler then takes the source and selects the inbox property on the object that we receive as the output. We are then immediately exporting it for deployment purposes.
The new and refactored compile script:
const path = require('path');
const fs = require('fs');
const solc = require('solc');
const inboxPath = path.resolve(__dirname, 'contracts', 'Inbox.sol');
const source = fs.readFileSync(inboxPath, 'utf8');
const input = {
language: 'Solidity',
sources: {
'Inbox.sol': {
content: source,
},
},
settings: {
outputSelection: {
'*': {
'*': ['*'],
},
},
},
};
module.exports = JSON.parse(solc.compile(JSON.stringify(input))).contracts[
'Inbox.sol'
].Inbox;
Explaining the code:
The new and refactored code to compile using Solc turned out slightly longer than it was before. Let us understand below if it is doing anything different or not:
- As usual, we are importing the required modules: fs, path, and solc.
- We are then taking the file path of the Inbox.sol file as before
- We are obviously taking that file path and reading the contents of it and specifying the utf-8 encoding value
- We then add a new object in the file called input that calls for requiring some keys like the source, and settings.
- We then take this input, convert it into a string value and pass it to the solc compiler. This solc compiler’s output is then parsed into a JSON output. We are then selecting the contracts key and on it, we are looking for the Inbox key.
With this change, we are good to go ahead and actually try to deploy our code on the Ethereum blockchain which is what we are doing next!
Deploying Contract for Testing Using Mocha
Well, before we actually deploy our contract on the Ethereum blockchain on Rinkeby, Ropsten, Kovan or Goerli, it is a good practice to always test your code locally.
For this we have Mocha. To I am using Mocha version 9.1.3 for this guide which is, while I write, the latest.
To begin with, I am going to write some tests in my test script in test/Inbox.test.js. I will use Ganache to grab a copy of the Ethereum blockchain on my machine so I can use it for testing with Mocha. I will also use web3 to connect with that blockchain.
Here’s what my test script looks like:
const assert = require('assert');
const ganache = require('ganache-cli');
const Web3 = require('web3');
const web3 = new Web3(ganache.provider());
const { abi, evm } = require('../compile');
let accounts;
let inbox;
beforeEach(async () => {
// Get a list of all accounts
accounts = await web3.eth.getAccounts();
inbox = await new web3.eth.Contract(abi)
.deploy({
data: evm.bytecode.object,
arguments: ['Hi there!'],
})
.send({ from: accounts[0], gas: '1000000' });
});
describe('Inbox', () => {
it('deploys a contract', () => {
assert.ok(inbox.options.address);
});
it('has a default message', async () => {
const message = await inbox.methods.message().call();
assert.equal(message, 'Hi there!');
});
it('can change the message', async () => {
await inbox.methods.setMessage('bye').send({ from: accounts[0] });
const message = await inbox.methods.message().call();
assert.equal(message, 'bye');
});
});
We are putting up 3 tests here in our file.
- To bring it to your attention, I have imported the abi and evm from my new compile script. I have also provided web3 with a ganache provider.
- We are first checking if the contract ever deploys to the network. Secondly, we want to check if it holds the default value, i.e., ‘Hi there!’ that we passed in our arguments key.
- Later, in the test we are checking if the contract can change the message to given value ‘bye’.
Running our test:
$ npm run test
> [email protected] test
> mocha
Inbox
✔ deploys a contract
✔ has a default message (205ms)
✔ can change the message (472ms)
3 passing (3s)
Here’s the result!
Deploying Smart Contract on Rinkeby
We are now ready to deploy our contract on the Rinkeby test network. We shall now write a deploy script for this purpose.
My deploy script looks like this:
const HDWalletProvider = require('@truffle/hdwallet-provider');
const Web3 = require('web3');
const { abi, evm } = require('./compile');
provider = new HDWalletProvider(
'key shrimp shell dump about fog death unit hard find doomy surprise,
'https://rinkeby.infura.io/v3/900629bb1516987e9a08e762ef085a1a'
);
const web3 = new Web3(provider);
const deploy = async () => {
const accounts = await web3.eth.getAccounts();
console.log('Attempting to deploy from account', accounts[0]);
const result = await new web3.eth.Contract(abi)
.deploy({ data: evm.bytecode.object, arguments: ['Hi there!'] })
.send({ gas: '1000000', from: accounts[0] });
console.log('Contract successfully deployed to', result.options.address);
provider.engine.stop();
};
deploy();
Great! Please make sure you use your own private key and Infura key😊.
Let us now run the script to see if it is working.
Running the deploy script:
$ node deploy.js
Attempting to deploy from account 0x5bA36E8dc1b0b5236f0a7330e0B34B70258F4De5
Contract successfully deployed to 0x83E0Cf866AaC4C228fa6350eC7e2e5956630A4B8
Perfect it was a success!
Conclusion
Learn to compile using Solc 0.5 and above versions in Solidity.
Noteworthy References
https://stackoverflow.com/questions/54412333/how-to-compile-solidity-using-solc-0-5