Skip to main content

Interact with a smart contract

Overview

This tutorial shows how to interact with a smart contract on Ronin using Ronin JSON-RPC endpoints. In the course of the tutorial, you complete the following tasks:

  • Review the sample smart contract along with its ABI (the schema document used by a web3 client to interact with a contract after it’s deployed to a blockchain).
  • Create and deploy your own smart contract based on the sample contract.
  • Interact with the smart contract to retrieve some information.

Prerequisites

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

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 Sky Mavis's private 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
  1. 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"
}
  1. Install the ethers.js library:
npm install ethers@5.7.2

This tutorial uses ethers.js version 5.7.2.

Step 2: Create and run a script

Create a script to update the value of a smart contract and read it after.

This is a sample smart contract called SimpleContract:

pragma solidity ^0.8.0;

contract SimpleContract {
uint256 private value;

// Event triggered when the value is set
event ValueSet(uint256 newValue);

// Set a new value and trigger the ValueSet event
function setValue(uint256 newValue) public {
value = newValue;
emit ValueSet(newValue);
}

// Retrieve the current value
function getValue() public view returns (uint256) {
return value;
}
}

This is the ABI of the SimpleContract contract:

[
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "newValue",
"type": "uint256"
}
],
"name": "ValueSet",
"type": "event"
},
{
"inputs": [],
"name": "getValue",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "newValue",
"type": "uint256"
}
],
"name": "setValue",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]

The SimpleContract smart contract is already deployed on the Saigon testnet at this address: 0x55634BbAfBd297b19472272f9E1FFAe4220040fe. You can view it in the Ronin app.

note

Optionally, you can copy the code of the SimpleContract contract and deploy it as a new contract following our other tutorial: Deploy and verify a smart contract. If you do so, make sure to modify the contract address in the subsequent sections of this tutorial.

Now, you need to update the value field inside this smart contract, and read it afterward.

  1. Create a file called interact_contract.js and enter the following code:

    const { ethers } = require('ethers');

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

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

  2. Connect to the smart contract and define the wallet.

    Heads-up

    To run this code, you need to replace YOUR_PRIVATE_KEY with the private key from your Ronin Wallet. To retrieve the private key, open the Ronin Wallet browser extension, go to Account > Manage, select your account, and then click View private key.

    const privateKey = 'YOUR_PRIVATE_KEY';
    const contractAddress = '0x55634BbAfBd297b19472272f9E1FFAe4220040fe';
    const contractAbi = [<ABI above>];
    const wallet = new ethers.Wallet(privateKey, provider);

    // Create a contract object using the contract address and ABI
    const contract = new ethers.Contract(contractAddress, contractAbi, wallet);
  3. Add two functions for interacting with the smart contract: one for setting a new value and one for retrieving the current value.

    // Set a new value:
    async function setValue(valueToSet) {
    const transaction = await contract.setValue(valueToSet);
    console.log(transaction);

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

    console.log('Transaction complete!');
    }

    // Get the current value:
    async function getValue() {
    const value = await contract.getValue();
    console.log("Current value:", value.toString());
    }

    (async () => {
    // Call the setValue function with the necessary parameters
    const valueToSet = 10;
    await setValue(valueToSet);

    // Call the getValue function after setValue
    await getValue()
    }
    )()

Description of the functions:

* `setValue(privateKey, valueToSet)`: This function allows you to set a new value in the smart contract. It takes two parameters: `privateKey` (the private key of the wallet used to sign the transaction) and `valueToSet` (the value you want to set).
* `getValue()`: This function retrieves the current value from the smart contract. The RPC method that this function uses is as follows:

