Webjs and the ABI Array¶
You're maybe wondering, what's this ABI array? And why do I need it for interacting with smart contracts.
Those are really good questions which I am trying to answer now in this lecture.
ABI stands for Application Binary Interface.
When you compile a smart contract then you get bytecode which gets deployed. Inside there are assembly opcodes telling the EVM during execution of a smart contract where to jump to. Those jump destinations are the first 4 bytes of the keccak hash of the function signature.
Best is, we're looking through the lens of the debugger into the execution of a smart contract and run through that.
Enable the Debugger Plugin¶
In Remix, go to the Plugins and enable the Debugger plugin.
For a short-cut, click this link
Add the following sample code:
//SPDX-License-Identifier: MIT
pragma solidity 0.8.14;
contract MyContract {
uint public myUint = 123;
function setMyUint(uint newUint) public {
myUint = newUint;
}
}
- Deploy the Smart Contract
- update the
myUint
throughsetMyUint
- Then hit the "debug" button in the console window
Using the Remix Debugger¶
The debugger will open up. On the left side, you see a horizontal scrollbar. Scroll it all the way to the beginning:
If you scroll (or step into) until instruction 041, you should see something like PUSH4 e492fd84
, which means, its now pushing the 4 bytes e492fd84 onto the stack and then in 046 its comparing it to the first 4 bytes of the calldata, which, incidentally also contains e492fd84 as the first 4 bytes.
Where are they coming from?
It's the first 4 bytes of the function signature bytes4(keccak256(setMyUint(uint256)))
.
As you know with hashes, once you hashed a value its hard to go back, unless you have a rainbow table or do brute forcing of some sorts.
And web3js tries to offer nice functions to interact with a smart contract. So, in web3js, you can do things like contractInstance.methods.setMyUint(123)
, all with auto-completion. That's only possible, if we provide the information what functions exist on a smart contract to web3js.
This is what the ABI array does. You can stop the debugger now...
The ABI Array¶
The ABI Array contains all functions, inputs and outputs, as well as all variables and their types from a smart contract.
If you open up the artifacts/MyContract.json file in the file-explorer, you can scroll all the way to the bottom. There you find the ABI array:
If you want to interact with a smart contract from web3js, you need two things:
- the ABI array
- the contract address (or you deploy the contract through web3js)
Add the following script and add the address of your contract from the Deploy & Send Transactions plugin
(async() => {
const address = "ENTER_ADDRESS_HERE_FROM_RUN_TX_PLUGIN";
const abi = [
{
"inputs": [],
"name": "myUint",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "newUint",
"type": "uint256"
}
],
"name": "setMyUint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
];
let contractInstance = new web3.eth.Contract(abi, address);
console.log(await contractInstance.methods.myUint().call());
let accounts = await web3.eth.getAccounts();
await contractInstance.methods.setMyUint(345).send({from: accounts[0]});
console.log(await contractInstance.methods.myUint().call());
})()
Then right-click on the file and run the script.
It should output 345 at the end:
Now you're ready for some more advanced contract interaction. Let's have a look at events next!