Ir al contenido principal
Time to read: 1 min

Project Setup & Smart Contract Deployment

This page covers everything from scaffolding the project to deploying the InclusiveDeFi contract on Rootstock Testnet. By the end of this page, you will have a live contract address on Chain ID 31 that the relay server can interact with.

nota

InclusiveDeFi is just a name of the contract; developers can change it as needed.

Prerequisites

Before starting, ensure you have the following:

Scaffolding the Project

This project uses Hardhat 3 Beta with the mocha + ethers toolbox. The folder structure is automatically generated by Hardhat's initializer, so no manual setup is required.

Run the following in your terminal to scaffold a new Hardhat 3 project:

mkdir ussd-rsk && cd ussd-rsk
npx hardhat --init

When prompted, select the TypeScript + mocha + ethers template. Hardhat will generate the base project structure:

ussd-rsk/
├── contracts/ ← Place your Solidity contracts here
├── ignition/
│ └── modules/ ← Hardhat Ignition deployment modules
├── test/ ← Mocha test files
├── hardhat.config.ts ← Network and compiler configuration
├── tsconfig.json
└── package.json

After scaffolding, install dependencies:

npm install

Then add the additional runtime dependencies needed for the relay server:

npm install express dotenv
npm install --save-dev @types/express tsx
npm install --save-dev @nomicfoundation/hardhat-toolbox-mocha-ethers

Your final package.json should look like this:

{
"name": "ussd-rsk",
"version": "1.0.0",
"type": "module",
"scripts": {
"start-bridge": "tsx index.ts"
},
"dependencies": {
"dotenv": "^17.3.1",
"express": "^5.2.1"
},
"devDependencies": {
"@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.3",
"@types/express": "^5.0.6",
"@types/node": "^22.19.11",
"chai": "^5.1.2",
"ethers": "^6.16.0",
"hardhat": "^3.1.11",
"tsx": "^4.21.0",
"typescript": "~5.8.0"
}
}

Environment Variables

Add a .env file to the project root with the following variables:

PRIVATE_KEY=your_relayer_wallet_private_key_here
RSK_TESTNET_RPC=https://rpc.rootstock.io/
advertencia

Never commit .env to version control. It contains the relayer private key.

Add .env to your .gitignore immediately:

node_modules/
dist/
artifacts/
cache/
.env

Hardhat Configuration

Update hardhat.config.ts to include Rootstock(RSK) Testnet as a named HTTP network:

import hardhatToolboxMochaEthersPlugin from "@nomicfoundation/hardhat-toolbox-mocha-ethers";
import { configVariable, defineConfig } from "hardhat/config";
import * as dotenv from "dotenv";

dotenv.config();

export default defineConfig({
plugins: [hardhatToolboxMochaEthersPlugin],

solidity: {
profiles: {
default: {
version: "0.8.28",
},
production: {
version: "0.8.28",
settings: {
optimizer: { enabled: true, runs: 200 },
},
},
},
},

networks: {
// Local simulated networks for testing
hardhatMainnet: {
type: "edr-simulated",
chainType: "l1",
},
hardhatOp: {
type: "edr-simulated",
chainType: "op",
},

// RSK Testnet - Chain ID 31
rskTestnet: {
type: "http",
chainType: "l1",
url: "https://rpc.rootstock.io/",
chainId: 31,
accounts: [process.env.PRIVATE_KEY!],
},
},
});
nota

Rootstock is fully EVM-compatible; therefore, set chainType: "l1". The public node at https://rpc.rootstock.io/ is rate-limited and intended for development only. Use a dedicated RPC endpoint for production environments.

The Smart Contract

Create contracts/InclusiveDeFi.sol, which serves as the on-chain core of the system. It maintains internal balance and loan state for all users who interact through the relay:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract InclusiveDeFi {
mapping(address => uint256) public balances;
mapping(address => uint256) public loans;

event Transfer(address indexed from, address indexed to, uint256 amount);
event LoanIssued(address indexed user, uint256 amount);

// P2P Transfer - moves balance between two internal accounts
function transfer(address to, uint256 amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
balances[to] += amount;
emit Transfer(msg.sender, to, amount);
}

// Micro-Loan - issues 0.01 tRBTC, one active loan per address
function applyForLoan() public {
require(loans[msg.sender] == 0, "Existing loan active");
uint256 loanAmount = 0.01 ether;
loans[msg.sender] = loanAmount;
balances[msg.sender] += loanAmount;
emit LoanIssued(msg.sender, loanAmount);
}

// Read - returns internal balance for any address
function getBalance(address user) public view returns (uint256) {
return balances[user];
}

// Deposit tRBTC into the contract (used for seeding and testing)
function deposit() public payable {
balances[msg.sender] += msg.value;
}
}

Contract Design Notes

The contract uses internal accounting and does not implement ERC-20 or hold externally transferred tokens. All balances tracked in getBalance() are denominated in wei (tRBTC) and represent funds that have been deposited via deposit() or credited via applyForLoan().

The transfer() function moves value between two entries in the getBalance() mapping. It does not send native tRBTC but updates internal records. This is intentional, as it allows the relayer to call transfer() on behalf of any user without requiring the user to hold tRBTC for gas.

nota

applyForLoan() credits the loan amount to the caller's getBalance() entry without requiring collateral. This is suitable for a demo only a production system must add a repayment flow along with either collateral requirements or a credit-scoring oracle before enabling this feature.

Ignition Deployment Module

Create ignition/modules/InclusiveDeFi.ts as the Hardhat Ignition module that describes how the contract should be deployed:

import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";

const InclusiveDeFiModule = buildModule("InclusiveDeFiModule", (m) => {
const inclusiveDeFi = m.contract("InclusiveDeFi");
return { inclusiveDeFi };
});

export default InclusiveDeFiModule;

Deploying to Rootstock Testnet

Run the following command to deploy:

npx hardhat ignition deploy --network rskTestnet ignition/modules/InclusiveDeFi.ts

On success, Hardhat Ignition outputs the deployed contract address and writes deployment artifacts to ignition/deployments/chain-31/:

Deployed Addresses
InclusiveDeFiModule#InclusiveDeFi: 0xYourDeployedContractAddress

The deployed_addresses.json file under ignition/deployments/chain-31/ will also record this address for future reference.

nota

Copy this contract address. You will need to paste it into CONTRACT_ADDRESS in index.ts before starting the relay server.

Verifying the Deployment

To verify your deployment, search for your contract address on the Rootstock Testnet Explorer to view the transaction, bytecode, and ABI. You can also inspect ignition/deployments/chain-31/journal.jsonl, a successful deployment entry ends with:

{
"futureId": "InclusiveDeFiModule#InclusiveDeFi",
"result": {
"address": "0xYourDeployedContractAddress",
"type": "SUCCESS"
},
"type": "DEPLOYMENT_EXECUTION_STATE_COMPLETE"
}

Next Steps

Once your contract is deployed to Rootstock Testnet, follow the Relay Server & Gateway Integration guide to build the USSD bridge for feature phone users.

Última actualización en por jayzalani