```json
{
"method": "eth_call",
"params": [
{
"to": "0x55634bbafbd297b19472272f9e1ffae4220040fe",
"data": "0x20965255"
},
"latest"
],
"id": 70,
"jsonrpc": "2.0"
}
  1. Execute the code:
node interact_contract.js

You should see output similar to this:

{
nonce: 55927,
gasPrice: BigNumber { _hex: '0x04a817c800', _isBigNumber: true },
gasLimit: BigNumber { _hex: '0x5d68', _isBigNumber: true },
to: '0x55634BbAfBd297b19472272f9E1FFAe4220040fe',
value: BigNumber { _hex: '0x00', _isBigNumber: true },
data: '0x55241077000000000000000000000000000000000000000000000000000000000000000a',
chainId: 2021,
v: 4078,
r: '0x187f247947ff8ed3e1c98c75204fd0dfabf2bf1aa5713f9794480c69d2f93583',
s: '0x2881add7d7d886fcbe34312300070f1ac218b346b4600464e3444618880b448a',
from: '0xf6fd5FcA4Bd769BA495B29B98dba5F2eCF4CEED3',
hash: '0x6b692983d05e664ee80dc29364098b6f5681c3ccdd19ef6a5e5054d176610a4f',
type: null,
confirmations: 0,
wait: [Function (anonymous)]
}

Transaction complete!
Current value: 10

Step 3. Verify the result

Verify the transaction detail

Use the Ronin app

Open the Ronin app and paste the transaction hash 0x6b692983d05e664ee80dc29364098b6f5681c3ccdd19ef6a5e5054d176610a4f into the search field.

Use Ronin JSON-RPC

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":[
"0x6b692983d05e664ee80dc29364098b6f5681c3ccdd19ef6a5e5054d176610a4f"
],
"id":1
}'

The response is the transaction's receipt:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"blockHash": "0xefb90a99dcb72974390683e2da12cd53110e0bdaf603134f23e8d9faf7e99180",
"blockNumber": "0x11706de",
"contractAddress": null,
"cumulativeGasUsed": "0x5c3f",
"effectiveGasPrice": "0x4a817c800",
"from": "0xf6fd5fca4bd769ba495b29b98dba5f2ecf4ceed3",
"gasUsed": "0x5c3f",
"logsBloom": "0x00000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000",
"status": "0x1",
"to": "0x55634bbafbd297b19472272f9e1ffae4220040fe",
"transactionHash": "0x6b692983d05e664ee80dc29364098b6f5681c3ccdd19ef6a5e5054d176610a4f",
"transactionIndex": "0x0",
"type": "0x0",
"logs": [
{
"address": "0x55634bbafbd297b19472272f9e1ffae4220040fe",
"topics": [
"0x012c78e2b84325878b1bd9d250d772cfe5bda7722d795f45036fa5e1e6e303fc"
],
"data": "0x000000000000000000000000000000000000000000000000000000000000000a",
"blockNumber": "0x11706de",
"transactionHash": "0x6b692983d05e664ee80dc29364098b6f5681c3ccdd19ef6a5e5054d176610a4f",
"transactionIndex": "0x0",
"blockHash": "0xefb90a99dcb72974390683e2da12cd53110e0bdaf603134f23e8d9faf7e99180",
"logIndex": "0x0",
"removed": false
}
]
}
}

Read the smart contract

Use the Ronin app

Open the Ronin app to view the contract. The value is shown under getValue > hex:

Use Ronin JSON-RPC

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

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

The response is the value of the smart contract:

{
"jsonrpc": "2.0",
"id": 70,
"result": "0x000000000000000000000000000000000000000000000000000000000000000a"
}

Step 4. Listen for events from the smart contract

The SimpleContract smart contract emits an event called ValueSet every time setValue is called. Let's set up an event listener so that you can receive updates whenever a new value is set in the contract.

  1. Create a file called listen_contract.js and paste the following code:
listen_contract.js
// Import ethers.js library
const ethers = require('ethers');

// Contract address and ABI
const contractAddress = '0x55634BbAfBd297b19472272f9E1FFAe4220040fe';
const contractABI = [<ABI above>];

// Create an ethers.js provider
const provider = new ethers.providers.JsonRpcProvider('https://saigon-testnet.roninchain.com/rpc');

// Create a contract instance
const contract = new ethers.Contract(contractAddress, contractABI, provider);

// Event listener for the 'ValueSet' event
contract.on('ValueSet', (newValue) => {
console.log('New value set:', newValue.toString());
});

// Keep the script running indefinitely
setTimeout(() => {}, 86400000); // 24 hours

The on method of the contract instance is used to listen for the ValueSet event. Whenever this event is emitted by the smart contract, the callback function is executed, printing the new value set. Here's the RPC method that this function uses:

{
"method": "eth_getLogs",
"params": [
{
"fromBlock": "0x116f601",
"toBlock": "0x116f60b",
"address": "0x55634bbafbd297b19472272f9e1ffae4220040fe",
"topics": [
"0x012c78e2b84325878b1bd9d250d772cfe5bda7722d795f45036fa5e1e6e303fc"
]
}
],
"id": 84,
"jsonrpc": "2.0"
}

The setTimeout function ensures that the script is running for 24 hours. You can adjust the duration as needed.

By running this script, you can listen for the ValueSet event emitted by the contract and receive updates whenever a new value is set.

  1. Execute the code:
node listen_contract.js

Try calling setValue() to the contract with value set to 10, and you can see the following log in the console:

New value set: 10

See also

Ronin JSON-RPC API

Was this helpful?
Happy React is loading...