From 6e72a94bd77a7ddd2eac9d43ea5bc0f1b4d937c3 Mon Sep 17 00:00:00 2001 From: ishitarastogi Date: Tue, 22 Apr 2025 01:10:40 +0530 Subject: [PATCH 1/3] docs: added Rootstock Foundry guide for ERC-20 token faucet --- docs/04-resources/04-tutorials/index.md | 20 +- .../rootstock-foundry-faucetToken-guide.md | 607 ++++++++++++++++++ 2 files changed, 626 insertions(+), 1 deletion(-) create mode 100644 docs/04-resources/04-tutorials/rootstock-foundry-faucetToken-guide.md diff --git a/docs/04-resources/04-tutorials/index.md b/docs/04-resources/04-tutorials/index.md index e916f9e4..7f0fdbb8 100644 --- a/docs/04-resources/04-tutorials/index.md +++ b/docs/04-resources/04-tutorials/index.md @@ -2,7 +2,16 @@ sidebar_position: 4 title: Tutorials sidebar_label: Tutorials -tags: [rsk, rootstock, beginner, quick starts, advanced, port to rootstock, tutorials] +tags: + [ + rsk, + rootstock, + beginner, + quick starts, + advanced, + port to rootstock, + tutorials, + ] description: "Tutorials and learning resources" --- @@ -12,6 +21,15 @@ values={[ {label: 'Advanced', value: 'advanced'}, {label: 'Port to Rootstock', value: 'port-dapps'} ]}> + + 🛠️ Setting Up Your Development Environment + +

This section walks you through installing Foundry, setting up the Rootstock development kit, configuring RPCs, and funding your wallet to begin deploying smart contracts.

+ +

Step 1: Install Foundry

+ +

Foundry is a fast, modular toolkit for EVM smart contract development.

+ +
curl -L https://foundry.paradigm.xyz | bash
+foundryup
+
+ +
    +
  • This installs forge (build/test), cast (CLI), anvil (local node), and chisel (REPL).
  • +
  • Windows users: Use Git BASH or WSL. PowerShell is not supported.
  • +
+ +
+ +

Step 2: Clone the Rootstock Foundry Kit

+ +
git clone https://github.com/rsksmart/rootstock-foundry-starterkit.git
+cd rootstock-foundry-starterkit
+
+ +
+ +

Step 3: Install Dependencies

+ +

This project uses OpenZeppelin's ERC20 implementation. Install it using:

+ +
forge install openzeppelin-contracts-08=OpenZeppelin/openzeppelin-contracts@v4.8.3 --no-commit
+
+ +

Note: The starter kit supports other versions too, if needed.

+ +
+ +

📁 Project Structure

+ +

Once set up, your folder structure will look like this:

+ +
.
+├── lib/            # Installed dependencies (e.g., OpenZeppelin)
+├── script/         # Deployment & utility scripts
+│   └── ERC20Token.s.sol
+├── src/            # Your smart contracts
+│   └── ERC20Token.sol
+├── test/           # Foundry test files
+│   └── ERC20Token.t.sol
+└── .env            # Environment variables (⚠️ never commit this)
+
+ +
+ +

Step 4: Configure Rootstock RPC & Fund Your Wallet

+ +

Option 1: Use Public RPC

+
    +
  • Testnet: https://public-node.testnet.rsk.co
  • +
  • Mainnet: https://public-node.rsk.co
  • +
+

+ To manually add Rootstock networks in MetaMask, refer to the official + MetaMask Setup Guide. +

+ +

Option 2: Use a Personal RPC

+

+ You can also create a custom RPC endpoint via the + Rootstock RPC Dashboard. After creating an account, generate and copy your API key from the dashboard. +

+ +

How to Get Testnet RBTC

+
    +
  1. + Visit the + Rootstock Testnet Faucet + and paste your wallet address. +
  2. +
  3. + You’ll receive a small amount of tRBTC to use for contract deployments. +
  4. +
+ +
+

Step 5: Set Up Environment Variables

+ +

Inside your project's root directory, create a .env file to securely store Private Key.

+ +
touch .env
+
+ +

And your wallet's private key (it should hold testnet RBTC):

+ +
PRIVATE_KEY=0xyour_testnet_private_key
+
+ +:::tip Ensure the private key copied starts with 0x... ::: + +

🚨 Ensure .env is listed in your .gitignore.

+ +
+

Compile, Test & Deploy ERC20Token

+ +

Now that your environment is set up and the dependencies are installed, let’s walk through building, testing, and deploying your ERC-20 faucet contract.

+ +

Step 6: Compile the Contracts

+ +

This ensures your contracts are valid and bytecode is generated in the out/ directory.

+ +
forge build
+
+ +

If everything works, you’ll see output confirming successful compilation.

+ +
+ +

Step 7: Run the Tests

+ +

Test the functionality of your ERC20Token contract by executing:

+ +
forge test -vv
+
+ +
    +
  • -vv provides verbose logs to help debug test failures (if any).
  • +
  • Tests are located in the test/ folder (e.g., ERC20Token.t.sol).
  • +
+ +

Ensure that all tests pass before proceeding to deployment.

+ +
+

✅ You are now fully set up to build, test, and deploy dApps on Rootstock!

+ +

Step 8: Deploy the ERC20Token to Rootstock Testnet

+ +

Your ERC-20 faucet contract (ERC20Token.sol) will be deployed using the script at script/Deploy.s.sol.

+ +

Command

+ +
forge script script/Deploy.s.sol --rpc-url https://public-node.testnet.rsk.co --broadcast --legacy --evm-version london
+ +
    +
  • --broadcast: Sends the deployment to the network
  • +
  • --legacy: Required since Rootstock doesn’t support EIP-1559
  • +
  • --evm-version london: Matches Rootstock’s EVM fork
  • +
