> For the complete documentation index, see [llms.txt](/ko/llms.txt).

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.

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

## Prerequisites

Before starting, ensure you have the following:

- Node.js v18+
- `npm` or `pnpm`
- A funded Rootstock Testnet wallet. Get tRBTC from the [Rootstock Testnet Faucet](https://faucet.rootstock.io).
- Basic familiarity with [Solidity](https://soliditylang.org/) and [Hardhat](https://hardhat.org/) is recommended.

## 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:

```bash
mkdir ussd-rsk && cd ussd-rsk
npx hardhat --init
```
When prompted, select the TypeScript + mocha + ethers template. Hardhat will generate the base project structure:

```plaintext
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:

```bash
npm install
```

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

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

Your final `package.json` should look like this:

```json
{
  "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:

```dotenv
PRIVATE_KEY=your_relayer_wallet_private_key_here
RSK_TESTNET_RPC=https://rpc.rootstock.io/
```

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

Add `.env` to your `.gitignore` immediately:

```gitignore
node_modules/
dist/
artifacts/
cache/
.env
```

## Hardhat Configuration

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

```typescript



dotenv.config();

export default defineConfig({
  plugins: [hardhatToolboxMochaEthersPlugin],

  solidity: {
    profiles: {
      default: {
        version: "0.8.30",
      },
      production: {
        version: "0.8.30",
        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!],
    },
  },
});
```

:::note
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:

export const inclusiveDeFiSource = `// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

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;
    }
}`;



:::info[Try this contract in Remix]
Want to deploy and interact with `InclusiveDeFi` without any local setup? Use the button below to open it directly in the Remix IDE. You'll need MetaMask with [Rootstock Testnet configured](/dev-tools/wallets/metamask/) — see the full [Remix + Rootstock guide](/developers/quickstart/remix/) for the exact steps.

{/* Remix deep-link for InclusiveDeFi: https://remix.ethereum.org/?#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4zMDsKCmNvbnRyYWN0IEluY2x1c2l2ZURlRmkgewogICAgbWFwcGluZyhhZGRyZXNzID0%2BIHVpbnQyNTYpIHB1YmxpYyBiYWxhbmNlczsKICAgIG1hcHBpbmcoYWRkcmVzcyA9PiB1aW50MjU2KSBwdWJsaWMgbG9hbnM7CgogICAgZXZlbnQgVHJhbnNmZXIoYWRkcmVzcyBpbmRleGVkIGZyb20sIGFkZHJlc3MgaW5kZXhlZCB0bywgdWludDI1NiBhbW91bnQpOwogICAgZXZlbnQgTG9hbklzc3VlZChhZGRyZXNzIGluZGV4ZWQgdXNlciwgdWludDI1NiBhbW91bnQpOwoKICAgIC8vIFAyUCBUcmFuc2ZlciAtIG1vdmVzIGJhbGFuY2UgYmV0d2VlbiB0d28gaW50ZXJuYWwgYWNjb3VudHMKICAgIGZ1bmN0aW9uIHRyYW5zZmVyKGFkZHJlc3MgdG8sIHVpbnQyNTYgYW1vdW50KSBwdWJsaWMgewogICAgICAgIHJlcXVpcmUoYmFsYW5jZXNbbXNnLnNlbmRlcl0gPj0gYW1vdW50LCAiSW5zdWZmaWNpZW50IGJhbGFuY2UiKTsKICAgICAgICBiYWxhbmNlc1ttc2cuc2VuZGVyXSAtPSBhbW91bnQ7CiAgICAgICAgYmFsYW5jZXNbdG9dICs9IGFtb3VudDsKICAgICAgICBlbWl0IFRyYW5zZmVyKG1zZy5zZW5kZXIsIHRvLCBhbW91bnQpOwogICAgfQoKICAgIC8vIE1pY3JvLUxvYW4gLSBpc3N1ZXMgMC4wMSB0UkJUQywgb25lIGFjdGl2ZSBsb2FuIHBlciBhZGRyZXNzCiAgICBmdW5jdGlvbiBhcHBseUZvckxvYW4oKSBwdWJsaWMgewogICAgICAgIHJlcXVpcmUobG9hbnNbbXNnLnNlbmRlcl0gPT0gMCwgIkV4aXN0aW5nIGxvYW4gYWN0aXZlIik7CiAgICAgICAgdWludDI1NiBsb2FuQW1vdW50ID0gMC4wMSBldGhlcjsKICAgICAgICBsb2Fuc1ttc2cuc2VuZGVyXSA9IGxvYW5BbW91bnQ7CiAgICAgICAgYmFsYW5jZXNbbXNnLnNlbmRlcl0gKz0gbG9hbkFtb3VudDsKICAgICAgICBlbWl0IExvYW5Jc3N1ZWQobXNnLnNlbmRlciwgbG9hbkFtb3VudCk7CiAgICB9CgogICAgLy8gUmVhZCAtIHJldHVybnMgaW50ZXJuYWwgYmFsYW5jZSBmb3IgYW55IGFkZHJlc3MKICAgIGZ1bmN0aW9uIGdldEJhbGFuY2UoYWRkcmVzcyB1c2VyKSBwdWJsaWMgdmlldyByZXR1cm5zICh1aW50MjU2KSB7CiAgICAgICAgcmV0dXJuIGJhbGFuY2VzW3VzZXJdOwogICAgfQoKICAgIC8vIERlcG9zaXQgdFJCVEMgaW50byB0aGUgY29udHJhY3QgKHVzZWQgZm9yIHNlZWRpbmcgYW5kIHRlc3RpbmcpCiAgICBmdW5jdGlvbiBkZXBvc2l0KCkgcHVibGljIHBheWFibGUgewogICAgICAgIGJhbGFuY2VzW21zZy5zZW5kZXJdICs9IG1zZy52YWx1ZTsKICAgIH0KfQ%3D%3D */}


:::

### 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.

:::note
`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:

```typescript

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:

```bash
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/`:

```plaintext
Deployed Addresses
InclusiveDeFiModule#InclusiveDeFi: 0xYourDeployedContractAddress
```

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

:::note
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](https://explorer.testnet.rootstock.io) to view the transaction, bytecode, and ABI. You can also inspect `ignition/deployments/chain-31/journal.jsonl`, a successful deployment entry ends with:

```json
{
  "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](../relay-server) guide to build the USSD bridge for feature phone users.