# Script Blockchain SRC20 Token Integration Guide

> Introduction

Script latest release provides support for the Ethereum RPC API similar to Binance Smart Chain and Polygon. With it, Script now supports the entire Etherum DApp dev stack including Metamask, Hardhat, Remix, Ethers.js, Web3.js, and Truffle Suite. Ethereum DApps that are ported over to Script can use the same API calls to interact with Script blockchain. This means Ethereum DApps can be deployed to Script with no or minor modifications and tap into the growing Script user and capital base.

> Hosted ETH RPC API for Integration Tests

To facilitate DApp development, we provide hosted ETH RPC API services for integration test purposes:

Script Testnet&#x20;

ETH RPC URL: <https://testeth-rpc-api.script.tv/rpc&#x20>;

Explorer: <https://explorer.script.tv/&#x20>;

Chain ID: 742

Through these hosted API services, you can interact with the Script blockchain like you would with the Ethereum blockchain. Below are a few examples demonstrating querying the chain ID, synchronization status, block number, and SPAY balances against the Script Testnet.

## Query Chain ID

curl -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"eth\_chainId","params":\[],"id":67}' <https://testeth-rpc-api.script.tv/rpc>

## Query synchronization status

curl -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"eth\_syncing","params":\[],"id":1}' <https://testeth-rpc-api.script.tv/rpc>

## Query block number

curl -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"eth\_blockNumber","params":\[],"id":83}' <https://testeth-rpc-api.script.tv/rpc>

## Query account SPAY balance (should return an integer which represents the current SPAY balance in wei)

curl -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"eth\_getBalance","params":\["0xc15149236229bd13f0aec783a9cc8e8059fb28da", "latest"],"id":1}' <https://testeth-rpc-api.script.tv/rpc>

> In House ETH RPC API Deployment

For production deployments, we highly recommend setting up your own in-house Script Ethereum RPC API, rather than using the above public endpoints. To enable the Script ETH RPC API service, you’d need to run two software on the same machine, namely

1. the Script Node, and
2. the Script/Ethereum RPC adapter. The adapter is a middleware which translates the Script native RPC APIs to the Ethereum RPC API.

> SRC-20 Token

With the full-EVM compatibility comes the SRC20 token, which is an ERC-20 like token standard on the Script blockchain. SRC stands for Script Network Token.

Here is OGN, an SRC20 Token on the Script Testnet. Please click on the "Contract" tab see the verified Solidity source code: <https://explorer.script.tv/account/0x7b8652a24a8c708c26c5f172e21590fdc5f941f3>

Below is a Javascript code snippet which reads the total supply, name, symbol of the OGN token using web3.js. The code snippet should look familiar to an Ethereum developer, as it is exactly the same code for querying the corresponding attributes of an ERC20 token on Ethereum. These queries can also be done using ethers.js.

> Example 1: Read SRC20 Token

const Web3 = require('web3')&#x20;

const web3 = new Web3('<https://testeth-rpc-api.script.tv/rpc')&#x20>;

const chainID = 742 // for the Script Testnet

