Smart Contracts using Ethers.js
Use the ethers.js library to interact with a smart contract deployed on the Ethereum Ropsten Testnet. First compile a contract, deploy it and finally invoke some of the contract’s functions once it’s deployed.
Compiling a Smart Contract
The Smart Contract object is a meta-class, so many of its functions are not defined until it is instantiated with an Application Binary Interface (ABI)
which is usually generated by a compiler, such as the Solidity Compiler. Therefore, we will use the solc-js
library – JavaScript bindings for the Solidity Compiler.
To start, create a new project directory in an appropriate place; open a terminal session and initialize a package.json file inside the project directory:
$ npm init -y
After that, install solc-js:
$ npm install ––save solc
Because we will be reading a smart contract from a file, we will need a file-system library:
$ npm install ––save fs-extra
Last but not least, we need to install ethers.js:
$ npm install ––save ethers
After we have installed our dependencies, create a JavaScript file called ethers-workflow.js
and require them.
Provider
links to a running node in order to connect to the Ethereum blockchain for issuing queries and sending state changing transactions. It is simply a connection to the network. For the purposes of this exercise, we will use Ropsten
as our provider.
Now, we will create a simple smart contract called ArrayOfFacts.sol which will store an array of strings called facts in the blockchain. Only the owner
of the contract can add facts
but anyone should be able to get a count
of how many facts there are and retrieve a specific fact by index
.
Now that we have written the smart contract, we will create a function in ethers-workflow.js which reads a file and returns its content.
Let’s now create a function to compile the smart contract: we will create a function called compileContract
which takes two parameters: the file name and the contract name. It will return an output of the compiled contract.
Save a reference to the ABI for later use:
const abi = compiledContract.interface;
Compile Contract
To compile the contract (2 Options):
- Follow tips at
ethers-abi-bytecode.js
- Use this command:
$ --bin --abi ArrayOfFacts.sol
Deploy a Smart Contract
Now that we have compiled our ArrayOfFacts.sol smart contract, it is time to deploy it on the Ropsten Testnet. For the example of the exercise, we will take one private key from MetaMask and use it to sign the deployment transaction.
If you do not have ETHt, use the MetaMask faucet.
Export the private key:
Create a constant to reference the private key copied from Metamask somewhere in ethers-workflow.js (don’t forget to prefix 0x
onto your private key!)
Then create a deployContract
function, which takes a private key, contract filename and the contract’s name as parameters.
To deploy a contract to the Ethereum Network, we must have its bytecode and its Application Binary Interface (ABI), both of which are usually generated by the Solidity Compiler during compilation. Then, we will use the Contract.getDeployTransaction (bytecode, interface …)
method, which generates the transaction needed to deploy the contract specified by the bytecode and interface. Any additional configuration details of the transaction can be passed in as the last parameter as an object (for example: gas limit, gas price, etc.).
Then, using the wallet object, we will send the transaction and receive the transaction through a callback.
As we can see, in this format, we receive hash of the transaction, the sender, the data, but on which address is the contract deployed? Therefore, we will use an ethers utility function which will give us the address of a deployed contract given a specific transaction. Let’s modify the deployContract
method.
In addition, you can wait for the transaction to be mined with Provider.waitForTransaction (txHash)
, which returns an object storing the contract’s address. Keep in mind you will have to wait a few seconds until the transaction is mined.
Save a reference to our contract address in ethers-workflow.js:
const contractAddress = '0x633e0cEAB8e6aE5F04ebD9F1eAf8EC0a10904b3C';
Now if we go to Ropsten Etherscan
and paste the address of the contract, we should see an overview of our contract.
Playing with the Smart Contract
Now that our smart contract is deployed, we will write to it using ethers to add facts. In order to do this, we will use ethers.Contract (addressOrName, abi, providerOrSigner)
method which connects to the contract address defined in the ABI. The method also takes a providerOrSigner
which may be any instance of a Wallet
, Provider
or Custom Signer
. For the purposes of this exercise, we will use a Wallet
instance.
Create a method called addFact
, which takes an contract address, an ABI of the contract, a private key for the wallet and a fact. The method will return a callback of the created transaction.
What will happen if someone, different from contract owner, tries to add a fact to the contract? RESULT: FAIL
Now, let’s create a method, which calls the contract’s function getFact(uint256 index)
. Keep in mind that when you want to GET
something from a contract, you do not need a wallet! Therefore, we will just use the provider
.
Last but not least, let’s create a function to call the count()
method of the contract, which returns the count of the facts in the contract.
Module
MI4: Module 5: E2