+ +
+ ℹ️ Info: Rootstock doesn’t support EIP-1559. Use --legacy for compatibility and --evm-version london to match its EVM version. + +
You can also inspect broadcast/Deploy.s.sol/run-latest.json for the deployed contract address and receipt. +
+ +

Simulate Deployment (Optional)

+ +
To dry-run the script without sending it, if you remove --broadcast, Foundry will simulate the deployment without actually submitting it. + +
forge script script/Deploy.s.sol --rpc-url https://public-node.testnet.rsk.co --legacy --evm-version london
+ +
+ +

Let’s Get Started: RootToken Contract, Testing & Deployment

+ +

Now that the environment is ready, let’s create, test, and deploy the RootToken — a simple ERC-20 faucet token with cooldown logic built on OpenZeppelin’s implementation.

+Complete github code: https://rootstock-foundry-example.vercel.app/ + +
+ +

📄 1. Write the Contract

+ +

Create the following file inside src/RootToken.sol and paste in this logic:

+ +
// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
+
+/// @title RootToken
+/// @notice A simple ERC‑20 “faucet” where anyone can claim a fixed amount once per 24h.
+contract RootToken is ERC20 {
+    uint256 public constant CLAIM_AMOUNT = 100 * 10 ** 18;
+    uint256 public constant COOLDOWN = 1 days;
+    mapping(address => uint256) public lastClaimed;
+
+    constructor(string memory name, string memory symbol) ERC20(name, symbol) {}
+
+    function claimTo(address recipient) external {
+        require(
+            block.timestamp >= lastClaimed[recipient] + COOLDOWN,
+            "Faucet: cooldown not passed"
+        );
+        lastClaimed[recipient] = block.timestamp;
+        _mint(recipient, CLAIM_AMOUNT);
+    }
+}
+
+ +--- + +

2. Update the Deployment Script

+ +

Edit script/Deploy.s.sol or create a new file named DeployRootToken.s.sol:

+ +
// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.13;
+
+import "forge-std/Script.sol";
+import "../src/RootToken.sol";
+
+contract DeployRootToken is Script {
+    function run() public {
+        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
+        vm.startBroadcast(deployerPrivateKey);
+
+        // Deploy with custom name and symbol
+        new RootToken("Root Token", "ROOT");
+
+        vm.stopBroadcast();
+    }
+}
+
+ +> 📌 This script passes the constructor arguments — `"Root Token"` and `"ROOT"` — during deployment. + +--- + +

3. Write the Test File

+ +

Create test/RootToken.t.sol and paste this test suite:

+ +
// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+import "forge-std/Test.sol";
+import "../src/RootToken.sol";
+
+contract RootTokenTest is Test {
+    RootToken token;
+    address alice = address(0xA1CE);
+    address bob = address(0xB0B);
+    uint256 constant CLAIM_AMOUNT = 100 * 10 ** 18;
+    uint256 constant COOLDOWN = 1 days;
+
+    function setUp() public {
+        token = new RootToken("Root Token", "ROOT");
+    }
+
+    function testMetadata() public {
+        assertEq(token.name(), "Root Token");
+        assertEq(token.symbol(), "ROOT");
+        assertEq(token.decimals(), 18);
+    }
+
+    function testClaimToMintsTokens() public {
+        vm.warp(block.timestamp + COOLDOWN);
+        vm.prank(alice);
+        token.claimTo(alice);
+        assertEq(token.balanceOf(alice), CLAIM_AMOUNT);
+    }
+
+    function testCannotClaimBeforeCooldown() public {
+        vm.warp(block.timestamp + COOLDOWN);
+        vm.prank(alice);
+        token.claimTo(alice);
+
+        vm.prank(alice);
+        vm.expectRevert("Faucet: cooldown not passed");
+        token.claimTo(alice);
+    }
+
+    function testClaimAfterCooldown() public {
+        vm.warp(block.timestamp + COOLDOWN);
+        vm.prank(bob);
+        token.claimTo(bob);
+
+        vm.warp(block.timestamp + COOLDOWN);
+        vm.prank(bob);
+        token.claimTo(bob);
+
+        assertEq(token.balanceOf(bob), CLAIM_AMOUNT * 2);
+    }
+
+    function testDifferentUsersHaveIndependentCooldowns() public {
+        vm.warp(block.timestamp + COOLDOWN);
+        vm.prank(alice);
+        token.claimTo(alice);
+
+        vm.prank(bob);
+        token.claimTo(bob);
+
+        assertEq(token.balanceOf(alice), CLAIM_AMOUNT);
+        assertEq(token.balanceOf(bob), CLAIM_AMOUNT);
+    }
+}
+
+ +--- + +

4. Compile the Contracts

+ +
forge build
+ +You should see a successful compiler output. Artifacts will be created inside the `out/` folder. + +--- + +

5. Run the Tests

+ +
forge test -vv
+ +- `-vv` shows full logs including emitted events and debug output. +- All test cases should pass — check your terminal for green ✅. + Screenshot 2025-04-22 at 12 46 19 AM + +--- + +

6. Deploy to Rootstock Testnet

+ +Use your deploy script with the following command: + +
forge script script/DeployRootToken.s.sol \
+  --rpc-url https://public-node.testnet.rsk.co \
+  --broadcast \
+  --legacy \
+  --evm-version london
+
+ +

+ 📌 This deploys your contract using your testnet wallet (loaded from .env as PRIVATE_KEY) and confirms compatibility with Rootstock by using --legacy and --evm-version london. +

+435534742-e280286e-9fa8-4b9b-9107-6cb93023aa29 + +--- + +

✅ That’s it — your RootToken faucet contract is live on Rootstock!

+ +

Next steps: verify it on the block explorer, interact with it via cast, or build a frontend UI for public claim access.

+ +

🔍 Step 9: Verify Your Contract on Rootstock Explorer