const abi = \[{"inputs":\[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":\[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":\[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":\[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":\[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":\[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":\[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":\[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":\[],"name":"decimals","outputs":\[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":\[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[],"name":"name","outputs":\[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":\[],"name":"owner","outputs":\[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":\[],"name":"renounceOwnership","outputs":\[],"stateMutability":"nonpayable","type":"function"},{"inputs":\[],"name":"symbol","outputs":\[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":\[],"name":"totalSupply","outputs":\[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":\[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":\[],"stateMutability":"nonpayable","type":"function"}] const address = '0x7b8652a24a8c708c26c5f172e21590fdc5f941f3' // The OGN SRC20 token (similar to ERC20) smart contract

const contract = new web3.eth.Contract(abi, address)

contract.methods.totalSupply().call((err, result) => { console.log("totalSupply:", result, "OGN (wei)") })

contract.methods.name().call((err, result) => { console.log("name:", result) })

contract.methods.symbol().call((err, result) => { console.log("symbol:", result) })

contract.methods.balanceOf('0x49706694aE934EF885b4391414003ff43786207a').call((err, result) => { console.log("balance of 0x49706694aE934EF885b4391414003ff43786207a:", result, "OGN (wei)") })

Transferring SRC20 is also similar to transferring ERC20 tokens. Moreover, same as an ERC20 token on Ethereum, whenever there is a SRC20 token transfer between two wallets, the Transfer event will be triggered. This could be useful for detecting SRC20 token deposits. Here is an SRC20 token transfer example on the Script explorer. Below we also provide a Javascript code snippet showing how to transfer the OGN token between two wallets:

> Example 2: Transfer SRC20 Tokens

const Web3 = require('web3');&#x20;

const web3 = new Web3('<https://testeth-rpc-api.script.tv/rpc')&#x20>;

const chainID = 742 // for the Script Testnet

// Variables definition

const senderPrivKey = '1111111111111111111111111111111111111111111111111111111111111111'

const senderAddr = "0x49706694aE934EF885b4391414003ff43786207a"

const recipientAddr = "0x8285E6BdFeB1413CD3a1CF733cA567A1B826e947"

const ognContractAddress = "0x7b8652a24a8c708c26c5f172e21590fdc5f941f3"; const abi = \[{"inputs":\[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":\[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":\[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":\[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":\[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":\[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":\[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":\[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":\[],"name":"decimals","outputs":\[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":\[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[],"name":"name","outputs":\[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":\[],"name":"owner","outputs":\[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":\[],"name":"renounceOwnership","outputs":\[],"stateMutability":"nonpayable","type":"function"},{"inputs":\[],"name":"symbol","outputs":\[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":\[],"name":"totalSupply","outputs":\[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":\[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":\[],"stateMutability":"nonpayable","type":"function"}] const contract = new web3.eth.Contract(abi, ognContractAddress)

// Create transaction const sendOGN = async(ognAmountInWei) => { console.log(`Attempting to send ${ognAmountInWei} wei of OGN from ${senderAddr} to ${recipientAddr}`);

const count = await web3.eth.getTransactionCount(senderAddr); const createTransaction = await web3.eth.accounts.signTransaction({ "from": senderAddr, "nonce": web3.utils.toHex(count), "gas": web3.utils.toHex(150000), "to": ognContractAddress, "data": contract.methods.transfer(recipientAddr, ognAmountInWei).encodeABI() }, senderPrivKey );

// Deploy transaction const createReceipt = await web3.eth.sendSignedTransaction( createTransaction.rawTransaction );

console.log(""); console.log("Transaction successful with hash:", createReceipt.transactionHash); console.log(""); console.log("Transaction details:", JSON.stringify(createReceipt, null, " ")); };

const ognAmountInWei = "100" // Sending 100 wei of OGN (OGN has 18 decimals) sendOGN(ognAmountInWei)

The following example script shows how to list all the events emitted by the OGN contract in the specified block range (please avoid large block ranges, best below 200):

> Example 3: List SRC20 Token Events

const Web3 = require('web3')&#x20;

const web3 = new Web3('<https://testeth-rpc-api.script.tv/rpc')&#x20>;

const chainID = 742 // for the Script Testnet

const ognContractAddress = '0x7b8652a24a8c708c26c5f172e21590fdc5f941f3' // The OGN SRC20 token (similar to ERC20) smart contract const abi = \[{"inputs":\[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":\[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":\[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":\[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":\[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":\[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":\[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":\[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":\[],"name":"decimals","outputs":\[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":\[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[],"name":"name","outputs":\[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":\[],"name":"owner","outputs":\[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":\[],"name":"renounceOwnership","outputs":\[],"stateMutability":"nonpayable","type":"function"},{"inputs":\[],"name":"symbol","outputs":\[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":\[],"name":"totalSupply","outputs":\[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":\[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":\[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":\[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":\[],"stateMutability":"nonpayable","type":"function"}] const contract = new web3.eth.Contract(abi, ognContractAddress)

let fromBlock = 1721045 let toBlock = 1721045

// Get all the events emitted by the OGN contract in the specified block range contract.getPastEvents("allEvents", {&#x20;

fromBlock: fromBlock,&#x20;

toBlock: toBlock}&#x20;

).then(console.log);

> Metamask Support

End users can send and receive SRC20 tokens using Metamask.

> Explorer Support

The Script explorer provides extensive details for SRC20 tokens and their transactions similar to EtherScan. Below are examples including a SRC20 token page, a transaction details page, and the SRC20 transaction list of an account:

SRC20 Token page <https://explorer.script.tv/account/0x49706694aE934EF885b4391414003ff43786207a#Contract-Code>

SRC20 Transaction detail page: <https://explorer.script.tv/txs/0xdffb7e32e0281dbb1dcf08d6adb6ab3180d606beba09498db2afe7e2709966ee>

SRC20 Token transactions of an account (please click on the “SRC20 Token Txns” tab): <https://explorer.script.tv/account/0x49706694ae934ef885b4391414003ff43786207a>

> Smart Contract Transaction On-Chain Confirmation

The Script blockchain supports the ETH-style transactions (those sent through Metamask, Web3.js, Ethers.js, etc) by translating them into the native smart contract format. This means the ETH-style transactions have two valid transaction hashes. Here is an example. As shown on the explorer, it has two hashes. You can query the Script native RPC with either one to get the transaction details:

curl -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"script.GetTransaction","params":\[{"hash":"0xbc09eef26b1b0d914f5d6bbf09e77320ee2968c631736776570ecc0daf83ac9e"}],"id":1}' <http://localhost:16888/rpc>

curl -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"script.GetTransaction","params":\[{"hash":" 0x86671a7323192fd273bf40c7a277a00d26ecc9dd3ec939195398a180d6fa6c7b"}],"id":1}' <http://localhost:16888/rpc>

Moreover, the script.GetBlockByHeight and script.GetBlock RPC endpoint can return both hashes when its query parameter include\_eth\_tx\_hashes is set to true. As the following example shows, the transaction details include both the hash and eth\_tx\_hash:

curl -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"script.GetBlockByHeight","params":\[{"height":"14158920", "include\_eth\_tx\_hashes":true}],"id":1}' <http://localhost:16888/rpc>

## The RPC API response

{

&#x20;      "jsonrpc": "2.0",

&#x20;      "id": 1,

&#x20;      "result": {

&#x20;                    "chain\_id": "scriptnet",

&#x20;                     "epoch": "14244042",

&#x20;                     "height": "14158920",

&#x20;                     ...,

&#x20;                      "status": 4,

&#x20;                      "transactions": \[&#x20;

&#x20;                       ...,

&#x20;                       {

&#x20;                        "raw": {...},&#x20;

&#x20;                        "type": 7,

"hash": "0xbc09eef26b1b0d914f5d6bbf09e77320ee2968c631736776570ecc0daf83ac9e",

"eth\_tx\_hash": "0x86671a7323192fd273bf40c7a277a00d26ecc9dd3ec939195398a180d6fa6c7b",

"receipt": {...}

}]&#x20;

}

}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://documentation.script.tv/smart-contract-and-app-development/script-blockchain-src20-token-integration-guide.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
