Comment on page
Read/Write Smart Contracts
ABIs (Application Binary Interface) can be thought of as a restaurant menu , they describe the possible functions that can be called to interact with a smart contract.
🍽
By knowing the functions available to a contract, we can programmatically use them — in situations where the project websites are down or when you need to automate certain transactions.
You will need Node.jsinstalled, a valid Arbiscan API Key and access to a node, such as from Infura or Alchemy.
In a new folder, initiate a new Node.js project with the command
npm init -y
to accept all default project parameters.A
package.json
file will be created for you, which contains all your packages and project information.
Create a new file named
script.js
.
In JavaScript, we'll be writing our code to make a request to the endpoint "Get Contract ABI for Verified Contract Source Codes", which you will need to specify your verified contract address.
https://api-goerli.arbiscan.io/api?module=contract&action=getabi&address=0xFc7a5BD22dFc48565D6f04698E566Dd0C71d3155&apikey=YourApiKeyToken
For this example, we'll be using a contract specifically deployed for this tutorial on the Goerli Testnet
async function main() {
// make an API call to the ABIs endpoint
const response = await fetch('https://api-ropsten.arbiscan.io/api?module=contract&action=getabi&address=0xFc7a5BD22dFc48565D6f04698E566Dd0C71d3155&apikey=YourApiKeyToken');
const data = await response.json();
// print the JSON response
let abi = data.result;
console.log(abi);
}
main();
We're using a public RPC endpoint hosted by Arbitrum in this case, if you are using Infura or Alchemy make sure to set your endpoint to the Goerli Testnet and copy the HTTPS endpoint.