+ +

After deploying your RootToken, you should verify it on the +Rootstock Testnet Explorer +for transparency and easy interaction.

+ +
+ +

1. Copy Your Contract Address

+ +

2. Open the Explorer

+
    +
  1. Go to explorer.testnet.rootstock.io
  2. +
  3. Paste your contract address and open the contract page
  4. +
  5. Click the Code tab → then Verify Contract
  6. +
+ +
+ +

3. Fill the Verification Form

+ +

Here’s what each field means and how to fill it:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldValue/Instructions
Contract NameRootToken (no .sol extension)
Compiler VersionMatch the version in pragma solidity (e.g., 0.8.20)
OptimizationYes
EVM VersionLondon
Constructor ArgumentsRoot Token,ROOT (no quotes)
ABI-encoded Args?No
Contract LibrariesLeave blank unless you're linking manually
Source FilePaste your flattened contract here (see below 👇)
+ +
+ +

4. Flatten the Contract (for Source File)

+ +

If you imported from OpenZeppelin or any other libraries, you need to flatten your contract. Use one of the following methods:

+ +

✔️ Option A: Using Foundry

+
forge flatten src/RootToken.sol > RootToken.flat.sol
+

Then copy-paste the contents of RootToken.flat.sol into the Source File field.

+ +

✔️ Option B: Using Remix

+
    +
  1. Go to Remix IDE
  2. +
  3. Create a new file and paste the full contract with imports
  4. +
  5. Right Click the file tab → choose “Flatten”
  6. +
  7. Paste the output into the Source File field in the verification form
  8. +
+ +
+ +

5. Submit

+ +

Click Verify. If all fields are correctly filled and your contract is properly flattened, the verification should succeed in seconds.

+ +--- + +

✅ Done — Interact With Your Verified Contract

+ +

You can now interact with the faucet directly via the explorer’s UI. Try calling claimTo(address) using MetaMask.

+ +

Here’s an example verified contract page: + +https://explorer.testnet.rootstock.io/address/0x9ad8a78833921ebc0bb4eb79c420020d212c8eff?__ctab=Contract%20Interaction +

+ +

Step-by-step to interact:

+ +
    +
  1. Go to the Contract Interaction tab
  2. +
  3. Click on Write Contract
  4. +
  5. Connect your MetaMask wallet by clicking "Connect to Web3"
  6. +
  7. Scroll down to the claimTo function
  8. +
  9. Enter any recipient address (it can be your own address)
  10. +
  11. Click Write and confirm the transaction in MetaMask
  12. +
+ +Screenshot of Write Contract section + +

✅ After the transaction confirms:

+ +
    +
  1. Go to the Read Contract tab
  2. +
  3. Find the balanceOf function
  4. +
  5. Enter the same address used in claimTo
  6. +
  7. You should see the result: 100 * 10^18 = 100 ROOT tokens
  8. +
+ +Screenshot of Read Contract balanceOf + +

🎉 You’ve successfully verified and interacted with your ERC-20 faucet contract live on Rootstock Testnet!

+ +

Step 10: Interact with RootToken Using Cast (Terminal)

+ +

You can interact with your contract directly from the terminal using cast — a CLI tool from Foundry.

+ +
+ +📖 Read: Check Token Balance + +

Use the balanceOf function to check how many tokens a wallet holds:

+ +
cast call <contract_address> "balanceOf(address)(uint256)" <wallet_address> --rpc-url <rpc_url>
+ +

Example:

+ +
cast call 0x9Ad8A78833921EBc0bB4eB79C420020D212c8efF \
+  "balanceOf(address)(uint256)" \
+  0x302fE507615F9fB25Ab842D66015c138DB5F8377 \
+  --rpc-url https://public-node.testnet.rsk.co
+
+ +

Output:

+ +
100000000000000000000
+# → 100 ROOT (with 18 decimals)
+
+ +
+ +✍ Write: Claim Tokens Using claimTo + +

This function writes to the blockchain (requires gas). It allows any user to claim 100 ROOT tokens if their cooldown has expired.

+ +
cast send <contract_address> "claimTo(address)" <recipient_address> \
+  --rpc-url <rpc_url> \
+  --private-key $PRIVATE_KEY \
+  --legacy
+
+ +

Example:

+ +
cast send 0x9Ad8A78833921EBc0bB4eB79C420020D212c8efF \
+  "claimTo(address)" 0x3e718E2D07D8aee0446E1c1188ed21094712Db57 \
+  --rpc-url https://public-node.testnet.rsk.co \
+  --private-key $PRIVATE_KEY \
+  --legacy
+
+ +

Output:

+ +
transactionHash:      0x87d6207e822d3eef500058d7359fa66b729c045f6061eacc0aa65242dbc7fa0e
+blockNumber:          6303222
+from:                 0x302fE507615F9fB25Ab842D66015c138DB5F8377
+to:                   0x9Ad8A78833921EBc0bB4eB79C420020D212c8efF
+gasUsed:              70402
+status:               1 (success)
+logs:
+  Transfer from 0x0 to 0x3e718... for 100 ROOT
+
+ +
+ +💡 Tips + +
    +
  • You can call any view or pure function (e.g., totalSupply(), cooldown()) using cast call.
  • +
  • Use cast send for writing to the blockchain (token transfers, claims, etc.).
  • +
  • Make sure to fund your testnet wallet with tRBTC before calling cast send.
  • +
+ +

✅ This gives you full control to test your contract on Rootstock directly from the command line.

