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
.
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
-
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 -
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"
} -
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.
- Create a sender's wallet. The example address used in this tutorial
0xf6fd5fca4bd769ba495b29b98dba5f2ecf4ceed3
. - Create a receiver's wallet. The example address in this tutorial is
0x283b4baa1d0415603c81edc1c68fadd3c790837c
. - 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.
- 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.
-
Create a file called
transfer_ron.js
and paste the following code:transfer_ron.jsconst { 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.
-
Create a function to send RON and verify the balance.
Heads-upTo 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:
- Open the extension, and at the top right corner, click the profile icon.
- Click Manage. You'll see a list of your accounts.
- 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
andRECIPIENT_ADDRESS
with the sender's private key and receiver's wallet address, respectively.transfer_ron.jsconst { 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); -
-
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.
-
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);
-
This line converts the amount of RON to Wei using the
parseEther
function fromethers.js
:const weiAmount = ethers.utils.parseEther(amount);
-
Here, the code creates a transaction object with the recipient address and the Wei amount:
const transaction = {
to: toAddress,
value: weiAmount,
}; -
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"
} -
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"
} -
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 theformatEther
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"
}