To interact with a Smart Contract running on Ethereum family blockchains you would need contract ABI (Application Binary Interface). You can copy/paste it from the Smart Contract source code documentation or you can automate the process by using blockchain explorer service and its API. Here is a quick guide on how to do it using Typescript. As Smart Contract example we will use Pancakeswap Prediction Smart Contract.
STEP 1. Find Smart Contract documentation
Do browser search for Pancakeswap Prediction Smart Contract. The link we are interested in is https://docs.pancakeswap.finance/products/prediction
STEP 2. Identify Smart Contract address and blockchain where it is deployed
Prediction Smart Contract address is 0x18B2A687610328590Bc8F2e5fEdDe3b582A49cdA
and it is running on BNB Smart Chain.
STEP 3. Identify explorer service for blockchain in use
BNB Smart Chain uses BscScan.
STEP 4. Open an account within blockchain explorer
To access BscScan API you would need to signup for an account.
STEP 5. Search for blockchain explorer Get Contract ABI
API documentation
The page we are looking for is https://docs.bscscan.com/api-endpoints/contracts and our endpoint looks as follows:
https://api.bscscan.com/api
?module=contract
&action=getabi
&address=0x18B2A687610328590Bc8F2e5fEdDe3b582A49cdA
&apikey=YourApiKeyToken
STEP 6. Integrate Get Contract ABI
endpoint into your code
Create project folder and init
mkdir common && cd common && npm init -y
Install typescript and axios as dependencies, init typescript
npm install -D typescript && npm install axios && tsc --init
Create project structure, we want it to be a npm module that we can publish into npm registry and import it into our main module, it will look as follows
- node_modules
- src
- smart-contract-utils
- types
- abi.ts
- abi.ts
- index.ts
- package.json
- package-lock.json
To build the above structure type the following commands from the root of your project
mkdir src
&& cd src && touch index.ts
&& mkdir smart-contract-utils
&& touch smart-contract-utils/abi.ts
&& mkdir smart-contract-utils/types
&& touch smart-contract-utils/types/abi.ts
&& cd ..
Now it is time to write our function, it will look as follows
import axios from "axios";
export const getContractABI = async (): Promise<string> => {
const data = await axios.get(
"https://api.bscscan.com/api
?module=contract
&action=getabi
&address=0x18B2A687610328590Bc8F2e5fEdDe3b582A49cdA
&apikey=YourApiKeyToken"
)
return data.data.result;
}
Place it into src/smart-contract-utils/abi.ts
file. Right now our function is tightly coupled to Prediction Smart Contract. Let's move contract address into function arguments and make it reusable for any Smart Contract deployed on BNB Smart Chain
import axios from "axios";
export const getContractABI = async (contract_address: string): Promise<string> => {
const data = await axios.get(
`https://api.bscscan.com/api
?module=contract
&action=getabi
&address=${contract_address}
&apikey=YourApiKeyToken`
);
return data.data.result;
}
Great. Can we do more? BscScan explorer is serving BNB Smart Chain which is a hard fork of the Go Ethereum protocol and as such, it shares many similarities with the Ethereum blockchain. Can we extend our function to retrieve ABI from Etherscan as well? Yes, we can. Etherscan has similar to BscScan API and it looks as follows
https://api.etherscan.io/api
?module=contract
&action=getabi
&address=0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413
&apikey=YourApiKeyToken
As you can see the only difference between Etherscan and BscScan is the base url. Excellent. Here is an improved version of our function
import axios from "axios";
export const getContractABI = async (
explorer_base_url: string, explorer_api_key: string, contract_address: string
): Promise<string> => {
const data = await axios.get(
`${explorer_base_url}
?module=contract
&action=getabi
&address=${contract_address}
&apikey=${explorer_api_key}`
)
return data.data.result;
}
We can reuse our function to retrieve ABI for any Smart Contract deployed on Ethereum or BNB Smart Chain and as additional touch, I would like to wrap function arguments into an object and give it an interface as a type guard. Place the following code into smart-contract-utils/types/abi.ts
file
export interface GetContractABIParams {
explorer_base_url: string;
explorer_api_key: string;
contract_address: string;
}
Import GetContractABIParams
interface into smart-contract-utils/abi.ts
file and use it
import axios from "axios";
import { GetContractABIParams } from "./types/abi"
export const getContractABI = async (
params: GetContractABIParams
): Promise<string> => {
const { explorer_base_url, explorer_api_key, contract_address } = params;
const data = await axios.get(
`${explorer_base_url}
?module=contract
&action=getabi
&address=${contract_address}
&apikey=${explorer_api_key}`
)
return data.data.result;
}
Our reusable function is ready, let's export it together with GetContractABIParams
interface through index.ts
file, our project entry point
export * from "./smart-contract-utils/abi"
export * from "./smart-contract-utils/types/abi"
That's it. In the next tutorial we will build our package and publish it to npm registry.
P.S. Other blockchains and explorers that could be used with this function are:
Polygon | PolygonScan
Optimism | OptimisticEtherScan
Top comments (0)