Skip to main content

Transfer RON

Overview

This tutorial shows how to transfer RON from one account to another, and verify the transaction using Ronin JSON-RPC methods.

Prerequisites

  • Node.js or your preferred web3 client written in another language.
  • npm or yarn for package installation. This tutorial uses npm.
  • Basic knowledge of JavaScript.
  • Basic knowledge of HTTP.
  • Basic knowledge of JSON-RPC. For more information, see the JSON-RPC specification.

Environment

Throughout this tutorial, you use the public RPC endpoint for the Saigon testnet: https://saigon-testnet.roninchain.com/rpc.

note

We recommend using the public endpoint only for testing. For production, make sure to use the developer portal's endpoint https://api-gateway.skymavis.com/rpc/testnet.

Step 1. Create a project

  1. Create a new directory for your project and open the terminal in that directory:

    cd ~/
    mkdir ronin_rpc_contract_sample
    cd ronin_rpc_contract_sample
  2. Initialize a new Node.js project:

    npm init -y

    You should see output similar to this:

    Wrote to ** * /ronin_rpc_contract_sample/package.json:

    {
    "name": "ronin_rpc_sample",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC"
    }
  3. Install the ethers.js library:

    npm install ethers@5.7.2

This tutorial uses ethers.js version 5.7.2.

Step 2. Create wallets

You need to create two wallets: one for the sender and one for the receiver. We recommend using the Ronin Wallet browser extension for wallet creation. To create a wallet, open the extension > select Account > Create Account.

  1. Create a sender's wallet. The example address used in this tutorial 0xf6fd5fca4bd769ba495b29b98dba5f2ecf4ceed3.
  2. Create a receiver's wallet. The example address in this tutorial is 0x283b4baa1d0415603c81edc1c68fadd3c790837c.
  3. Retrieve the private key from the sender's Ronin Wallet. Open the Ronin Wallet browser extension, go to Account > Manage, select the sender's account, and then click View private key.
  4. Claim some RON to the sender's wallet using Ronin Faucet before transferring to others. You can create up to five requests a day, 1 RON per request.

Step 3. Create a script and run it

At this step, you create a script to transfer RON between wallets and verify the balance after.

  1. Create a file called transfer_ron.js and paste the following code:

    transfer_ron.js
    const { ethers } = require('ethers');
    const { JsonRpcProvider } = require('@ethersproject/providers');
    const { resolveProperties } = require('@ethersproject/properties');

    // A wrapper to workaround the gasPrice issue in etherjs version 5 after
    // London hardfork when sending transaction
    //
    // This is a modified version based on @ethersproject/abstract-provider
    class WrappedJsonProvider extends JsonRpcProvider {
    async getFeeData() {
    const { block, gasPrice } = await resolveProperties({
    block: this.getBlock("latest"),
    gasPrice: this.getGasPrice().catch((_) => {
    return null;
    })
    });

    let lastBaseFeePerGas = null, maxFeePerGas = null, maxPriorityFeePerGas = null;

    if (block && block.baseFeePerGas) {
    lastBaseFeePerGas = block.baseFeePerGas;
    maxPriorityFeePerGas = (gasPrice != null) ? gasPrice : BigNumber.from("1500000000");
    maxFeePerGas = block.baseFeePerGas.mul(2).add(maxPriorityFeePerGas);
    }

    return { lastBaseFeePerGas, maxFeePerGas, maxPriorityFeePerGas, gasPrice };
    }
    };

    // Initialize the provider
    const provider = new WrappedJsonProvider('https://saigon-testnet.roninchain.com/rpc');

This code imports the required libraries and initializes the node provider, which is the public Ronin RPC endpoint.

  1. Create a function to send RON and verify the balance.

    Heads-up

    To run this code, you need the following:

    • The private key from the sender's Ronin Wallet. Retrieve the private key in your Ronin Wallet browser extension:

      1. Open the extension, and at the top right corner, click the profile icon.
      2. Click Manage. You'll see a list of your accounts.
      3. Select the account from which you wish to deploy the contract, then click View private key, and then enter your password.
    • The receiver's wallet, which you created at the previous step.

    Replace YOUR_PRIVATE_KEY and RECIPIENT_ADDRESS with the sender's private key and receiver's wallet address, respectively.

    transfer_ron.js
    const { ethers } = require('ethers');

    // Initialize the Provider
    const provider = new ethers.providers.JsonRpcProvider('https://saigon-testnet.roninchain.com/rpc');

    async function sendRON(privateKey, toAddress, amount) {
    // Create a wallet from the private key
    const wallet = new ethers.Wallet(privateKey, provider);

    // Convert amount to Wei
    const weiAmount = ethers.utils.parseEther(amount);

    // Create a transaction object
    const transaction = {
    to: toAddress,
    value: weiAmount,
    };

    // Sign and send the transaction
    const transactionResponse = await wallet.sendTransaction(transaction);
    console.log(transactionResponse)

    // Wait for the transaction to be confirmed
    await transactionResponse.wait();

    // Verify the balance after the transaction
    const balance = await provider.getBalance(wallet.address);
    console.log('Balance after sending RON:', ethers.utils.formatEther(balance), 'RON');
    }

    // Call the sendRON function with the necessary parameters
    const privateKey = 'YOUR_PRIVATE_KEY';
    const toAddress = 'RECIPIENT_ADDRESS';
    const amount = '0.1'; // Amount of RON to send

    sendRON(privateKey, toAddress, amount);
  2. Execute the code by running the following command:

    node transfer_ron.js

    You should see output similar to this:

    {
    nonce: 55925,
    gasPrice: BigNumber {
    _hex: '0x04a817c800',
    _isBigNumber: true
    },
    gasLimit: BigNumber {
    _hex: '0x5208',
    _isBigNumber: true
    },
    to: '0x283b4Baa1d0415603C81edc1C68FadD3C790837C',
    value: BigNumber {
    _hex: '0x016345785d8a0000',
    _isBigNumber: true
    },
    data: '0x',
    chainId: 2021,
    v: 4078,
    r: '0x384a2ed47a690349e47383af78b065d9b36c2a8e716d3027fc386d7b0f354106',
    s: '0x51b068a8f9ff66daa1b52611ad87dffb434179d5f615dfe3d97497fbd60dee97',
    from: '0xf6fd5FcA4Bd769BA495B29B98dba5F2eCF4CEED3',
    hash: '0x0c11bfd6035665c34377d0eb9de4cff98ed9e27ada4ab087aa842a8eaa6fa55d',
    type: null,
    confirmations: 0,
    wait: [Function(anonymous)]
    }

    Balance after sending RON: 976242834.971306728277726832 RON