+ +--- + +## 🌱 Bonus: TapRoot dApp Built on Rootstock + +Live Demo: https://rootstock-foundry-example.vercel.app/ +Complete github code: https://rootstock-foundry-example.vercel.app/ + +Built a fullstack dApp on the Rootstock blockchain using the Foundry kit, Solidity, and ReactJS. + +### TapRoot: Root Yourself Onchain + +**TapRoot 🌱** is a playful, minimalist dApp built on Rootstock that lets users _"root"_ themselves—or their friends—onchain with a single tap. +Screenshot 2025-04-21 at 5 28 38 PM + +### How It Works + +- Users call the `root()` function via the frontend. +- The smart contract increments: + - their personal root count (`mapping(address => uint256)`) + - the global root count (`uint256`) +- It emits a `Rooted` event containing: + - the user's address + - their personal total + - the global total + +### Why TapRoot? + +It’s a simple, feel-good way to leave your mark **onchain**: +Root yourself. Root your friends. +Grow the global counter—together. + +

✅ That’s a Wrap: What You’ve Built

+By the end of this guide, you’ve successfully: +- Set up a modern EVM development environment using Rootstock Foundry Kit +- Created a custom ERC-20 token contract with faucet logic +- Tested it thoroughly using Forge’s powerful test suite +- Deployed the contract to the Rootstock Testnet +- Verified the contract on the Rootstock Explorer +- Interacted with it both via explorer UI and Cast CLI + +All of this on Rootstock, an EVM-compatible chain secured by Bitcoin. From 70f00a955c4be52de425961271b5beb43b7d05e5 Mon Sep 17 00:00:00 2001 From: Ishita Rastogi <46647968+ishitarastogi@users.noreply.github.com> Date: Wed, 30 Apr 2025 10:22:16 +0530 Subject: [PATCH 2/3] docs: Update rootstock-foundry-faucetToken-guide.md --- .../04-tutorials/rootstock-foundry-faucetToken-guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/04-resources/04-tutorials/rootstock-foundry-faucetToken-guide.md b/docs/04-resources/04-tutorials/rootstock-foundry-faucetToken-guide.md index 7c6753cd..3f9922e7 100644 --- a/docs/04-resources/04-tutorials/rootstock-foundry-faucetToken-guide.md +++ b/docs/04-resources/04-tutorials/rootstock-foundry-faucetToken-guide.md @@ -128,9 +128,9 @@ cd rootstock-foundry-starterkit
PRIVATE_KEY=0xyour_testnet_private_key
 
-:::tip Ensure the private key copied starts with 0x... ::: +

Tip: Ensure the private key copied starts with 0x....

+

Also, make sure your .env file is listed in .gitignore to prevent accidental commits.

-

🚨 Ensure .env is listed in your .gitignore.


Compile, Test & Deploy ERC20Token

From 660518a056bb0ab354e0b2758e61410da54e9025 Mon Sep 17 00:00:00 2001 From: Ishita Rastogi <46647968+ishitarastogi@users.noreply.github.com> Date: Wed, 30 Apr 2025 12:14:56 +0530 Subject: [PATCH 3/3] docs: Update rootstock-foundry-faucetToken-guide.md --- .../rootstock-foundry-faucetToken-guide.md | 553 +++++++----------- 1 file changed, 199 insertions(+), 354 deletions(-) diff --git a/docs/04-resources/04-tutorials/rootstock-foundry-faucetToken-guide.md b/docs/04-resources/04-tutorials/rootstock-foundry-faucetToken-guide.md index 3f9922e7..0d5d9b16 100644 --- a/docs/04-resources/04-tutorials/rootstock-foundry-faucetToken-guide.md +++ b/docs/04-resources/04-tutorials/rootstock-foundry-faucetToken-guide.md @@ -1,216 +1,189 @@ # Build an ERC‑20 Faucet on Rootstock with Foundry -**Sidebar Label:** ERC‑20 Faucet with Foundry -**Description:** Complete guide to deploy a claim‑based ERC‑20 token on Rootstock using Rootstock Foundry Kit -**Tags:** `foundry`, `erc20`, `faucet`, `rootstock` +**Sidebar Label:** ERC‑20 Faucet with Foundry +**Description:** Complete guide to deploy a claim‑based ERC‑20 token on Rootstock using Rootstock Foundry Kit +**Tags:** `foundry` `erc20` `faucet` `rootstock` --- ## What you’ll build -Create a custom ERC-20 faucet token on Rootstock using the [Rootstock Foundry starter kit](https://github.com/rsksmart/rootstock-foundry-starterkit) where users can claim a fixed amount of token every 24 hours. +Create a custom ERC‑20 faucet token on Rootstock using the [Rootstock Foundry starter kit](https://github.com/rsksmart/rootstock-foundry-starterkit). Users can claim a fixed amount of token every 24 hours. -| Item | Value | -| ----------- | ------------------------------- | -| Token name | **Root Token** | -| Symbol | **ROOT** | -| Faucet rule | 100 ROOT per address every 24 h | +| Item | Value | +|------|-------| +| **Token name** | **Root Token** | +| **Symbol** | **ROOT** | +| **Faucet rule** | 100 ROOT per address every 24 h | --- ## Prerequisites -| Requirement | Notes | -| ----------------- | ---------------------------------------------------------------------------- | -| Blockchain basics | Tx, gas, EVM, Solidity | -| Tools | `git`, `curl`, `node`, code editor (e.g., VS Code) | -| Wallet | MetaMask (or any Rootstock-compatible wallet) | +| Requirement | Notes | +|-------------|-------| +| Blockchain basics | Tx, gas, EVM, Solidity | +| Tools | `git`, `curl`, `node`, code editor (e.g., VS Code) | +| Wallet | MetaMask (or any Rootstock‑compatible wallet) | | Add Rootstock RPC | [MetaMask Setup Guide](https://dev.rootstock.io/dev-tools/wallets/metamask/) | -| Testnet RBTC | [Get from Faucet](https://faucet.testnet.rsk.co/) | +| Testnet RBTC | [Get from Faucet](https://faucet.testnet.rsk.co/) | --- -

🛠️ Setting Up Your Development Environment

