In order to automate processes related to Axie Infinity I needed to read data from smart contracts deployed to the Ronin sidechain. Because Ronin is an EVM compatible blockchain, the same tools used for Ethereum will work for Ronin. However, you still need three critical things: the URL of a Ronin RPC server, the ABI of the smart contract you want to interact with and the address it was deployed to on Ronin.
After doing some research I was able to find the RPC server and the smart contract addresses but I haven’t been able to fin the ABIs yet. Unfortunately I can’t share the URL of the RPC server or the addresses of the smart contracts as it has been forbidden by someone on Discord who I imagine is a mod from Sky Mavis. You’ll need to find that information by yourself.
If you do manage to find the RPC endpoint and the addresses I’ll show you how to read data from the SLP, AXS, WETH and Axie smart contracts even if you don’t have access to their specific ABIs as they should follow the standardize interfaces for ERC20 and ERC721 tokens. The goal here is to create a generic ERC20 and ERC721 ABI that we can use with web3
to query data from any of those smart contracts.
Creating a Generic ERC20 Token ABI
To start, we should create a folder for our project that I’m calling simply “ronin”.
$ mkdir ronin
$ cd ronin
Because it’s an EVM compatible blockchain we are going to use truffle as with any other Ethereum smart contract.
$ npm install -g truffle
$ truffle init
Truffle comes with tools for deploying and testing smart contracts but we are not interested in any of that. We are not going to develop a smart contract, we just want to create a generic ABI that we can use with web3
so let’s get rid of the extra boilerplate.
$ rm -rf test migrations contracts/Migrations.sol
After removing those files and folders our project structure is very simple.
$ tree
>>>
.
├── contracts
└── truffle-config.js
We can now create a template for our generic ERC20 smart contract using truffle.
$ truffle create contract GenericERC20
Running that command creates the following file:
contracts/GenericERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
contract GenericERC20 {
constructor() public {
}
}
Because we just want to create the ABI we can focus on the interface and not the implementation of our smart contract. For this reason we can turn our GenericERC20 smart contract into an “abstract” one so we can omit any implementation details.
contracts/GenericERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
abstract contract GenericERC20 {}
Just because we have named our smart contract “GenericERC20” doesn’t make it ERC20 compliant. For that we can use OpenZeppelin to inherit from a well known implementation of the ERC20 token. To use this smart contract library we need to use npm so the first step is to actually create a package.json
file to track our dependencies.
$ npm init -y
We can now go ahead and download the OpenZeppelin library.
$ npm install @openzeppelin/contracts
To convert our GenericERC20 token into a real one, we have to inherit from the appropriate ERC20 library.
contracts/GenericERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
abstract contract GenericERC20 is ERC20 {}
At this point we could try to compile our smart contract to generate the ABI but this would fail. By default Truffle uses an old version of the solc
compiler while OpenZeppelin expects a newer version. To fix this mismatch we can modify Truffle’s config file to instruct the framework to download and use a newer version of the compiler.
truffle-config.js
module.exports = {
compilers: {
solc: {
version: "0.8.6",
},
},
};
We are now ready to compile.
$ truffle compile
This compilation will create the ABI we need along with other related ones that we can ignore. The new folder structure is presented below.
$ tree -I node_modules
>>>
.
├── build
│ └── contracts
│ ├── Context.json
│ ├── ERC20.json
│ ├── GenericERC20.json
│ ├── IERC20.json
│ └── IERC20Metadata.json
├── contracts
│ └── GenericERC20.sol
├── package-lock.json
├── package.json
└── truffle-config.js
We are only interested in the GenericERC20.json
file that has the ABI we need to read data from any of the ERC20 tokens deployed to Ronin.
Using web3 to Interact with Ronin
Next, we are going to use web3
to talk to Ronin using our newly created ABI. Along with this library I’m going to install typescript
and ts-node
to enable advanced autocomplete, strong typing and to avoid having a build process.
$ npm install web3 typescript ts-node
To use Typescript it’s always recommended to have a tsconfig.json
for our IDE and for more advanced configurations of the language interpreter.
$ npx tsc --init
Next, we create a folder to hold web3
related files for organization.
$ mkdir web3
$ touch web3/main.ts
We can finally create our script to talk to Ronin.
web3/main.ts
import Web3 from "web3";
import { AbiItem } from "web3-utils/types/index.d";
import GenericERC20 from "../build/contracts/GenericERC20.json";
const roninRpcUrl = "you-have-to-find-the-url-yourself";
const slpAddress = "you-have-to-find-the-address-yourself";
const init = async () => {
const web3 = new Web3(roninRpcUrl);
const contract = new web3.eth.Contract(
GenericERC20.abi as AbiItem[],
slpAddress
);
const name = await contract.methods.name().call();
console.log(name);
};
init();
The script is fairly simple as it first connects to the Ronin blockchain through the RPC server, creates an instance of the GenericERC20
smart contract using the ABI and the address for the SLP smart contract, and finally calls the function name()
on the smart contract.
If we try to execute this Typescript file it will fail because by default it doesn’t know how to import JSON files as it’s the case of the ABI. This could be fixed by a simple tweak of its configuration file.
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true
}
}
Finally we can create a couple of scripts in our package.json
to describe how to compile and run our code.
package.json
{
//...
"scripts": {
"start": "ts-node ./web3/main.ts",
"compile": "truffle compile"
},
//...
}
We are now ready to use our script to get our first piece of information directly from the SLP contract deployed to the Ronin sidechain.
$ npm start
>>>
Smooth Love Potion
It works!
Conclusion
The same ABI can be used to interact with the AXS and WETH smart contract if you are able to find their addresses. You can follow a similar pattern to create a generic ERC721 ABI by using the corresponding implementation from OpenZeppelin and then talking to the Axie smart contract.
Another very interesting smart contract to read data from is the marketplace but unfortunately that’s a custom smart contract that doesn’t follow a well known standard as the tokens. The challenge here is not only to find the address of such smart contract, but find and potentially reverse engineer its ABI.
All these hurdles should be over once the Sky Mavis team is able to protect their RPC server with an API key and the interface is stable enough to be shared. I hope that happens soon.
Always following your articles. Congratulations
hello, i found the rpc server url, but it seens like a read only network, can’t send any transaction to write it
i found the rpc server url, but i can’t send a write transaction to write the network, can you help me ?
I’m sorry but I haven’t tried myself sending write transactions to the blockchain yet
I also can’t write to the Ronin network. Can you recommend any other side chains that I can use to build a game?
The only other EVM compatible sidechain that it’s open to devs that I’m aware of is Polygon. Another option that’s not EVM compatible but promising IMO is Flow. The third option, but more far fetched as the technology is under development, is Gala Chain as they have a program to fund indy games in their platform with up to $1 million dollars in funding.