We'll need to integrate a JavaScript library, known as Ether.js that will be used to interact with the Ethereum blockchain.
To do so, run the command
npm i ethers
from a terminal within this project directory to install it.Ether.js provides several classes such as a
Provider
, which represents the state of the Ethereum blockchain. We can create a new Provider
using the syntax below, and pass in our node URL to initiate a connection to the Ethereum network.const ethers = require("ethers");
async function main() {
const response = await fetch('https://api-goerli.arbiscan.io/api?module=contract&action=getabi&address=0xFc7a5BD22dFc48565D6f04698E566Dd0C71d3155&apikey=YourApiKeyToken');
const data = await response.json();
let abi = data.result;
console.log(abi);
// creating a new Provider, and passing in our node URL
const node = "https://goerli-rollup.arbitrum.io/rpc";
const provider = new ethers.providers.JsonRpcProvider(node);
main();
Another class that Ether.js allows us to create is a
Wallet
, which will allow us to specify a private key and use an Ethereum address.Performing write operations will incur gas costs, as such you may get some testnet ETH from a faucet to pay for transaction fees.
const ethers = require("ethers");
async function main() {
const response = await fetch('https://api-goerli.arbiscan.io/api?module=contract&action=getabi&address=0xFc7a5BD22dFc48565D6f04698E566Dd0C71d3155&apikey=YourApiKeyToken');
const data = await response.json();
let abi = data.result;
console.log(abi);
const node = "https://goerli-rollup.arbitrum.io/rpc";
const provider = new ethers.providers.JsonRpcProvider(node);
// initiating a new Wallet, passing in our private key to sign transactions
let privatekey = "fdfb72ce9754e3cbc1e79e44a8e20804cebd3c4a347605c6a3462a8de05b8784";
let wallet = new ethers.Wallet(privatekey, provider);
// print the wallet address
console.log("Using wallet address " + wallet.address);
}
main();
Finally, to interact with a smart contract we'll need to create a new
Contract
class.The Contract class accepts an input of a contract address, an ABI (which we retrieved from the API earlier), and a wallet address to pay gas for any contract interactions.
const ethers = require("ethers");
async function main() {
const response = await fetch('https://api-goerli.arbiscan.io/api?module=contract&action=getabi&address=0xFc7a5BD22dFc48565D6f04698E566Dd0C71d3155&apikey=YourApiKeyToken');
const data = await response.json();
let abi = data.result;
console.log(abi);
const node = "https://goerli-rollup.arbitrum.io/rpc";
const provider = new ethers.providers.JsonRpcProvider(node);
let privatekey = "fdfb72ce9754e3cbc1e79e44a8e20804cebd3c4a347605c6a3462a8de05b8784";
let wallet = new ethers.Wallet(privatekey, provider);
console.log("Using wallet address " + wallet.address);
// specifying the deployed contract address
let contractaddress = "0xFc7a5BD22dFc48565D6f04698E566Dd0C71d3155";
// initiating a new Contract
let contract = new ethers.Contract(contractaddress, abi, wallet);
}
main();
Having a closer look at the ABI we retrieved in Step 2, we can see that the contract has a function named
read
, that doesn't accept an input
however does return a uint256
number as an output
.[{
"inputs": [],
"name": "read" // Function named read
"outputs": [{
"internalType": "uint256",
"name": "",
"type": "uint256" //returns a uint256 as output
}],
"stateMutability": "view",
"type": "function"
}, {
"inputs": [{
"internalType": "uint256",
"name": "newScore",
"type": "uint256"
}],
"name": "write",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}]
We can therefore call that function of the contract, read the value stored and print it out.
You may run this code from your console using the command
node script.js
.Reading data stored in a contract incurs no gas cost, as it does not change the state of the Ethereum blockchain.
const ethers = require("ethers");
async function main() {
const response = await fetch('https://api-goerli.arbiscan.io/api?module=contract&action=getabi&address=0xFc7a5BD22dFc48565D6f04698E566Dd0C71d3155&apikey=YourApiKeyToken');
const data = await response.json();
let abi = data.result;
console.log(abi);
const node = "https://goerli-rollup.arbitrum.io/rpc";
const provider = new ethers.providers.JsonRpcProvider(node);
let privatekey = "fdfb72ce9754e3cbc1e79e44a8e20804cebd3c4a347605c6a3462a8de05b8784";
let wallet = new ethers.Wallet(privatekey, provider);
console.log("Using wallet address " + wallet.address);
let contractaddress = "0xFc7a5BD22dFc48565D6f04698E566Dd0C71d3155";
let contract = new ethers.Contract(contractaddress, abi, wallet);
// calling the "read" function to read the stored value
let read = await contract.read();
console.log("Value stored in contract is " + read.toString());
}
main();
Referring to the ABI once again, we can see that the contract has another method
write
, which accepts a uint256
number as an input and does not return any output
.[{
"inputs": [],
"name": "read"
"outputs": [{
"internalType": "uint256",
"name": "",
"type": "uint256"
}],
"stateMutability": "view",
"type": "function"
}, {
"inputs": [{
"internalType": "uint256", // Requires an uint256 input
"name": "newScore",
"type": "uint256"
}],
"name": "write", // Function named as write
"outputs": [], //Does not return an output
"stateMutability": "nonpayable",
"type": "function"
}]
We can call that function and pass in any
number
as a parameter. To check that its updated, we'll wait for a 2 block confirmation, and read the contract again to confirm that the number has been updated.You may run this code from your console using the command
node script.js
.Writing new data to a contract will incur gas costs, as it requires fees to be paid to miners to process your transaction. Make sure your wallet has been funded with some testnet ETH
const ethers = require("ethers");
async function main() {
const response = await fetch('https://api-goerli.arbiscan.io/api?module=contract&action=getabi&address=0xFc7a5BD22dFc48565D6f04698E566Dd0C71d3155&apikey=YourApiKeyToken');
const data = await response.json();
let abi = data.result;
console.log(abi);
const node = "https://goerli-rollup.arbitrum.io/rpc";
const provider = new ethers.providers.JsonRpcProvider(node);
let privatekey = "fdfb72ce9754e3cbc1e79e44a8e20804cebd3c4a347605c6a3462a8de05b8784";
let wallet = new ethers.Wallet(privatekey, provider);
console.log("Using wallet address " + wallet.address);
let contractaddress = "0xFc7a5BD22dFc48565D6f04698E566Dd0C71d3155";
let contract = new ethers.Contract(contractaddress, abi, wallet);
let read = await contract.read();
console.log("Value stored in contract is " + read.toString());
// call the "write" function to update the value to 420
let write = await contract.write(420);
// wait for 2 blocks of confirmation
write.wait(2)
.then(async () => {
// read the contract again, similar to above
let read = await contract.write();
console.log("Updated value stored in contract is " + read.toString());
});
}
main();
You've now mastered how to programmatically interact with smart contracts , using ABIs retrieved from the Arbiscan APIs.
✨
Possible use cases from this include minting NFTs right on the dot , performing trades on Decentralised Exchanges (DEXs) and automating token transfers at certain time intervals .
🎯
💰
⏰
The full sample code is on Github, feel free to experiment and use it ( with caution ) on real world contracts out there.