+## 🛠️ Setting Up Your Development Environment -

This section walks you through installing Foundry, setting up the Rootstock development kit, configuring RPCs, and funding your wallet to begin deploying smart contracts.

+This section walks you through installing Foundry, setting up the Rootstock development kit, configuring RPCs, and funding your wallet to begin deploying smart contracts. -

Step 1: Install Foundry

+### Step 1 — Install Foundry -

Foundry is a fast, modular toolkit for EVM smart contract development.

+Foundry is a fast, modular toolkit for EVM smart‑contract development. -
curl -L https://foundry.paradigm.xyz | bash
+```bash
+curl -L https://foundry.paradigm.xyz | bash
 foundryup
-
+``` -
    -
  • This installs forge (build/test), cast (CLI), anvil (local node), and chisel (REPL).
  • -
  • Windows users: Use Git BASH or WSL. PowerShell is not supported.
  • -
+*This installs **forge** (build/test), **cast** (CLI), **anvil** (local node), and **chisel** (REPL).* +**Windows users:** use **Git BASH** or **WSL**. PowerShell is not supported. -
+--- -

Step 2: Clone the Rootstock Foundry Kit

+### Step 2 — Clone the Rootstock Foundry Kit -
git clone https://github.com/rsksmart/rootstock-foundry-starterkit.git
+```bash
+git clone https://github.com/rsksmart/rootstock-foundry-starterkit.git
 cd rootstock-foundry-starterkit
-
- -
+``` -

Step 3: Install Dependencies

+--- -

This project uses OpenZeppelin's ERC20 implementation. Install it using:

+### Step 3 — Install Dependencies -
forge install openzeppelin-contracts-08=OpenZeppelin/openzeppelin-contracts@v4.8.3 --no-commit
-
+This project uses OpenZeppelin’s ERC‑20 implementation: -

Note: The starter kit supports other versions too, if needed.

+```bash +forge install openzeppelin-contracts-08=OpenZeppelin/openzeppelin-contracts@v4.8.3 --no-commit +``` -
+*The starter kit supports other versions too, if needed.* -

📁 Project Structure

+--- -

Once set up, your folder structure will look like this:

+### 📁 Project Structure -
.
+```text
+.
 ├── lib/            # Installed dependencies (e.g., OpenZeppelin)
 ├── script/         # Deployment & utility scripts
 │   └── ERC20Token.s.sol
-├── src/            # Your smart contracts
+├── src/            # Smart contracts
 │   └── ERC20Token.sol
 ├── test/           # Foundry test files
 │   └── ERC20Token.t.sol
 └── .env            # Environment variables (⚠️ never commit this)
-
+``` -
- -

Step 4: Configure Rootstock RPC & Fund Your Wallet

- -

Option 1: Use Public RPC

-
    -
  • Testnet: https://public-node.testnet.rsk.co
  • -
  • Mainnet: https://public-node.rsk.co
  • -
-

- To manually add Rootstock networks in MetaMask, refer to the official - MetaMask Setup Guide. -

+--- -

Option 2: Use a Personal RPC

-

- You can also create a custom RPC endpoint via the - Rootstock RPC Dashboard. After creating an account, generate and copy your API key from the dashboard. -

+### Step 4 — Configure RPC & Fund Your Wallet -

How to Get Testnet RBTC

-
    -
  1. - Visit the - Rootstock Testnet Faucet - and paste your wallet address. -
  2. -
  3. - You’ll receive a small amount of tRBTC to use for contract deployments. -
  4. -
+#### Option 1 — Use Public RPC -
-

Step 5: Set Up Environment Variables

+* Testnet  `https://public-node.testnet.rsk.co` +* Mainnet  `https://public-node.rsk.co` -

Inside your project's root directory, create a .env file to securely store Private Key.