Step 4. Verify the result

Verify the transaction details

Verify using the Ronin app

Open the Ronin app and paste the transaction hash in the search field.

Verify using the Ronin JSON-RPC API

Make a request to the eth_getTransactionReceipt method by running the following command:

curl --location 'https://saigon-testnet.roninchain.com/rpc' \
--header 'Content-Type: application/json' \
--data '{
"jsonrpc":"2.0",
"method":"eth_getTransactionReceipt",
"params":[
"0x0c11bfd6035665c34377d0eb9de4cff98ed9e27ada4ab087aa842a8eaa6fa55d"
],
"id":1
}'

The response is the transaction's receipt:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"blockHash": "0x0dcaa2ebb57531322c80e2b9d8165d5d947f25ee0aa66745349b5c4067a7c80e",
"blockNumber": "0x116fcd5",
"contractAddress": null,
"cumulativeGasUsed": "0x5208",
"effectiveGasPrice": "0x4a817c800",
"from": "0xf6fd5fca4bd769ba495b29b98dba5f2ecf4ceed3",
"gasUsed": "0x5208",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": "0x283b4baa1d0415603c81edc1c68fadd3c790837c",
"transactionHash": "0x0c11bfd6035665c34377d0eb9de4cff98ed9e27ada4ab087aa842a8eaa6fa55d",
"transactionIndex": "0x0",
"type": "0x0",
"logs": []
}
}

Verify recipient balance

Using Ronin app

Open the Ronin app and paste the recipient's address in the search field.

Using JSON-RPC API

Make a request to the eth_getBalance method by running the following command:

curl --location 'https://saigon-testnet.roninchain.com/rpc' \
--header 'Content-Type: application/json' \
--data '{
"jsonrpc":"2.0",
"method":"eth_getBalance",
"params":[
"0x283b4baa1d0415603c81edc1c68fadd3c790837c",
"latest"
],
"id":1
}'

The latest parameter is used to request the most recent result, which means that the response you receive may be different from the example:

{
"jsonrpc": "2.0",
"id": 1,
"result": "0x110c3344c12ff03a994c5d"
}

Code explanation

This section walks you through the code of the sendRON function.

  1. This line creates a wallet using the private key by creating a new Wallet object with the private key and provider.

    const wallet = new ethers.Wallet(privateKey, provider);
  2. This line converts the amount of RON to Wei using the parseEther function from ethers.js:

    const weiAmount = ethers.utils.parseEther(amount);
  3. Here, the code creates a transaction object with the recipient address and the Wei amount:

    const transaction = {
    to: toAddress,
    value: weiAmount,
    };
  4. The following line signs and sends the transaction by using the sendTransaction method of the wallet:

    const transactionResponse = await wallet.sendTransaction(transaction);

    The RPC methods used by this function are as follows:

    eth_getTransactionCount
    {
    "method": "eth_getTransactionCount",
    "params": [
    "<YOUR_PUBLIC_KEY (detect from YOUR_PRIVATE_KEY)>",
    "pending"
    ],
    "id": 47,
    "jsonrpc": "2.0"
    }
    eth_gasPrice
    {
    "method": "eth_gasPrice",
    "params": [],
    "id": 50,
    "jsonrpc": "2.0"
    }
    eth_estimateGas
    {
    "method": "eth_estimateGas",
    "params": [
    {
    "gasPrice": "0x4a817c800",
    "value": "0x8ac7230489e80000",
    "from": "<YOUR_PUBLIC_KEY (detect from YOUR_PRIVATE_KEY)>",
    "to": "<RECIPIENT_ADDRESS>"
    }
    ],
    "id": 52,
    "jsonrpc": "2.0"
    }
    eth_sendRawTransaction
    {
    "method": "eth_sendRawTransaction",
    "params": [
    "<Signature when use YOUR_PRIVATE_KEY to sign transaction>"
    ],
    "id": 56,
    "jsonrpc": "2.0"
    }
  5. This line waits for the transaction to be confirmed using the wait method of the transaction response.

    await transactionResponse.wait();

    The RPC method used by this function is eth_getTransactionReceipt:

    eth_getTransactionReceipt
    {
    "method": "eth_getTransactionReceipt",
    "params": [
    "<Your transaction hash after call eth_sendRawTransaction success>"
    ],
    "id": 68,
    "jsonrpc": "2.0"
    }
  6. The following line verifies the balance after the transaction by getting the balance of the wallet's address using the getBalance method of the provider and printing it out in RON using the formatEther function.

    const balance = await provider.getBalance(wallet.address);

    The RPC method used by this function is eth_getBalance:

    {
    "method": "eth_getBalance",
    "params": [
    "<YOUR_PUBLIC_KEY (detect from YOUR_PRIVATE_KEY)>",
    "latest"
    ],
    "id": 72,
    "jsonrpc": "2.0"
    }

See also

Ronin JSON-RPC API reference