Automating Smart Contract ABI Loading with TypeScript
Tags: smartcontract, typescript, blockchain, web3
Published: 2023-03-07 13:44:16

Blockchain development necessitates interaction with smart contracts, which requires Application Binary Interfaces (ABIs). Automating the retrieval of ABIs can significantly enhance developer productivity and minimize errors. This guide provides a TypeScript-based approach to automate ABI retrieval, aiming to streamline the development workflow for Ethereum and EVM-compatible blockchain projects.

### Introduction to ABIs

ABIs are crucial for smart contract interactions, serving as the interface between blockchain applications and the contracts themselves. Manual handling of ABIs can be tedious and error-prone. This tutorial introduces an automated method to retrieve ABIs, using TypeScript, to simplify and improve the development process.

### Essential concepts

Before diving into the automation process, it's important to understand several key concepts:

**ABI (Application Binary Interface)**: The JSON-formatted description of a smart contract's functions and events, enabling interaction with the contract.
**EVM (Ethereum Virtual Machine)**: The runtime environment for executing smart contracts on Ethereum and EVM-compatible chains.
**BNB Smart Chain**: An EVM-compatible blockchain known for fast transactions and low fees.

### Prerequisites

To follow this guide, ensure you have:

Node.js and npm installed.
Basic knowledge of TypeScript and Node.js.
An IDE or text editor.

## Part 1: Project setup with VSCode

**Step 1: create the setup script using VSCode**
First, ensure you have Visual Studio Code installed on your system. Then, follow these steps to create your project setup script:

- **open Visual Studio Code:** launch VSCode from your applications menu or by typing code in your terminal, if you have the command line utilities installed.
- **create a new file:** in VSCode, go to File > New File to create a new file. Save this file with the name setup_project.sh in your desired workspace directory. You can save it by going to File > Save As and navigating to your workspace directory.
- **edit the script:** with setup_project.sh open in VSCode, copy and paste the following script into the editor:

```bash
#!/bin/bash

# Set your project name
PROJECT_NAME="your-project-name"

# Create project directory and enter it
mkdir $PROJECT_NAME
cd $PROJECT_NAME

# Initialize Node.js project
npm init -y

# Install TypeScript and other required dependencies
npm install --save-dev ts-node typescript @types/node dotenv axios

# Initialize tsconfig.json with default settings
npx tsc --init

# Create src directory and subdirectories
mkdir -p src/config src/blockchain-utils src/types

# Create TypeScript files with initial placeholder content
echo "// Config function for environment variables" > src/config/index.ts
echo "// Function to retrieve smart contract ABIs" > src/blockchain-utils/abi.ts
echo "// Type definitions for ABI-related functions" > src/types/abi.ts
echo "// Type definitions for config-related functions" > src/types/config.ts
echo "// Module entry point, exporting functions" > src/index.ts

# Create .env with specified content
echo "BSCSCAN_API_KEY=your_bscscan_api_key
BSCSCAN_BASE_URL=https://api.bscscan.com/api
PREDICTION_CONTRACT_ADDRESS=0x18B2A687610328590Bc8F2e5fEdDe3b582A49cdA" > .env

# Create .gitignore with specified content
echo "/node_modules
/.env" > .gitignore

echo "Project structure created and dependencies installed successfully."
```

- **save the Script:** After copying the script, save your changes by going to File > Save or pressing Ctrl+S (or Cmd+S on macOS).

**Step 2: open terminal in VSCode**
You can directly use the integrated terminal in VSCode to run commands. To open the terminal in VSCode, you can go to Terminal > New Terminal or use the shortcut Ctrl+`` (backtick) on Windows and Linux, or Cmd+`` on macOS.

**Step 3: make the script executable**
In the VSCode terminal, navigate to the directory where you saved setup_project.sh and run the following command to make the script executable:

```bash
chmod +x setup_project.sh
```

**Step 4: execute the script**
Still in the terminal, execute the script by running:

```bash
./setup_project.sh
```
This will create your project directory, set up the initial project structure, and install the necessary dependencies.

```
your-project-name/
│
├── src/
│   ├── config/
│   │   └── index.ts             # Config function for environment variables
│   │
│   ├── blockchain-utils/        
│   │   └── abi.ts               # Function to retrieve smart contract ABIs
│   │
│   ├── types/                  
│   │   └── abi.ts  
|   |          # Type definitions for ABI-related functions
│   │   └── config.ts 
|   |          # # Type definitions for config-related functions
│   └── index.ts                 # Module entry point, exporting functions
│
├── .env                         # Environment variables (not committed)
├── .gitignore                   # Untracked files to ignore (e.g., .env, node_modules/)
├── package.json                 # Project manifest
├── package-lock.json            # Locked versions of installed packages
└── tsconfig.json                # TypeScript compiler configuration

```