+Add these networks in MetaMask via the official [MetaMask setup guide](https://dev.rootstock.io/dev-tools/wallets/metamask/). -
touch .env
-
+#### Option 2 — Use a Personal RPC -

And your wallet's private key (it should hold testnet RBTC):

+Create a custom endpoint via the [Rootstock RPC Dashboard](https://developers.rsk.co/rpc/) and copy your API key. -
PRIVATE_KEY=0xyour_testnet_private_key
-
+#### How to Get Testnet RBTC -

Tip: Ensure the private key copied starts with 0x....

-

Also, make sure your .env file is listed in .gitignore to prevent accidental commits.

+1. Visit the [Rootstock Testnet Faucet](https://faucet.testnet.rsk.co/) and paste your wallet address. +2. You’ll receive a small amount of **tRBTC** to use for contract deployments. +--- -
-

Compile, Test & Deploy ERC20Token

+### Step 5 — Set Up Environment Variables -

Now that your environment is set up and the dependencies are installed, let’s walk through building, testing, and deploying your ERC-20 faucet contract.

+Inside the project root, create a `.env` file: -

Step 6: Compile the Contracts

+```bash +touch .env +``` -

This ensures your contracts are valid and bytecode is generated in the out/ directory.

+```dotenv +PRIVATE_KEY=0xyour_testnet_private_key +``` -
forge build
-
+*The private key **must** start with `0x…`.* +Ensure `.env` is listed in `.gitignore` to prevent accidental commits. -

If everything works, you’ll see output confirming successful compilation.

+--- -
+## Compile, Test & Deploy **ERC20Token** -

Step 7: Run the Tests

+Now that your environment is ready, let’s build, test, and deploy your ERC‑20 faucet contract. -

Test the functionality of your ERC20Token contract by executing:

+### Step 6 — Compile the Contracts -
forge test -vv
-
+```bash +forge build +``` -
    -
  • -vv provides verbose logs to help debug test failures (if any).
  • -
  • Tests are located in the test/ folder (e.g., ERC20Token.t.sol).
  • -
+Successful compilation will output artifacts in `out/`. -

Ensure that all tests pass before proceeding to deployment.

+--- -
-

✅ You are now fully set up to build, test, and deploy dApps on Rootstock!

+### Step 7 — Run the Tests -

Step 8: Deploy the ERC20Token to Rootstock Testnet

+```bash +forge test -vv +``` -

Your ERC-20 faucet contract (ERC20Token.sol) will be deployed using the script at script/Deploy.s.sol.

+* `-vv` provides verbose logs to help debug. +* Tests live in `test/` (e.g., `ERC20Token.t.sol`). +Make sure **all tests pass** before deploying. -

Command

+--- -
forge script script/Deploy.s.sol --rpc-url https://public-node.testnet.rsk.co --broadcast --legacy --evm-version london
+✅ You are now fully set up to build, test, and deploy dApps on Rootstock! -
    -
  • --broadcast: Sends the deployment to the network
  • -
  • --legacy: Required since Rootstock doesn’t support EIP-1559
  • -
  • --evm-version london: Matches Rootstock’s EVM fork
  • -
+--- -
- ℹ️ Info: Rootstock doesn’t support EIP-1559. Use --legacy for compatibility and --evm-version london to match its EVM version. - -
You can also inspect broadcast/Deploy.s.sol/run-latest.json for the deployed contract address and receipt. -
+### Step 8 — Deploy the ERC20Token to Rootstock Testnet -

Simulate Deployment (Optional)

+```bash +forge script script/Deploy.s.sol --rpc-url https://public-node.testnet.rsk.co --broadcast --legacy --evm-version london +``` -
To dry-run the script without sending it, if you remove --broadcast, Foundry will simulate the deployment without actually submitting it. +* `--broadcast` — sends the deployment +* `--legacy` — Rootstock doesn’t support EIP‑1559 +* `--evm-version london` — matches Rootstock’s EVM fork -
forge script script/Deploy.s.sol --rpc-url https://public-node.testnet.rsk.co --legacy --evm-version london
+**Dry‑run:** omit `--broadcast` to simulate the deployment. -
+You can inspect `broadcast/Deploy.s.sol/run-latest.json` for the deployed address and receipt. -

Let’s Get Started: RootToken Contract, Testing & Deployment

+--- -

Now that the environment is ready, let’s create, test, and deploy the RootToken — a simple ERC-20 faucet token with cooldown logic built on OpenZeppelin’s implementation.

-Complete github code: https://rootstock-foundry-example.vercel.app/ +## Let’s Get Started: RootToken Contract, Testing & Deployment -
+Complete GitHub code: -

📄 1. Write the Contract

+### 📄 1. Write the Contract -

Create the following file inside src/RootToken.sol and paste in this logic:

+Create `src/RootToken.sol`: -
// SPDX-License-Identifier: MIT
+```solidity
+// SPDX-License-Identifier: MIT
 pragma solidity ^0.8.20;
 
 import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
 
 /// @title RootToken
-/// @notice A simple ERC‑20 “faucet” where anyone can claim a fixed amount once per 24h.
+/// @notice A simple ERC‑20 faucet where anyone can claim a fixed amount once per 24 h.
 contract RootToken is ERC20 {
     uint256 public constant CLAIM_AMOUNT = 100 * 10 ** 18;
     uint256 public constant COOLDOWN = 1 days;
@@ -227,15 +200,16 @@ contract RootToken is ERC20 {
         _mint(recipient, CLAIM_AMOUNT);
     }
 }
-
+``` --- -

2. Update the Deployment Script

+### 2. Update the Deployment Script -

Edit script/Deploy.s.sol or create a new file named DeployRootToken.s.sol:

+Create `script/DeployRootToken.s.sol`: -
// SPDX-License-Identifier: MIT
+```solidity
+// SPDX-License-Identifier: MIT
 pragma solidity ^0.8.13;
 
 import "forge-std/Script.sol";
@@ -246,23 +220,21 @@ contract DeployRootToken is Script {
         uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
         vm.startBroadcast(deployerPrivateKey);
 
-        // Deploy with custom name and symbol
         new RootToken("Root Token", "ROOT");
 
         vm.stopBroadcast();
     }
 }
-
- -> 📌 This script passes the constructor arguments — `"Root Token"` and `"ROOT"` — during deployment. +``` --- -

3. Write the Test File

+### 3. Write the Test File -

Create test/RootToken.t.sol and paste this test suite:

+Create `test/RootToken.t.sol`: -
// SPDX-License-Identifier: MIT
+```solidity
+// SPDX-License-Identifier: MIT
 pragma solidity ^0.8.20;
 
 import "forge-std/Test.sol";
@@ -271,7 +243,7 @@ import "../src/RootToken.sol";
 contract RootTokenTest is Test {
     RootToken token;
     address alice = address(0xA1CE);
-    address bob = address(0xB0B);
+    address bob   = address(0xB0B);
     uint256 constant CLAIM_AMOUNT = 100 * 10 ** 18;
     uint256 constant COOLDOWN = 1 days;
 
@@ -314,7 +286,7 @@ contract RootTokenTest is Test {
         assertEq(token.balanceOf(bob), CLAIM_AMOUNT * 2);
     }
 
-    function testDifferentUsersHaveIndependentCooldowns() public {
+    function testIndependentCooldowns() public {
         vm.warp(block.timestamp + COOLDOWN);
         vm.prank(alice);
         token.claimTo(alice);
@@ -326,223 +298,110 @@ contract RootTokenTest is Test {
         assertEq(token.balanceOf(bob), CLAIM_AMOUNT);
     }
 }
-
+``` --- -

4. Compile the Contracts

+### 4. Compile the Contracts -
forge build
+```bash +forge build +``` -You should see a successful compiler output. Artifacts will be created inside the `out/` folder. +You should see a successful output in **green** ✅. --- -

5. Run the Tests

+### 5. Run the Tests -
forge test -vv
+```bash +forge test -vv +``` -- `-vv` shows full logs including emitted events and debug output. -- All test cases should pass — check your terminal for green ✅. - Screenshot 2025-04-22 at 12 46 19 AM +All test cases should pass. ---- - -

6. Deploy to Rootstock Testnet

- -Use your deploy script with the following command: - -
forge script script/DeployRootToken.s.sol \
-  --rpc-url https://public-node.testnet.rsk.co \
-  --broadcast \
-  --legacy \
-  --evm-version london
-
- -

- 📌 This deploys your contract using your testnet wallet (loaded from .env as PRIVATE_KEY) and confirms compatibility with Rootstock by using --legacy and --evm-version london. -

-435534742-e280286e-9fa8-4b9b-9107-6cb93023aa29 +![Forge tests](https://github.com/user-attachments/assets/57563a2f-c46e-4ec3-a43a-8cf1effe993b) --- -

✅ That’s it — your RootToken faucet contract is live on Rootstock!

- -

Next steps: verify it on the block explorer, interact with it via cast, or build a frontend UI for public claim access.

- -

🔍 Step 9: Verify Your Contract on Rootstock Explorer

- -

After deploying your RootToken, you should verify it on the -Rootstock Testnet Explorer -for transparency and easy interaction.

- -
- -

1. Copy Your Contract Address

- -

2. Open the Explorer

-
    -
  1. Go to explorer.testnet.rootstock.io
  2. -
  3. Paste your contract address and open the contract page
  4. -
  5. Click the Code tab → then Verify Contract
  6. -
- -
- -

3. Fill the Verification Form

- -

Here’s what each field means and how to fill it:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FieldValue/Instructions
Contract NameRootToken (no .sol extension)
Compiler VersionMatch the version in pragma solidity (e.g., 0.8.20)
OptimizationYes
EVM VersionLondon
Constructor ArgumentsRoot Token,ROOT (no quotes)
ABI-encoded Args?No
Contract LibrariesLeave blank unless you're linking manually
Source FilePaste your flattened contract here (see below 👇)
- -
- -

4. Flatten the Contract (for Source File)

- -

If you imported from OpenZeppelin or any other libraries, you need to flatten your contract. Use one of the following methods:

- -

✔️ Option A: Using Foundry

-
forge flatten src/RootToken.sol > RootToken.flat.sol
-

Then copy-paste the contents of RootToken.flat.sol into the Source File field.

- -

✔️ Option B: Using Remix

-
    -
  1. Go to Remix IDE
  2. -
  3. Create a new file and paste the full contract with imports
  4. -
  5. Right Click the file tab → choose “Flatten”
  6. -
  7. Paste the output into the Source File field in the verification form
  8. -
- -
- -

5. Submit

- -

Click Verify. If all fields are correctly filled and your contract is properly flattened, the verification should succeed in seconds.

+### 6. Deploy to Rootstock Testnet ---- - -

✅ Done — Interact With Your Verified Contract

+```bash +forge script script/DeployRootToken.s.sol --rpc-url https://public-node.testnet.rsk.co --broadcast --legacy --evm-version london +``` -

You can now interact with the faucet directly via the explorer’s UI. Try calling claimTo(address) using MetaMask.

+![Deployment](https://github.com/user-attachments/assets/76f66b37-e498-4f24-96e8-b60b902063aa) -

Here’s an example verified contract page: - -https://explorer.testnet.rootstock.io/address/0x9ad8a78833921ebc0bb4eb79c420020d212c8eff?__ctab=Contract%20Interaction -

+✅ Your RootToken faucet contract is live on Rootstock! -

Step-by-step to interact:

+--- -
    -
  1. Go to the Contract Interaction tab
  2. -
  3. Click on Write Contract
  4. -
  5. Connect your MetaMask wallet by clicking "Connect to Web3"
  6. -
  7. Scroll down to the claimTo function
  8. -
  9. Enter any recipient address (it can be your own address)
  10. -
  11. Click Write and confirm the transaction in MetaMask
  12. -
+## 🔍 Step 9 — Verify Your Contract on Rootstock Explorer -Screenshot of Write Contract section +After deploying, verify it on the [Rootstock Testnet Explorer](https://explorer.testnet.rootstock.io/). -

✅ After the transaction confirms:

+1. Copy your contract address. +2. Go to the explorer, search the address, open the **Code** tab and click **Verify Contract**. -
    -
  1. Go to the Read Contract tab
  2. -
  3. Find the balanceOf function
  4. -
  5. Enter the same address used in claimTo
  6. -
  7. You should see the result: 100 * 10^18 = 100 ROOT tokens
  8. -
+| Field | Value | +|-------|-------| +| Contract Name | `RootToken` | +| Compiler Version | Match `pragma` (e.g., `0.8.20`) | +| Optimization | Yes | +| EVM Version | London | +| Constructor Arguments | `Root Token,ROOT` | +| ABI‑encoded Args? | No | +| Contract Libraries | *(blank)* | +| Source File | Paste flattened contract | -Screenshot of Read Contract balanceOf +### Flatten the Contract -

🎉 You’ve successfully verified and interacted with your ERC-20 faucet contract live on Rootstock Testnet!

+**Option A — Foundry** -

Step 10: Interact with RootToken Using Cast (Terminal)

+```bash +forge flatten src/RootToken.sol > RootToken.flat.sol +``` -

You can interact with your contract directly from the terminal using cast — a CLI tool from Foundry.

+**Option B — Remix** -
+1. Open +2. Paste contract with imports, right‑click → **Flatten**. +3. Copy the output. -📖 Read: Check Token Balance +Click **Verify**. If everything is correct, verification succeeds in seconds. -

Use the balanceOf function to check how many tokens a wallet holds:

+--- -
cast call <contract_address> "balanceOf(address)(uint256)" <wallet_address> --rpc-url <rpc_url>
+## ✅ Interact With Your Verified Contract -

Example:

+Try calling `claimTo(address)` using MetaMask. -
cast call 0x9Ad8A78833921EBc0bB4eB79C420020D212c8efF \
-  "balanceOf(address)(uint256)" \
-  0x302fE507615F9fB25Ab842D66015c138DB5F8377 \
-  --rpc-url https://public-node.testnet.rsk.co
-
+![Write Contract](https://github.com/user-attachments/assets/e0776e4b-931b-4d6f-b572-4dd2ec9a3e75) -

Output:

+After confirmation, check `balanceOf`: -
100000000000000000000
-# → 100 ROOT (with 18 decimals)
-
+![Read Contract](https://github.com/user-attachments/assets/cf8f0b72-e1c1-4698-b3cc-7c548b0b7c1e) -
+--- -✍ Write: Claim Tokens Using claimTo +## Step 10 — Interact Using **cast** (Terminal) -

This function writes to the blockchain (requires gas). It allows any user to claim 100 ROOT tokens if their cooldown has expired.

+### 📖 Read: Check Token Balance -
cast send <contract_address> "claimTo(address)" <recipient_address> \
-  --rpc-url <rpc_url> \
-  --private-key $PRIVATE_KEY \
-  --legacy
-
+```bash +cast call "balanceOf(address)(uint256)" --rpc-url https://public-node.testnet.rsk.co +``` -

Example:

+### ✍️ Write: Claim Tokens -
cast send 0x9Ad8A78833921EBc0bB4eB79C420020D212c8efF \
-  "claimTo(address)" 0x3e718E2D07D8aee0446E1c1188ed21094712Db57 \
-  --rpc-url https://public-node.testnet.rsk.co \
-  --private-key $PRIVATE_KEY \
-  --legacy
-
+```bash +cast send "claimTo(address)" --rpc-url https://public-node.testnet.rsk.co --private-key $PRIVATE_KEY --legacy +``` -

Output:

+Example output: -
transactionHash:      0x87d6207e822d3eef500058d7359fa66b729c045f6061eacc0aa65242dbc7fa0e
+```
+transactionHash:      0x87d6207e822d3eef500058d7359fa66b729c045f6061eacc0aa65242dbc7fa0e
 blockNumber:          6303222
 from:                 0x302fE507615F9fB25Ab842D66015c138DB5F8377
 to:                   0x9Ad8A78833921EBc0bB4eB79C420020D212c8efF
@@ -550,58 +409,44 @@ gasUsed:              70402
 status:               1 (success)
 logs:
   Transfer from 0x0 to 0x3e718... for 100 ROOT
-
+``` -
+**Tips** -💡 Tips +* `cast call` for **view/pure** functions +* `cast send` for **state‑changing** functions (needs tRBTC) +* Fund your testnet wallet before sending transactions. -
    -
  • You can call any view or pure function (e.g., totalSupply(), cooldown()) using cast call.
  • -
  • Use cast send for writing to the blockchain (token transfers, claims, etc.).
  • -
  • Make sure to fund your testnet wallet with tRBTC before calling cast send.
  • -
+--- -

✅ This gives you full control to test your contract on Rootstock directly from the command line.

+## 🌱 Bonus: TapRoot dApp Built on Rootstock ---- +- **Live Demo:** +- **Complete Source:** -## 🌱 Bonus: TapRoot dApp Built on Rootstock +### TapRoot: Root Yourself Onchain -Live Demo: https://rootstock-foundry-example.vercel.app/ -Complete github code: https://rootstock-foundry-example.vercel.app/ +**TapRoot 🌱** is a playful dApp that lets users “root” themselves—or friends—onchain with a single tap. -Built a fullstack dApp on the Rootstock blockchain using the Foundry kit, Solidity, and ReactJS. +![TapRoot UI](https://github.com/user-attachments/assets/81227633-278d-4683-9911-d2abc0b4cdd5) -### TapRoot: Root Yourself Onchain +#### How It Works -**TapRoot 🌱** is a playful, minimalist dApp built on Rootstock that lets users _"root"_ themselves—or their friends—onchain with a single tap. -Screenshot 2025-04-21 at 5 28 38 PM +- Users call `root()` via the frontend. +- Contract increments their personal and global counters. +- A `Rooted` event logs the address, personal total, and global total. -### How It Works +*Root yourself. Root your friends. Grow the global counter—together.* -- Users call the `root()` function via the frontend. -- The smart contract increments: - - their personal root count (`mapping(address => uint256)`) - - the global root count (`uint256`) -- It emits a `Rooted` event containing: - - the user's address - - their personal total - - the global total +--- -### Why TapRoot? +### ✅ That’s a Wrap -It’s a simple, feel-good way to leave your mark **onchain**: -Root yourself. Root your friends. -Grow the global counter—together. +By the end of this guide you have: -

✅ That’s a Wrap: What You’ve Built

-By the end of this guide, you’ve successfully: -- Set up a modern EVM development environment using Rootstock Foundry Kit -- Created a custom ERC-20 token contract with faucet logic -- Tested it thoroughly using Forge’s powerful test suite -- Deployed the contract to the Rootstock Testnet -- Verified the contract on the Rootstock Explorer -- Interacted with it both via explorer UI and Cast CLI +- Set up a modern EVM development environment with Foundry on Rootstock. +- Created, tested, and deployed a custom ERC‑20 faucet token. +- Verified it on-chain and interacted via explorer and CLI. +- Explored a full‑stack dApp example on Rootstock. -All of this on Rootstock, an EVM-compatible chain secured by Bitcoin. +Rootstock combines Bitcoin’s merge‑mined security with EVM flexibility—ready for your next dApp!