## Part 2: Implementation 

**Step 1: Identifying the Smart Contract**
Begin by searching for the PancakeSwap Prediction Smart Contract [documentation](https://docs.pancakeswap.finance/products/prediction), which contains the necessary ABI information.

**Step 2: Getting Smart Contract details**
Find the Prediction Smart Contract's address (0x18B2A687610328590Bc8F2e5fEdDe3b582A49cdA) and its deployment network (BNB Smart Chain).

**Step 3: Using a blockchain explorer**
For BNB Smart Chain, [BscScan](https://bscscan.com/) is the preferred blockchain explorer with API support for retrieving contract ABIs.

**Step 4: BscScan account setup**
Create an [account](https://bscscan.com/register) on BscScan to obtain an API key, which is necessary for accessing their API services.

**Step 5: Exploring the API**
Consult BscScan's [API documentation](https://docs.bscscan.com/) to find the [Get Contract ABI endpoint](https://docs.bscscan.com/api-endpoints/contracts). The endpoint structure is as follows:

```
https://api.bscscan.com/api
      ?module=contract
      &action=getabi
      &address=<SmartContractAddress>
      &apikey=<YourApiKey>

```

**Step 6: Implementing the ABI loader**
- **Creating function parameters types**:  Define the types that will be utilized throughout the project for clarity and to ensure type safety. We are specifying two interfaces: GetContractABIParams and Config. 

```javascript
// src/types/abi.ts
export interface GetContractABIParams {
    explorerBaseUrl: string;
    explorerApiKey: string;
    contractAddress: string;
}
```

```javascript
// src/types/config.ts
export interface Config {
    bscScanApiKey: string;
    bscScanBaseUrl: string;
    predictionContractAddress: string;
}
```


- **Creating a configuration function**: to securely manage your API keys and other sensitive information, wrap environment variable loading into a dedicated configuration function:

```javascript
// src/config/index.ts
import dotenv from 'dotenv';
import { Config } from '../types/config';

dotenv.config();

export const loadConfig = (): Config => {
    const bscScanApiKey = process.env.BSCSCAN_API_KEY;
    const bscScanBaseUrl = process.env.BSCSCAN_BASE_URL;
    const predictionContractAddress = process.env.PREDICTION_CONTRACT_ADDRESS;


    if (!bscScanApiKey || !bscScanBaseUrl || !predictionContractAddress) {
        throw new Error('Missing API keys in environment variables');
    }

    return {
        bscScanApiKey,
        bscScanBaseUrl,
        predictionContractAddress,
    };
};

```

- **Creating the ABI loader function:** Design your ABI loader function with flexibility and comprehensive error handling in mind. Introduce parameters for the blockchain explorer URL and API key to make the function reusable across different blockchains:

```javascript
// src/blockchain-utils/abi.ts
import axios from 'axios';
import { GetContractABIParams } from '../types/abi';


export const getContractABI = async (params: GetContractABIParams): Promise<string> => {

    const { explorerBaseUrl, explorerApiKey, contractAddress } = params;
    try {
        const response = await axios.get(`${explorerBaseUrl}/api?module=contract&action=getabi&address=${contractAddress}&apikey=${explorerApiKey}`);
        return response.data.result;
    } catch (error) {
        console.error('Error retrieving contract ABI:', error);
        throw error;
    }
};
```

- **Usage**: here's how you can use the setup to retrieve a smart contract's ABI:

```javascript
//src/index.ts
import { getContractABI } from "./blockchain-utils/abi";
import { loadConfig } from "./config";

const config = loadConfig();

const main = async () => {
    const abi = await getContractABI({
        explorerBaseUrl: config.bscScanBaseUrl,
        explorerApiKey: config.bscScanApiKey,
        contractAddress: config.predictionContractAddress,
    });
    return abi;

}

main().then((abi) => {
    console.log(abi);
}).catch((error) => {
    console.error(error);
});

```

- **Running the script:** use the ts-node command from your terminal (root of the project):

```
ts-node src/index.ts
```

### Wrapping Up and Looking Ahead

This guide has walked you through automating the retrieval of Smart Contract ABIs, a process that enhances efficiency and reduces errors in blockchain development. As the blockchain ecosystem evolves, staying informed and adaptable is crucial for success.

### Next Steps

- Interact with Smart Contracts: Use the retrieved ABIs to interact with smart contracts through libraries like Web3.js or Ethers.js.
- Explore dApp Development: Consider building a decentralized application (dApp) to deepen your understanding of blockchain development.

Link to [github repository](https://github.com/BellaBe/evm-abi-fetcher)