diff --git a/website/docs/xdcchain/developers/quick-guide.md b/website/docs/xdcchain/developers/quick-guide.md new file mode 100644 index 00000000..afa842d0 --- /dev/null +++ b/website/docs/xdcchain/developers/quick-guide.md @@ -0,0 +1,211 @@ +--- +title: Deploy Your First Contract on XDC +--- + +# Deploy Your First Contract on XDC + +> ⏱️ Time: 5 minutes | 🎯 Skill Level: Beginner | 🔗 EVM Experience: Not required + +This guide takes you from zero to a deployed smart contract on the **XDC Apothem Testnet** — no prior blockchain experience needed. By the end, you'll have a live "Hello World" contract you can interact with. + +```mermaid +journey + title First Contract on XDC in 5 Minutes + section Wallet + Install MetaMask: 5: User + Add Apothem network: 4: User + section Fund + Visit faucet: 5: User + Receive test XDC: 5: Faucet + section Deploy + Write HelloWorld.sol: 4: User + Compile in Remix: 5: Remix + Deploy to Apothem: 5: User + section Verify + Verify on XDCScan: 5: XDCScan + Interact with contract: 5: User +``` + +--- + +## What You'll Build + +A simple `HelloWorld` smart contract that stores a message and lets anyone update it. You'll deploy it using [Remix IDE](https://remix.xdc.network/) and verify it on [XDCScan](https://testnet.xdcscan.com/). + +--- + +## Prerequisites + +- [Chrome](https://www.google.com/chrome/), [Firefox](https://www.mozilla.org/firefox/), or [Brave](https://brave.com/) browser +- [MetaMask](https://metamask.io/download/) browser extension installed + +--- + +## Step 1: Install MetaMask + +1. Visit [metamask.io/download](https://metamask.io/download/) and install the extension for your browser. +2. Follow the setup wizard to create a new wallet. +3. **Save your Secret Recovery Phrase** somewhere safe (offline). Never share it with anyone. + +> 💡 **Tip:** MetaMask will ask you to set a password. This is only for unlocking the extension on your computer — your seed phrase controls the actual wallet. + +--- + +## Step 2: Add XDC Apothem Testnet to MetaMask + +Click the button below, or add the network manually using the values below: + +| Field | Value | +|-------|-------| +| **Network Name** | XDC Apothem Testnet | +| **RPC URL** | `https://rpc.apothem.network` | +| **Chain ID** | `51` | +| **Currency Symbol** | XDC | +| **Block Explorer** | `https://testnet.xdcscan.com` | + +MetaMask Add Network + +> 🔗 **Mainnet equivalent:** To add XDC Mainnet later, use Chain ID `50` and RPC `https://rpc.xinfin.network`. + +--- + +## Step 3: Get Test XDC from the Faucet + +You need a small amount of test XDC to pay for deployment (gas fees). + +1. Copy your wallet address from MetaMask (click the address at the top to copy). + - It will look like `0x...` — this is normal. XDC also supports the `xdc...` prefix, but MetaMask uses `0x` format. +2. Go to **[faucet.apothem.network](https://faucet.apothem.network/)** +3. Paste your wallet address and click **Request 1000 XDC**. +4. Wait 10–30 seconds. You should see 1000 XDC appear in your MetaMask (make sure the XDC Apothem network is selected). + +> ⚠️ **Note:** If the faucet doesn't respond, try refreshing the page or using the [BlocksScan faucet](https://faucet.blocksscan.io/). + +--- + +## Step 4: Write Your HelloWorld Contract + +We'll write the contract in [Remix IDE](https://remix.xdc.network/) — no local setup needed. + +1. Open **[Remix IDE](https://remix.xdc.network/)** in your browser. +2. In the **File Explorer** (left sidebar), click the **📁 contracts** folder. +3. Click **➕** (Create New File) and name it `HelloWorld.sol`. +4. Paste this code: + +```solidity title="HelloWorld.sol" +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +contract HelloWorld { + string public message = "Hello, XDC!"; + + function updateMessage(string memory _newMessage) public { + message = _newMessage; + } +} +``` + +> 💡 **What this does:** It stores a `message` string and provides a function `updateMessage()` that anyone can call to change it. + +--- + +## Step 5: Compile the Contract + +1. Click the **Solidity Compiler** tab (🛠️ icon) in the left sidebar. +2. Select compiler version `0.8.19` (or any `0.8.x` that matches the `pragma` line). +3. Click **Compile HelloWorld.sol**. + +> ✅ You should see a green checkmark next to the compiler tab. If you see errors, double-check the Solidity version matches. + +--- + +## Step 6: Deploy to Apothem Testnet + +1. Click the **Deploy & Run Transactions** tab (▶️ icon) in the left sidebar. +2. Under **Environment**, select **Injected Provider — MetaMask**. +3. MetaMask will pop up and ask you to connect — click **Connect**. +4. Make sure your MetaMask is set to the **XDC Apothem Testnet** (Chain ID 51). +5. Select `HelloWorld` from the contract dropdown. +6. Click **Deploy**. +7. MetaMask will ask you to confirm the transaction — click **Confirm**. + +> ⏱️ Deployment takes about **2 seconds** on XDC (compared to 12+ seconds on Ethereum). + +--- + +## Step 7: Verify Your Deployment on XDCScan + +Once deployed, you can see your contract live on the blockchain. + +1. In Remix, scroll down to the **Deployed Contracts** section. +2. Click the 📋 copy icon next to your contract address. +3. Go to **[testnet.xdcscan.com](https://testnet.xdcscan.com/)** +4. Paste the address in the search bar and press Enter. +5. You should see your contract page. Click **Contract** → **Verify & Publish**. +6. Select: + - **Compiler Type:** Solidity (Single file) + - **Compiler Version:** 0.8.19 + - **License:** MIT +7. Paste your `HelloWorld.sol` code into the text box. +8. Click **Verify & Publish**. + +> ✅ Once verified, anyone can read your source code directly on XDCScan. This builds trust and transparency. + +--- + +## Step 8: Interact with Your Contract + +Back in Remix, under **Deployed Contracts**, you can interact directly: + +- **message** — Click this button to read the current message (it should show `"Hello, XDC!"`). +- **updateMessage** — Type something like `"XDC is awesome!"` in the text field, then click the button. MetaMask will ask you to confirm (no cost on testnet for simple calls, but state changes need a small gas fee). +- Refresh the **message** button — it should now show your new text! + +> 🎉 **Congratulations!** You've deployed, verified, and interacted with your first smart contract on XDC. + +--- + +## Troubleshooting + +| Problem | Solution | +|---------|----------| +| MetaMask won't connect | Make sure you're on **Injected Provider — MetaMask**, not JavaScript VM | +| "Insufficient funds" error | Get more test XDC from the [faucet](https://faucet.apothem.network/) | +| Deployment takes too long | Check that MetaMask is set to **XDC Apothem Testnet** (Chain ID 51), not Ethereum | +| Contract not showing on XDCScan | Wait 5–10 seconds and refresh. XDC's 2-second block time means it's usually instant | +| Can't verify contract | Make sure compiler version in Remix matches exactly what you selected on XDCScan | + +--- + +## Quick Reference — XDC Networks + +| Network | Chain ID | RPC URL | Explorer | +|---------|----------|---------|----------| +| **Mainnet** | `50` | `https://rpc.xinfin.network` | [xdcscan.com](https://xdcscan.com) | +| **Apothem Testnet** | `51` | `https://rpc.apothem.network` | [testnet.xdcscan.com](https://testnet.xdcscan.com) | +| **Devnet** | `551` | `https://devnetrpc.xinfin.network` | — | + +- **Native token:** `XDC` +- **Address prefix:** `xdc` (XDCScan shows `xdc`; EVM tools use `0x` — both are valid) +- **Faucet:** [faucet.apothem.network](https://faucet.apothem.network) +- **Block time:** ~2 seconds +- **Gas model:** Legacy (not EIP-1559 on mainnet; EIP-1559 testnet rollout in progress) + +--- + +## 🚀 Next Steps + +Now that you've deployed your first contract, continue your journey: + +1. **[Environment Setup →](/smartcontract/setup)** — Set up Hardhat/Foundry locally (⏱️ 15 min) +2. **[Write Your First Contract →](/smartcontract/writing)** — Learn Solidity basics (⏱️ 20 min) +3. **[Get Test XDC](https://faucet.apothem.network)** — Fund your wallet for more experiments + +Or explore: +- **[Verify on XDCScan →](/smartcontract/verify)** — Publish your source code for transparency +- **[Token Standards →](/smartcontract/tokens)** — Build your own XRC20 token +- **[XDC Faucet](https://faucet.apothem.network)** — Get more test XDC for experiments + +--- + +*Happy building on XDC! 🚀* diff --git a/website/docs/xdcchain/developers/rpc.md b/website/docs/xdcchain/developers/rpc.md new file mode 100644 index 00000000..ffaccaaf --- /dev/null +++ b/website/docs/xdcchain/developers/rpc.md @@ -0,0 +1,3963 @@ +--- +title: XDC blockchain JSONRPC API +--- + +# Network Endpoints + +The XDC Network is a robust, enterprise-grade blockchain platform designed for decentralized finance (DeFi), global trade, and other high-demand applications. For developers and users interacting with the XDC Network, the Remote Procedure Call (RPC) interface is a critical component. This guide provides a detailed overview of the RPC endpoints for both the XDC Mainnet and the Apothem Testnet, including their specifications and usage. + +## What is RPC? +Remote Procedure Call (RPC) is a protocol that allows communication between a client and a server over a network. In the context of blockchain, RPC is used to interact with the blockchain network by sending requests to full nodes. These requests can include reading blockchain data, creating and broadcasting transactions, and deploying smart contracts. + +## Mainnet Environment + +| Service | URL | +|------------------|------------------------------------------------------------------------| +| RPC | [https://erpc.xinfin.network](https://erpc.xinfin.network) | +| Chain Id | 50 | +| Faucet endpoint | [https://chains.tools/faucet](https://chains.tools/faucet) | +| Explorer | [https://xdcscan.io/](https://xdcscan.io/) | + +## Apothem Environment + +| Service | URL | +|------------------|------------------------------------------------------------------------| +| RPC | [https://rpc.apothem.network](https://rpc.apothem.network) | +| Chain Id | 51 | +| Faucet endpoint | [https://faucet.blocksscan.io/](https://faucet.blocksscan.io/) | +| Explorer | [https://apothem.xdcscan.io/](https://apothem.xdcscan.io/) | + + +## Devnet Environment + +| Service | URL | +|------------------|------------------------------------------------------------------------| +| RPC | [https://devnetstats.hashlabs.apothem.network/devnet](https://devnetstats.hashlabs.apothem.network/devnet) | +| Chain Id | 551 | +| Faucet endpoint | [https://faucet.blocksscan.io/](https://faucet.blocksscan.io/) | +| Explorer | [https://devnet.xdcscan.io/](https://devnet.xdcscan.io/) | + + + +# XDC Blockchain JSONRPC API + +Notice: type `BlockNumber` is the block number in hexadecimal format or the string `latest`, `earliest`, `pending` or `finalized`. + +## module XDPoS + +### XDPoS_getBlockInfoByEpochNum + +Parameters: + +- epochNumber: integer, required, epoch number + +Returns: + +result: object EpochNumInfo: + +- hash: hash of first block in this epoch +- round: round of epoch +- firstBlock: number of first block in this epoch +- lastBlock: number of last block in this epoch + +Example: + +```shell +epoch=89300 + +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "XDPoS_getBlockInfoByEpochNum", + "params": [ + '"${epoch}"' + ] +}' | jq +``` + +### XDPoS_getEpochNumbersBetween + +Parameters: + +- begin: string, required, block number +- end: string, required, block number + +Returns: + +result: array of uint64 + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "XDPoS_getEpochNumbersBetween", + "params": [ + "0x5439860", + "0x5439c48" + ] +}' | jq +``` + +### XDPoS_getLatestPoolStatus + +The `XDPoS_getLatestPoolStatus` method retrieves current vote pool and timeout pool content and missing messages. + +Parameters: + +None + +Returns: + +result: object MessageStatus + +- vote: object +- timeout: object + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "XDPoS_getLatestPoolStatus" +}' | jq +``` + +### XDPoS_getMasternodesByNumber + +Parameters: + +- number: string, required, BlockNumber + +Returns: + +result: object MasternodesStatus: + +- Number: uint64 +- Round: uint64 +- MasternodesLen: int +- Masternodes: array of address +- PenaltyLen: int +- Penalty: array of address +- StandbynodesLen: int +- Standbynodes: array of address +- Error: string + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "XDPoS_getMasternodesByNumber", + "params": [ + "latest" + ] +}' | jq +``` + +### XDPoS_getMissedRoundsInEpochByBlockNum + +Parameters: + +- number: string, required, BlockNumber + +Returns: + +result: object PublicApiMissedRoundsMetadata: + +- EpochRound: uint64 +- EpochBlockNumber: big.Int +- MissedRounds: array of MissedRoundInfo + +MissedRoundInfo: + +- Round: uint64 +- Miner: address +- CurrentBlockHash: hash +- CurrentBlockNum: big.Int +- ParentBlockHash: hash +- ParentBlockNum: big.Int + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "XDPoS_getMissedRoundsInEpochByBlockNum", + "params": [ + "latest" + ] +}' | jq +``` + +### XDPoS_getSigners + +The `getSigners` method retrieves the list of authorized signers at the specified block. + +Parameters: + +- number: string, required, BlockNumber + +Returns: + +result: array of address + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "XDPoS_getSigners", + "params": [ + "latest" + ] +}' | jq +``` + +### XDPoS_getSignersAtHash + +The `getSignersAtHash` method retrieves the state snapshot at a given block. + +Parameters: + +- hash: string, required, block hash + +Returns: + +same as `XDPoS_getSigners` + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "XDPoS_getSignersAtHash", + "params": [ + "'"${hash}"'" + ] +}' | jq +``` + +### XDPoS_getSnapshot + +The `getSnapshot` method retrieves the state snapshot at a given block. + +Parameters: + +- number: string, required, BlockNumber + +Returns: + +result: object PublicApiSnapshot: + +- number: block number where the snapshot was created +- hash: block hash where the snapshot was created +- signers: array of authorized signers at this moment +- recents: array of recent signers for spam protections +- votes: list of votes cast in chronological order +- tally: current vote tally to avoid recalculating + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "XDPoS_getSnapshot", + "params": [ + "latest" + ] +}' | jq +``` + +### XDPoS_getSnapshotAtHash + +The `getSnapshotAtHash` method retrieves the state snapshot at a given block. + +Parameters: + +- hash: string, required, block hash + +Returns: + +same as `XDPoS_getSnapshot` + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "XDPoS_getSnapshotAtHash", + "params": [ + "latest" + ] +}' | jq +``` + +### XDPoS_getV2BlockByHash + +Parameters: + +- hash: string, required, block hash + +Returns: + +same as `XDPoS_getV2BlockByNumber` + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "XDPoS_getV2BlockByHash", + "params": [ + "'"${hash}"'" + ] +}' | jq +``` + +### XDPoS_getV2BlockByNumber + +Parameters: + +- number: string, required, BlockNumber + +Returns: + +result: object V2BlockInfo: + +- Hash: hash +- Round: uint64 +- Number: big.Int +- ParentHash: hash +- Committed: bool +- Miner: common.Hash +- Timestamp: big.Int +- EncodedRLP: string +- Error: string + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "XDPoS_getV2BlockByNumber", + "params": [ + "latest" + ] +}' | jq +``` + +### XDPoS_networkInformation + +Parameters: + +None + +Returns: + +result: object NetworkInformation: + +- NetworkId: big.Int +- XDCValidatorAddress: address +- RelayerRegistrationAddress: address +- XDCXListingAddress: address +- XDCZAddress: address +- LendingAddress: address +- ConsensusConfigs: object of XDPoSConfig + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "XDPoS_networkInformation" +}' | jq +``` + +## module admin + +The `admin` API gives you access to several non-standard RPC methods, which will allow you to have a fine grained control over your Geth instance, including but not limited to network peer and RPC endpoint management. + +### admin_addPeer + +The `addPeer` administrative method requests adding a new remote node to the list of tracked static nodes. The node will try to maintain connectivity to these nodes at all times, reconnecting every once in a while if the remote connection goes down. + +Parameters: + +- url: string, required, the enode URL of the remote peer to start tracking + +Returns: + +result: bool, indicating whether the peer was accepted for tracking or some error occurred. + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_addPeer", + "params": [ + "enode://1f5a9bd8bd4abb4ecec8812f0f440fec30dd745c91871ac57ebbadcd23ceafbdf7035f29bf0092feb5087ad72ad208dd12966bfcb88b339884e08cff4d167d87@194.180.176.105:38645" + ] +}' | jq +``` + +### admin_addTrustedPeer + +The `addTrustedPeer` method allows a remote node to always connect, even if slots are full. + +Parameters: + +- url: string, required + +Returns: + +result: bool + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_addTrustedPeer", + "params": [ + "enode://1f5a9bd8bd4abb4ecec8812f0f440fec30dd745c91871ac57ebbadcd23ceafbdf7035f29bf0092feb5087ad72ad208dd12966bfcb88b339884e08cff4d167d87@194.180.176.105:38645" + ] +}' | jq +``` + +### admin_datadir + +The `datadir` administrative property can be queried for the absolute path the running Geth node currently uses to store all its databases. + +Parameters: + +None + +Returns: + +result: string + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_datadir" +}' | jq +``` + +### admin_exportChain + +The `exportChain` method exports the current blockchain into a local file. It optionally takes a first and last block number, in which case it exports only that range of blocks. + +Parameters: + +- fn: string, required, filen name + +Returns: + +result: bool, indicating whether the operation succeeded + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_exportChain", + "params": [ + "filename" + ] +}' | jq +``` + +### admin_importChain + +The `importChain` method imports an exported list of blocks from a local file. Importing involves processing the blocks and inserting them into the canonical chain. The state from the parent block of this range is required. It returns a boolean indicating whether the operation succeeded. + +Parameters: + +- file: string, required, filen name + +Returns: + +result: bool, indicating whether the operation succeeded + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_importChain", + "params": [ + "filename" + ] +}' | jq +``` + +### admin_nodeInfo + +The `nodeInfo` administrative property can be queried for all the information known about the running Geth node at the networking granularity. These include general information about the node itself as a participant of the P2P overlay protocol, as well as specialized information added by each of the running application protocols (e.g. eth, les, shh, bzz). + +Parameters: + +None + +Returns: + +result: object NodeInfo: + +- id: string, unique node identifier (also the encryption key) +- name: string, name of the node, including client type, version, OS, custom data +- enode: string, enode URL for adding this peer from remote peers +- ip: string, IP address of the node +- ports: object + - discovery: int, UDP listening port for discovery protocol + - listener: int, TCP listening port for RLPx +- listenAddr: string +- protocols: object + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_nodeInfo" +}' | jq +``` + +### admin_peerEvents + +The `peerEvents` creates an RPC subscription which receives peer events from the node's p2p server. The type of events emitted by the server are as follows: + +- add: emitted when a peer is added +- drop: emitted when a peer is dropped +- msgsend: emitted when a message is successfully sent to a peer +- msgrecv: emitted when a message is received from a peer + +Parameters: + +None + +Returns: + +result: object Subscription + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_peerEvents" +}' | jq +``` + +### admin_peers + +The `peers` administrative property can be queried for all the information known about the connected remote nodes at the networking granularity. + +Parameters: + +None + +Returns: + +result: array of PeerInfo: + +- id: string,unique node identifier (also the encryption key) +- name: string, name of the node, including client type, version, OS, custom data +- caps: array of string, sum-protocols advertised by this particular peer +- network object: + - localAddress: string, local endpoint of the TCP data connection + - remoteAddress: string, remote endpoint of the TCP data connection + - inbound: bool + - trusted: bool + - static: bool +- protocols: object, sub-protocol specific metadata fields + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_peers" +}' | jq +``` + +### admin_removePeer + +The `removePeer` method disconnects from a remote node if the connection exists. It returns a boolean indicating validations succeeded. Note a true value doesn't necessarily mean that there was a connection which was disconnected. + +Parameters: + +- url: string, required + +Returns: + +result: bool, indicating validations succeeded + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_removePeer", + "params": [ + "enode://1f5a9bd8bd4abb4ecec8812f0f440fec30dd745c91871ac57ebbadcd23ceafbdf7035f29bf0092feb5087ad72ad208dd12966bfcb88b339884e08cff4d167d87@194.180.176.105:38645" + ] +}' | jq +``` + +### admin_removeTrustedPeer + +The `removeTrustedPeer` method removes a remote node from the trusted peer set, but it does not disconnect it automatically. + +Parameters: + +- url: string, required + +Returns: + +result: bool, indicating validations succeeded + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_removeTrustedPeer", + "params": [ + "enode://1f5a9bd8bd4abb4ecec8812f0f440fec30dd745c91871ac57ebbadcd23ceafbdf7035f29bf0092feb5087ad72ad208dd12966bfcb88b339884e08cff4d167d87@194.180.176.105:38645" + ] +}' | jq +``` + +### admin_startRPC + +The `startRPC` method starts the HTTP RPC API server. + +Parameters: + +- host: string, optional, network interface to open the listener socket on (defaults to "localhost") +- port: int, optional, network port to open the listener socket on (defaults to 8546) +- cors: string, optional, cross-origin resource sharing header to use (defaults to "") +- apis: string, optional, API modules to offer over this interface (defaults to "eth,net,web3") +- vhosts: string, optional + +Returns: + +result: bool, indicating whether the operation succeeded + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_startRPC" +}' | jq +``` + +### admin_startWS + +The startWS administrative method starts an WebSocket based JSON RPC API webserver to handle client requests. + +Parameters: + +- host: string, optional, network interface to open the listener socket on (defaults to "localhost") +- port: int, optional, network port to open the listener socket on (defaults to 8546) +- cors: string, optional, cross-origin resource sharing header to use (defaults to "") +- apis: string, optional, API modules to offer over this interface (defaults to "eth,net,web3") + +Returns: + +result: bool, indicating whether the operation succeeded + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_startWS" +}' | jq +``` + +### admin_stopRPC + +The `stopRPC` method shuts down the HTTP server. + +Parameters: + +None + +Returns: + +result: bool, indicating whether the operation succeeded + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_stopRPC" +}' | jq +``` + +### admin_stopWS + +The `stopWS` administrative method closes the currently open WebSocket RPC endpoint. + +Parameters: + +None + +Returns: + +result: bool, indicating whether the endpoint was closed or not + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "admin_stopWS" +}' | jq +``` + +## module debug + +The `debug` API gives you access to several non-standard RPC methods, which will allow you to inspect, debug and set certain debugging flags during runtime. + +### debug_blockProfile + +The `blockProfile` method turns on block profiling for the given duration and writes profile data to disk. It uses a profile rate of 1 for most accurate information. If a different rate is desired, set the rate and write the profile manually using debug_writeBlockProfile. + +Parameters: + +- file: string, required, file name +- nsec: uint, required, number of seconds + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_blockProfile", + "params": [ + "block-profile.bin", + 10 + ] +}' | jq +``` + +### debug_chaindbCompact + +The `chaindbCompact` method flattens the entire key-value database into a single level, removing all unused slots and merging all keys. + +Parameters: + +None + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_chaindbCompact" +}' | jq +``` + +### debug_chaindbProperty + +The `chaindbProperty` method returns leveldb properties of the key-value database. + +Parameters: + +- property: string, required + +Returns: + +result: string + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_chaindbProperty", + "params": [ + "" + ] +}' | jq +``` + +### debug_cpuProfile + +The `cpuProfile` method turns on CPU profiling for the given duration and writes profile data to disk. + +Parameters: + +- file: string, required, file name +- nsec: uint, required, number of seconds + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_cpuProfile", + "params": [ + "cpu-profile.bin", + 10 + ] +}' | jq +``` + +### debug_dbGet + +The `dbGet` method returns the raw value of a key stored in the database. + +Parameters: + +- key: string, required + +Returns: + +result: array of byte + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_dbGet", + "params": [ + "key" + ] +}' | jq +``` + +### debug_dumpBlock + +The `dumpBlock` method retrieves the entire state of the database at a given block. + +Parameters: + +- number: BlockNumber, required, block number + +Returns: + +result: object Dump + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_dumpBlock", + "params": [ + "earliest" + ] +}' | jq +``` + +### debug_getBadBlocks + +The `getBadBlocks` method returns a list of the last 'bad blocks' that the client has seen on the network and returns them as a JSON list of block-hashes. + +Parameters: + +None + +Returns: + +result: array of BadBlockArgs + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_getBadBlocks" +}' | jq +``` + +### debug_gcStats + +The `gcStats` method returns garbage collection statistics. + +Parameters: + +None + +Returns: + +result: ojbect GCStats + +See [https://golang.org/pkg/runtime/debug/#GCStats](https://golang.org/pkg/runtime/debug/#GCStats) for information about the fields of the returned object. + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_gcStats" +}' | jq +``` + +### debug_getBlockRlp + +The `getBlockRlp` retrieves the RLP encoded for of a single block. + +Parameters: + +- number: uint64, required, block number + +Returns: + +result: string + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_getBlockRlp", + "params": [ + 0 + ] +}' | jq +``` + +### debug_getModifiedAccountsByHash + +The `getModifiedAccountsByHash` method returns all accounts that have changed between the two blocks specified. A change is defined as a difference in nonce, balance, code hash, or storage hash. With one parameter, returns the list of accounts modified in the specified block. + +Parameters: + +- startHash: hash, required, start block hash +- endHash: hash optional, end block hash + +Returns: + +result: array of address + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_getModifiedAccountsByNumber", + "params": [ + "start-hash", + "end-hash" + ] +}' | jq +``` + +### debug_getModifiedAccountsByNumber + +The `getModifiedAccountsByNumber` method returns all accounts that have changed between the two blocks specified. A change is defined as a difference in nonce, balance, code hash or storage hash. + +Parameters: + +- startNum: uint64, required, start block number +- endNum: uint64, optional, end block number + +Returns: + +result: array of address + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_getModifiedAccountsByNumber", + "params": [ + 1 + ] +}' | jq +``` + +### debug_goTrace + +The `goTrace` method turns on Go runtime tracing for the given duration and writes trace data to disk. + +Parameters: + +- file: string, required, file name +- nsec: uint, required, number of seconds + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_goTrace", + "params": [ + "go-trace.bin", + 10 + ] +}' | jq +``` + +### debug_freeOSMemory + +The debug `freeOSMemory` forces garbage collection. + +Parameters: + +None + +Returns: + +result: null + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_freeOSMemory" +}' | jq +``` + +### debug_memStats + +The `memStats` method returns detailed runtime memory statistics. + +Parameters: + +None + +Returns: + +result: object MemStats + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_memStats" +}' | jq +``` + +### debug_mutexProfile + +The `mutexProfile` method turns on mutex profiling for nsec seconds and writes profile data to file. It uses a profile rate of 1 for most accurate information. If a different rate is desired, set the rate and write the profile manually. + +Parameters: + +- file: string, required, file name +- nsec: uint, required, number of seconds + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_mutexProfile", + "params": [ + "mutex-profile.bin", + 10 + ] +}' | jq +``` + +### debug_preimage + +The `preimage` method returns the preimage for a sha3 hash, if known. + +Parameters: + +- hash: hash, required + +Returns: + +result: array of bytes + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_preimage", + "params": [ + "hash", + ] +}' | jq +``` + +### debug_printBlock + +The `printBlock` method retrieves a block and returns its pretty printed form. + +Parameters: + +- number: uint64, required, block number + +Returns: + +result: string + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_printBlock", + "params": [ + 0 + ] +}' | jq +``` + +### debug_seedHash + +The `seedHash` method retrieves the seed hash of a block. + +Parameters: + +- number: uint64, required, block number + +Returns: + +result: string + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_seedHash", + "params": [ + 0 + ] +}' | jq +``` + +### debug_setBlockProfileRate + +The `setBlockProfileRate` method sets the rate (in samples/sec) of goroutine block profile data collection. A non-zero rate enables block profiling, setting it to zero stops the profile. Collected profile data can be written using `debug_writeBlockProfile`. + +Parameters: + +- rate: int, required + +Returns: + +result: null + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_setBlockProfileRate", + "params": [ + 0 + ] +}' | jq +``` + +### debug_setGCPercent + +The `setGCPercent` method sets the garbage collection target percentage. A negative value disables garbage collection. + +Parameters: + +- v: int, required + +Returns: + +result: int + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_setGCPercent", + "params": [ + 80 + ] +}' | jq +``` + +### debug_setHead + +The `setHead` method sets the current head of the local chain by block number. Note, this is a destructive action and may severely damage your chain. Use with extreme caution. + +Parameters: + +- number: uint64, required, block number + +Returns: + +result: string + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_setHead", + "params": [ + "0x544b420" + ] +}' | jq +``` + +### debug_stacks + +The `stacks` method returns a printed representation of the stacks of all goroutines. Note that the web3 wrapper for this method takes care of the printing and does not return the string. + +Parameters: + +None + +Returns: + +result: string + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_stacks" +}' | jq +``` + +### debug_startCPUProfile + +The `startCPUProfile` method turns on CPU profiling indefinitely, writing to the given file. + +Parameters: + +- file: string, required, file name + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_startCPUProfile", + "params": [ + "cpu-profile.bin" + ] +}' | jq +``` + +### debug_startGoTrace + +The `startGoTrace` starts writing a Go runtime trace to the given file. + +Parameters: + +- file: string, required, file name + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_startGoTrace", + "params": [ + "go-trace.bin" + ] +}' | jq +``` + +### debug_stopCPUProfile + +The `stopCPUProfile` method stops an ongoing CPU profile. + +Parameters: + +None + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_stopCPUProfile" +}' | jq +``` + +### debug_stopGoTrace + +The `stopGoTrace` method stops writing the Go runtime trace. + +Parameters: + +None + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_stopGoTrace" +}' | jq +``` + +### debug_storageRangeAt + +The `storageRangeAt` method returns the storage at the given block height and transaction index. The result can be paged by providing a maxResult to cap the number of storage slots returned as well as specifying the offset via keyStart (hash of storage key). + +Parameters: + +- blockHash: Hash, required +- txIndex: int, required +- contractAddress: address, required +- keyStart: array of bytes, required +- maxResult: int, required + +Returns: + +result: object StorageRangeResult + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_storageRangeAt" +}' | jq +``` + +### debug_traceBlock + +The `traceBlock` method will return a full stack trace of all invoked opcodes of all transaction that were included in this block. Note, the parent of this block must be present or it will fail. For the second parameter see TraceConfig reference. + +Parameters: + +- blob: array of byte, required, the RLP encoded block +- config: object of TraceConfig, optional + +Returns: + +result: array of object txTraceResult + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_writeMemProfile", + "params": [ + "memory-profile.bin", + ] +}' | jq +``` + +### debug_traceBlockByHash + +The `traceBlockByHash` method accepts a block hash and will replay the block that is already present in the database. + +Parameters: + +- hash: Hash, required, block hash +- config: TraceConfig, optional + +Returns: + +result: array of object txTraceResult + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_traceBlockByHash", + "params": [ + "block-hash" + ] +}' | jq +``` + +### debug_traceBlockByNumber + +The `traceBlockByNumber` method accepts a block number and will replay the block that is already present in the database. + +Parameters: + +- number: BlockNumber, required, block number +- config: TraceConfig, optional + +Returns: + +result: array of object txTraceResult + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "traceBlockByNumber", + "params": [ + "latest" + ] +}' | jq +``` + +### debug_traceBlockFromFile + +The `traceBlockFromFile` meothod accepts a file containing the RLP of the block. + +Parameters: + +- file: string, required, file name +- config: object of TraceConfig, optional + +Returns: + +result: array of object txTraceResult + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_traceBlockFromFile", + "params": [ + "filename" + ] +}' | jq +``` + +### debug_traceCall + +The `traceCall` method lets you run an eth_call within the context of the given block execution using the final state of parent block as the base. + +Parameters: + +- args: TransactionArgs, required +- blockNrOrHash: BlockNumberOrHash, required, hash or number +- config: TraceCallConfig, optional + +Returns: + +same as debug_traceTransaction + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_traceCall", + "params": [ + { + "to": "0x46eda75e7ca73cb1c2f83c3927211655420dbc44", + "data": "0x3fb5c1cb00000000000000000000000000000000000000000000000000000000000003e7" + }, + "latest", + ] +}' | jq +``` + +### debug_traceTransaction + +The `traceTransaction` method debugging method will attempt to run the transaction in the exact same manner as it was executed on the network. It will replay any transaction that may have been executed prior to this one before it will finally attempt to execute the transaction that corresponds to the given hash. + +Parameters: + +- hash: Hash, required, transaction hash +- config: TraceConfig, optional + +Returns: + +result: object + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_traceTransaction", + "params": [ + "tx-hash" + ] +}' | jq +``` + +### debug_verbosity + +The `verbosity` method sets the logging verbosity ceiling. Log messages with level up to and including the given level will be printed. + +Parameters: + +- level: int, required + +Returns: + +result: null + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_verbosity", + "params": [ + 3 + ] +}' | jq +``` + +### debug_vmodule + +The `vmodule` method sets the logging verbosity pattern. + +Parameters: + +- pattern: string, required + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_vmodule", + "params": [ + "eth/*=3,p2p=4" + ] +}' | jq +``` + +### debug_writeBlockProfile + +The `writeBlockProfile` method writes a goroutine blocking profile to the given file. + +Parameters: + +- file: string, required + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_writeBlockProfile", + "params": [ + "block-profile.bin" + ] +}' | jq +``` + +### debug_writeMemProfile + +The `writeMemProfile` method writes an allocation profile to the given file. Note that the profiling rate cannot be set through the API, it must be set on the command line using the `--pprof-memprofilerate` flag. + +Parameters: + +- file: string, required, file name + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_writeMemProfile", + "params": [ + "memory-profile.bin", + ] +}' | jq +``` + +### debug_writeMutexProfile + +The `writeMutexProfile` method writes a goroutine blocking profile to the given file. + +Parameters: + +- file: string, required, file name + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "debug_writeMutexProfile", + "params": [ + "mutex-profile.bin", + ] +}' | jq +``` + +## module eth + +### eth_accounts + +The `accounts` method returns a list of addresses owned by the client. + +Parameters: + +None + +Returns + +result: array of address + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_accounts" +}' | jq +``` + +### eth_blobBaseFee + +The `blobBaseFee` method returns the expected base fee for blobs in the next block. + +Parameters: + +None + +Returns: + +result: big.Int, The expected base fee in wei, represented as a hexadecimal. + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_blobBaseFee" +}' | jq +``` + +### eth_blockNumber + +The `blockNumber` method returns the current latest block number. + +Parameters: + +None + +Returns: + +result: uint64, A hexadecimal of an integer representing the current block number the client is on. + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_blockNumber" +}' | jq +``` + +### eth_call + +The `call` method executes a new message call immediately, without creating a transaction on the block chain. Often used for executing read-only smart contract functions, for example the balanceOf for an ERC-20 contract. + +Parameters: + +- args: object TransactionArgs, required +- blockNrOrHash: object BlockNumberOrHash, optional +- overrides: object StateOverride, optional + +Returns: + +result: array of byte, the return value of executed contract. + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 8001, + "method": "eth_call", + "params": [ + { + "to": "0x0000000000000000000000000000000000000088", + "data": "0x0db02622" + }, + "latest" + ] +}' | jq +``` + +### eth_chainId + +The `chainId` method returns the currently configured chain ID, a value used in replay-protected transaction signing as introduced by EIP-155. + +Parameters: + +None + +Returns: + +result: uint64, a hexadecimal of the current chain ID. + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_chainId" +}' | jq +``` + +### eth_coinbase + +The `coinbase` method returns the client coinbase address. The coinbase address is the account to pay mining rewards to. This is the alias for `eth_etherbase`. + +Parameters: + +None + +Returns: + +result: address + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_coinbase" +}' | jq +``` + +### eth_createAccessList + +The `createAccessList` method creates an EIP2930 type accessList based on a given Transaction. The accessList contains all storage slots and addresses read and written by the transaction, except for the sender account and the precompiles. This method uses the same transaction call Transaction Call Object and blockNumberOrTag object as eth_call. An accessList can be used to unstuck contracts that became inaccessible due to gas cost increases. + +Parameters: + +- args: object transactionArgs, required + - from: optional, 20 bytes. The address of the sender. + - to: 20 bytes. address the transaction is directed to. + - gas: optional, hexadecimal value of the gas provided for the transaction execution. + - gasPrice: optional, hexadecimal value gas price, in wei, provided by the sender. The default is 0. Used only in non-EIP-1559 transactions. + - maxPriorityFeePerGas: optional, maximum fee, in wei, the sender is willing to pay per gas above the base fee. See EIP-1559 transactions. If used, must specify maxFeePerGas. + - maxFeePerGas: optional, maximum total fee (base fee + priority fee), in wei, the sender is willing to pay per gas. See EIP-1559 transactions. If used, must specify maxPriorityFeePerGas. + - value: optional, hexadecimal of the value transferred, in wei. + - data: optional, hash of the method signature and encoded parameters. See Ethereum contract ABI specification. +- blockNrOrHash: BlockNumberOrHash, optional, a string representing a block number, block hash, or one of the string tags + - latest + - earliest + - pending + - finalized. + +Returns: + +result: object accessListResult: + +- accessList: A list of objects with the following fields: + - address: Addresses to be accessed by the transaction. + - storageKeys: Storage keys to be accessed by the transaction. +- gasUsed: A hexadecimal string representing the approximate gas cost for the transaction if the access list is included. + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_createAccessList", + "params": [ + { + "from": "0x3bc5885c2941c5cda454bdb4a8c88aa7f248e312", + "data": "0x20965255", + "gasPrice": "0x3b9aca00", + "gas": "0x3d0900", + "to": "0x00f5f5f3a25f142fafd0af24a754fafa340f32c7" + }, + "latest" + ] +}' | jq +``` + +### eth_etherbase + +The `etherbase` method returns the client coinbase address. The etherbase address is the account to pay mining rewards to. + +Parameters: + +None + +Returns: + +result: address + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_etherbase" +}' | jq +``` + +### eth_estimateGas + +The `estimateGas` method generates and returns an estimate of how much gas is necessary to allow the transaction to complete. The transaction will not be added to the blockchain. Note that the estimate may be significantly more than the amount of gas actually used by the transaction, for a variety of reasons including EVM mechanics and node performance. + +Parameters: + +- args: object TransactionArgs, required +- blockNrOrHash: object BlockNumberOrHash, optional +- overrides: object StateOverride, optional + +Returns: + +result: uint64 + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1004, + "method": "eth_estimateGas", + "params": [ + { + "from": "0xD4CE02705041F04135f1949Bc835c1Fe0885513c", + "to": "0x85f33E1242d87a875301312BD4EbaEe8876517BA", + "value": "0x1" + } + ] +}' | jq +``` + +### eth_feeHistory + +The `feeHistory` returns transaction base fee per gas and effective priority fee per gas for the requested block range. + +Parameters: + +- blockCount math.HexOrDecimal64, required, Number of blocks in the requested range. Between 1 and 1024 blocks can be requested in a single query. If blocks in the specified block range are not available, then only the fee history for available blocks is returned. +- lastBlock: BlockNumber, required, integer representing the highest number block of the requested range, or one of the string tags `latest`, `earliest`, or `pending`. +- rewardPercentiles: array of integers, optional, a monotonically increasing list of percentile values to sample from each block's effective priority fees per gas in ascending order, weighted by gas used. + +Returns: + +result: object feeHistoryResult + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1004, + "method": "eth_feeHistory", + "params": [ + "0x3", + "latest", + [20,50] + ] +}' | jq +``` + +### eth_gasPrice + +The `gasPrice` method returns the current gas price in wei. + +Parameters: + +None. + +Returns: + +result: big.Int + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1003, + "method": "eth_gasPrice" +}' | jq +``` + +### eth_getBalance + +The `getBalance` returns the balance of the account of a given address. The balance is in wei. + +Parameters: + +- address: address, required, a string representing the address (20 bytes) to check for balance. +- blockNrOrHash: object BlockNumberOrHash, required, a hexadecimal block number, or one of the string tags latest, earliest, pending, or finalized. + +Returns: + +result: big.Int + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1003, + "method": "eth_getBalance", + "params": [ + "0xD4CE02705041F04135f1949Bc835c1Fe0885513c", + "latest" + ] +}' | jq +``` + +### eth_getBlockByHash + +The `getBlockByHash` returns information about a block whose hash is in the request. + +Parameters: + +- blockHash: hash, required, block hash +- fullTx: bool, required, if true returns the full transaction objects, if false returns only the hashes of the transactions + +Returns: + +result: object + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1003, + "method": "eth_getBlockByHash", + "params": [ + "0xb6fbeabaa5682445b825c5bb02faf9290a38be44d9a47834b65224478923ebce", + true + ] +}' | jq +``` + +### eth_getBlockByNumber + +The `getBlockByNumber` method returns information about a block by block number. + +Parameters + +- blockNr: BlockNumber, integer of a block number, or the string "earliest", "latest", "pending", or "finalized", as in the default block parameter. +- fullTx: bool, if true returns the full transaction objects, if false only the hashes of the transactions. + +result: object + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getBlockByNumber", + "params": [ + "latest", + true + ] +}' | jq +``` + +### eth_getBlockReceipts + +The `getBlockReceipts` returns the block receipts for the given block hash or number or tag. + +Parameters: + +- blockNrOrHash: BlockNumberOrHash, required, hexadecimal or decimal integer representing a block number, or one of the string tags: + - latest + - earliest + - pending + - finalized + +note: pending returns the same data as latest. + +Returns: + +result: object, block object or null when there is no corresponding block. + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1004, + "method": "eth_getBlockReceipts", + "params": [ + "latest" + ] +}' | jq +``` + +### eth_getBlockTransactionCountByHash + +The `getBlockTransactionCountByHash` method returns the number of transactions in the block with the given block hash. + +Parameters: + +- blockHash: hash, required, block hash + +Returns: + +result: uint, block transaction count + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1004, + "method": "eth_getBlockTransactionCountByHash", + "params": [ + "0xb6fbeabaa5682445b825c5bb02faf9290a38be44d9a47834b65224478923ebce" + ] +}' | jq +``` + +### eth_getBlockTransactionCountByNumber + +The `getBlockTransactionCountByNumber` method returns the number of transactions in the block with the given block number. + +Parameters: + +- blockNr: BlockNumber, required, block number, or one of the string tags latest, earliest, pending, or finalized. + +Returns: + +result: uint, block transaction count + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1004, + "method": "eth_getBlockTransactionCountByNumber", + "params": [ + "latest" + ] +}' | jq +``` + +### eth_getCode + +The `getCode` method returns the compiled byte code of a smart contract, if any, at a given address. + +Parameters: + +- address: address, required +- blockNrOrHash: BlockNumberOrHash, required + +Returns: + +result: array of byte + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1004, + "method": "eth_getCode", + "params": [ + "0x0000000000000000000000000000000000000088", + "latest" + ] +}' | jq +``` + +### eth_getLogs + +The `getLogs` method returns an array of all the logs matching the given filter object. + +Parameters: + +- crit: ojbect FilterCriteria, a filter object containing the following: + +- address: optional, contract address (20 bytes) or a list of addresses from which logs should originate. +- fromBlock: optional, default is "latest", a hexadecimal block number, or one of the string tags latest, earliest, pending, safe, or finalized. See the default block parameter. +- toBlock: optional, default is "latest", a hexadecimal block number, or one of the string tags latest, earliest, pending, safe, or finalized. See the default block parameter. +- topics: optional, array of 32 bytes DATA topics. Topics are order-dependent. +- blockhash: optional, restricts the logs returned to the single block referenced in the 32-byte hash blockHash. Using blockHash is equivalent to setting fromBlock and toBlock to the block number referenced in the blockHash. If blockHash is present in the filter criteria, then neither fromBlock nor toBlock are allowed. + +Returns: + +result: array of Log + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1004, + "method": "eth_getLogs", + "params": [ + { + "address": "0x53350795c11cee781a7e174479778f848d76ab2a", + "fromBlock": "0x22b2277", + "toBlock": "0x22b2277", + "topics": [ + [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x6a12b3df6cba4203bd7fd06b816789f87de8c594299aed5717ae070fac781bac" + ] + ] + } + ] +}' | jq +``` + +### eth_getOwnerByCoinbase + +The `getOwnerByCoinbase` return masternode owner of the given coinbase address. + +Parameters: + +- coinbase: address, required, account +- blockNr: BlockNumber, required, block number + +Returns: + +result: address + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getOwnerByCoinbase", + "params": [ + "0xD4CE02705041F04135f1949Bc835c1Fe0885513c", + "latest" + ] +}' | jq +``` + +### eth_getProof + +The `getProof` returns the account and storage values of the specified account including the Merkle-proof. The block number can be nil, in which case the value is taken from the latest known block. + +Parameters: + +- account: address, required +- keys: array of string, required +- blockNumber: big.Int, optional + +Returns: + +result: object AccountResult + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getProof", + "params": [ + "0xe5cB067E90D5Cd1F8052B83562Ae670bA4A211a8", + [ + "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "0x283s34c8e2b1456f09832c71e5d6a0b4f8c9e1d3a2b5c7f0e6d4a8b2c1f3e5d7" + ], + "latest" + ], +}' | jq +``` + +### eth_getStorageAt + +The `getStorageAt` method returns the value from a storage position at a given address. + +Parameters: + +- address: address, required +- key: string, required +- blockNrOrHash: BlockNumberOrHash, required + +Returns: + +result: array of byte + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getStorageAt", + "params": [ + "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "0x0", + "latest" + ], +}' | jq +``` + +### eth_getRawTransactionByBlockHashAndIndex + +Teh `getRawTransactionByBlockHashAndIndex` method returns the bytes of the transaction for the given block hash and index. + +Parameters: + +- blockHash: hash, required, block hash +- index: uint, required, transaction index + +Returns: + +result: object + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getRawTransactionByBlockHashAndIndex", + "params": [ + "0xb6fbeabaa5682445b825c5bb02faf9290a38be44d9a47834b65224478923ebce", + 0 + ] +}' | jq +``` + +### eth_getRawTransactionByBlockNumberAndIndex + +The `getRawTransactionByBlockNumberAndIndex` returns the bytes of the transaction for the given block number and index. + +Parameters: + +- blockNr: BlockNumber, required, blcok number +- index: uint, required, transaction index + +Returns: + +result: object + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getRawTransactionByBlockNumberAndIndex", + "params": [ + "latest", + 0 + ] +}' | jq +``` + +### eth_getRawTransactionByHash + +The `getRawTransactionByHash` method returns the bytes of the transaction for the given hash. + +Parameters: + +- hash, required, transaction hash + +Returns: + +result: array of byte + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getRawTransactionByHash", + "params": [ + "0x5bbcde52084defa9d1c7068a811363cc27a25c80d7e495180964673aa5f47687" + ] +}' | jq +``` + +### eth_getRewardByHash + +The `getRewardByHash` method returns the reward by block hash. + +Parameters: + +- hash, required, block hash + +Returns: + +result: object + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getRewardByHash", + "params": [ + "0xb6fbeabaa5682445b825c5bb02faf9290a38be44d9a47834b65224478923ebce" + ] +}' | jq +``` + +### eth_getTransactionAndReceiptProof + +The `getTransactionAndReceiptProof` method returns the Trie transaction and receipt proof of the given transaction hash. + +Parameters: + +- hash, required, transaction hash + +Returns: + +result: object + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getTransactionAndReceiptProof", + "params": [ + "0xbf83342ccdd6592eff8e2acfed87e23e852d684a4e2cfade89ba3b304c2b66a9" + ] +}' | jq +``` + +### eth_getTransactionByBlockHashAndIndex + +The `getTransactionByBlockHashAndIndex` method returns information about a transaction given block hash and transaction index position. + +Parameters: + +- blockHash: hash, required, a string representing the hash (32 bytes) of a block +- index: uint, required, a hexadecimal of the integer representing the position in the block + +Returns: + +result: object RPCTransaction + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getTransactionByBlockHashAndIndex", + "params": [ + "0xb6fbeabaa5682445b825c5bb02faf9290a38be44d9a47834b65224478923ebce", + "0x0" + ] +}' | jq +``` + +### eth_getTransactionByBlockNumberAndIndex + +The `getTransactionByBlockNumberAndIndex` method returns information about a transaction given block number and transaction index position. + +Parameters: + +- blockNr: BlockNumber, required, a hexadecimal block number, or one of the string tags latest, earliest, pending, or finalized +- index: uint, required, a hexadecimal of the integer representing the position in the block + +Returns: + +result: object RPCTransaction + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getTransactionByBlockNumberAndIndex", + "params": [ + "0x548f4f1", + "0x0" + ] +}' | jq +``` + +### eth_getTransactionByHash + +The `getTransactionByHash` method returns information about a transaction for a given hash. + +Parameters: + +- hash: hash, required, a string representing the hash (32 bytes) of a transaction + +Returns: + +result: object RPCTransaction + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getTransactionByHash", + "params": [ + "0xbf83342ccdd6592eff8e2acfed87e23e852d684a4e2cfade89ba3b304c2b66a9" + ] +}' | jq +``` + +### eth_getTransactionCount + +The `getTransactionCount` method returns the number of transactions sent from an address. + +Parameters: + +- address: address, required, a string representing the address (20 bytes) +- blockNrOrHash: BlockNumberOrHash, required, a hexadecimal block number, or one of the string tags latest, earliest, pending, or finalized. + +Returns: + +result: uint64 + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getTransactionCount", + "params": [ + "0xD4CE02705041F04135f1949Bc835c1Fe0885513c", + "latest" + ] +}' | jq +``` + +### eth_getTransactionReceipt + +The `getTransactionReceipt` method returns the receipt of a transaction given transaction hash. Note that the receipt is not available for pending transactions. + +Parameters: + +- hash: hash, required, a string representing the hash (32 bytes) of a transaction + +Returns: + +result: object + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 5002, + "method": "eth_getTransactionReceipt", + "params": [ + "0xbf83342ccdd6592eff8e2acfed87e23e852d684a4e2cfade89ba3b304c2b66a9" + ] +}' | jq +``` + +### eth_getUncleByBlockHashAndIndex + +The `getUncleByBlockHashAndIndex` method returns information about an uncle of a block given the block hash and the uncle index position. + +Parameters: + +- blockHash: hash, required, a string representing the hash (32 bytes) of a block. +- index: uint, required, a hexadecimal equivalent of the integer indicating the uncle's index position. + +Returns: + +result: object + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 5002, + "method": "eth_getUncleByBlockHashAndIndex", + "params": [ + "0xb6fbeabaa5682445b825c5bb02faf9290a38be44d9a47834b65224478923ebce", + "0x0" + ] +}' | jq +``` + +### eth_getUncleByBlockNumberAndIndex + +The `getUncleByBlockNumberAndIndex` method returns information about an uncle of a block given the block number and the uncle index position. + +Parameters: + +- blockNr: BlockNumber, required, a hexadecimal block number, or one of the string tags latest, earliest, pending, or finalized +- index: uint, required, a hexadecimal equivalent of the integer indicating the uncle's index position + +Returns: + +result: object + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 5002, + "method": "eth_getUncleByBlockNumberAndIndex", + "params": [ + "0x548f4f1", + "0x0" + ] +}' | jq +``` + +### eth_getUncleCountByBlockHash + +The `getUncleCountByBlockHash` method returns the number of uncles in a block from a block matching the given block hash. + +Parameters: + +- blockHash: hash, required, a string representing the hash (32 bytes) of a block + +Returns: + +result: uint + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 5002, + "method": "eth_getUncleCountByBlockHash", + "params": [ + "0xb6fbeabaa5682445b825c5bb02faf9290a38be44d9a47834b65224478923ebce" + ] +}' | jq +``` + +### eth_getUncleCountByBlockNumber + +The `getUncleCountByBlockNumber` method returns the number of uncles in a block from a block matching the given block number. + +Parameters: + +- blockNr: BlockNumber, required, a hexadecimal block number, or one of the string tags latest, earliest, pending, or finalized + +Returns: + +result: uint + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 5002, + "method": "eth_getUncleCountByBlockNumber", + "params": [ + "latest" + ] +}' | jq +``` + +### eth_getWork + +The `getWork` method returns the hash of the current block, the seed hash, and the boundary condition to be met ("target"). + +Parameters: + +None + +Returns: + +result: array of string, with the following properties: + +- Current block header PoW-hash (32 bytes). +- The seed hash used for the DAG (32 bytes). +- The boundary condition ("target") (32 bytes), 2^256 / difficulty. + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 5002, + "method": "eth_getWork" +}' | jq +``` + +### eth_hashrate + +The `hashrate` method returns the number of hashes per second that the node is mining with. Only applicable when the node is mining. + +Parameters: + +None + +Returns: + +result: uint64 + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 5002, + "method": "eth_hashrate" +}' | jq +``` + +### eth_maxPriorityFeePerGas + +The `maxPriorityFeePerGas` method returns an estimate of how much priority fee, in wei, you need to be included in a block. + +Parameters: + +None + +Returns + +result: big.Int, a hexadecimal value of the priority fee, in wei, needed to be included in a block. + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1002, + "method": "eth_maxPriorityFeePerGas" +}' | jq +``` + +### eth_mining + +The `mining` method returns true if client is actively mining new blocks. + +Parameters: + +None + +Returns + +result: bool + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 5002, + "method": "eth_mining" +}' | jq +``` + +### eth_pendingTransactions + +The `pendingTransactions` returns the transactions that are in the transaction pool and have a from address that is one of the accounts this node manages. + +Parameters: + +None + +Returns: + +result: array of RPCTransaction + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1004, + "method": "eth_pendingTransactions" +}' | jq +``` + +### eth_protocolVersion + +The `protocolVersion` method returns the current Ethereum protocol version. + +Parameters: + +None + +Returns: + +result: uint + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1004, + "method": "eth_protocolVersion" +}' | jq +``` + +### eth_resend + +The `resend` method accepts an existing transaction and a new gas price and limit. It will remove the given transaction from the pool and reinsert it with the new gas price and limit. + +Parameters: + +- sendArgs: object TransactionArgs, required, the arguments to construct a new transaction +- gasPrice: big.Int, optional, gas price +- gasLimit: uint64, optional, gas limit + +Returns: + +result: hash, transaction hash + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_resend", + "params":[ + { + "from": "0xca7a99380131e6c76cfa622396347107aeedca2d", + "to": "0x8c9f4468ae04fb3d79c80f6eacf0e4e1dd21deee", + "value": "0x1", + "gas": "0x9999", + "maxFeePerGas": "0x5d21dba00", + "maxPriorityPerGas": "0x5d21dba00" + }, + "0x5d21dba99", + "0x5d21dba99" + ] +}' | jq +``` + +### eth_sendRawTransaction + +The `sendRawTransaction` method submits a pre-signed transaction for broadcast to the Ethereum network. + +Parameters: + +- input: array of byte + +Returns: + +result: hash + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_sendRawTransaction", + "params":[ + "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" + ] +}' | jq +``` + +### eth_sendTransaction + +The `sendTransaction` method creates new message call transaction or a contract creation, if the data field contains code, and signs it using the account specified in from. + +Parameters: + +- args: object TransactionArgs + +Returns: + +result: hash + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_sendTransaction", + "params":[ + { + from: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + to: "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + gas: "0x76c0", + gasPrice: "0x9184e72a000", + value: "0x9184e72a", + input: "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" + } + ] +}' | jq +``` + +### eth_sign + +The `sign` method calculates an Ethereum specific signature with: `sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))`. + +By adding a prefix to the message makes the calculated signature recognizable as an Ethereum specific signature. This prevents misuse where a malicious dapp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim. + +Note: the address to sign with must be unlocked. + +Parameters: + +- addr: address, required, account address +- data: array of byte, required, message to sign + +Returns: + +result: array of byte + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_sign", + "params":[ + "0xD4CE02705041F04135f1949Bc835c1Fe0885513c", + "0x1234abcd" + ] +}' | jq +``` + +### eth_signTransaction + +The `signTransaction` method signs a transaction that can be submitted to the network at a later time using with `eth_sendRawTransaction`. + +Parameters: + +- args: object TransactionArgs, required + - nonce: uint64, optional, anti-replay parameter + - to: address, optional, recipient address, or null if this is a contract creation transaction + - from: address, required, sender address + - value: big.Int, optional, value to be transferred, in wei + - data: array of byte, optional, compiled code of a contract or hash of the invoked method signature and encoded parameters + - input: same as data + - gas: uint64, optional, gas provided by the sender + - gasPrice: big.Int, optional, gas price, in wei, provided by the sender + - maxPriorityFeePerGas: big.Int, optional, maximum fee, in wei, the sender is willing to pay per gas above the base fee + - maxFeePerGas: big.Int, optional, maximum total fee (base fee + priority fee), in wei, the sender is willing to pay per gas. + - accessList: array of object, optional, list of addresses and storage keys the transaction plans to access + - chainId: big.Int, optional, chain ID + +Returns: + +result: object SignTransactionResult + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_signTransaction", + "params": [ + { + "data":"0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "value": "0x9184e72a" + } + ] +}' | jq +``` + +### eth_submitWork + +The `submitWork` method can be used by external miner to submit their POW solution. It returns an indication if the work was accepted. + +Note, this is not an indication if the provided work was valid! + +Parameters: + +- nonce: BlockNonce, required +- solution: hash, required +- digest: hash, required + +Returns: + +result: bool + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_submitWork", + "params": [ + "0x0000000000000001", + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + "0xD1FE5700000000000000000000000000D1FE5700000000000000000000000000" + ] +}' | jq +``` + +### eth_syncing + +The `syncing` method returns an object with data about the sync status or false. + +Parameters: + +None + +Returns: + +result: bool + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_syncing" +}' | jq +``` + +### Filter methods + +#### eth_getFilterChanges + +The `getFilterChanges` method polling method for a filter, which returns an array of logs which occurred since the last poll. Filter must be created by calling either `eth_newFilter` or `eth_newBlockFilter`. + +Parameters: + +- id: string, required, a string denoting the filter ID + +Returns: + +result: object + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getFilterChanges", + "params": [ + "0x68ce60ffdb0c9480c307b0c3d2ae9391" + ] +}' | jq +``` + +#### eth_getFilterLogs + +The `getFilterLogs` method returns an array of all logs matching the filter with the given filter ID. + +Parameters: + +- id: string, required, a string denoting the filter ID + +Returns: + +result: array of Log, Log objects contain the following keys and their values: + +- address: Address from which this log originated. +- blockHash: The hash of the block where this log was in. null when it's a pending log. +- blockNumber: The block number where this log was in. null when it's a pending log. +- data: DATA. Contains the non-indexed arguments of the log. +- logIndex: A hexadecimal of the log index position in the block. null when it is a pending log. +- removed: true when the log was removed, due to a chain reorganization. false if it's a valid log. +- topics: Array of DATA. An array of 0 to 4 32-bytes DATA of indexed log arguments. In Solidity the first topic is the hash of the signature of the event (for example, Deposit(address,bytes32,uint256)), except when you declared the event with the anonymous specifier. +- transactionHash: A hash of the transactions from which this log was created. null when it's a pending log. +- transactionIndex: A hexadecimal of the transactions index position from which this log was created. null when it's a pending log. + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_getFilterLogs", + "params": [ + "0x68ce60ffdb0c9480c307b0c3d2ae9391" + ] +}' | jq +``` + +#### eth_newBlockFilter + +The `newBlockFilter` method creates a filter in the node, to notify when a new block arrives. To check if the state has changed, call `eth_getFilterChanges`. + +Parameters: + +None + +Returns: + +result: string + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_newBlockFilter" +}' | jq +``` + +#### eth_newFilter + +The `newFilter` method creates a filter object based on the given filter options, to notify when the state changes (logs). To check if the state has changed, call `eth_getFilterChanges`. + +Parameters: + +- crit: ojbect FilterCriteria, a filter object with the following keys and their values: + +- address: optional, a contract address or a list of addresses from which logs should originate. +- fromBlock: optional, default is latest, a hexadecimal block number, or one of the string tags latest, earliest, pending, safe, or finalized. See the default block parameter. +- toBlock: optional, default is latest, a hexadecimal block number, or one of the string tags latest, earliest, pending, safe, or finalized. See the default block parameter. +- topics: aoptional, an array of 32 bytes DATA topics. Topics are order-dependent. + +Returns: + +result: string + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_newFilter", + "params": [ + { + "fromBlock": "0x2bb7231", + "toBlock": "0x2bb7233" + } + ] +}' | jq +``` + +#### eth_newPendingTransactionFilter + +The `newPendingTransactionFilter` method creates a filter in the node, to notify when new pending transactions arrive. To check if the state has changed, call `eth_getFilterChanges`. + +Parameters: + +None + +Returns: + +result: string + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_newPendingTransactionFilter" +}' | jq +``` + +#### eth_uninstallFilter + +The `uninstallFilter` method uninstalls a filter with given ID. This method should always be called when watching is no longer needed. Additionally, filters time out when they aren't requested with `eth_getFilterChanges` for a period of time. + +Parameters: + +- id: string, required, a string denoting the ID of the filter to be uninstalled. + +Returns: + +result: bool, true if the filter was successfully uninstalled, otherwise false + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "eth_uninstallFilter", + "params": [ + "0x43f0c93bf463861b7c15a5d11d402d9b" + ] +}' | jq +``` + +## module miner + +The `miner` API is now deprecated because mining was switched off at the transition to proof-of-stake. It existed to provide remote control the node's mining operation and set various mining specific settings. It is provided here for historical interest! + +### miner_getHashrate + +The `getHashrate` method get hashrate in H/s (Hash operations per second). + +Parameters: + +None + +Returns: + +result: uint64 + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "miner_getHashrate" +}' | jq +``` + +### miner_setEtherbase + +The `getHashrate` method get hashrate in H/s (Hash operations per second). + +Parameters: + +- etherbase: address, required + +Returns: + +result: bool + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "miner_setEtherbase", + "params": [ + "0xD4CE02705041F04135f1949Bc835c1Fe0885513c" + ] +}' | jq +``` + +### miner_setExtra + +The `setExtra` method sets the extra data a miner can include when miner blocks. This is capped at 32 bytes. + +Parameters: + +- extra: string, required + +Returns: + +result: bool + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "miner_setExtra", + "params": [ + "string" + ] +}' | jq +``` + +### miner_setGasPrice + +The `setGasPrice` method sets the minimal accepted gas price when mining transactions. Any transactions that are below this limit are excluded from the mining process. + +Parameters: + +- gasPrice: big.Int, required + +Returns: + +result: bool + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "miner_setGasPrice", + "params": [ + "0x1" + ] +}' | jq +``` + +### miner_start + +The `start` method start the miner with the given number of threads. If threads is nil the number of workers started is equal to the number of logical CPUs that are usable by this process. If mining is already running, this method adjust the number of threads allowed to use. + +Parameters: + +- threads: int, optional + +Returns: + +result: bool + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "miner_start", + "params": [ + 1 + ] +}' | jq +``` + +### miner_stop + +The `stop` method stop the CPU mining operation. + +Parameters: + +None + +Returns: + +result: bool + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "miner_stop" +}' | jq +``` + +## module net + +The `net` API provides insight about the networking aspect of the client. + +### net_listening + +The `listening` method returns an indication if the node is listening for network connections. + +Parameters: + +None + +Returns: + +result: bool, always listening + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "net_listening" +}' | jq +``` + +### net_peerCount + +The `peerCount` method returns the number of connected peers. + +Parameters: + +None + +Returns: + +result: uint + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "net_peerCount" +}' | jq +``` + +### net_version + +The `version` method returns the devp2p network ID + +Parameters: + +None + +Returns: + +result: string + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "net_version" +}' | jq +``` + +## module personal + +The JSON-RPC API's `personal` namespace has historically been used to manage accounts and sign transactions and data over RPC. + +### personal_listAccounts + +The `listAccounts` method displays the addresses of all accounts in the keystore. It is identical to eth.accounts. + +Parameters: + +None + +Returns: + +result: array of address + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "personal_listAccounts" +}' | jq +``` + +### personal_deriveAccount + +The `deriveAccount` method requests a hardware wallet to derive a new account, optionally pinning it for later use. + +Parameters: + +- url: string, required +- path: string, required +- pin: bool, optional + +Returns: + +result: object of Account + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "personal_deriveAccount", + "params": [ + "http://127.0.0.1/", + "m/44/60/0/0/0", + true + ] +}' | jq +``` + +### personal_ecRecover + +The `ecRecover` method returns the address for the account that was used to create a signature. + +Parameters: + +- data: array of byte, required +- sig: array of byte, required + +Returns: + +result: address + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "personal_ecRecover", + "params": [ + "0xaabbccdd", + "0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c" + ] +}' | jq +``` + +### personal_importRawKey + +The `importRawKey` method was used to create a new account in the keystore from a raw private key. + +Parameters: + +- privkey: string, required, private key +- password: string, required, password + +Returns: + +result: address + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "personal_importRawKey", + "params": [ + "cd87934ee007b7a458fa00dc0314fff8b2bd43b3071f46c820c379e483b4fd8e", + "password" + ] +}' | jq +``` + +### personal_listWallets + +The `listWallets` method lists full details, including usb path or keystore-file paths. + +Parameters: + +- privkey: string, required, private key +- password: string, required, password + +Returns: + +result: address + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "personal_listWallets", + "params": [ + "cd87934ee007b7a458fa00dc0314fff8b2bd43b3071f46c820c379e483b4fd8e", + "password" + ] +}' | jq +``` + +### personal_lockAccount + +The `lockAccount` method removes the private key with a given address from memory. The account can no longer be used to send transactions. + +Parameters: + +- addr: address, required + +Returns: + +result: bool + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "personal_lockAccount", + "params": [ + "0xD4CE02705041F04135f1949Bc835c1Fe0885513c" + ] +}' | jq +``` + +### personal_newAccount + +The `newAccount` method was used to create a new account and save it in the keystore. + +Parameters: + +- password: string, required + +Returns: + +result: address + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "personal_newAccount", + "params": [ + "password" + ] +}' | jq +``` + +### personal_openWallet + +The `openWallet` method initiates a hardware wallet opening procedure by establishing a USB connection and then attempting to authenticate via the provided passphrase. Note, the method may return an extra challenge requiring a second open (e.g. the Trezor PIN matrix challenge). + +Parameters: + +- url: string, required +- passphrase: string, optional + +Returns: + +result: error + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "personal_openWallet", + "params": [ + "keystore://", + "password" + ] +}' | jq +``` + +### personal_sendTransaction + +The `sendTransaction` method is used to sign and submit a transaction. This can be done using eth_sendTransaction + +Parameters: + +- args: object TransactionArgs, required +- passwd: string, required + +Returns: + +result: hash + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "personal_sendTransaction", + "params": [ + { + "from": "0x1d4e05bb72677cb8fa576149c945b57d13f855e4", + "to": "0xafa3f8684e54059998bc3a7b0d2b0da075154d66", + "value": "0x1230000000" + }, + "password" + ] +}' | jq +``` + +### personal_sign + +The `sign` method calculates an Ethereum specific signature with sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)). Adding a prefix to the message makes the calculated signature recognisable as an Ethereum specific signature. This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim. + +Parameters: + +- data: array of bytes, required +- addr: address, required +- passwd: string, required + +Returns: + +result: array of byte + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "personal_sign", + "params": [ + "0xdeadbeaf", + "0x413ba0e5f6f00664598b5c80042b1308f4ff1408", + "password" + ] +}' | jq +``` + +### personal_signTransaction + +The `signTransaction` was used to create and sign a transaction from the given arguments. The transaction was returned in RLP-form, not broadcast to other nodes. + +Parameters: + +- args: object TransactionArgs, required +- passwd: string, required + +Returns: + +result: ojbect Transaction + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "personal_signTransaction", + "params": [ + { + "from": "0x77982323172e5b6182539d3522d5a33a944206d4", + "to": "0xcd6bfdb523a4d030890d28bf1eb6ef36307c9aaa", + "value": "0x10000", + "gas": "0x1000000", + "nonce": "0x2", + "gasPrice": "0x25000000000" + } + ] +}' | jq +``` + +### personal_unlockAccount + +The `unlockAccount` method decrypts the key with the given address from the key store. + +Parameters: + +- addr: address, required +- password: string, required +- duration: uint64, optional + +Returns: + +result: bool + +Example: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "personal_unlockAccount", + "params": [ + "0xD4CE02705041F04135f1949Bc835c1Fe0885513c", + "password", + 30 + ] +}' | jq +``` + +## module rpc + +### rpc_modules + +The `modules` returns the list of RPC services with their version number. + +Parameters: + +None + +Returns: + +result: ojbect + +Example: + +Request: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "rpc_modules" +}' | jq +``` + +Response: + +```json +{ + "jsonrpc": "2.0", + "id": 1001, + "result": { + "XDPoS": "1.0", + "debug": "1.0", + "eth": "1.0", + "net": "1.0", + "personal": "1.0", + "rpc": "1.0", + "txpool": "1.0", + "web3": "1.0" + } +} +``` + +## module txpool + +### txpool_content + +The `content` method lists the exact details of all the transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only. + +The result is an object with two fields pending and queued. Each of these fields are associative arrays, in which each entry maps an origin-address to a batch of scheduled transactions. These batches themselves are maps associating nonces with actual transactions. + +Please note, there may be multiple transactions associated with the same account and nonce. This can happen if the user broadcast multiple ones with varying gas allowances (or even completely different transactions). + +Parameters: + +None + +Returns: + +result: ojbect + +Example: + +Request: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "txpool_content" +}' | jq +``` + +### txpool_contentFrom + +The `contentFrom` method retrieves the transactions contained within the txpool, returning pending as well as queued transactions of this address, grouped by nonce. + +Parameters: + +- addr: addrress, required + +Returns: + +result: ojbect + +Example: + +Request: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "txpool_contentFrom", + "params": [ + "0xD4CE02705041F04135f1949Bc835c1Fe0885513c" + ] +}' | jq +``` + +Response: + +```json +{ + "jsonrpc": "2.0", + "id": 1001, + "result": { + "pending": {}, + "queued": {} + } +} +``` + +### txpool_inspect + +The `inspect` lists a textual summary of all the transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only. This is a method specifically tailored to developers to quickly see the transactions in the pool and find any potential issues. + +The result is an object with two fields pending and queued. Each of these fields are associative arrays, in which each entry maps an origin-address to a batch of scheduled transactions. These batches themselves are maps associating nonces with transactions summary strings. + +Please note, there may be multiple transactions associated with the same account and nonce. This can happen if the user broadcast multiple ones with varying gas allowances (or even completely different transactions). + +Parameters: + +None + +Returns: + +result: ojbect + +Example: + +Request: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "txpool_inspect" +}' | jq +``` + +Response: + +```json +{ + "jsonrpc": "2.0", + "id": 1001, + "result": { + "pending": {}, + "queued": {} + } +} +``` + +### txpool_status + +The `status` method returns the number of pending and queued transaction in the pool. + +The result is an object with two fields pending and queued, each of which is a counter representing the number of transactions in that particular state. + +Parameters: + +None + +Returns: + +result: ojbect + +Example: + +Request: + +```shell +curl -s -X POST -H "Content-Type: application/json" ${RPC} -d '{ + "jsonrpc": "2.0", + "id": 1001, + "method": "txpool_status" +}' | jq +``` + +Response: + +```json +{ + "jsonrpc": "2.0", + "id": 1001, + "result": { + "pending": "0x3", + "queued": "0x0" + } +} +``` + + + + + + + + + + + + diff --git a/website/docs/xdcchain/developers/sdks/javascript.md b/website/docs/xdcchain/developers/sdks/javascript.md new file mode 100644 index 00000000..6d1c5f46 --- /dev/null +++ b/website/docs/xdcchain/developers/sdks/javascript.md @@ -0,0 +1,539 @@ +--- +title: "JavaScript & TypeScript SDK Guide +description: Complete guide to building dApps on XDC using web3.js, ethers.js, and React with XDC-specific configurations and copy-pasteable code." +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +**Difficulty:** Beginner | **Time:** ~20 minutes | **Tools:** Node.js `v18+`, npm, MetaMask + +# JavaScript & TypeScript SDK Guide + +This page covers everything needed to connect a JavaScript or TypeScript application to the XDC Network. You will have a working dApp that reads on-chain data, sends transactions, and listens for events on both XDC Mainnet and Apothem Testnet. + +## Prerequisites + +- Node.js `v18+` — [Download](https://nodejs.org/) +- MetaMask extension installed in your browser +- XDC testnet wallet with funds — [Apothem faucet](https://faucet.apothem.network) + +## 1. Install Dependencies + + + + + ```bash + npm install web3 ethers + ``` + + + + + + + + ```bash + yarn add web3 ethers + ``` + + + +Expected output: + +```text +added 42 packages in 3s +``` + +## 2. Configure Network Constants + +Create a file that holds XDC-specific network configuration. These values never change. + +```javascript title="networks.js" +export const XDC_MAINNET = { + chainId: 50, + name: 'XDC Network', + rpc: 'https://rpc.xinfin.network', + explorer: 'https://xdcscan.com', + nativeCurrency: { name: 'XDC', symbol: 'XDC', decimals: 18 } +}; + +export const XDC_APOTHEM = { + chainId: 51, + name: 'XDC Apothem Testnet', + rpc: 'https://rpc.apothem.network', + explorer: 'https://testnet.xdcscan.com', + nativeCurrency: { name: 'XDC', symbol: 'TXDC', decimals: 18 } +}; + +export const XDC_DEVNET = { + chainId: 551, + name: 'XDC Devnet', + rpc: 'https://devnetrpc.xinfin.network', + nativeCurrency: { name: 'XDC', symbol: 'XDC', decimals: 18 } +}; +``` + +!!! warning "XDC address prefix differs from Ethereum" + XDCScan displays `xdc` prefix. EVM tools use `0x`. Same address, different display. + Convert: `"0x" + xdcAddress.slice(3)` or `"xdc" + ethAddress.slice(2)` + +## 3. Connect MetaMask to XDC + + + + + ```javascript title="connect-wallet.js" + import { XDC_APOTHEM } from './networks.js'; + + export async function connectWallet() { + if (!window.ethereum) { + throw new Error('MetaMask not installed'); + } + + // Add XDC Apothem to MetaMask + await window.ethereum.request({ + method: 'wallet_addEthereumChain', + params: [{ + chainId: '0x' + XDC_APOTHEM.chainId.toString(16), + chainName: XDC_APOTHEM.name, + rpcUrls: [XDC_APOTHEM.rpc], + nativeCurrency: XDC_APOTHEM.nativeCurrency, + blockExplorerUrls: [XDC_APOTHEM.explorer] + }] + }); + + // Request account access + const accounts = await window.ethereum.request({ + method: 'eth_requestAccounts' + }); + + return accounts[0]; // Returns 0x... format + } + ``` + + + + + + + + ```typescript title="connect-wallet.ts" + import { XDC_APOTHEM } from './networks.js'; + + declare global { + interface Window { + ethereum?: any; + } + } + + export async function connectWallet(): Promise { + if (!window.ethereum) { + throw new Error('MetaMask not installed'); + } + + await window.ethereum.request({ + method: 'wallet_addEthereumChain', + params: [{ + chainId: '0x' + XDC_APOTHEM.chainId.toString(16), + chainName: XDC_APOTHEM.name, + rpcUrls: [XDC_APOTHEM.rpc], + nativeCurrency: XDC_APOTHEM.nativeCurrency, + blockExplorerUrls: [XDC_APOTHEM.explorer] + }] + }); + + const accounts: string[] = await window.ethereum.request({ + method: 'eth_requestAccounts' + }); + + return accounts[0]; + } + ``` + + + +Expected output in browser console: + +```text +Connected: 0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB +``` + +!!! danger "Never paste your private key" + Use MetaMask or environment variables. Never commit keys to source control. + +## 4. Read On-Chain Data + + + + + ```javascript title="read-data.js" + import Web3 from 'web3'; + import { XDC_APOTHEM } from './networks.js'; + + const web3 = new Web3(XDC_APOTHEM.rpc); + + async function getBalance(address) { + // Accepts both 0x... and xdc... formats + const cleanAddress = address.startsWith('xdc') + ? '0x' + address.slice(3) + : address; + + const balanceWei = await web3.eth.getBalance(cleanAddress); + const balanceXdc = web3.utils.fromWei(balanceWei, 'ether'); + return balanceXdc; + } + + getBalance('0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB') + .then(bal => console.log(`Balance: ${bal} XDC`)); + ``` + + + + + + + + ```javascript title="read-data.js" + import { ethers } from 'ethers'; + import { XDC_APOTHEM } from './networks.js'; + + const provider = new ethers.JsonRpcProvider(XDC_APOTHEM.rpc); + + async function getBalance(address) { + const cleanAddress = address.startsWith('xdc') + ? '0x' + address.slice(3) + : address; + + const balanceWei = await provider.getBalance(cleanAddress); + const balanceXdc = ethers.formatEther(balanceWei); + return balanceXdc; + } + + getBalance('0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB') + .then(bal => console.log(`Balance: ${bal} XDC`)); + ``` + + + +Expected output: + +```text +Balance: 1250.5 XDC +``` + +## 5. Send a Transaction + +!!! tip "Always deploy to Apothem first" + Chain ID 51. Free testnet XDC at https://faucet.apothem.network + + + + + ```javascript title="send-tx.js" + import Web3 from 'web3'; + import { XDC_APOTHEM } from './networks.js'; + + const web3 = new Web3(window.ethereum); + + async function sendXdc(toAddress, amount) { + const accounts = await web3.eth.getAccounts(); + const from = accounts[0]; + + // Handle xdc... prefix + const cleanTo = toAddress.startsWith('xdc') + ? '0x' + toAddress.slice(3) + : toAddress; + + const tx = { + from, + to: cleanTo, + value: web3.utils.toWei(amount.toString(), 'ether'), + gas: 21000, + gasPrice: await web3.eth.getGasPrice() + }; + + const receipt = await web3.eth.sendTransaction(tx); + console.log('Tx hash:', receipt.transactionHash); + return receipt; + } + + sendXdc('xdc3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB', 1.5); + ``` + + + + + + + + ```javascript title="send-tx.js" + import { ethers } from 'ethers'; + import { XDC_APOTHEM } from './networks.js'; + + const provider = new ethers.BrowserProvider(window.ethereum); + + async function sendXdc(toAddress, amount) { + const signer = await provider.getSigner(); + + const cleanTo = toAddress.startsWith('xdc') + ? '0x' + toAddress.slice(3) + : toAddress; + + const tx = await signer.sendTransaction({ + to: cleanTo, + value: ethers.parseEther(amount.toString()) + }); + + const receipt = await tx.wait(); + console.log('Tx hash:', tx.hash); + return receipt; + } + + sendXdc('xdc3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB', 1.5); + ``` + + + +Expected output: + +```text +Tx hash: 0xabc123... +``` + +## 6. Interact with a Smart Contract + + + + + ```javascript title="contract-interaction.js" + import Web3 from 'web3'; + + const ABI = [ + { + "inputs": [], + "name": "message", + "outputs": [{"internalType": "string", "name": "", "type": "string"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{"internalType": "string", "name": "_message", "type": "string"}], + "name": "updateMessage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ]; + + const CONTRACT_ADDRESS = '0x...'; // Your deployed contract + + const web3 = new Web3(window.ethereum); + const contract = new web3.eth.Contract(ABI, CONTRACT_ADDRESS); + + async function readMessage() { + const msg = await contract.methods.message().call(); + console.log('Message:', msg); + return msg; + } + + async function updateMessage(newMessage) { + const accounts = await web3.eth.getAccounts(); + const receipt = await contract.methods.updateMessage(newMessage) + .send({ from: accounts[0] }); + console.log('Updated in block:', receipt.blockNumber); + return receipt; + } + ``` + + + + + + + + ```javascript title="contract-interaction.js" + import { ethers } from 'ethers'; + + const ABI = [ + "function message() view returns (string)", + "function updateMessage(string _message)" + ]; + + const CONTRACT_ADDRESS = '0x...'; // Your deployed contract + + const provider = new ethers.BrowserProvider(window.ethereum); + + async function readMessage() { + const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, provider); + const msg = await contract.message(); + console.log('Message:', msg); + return msg; + } + + async function updateMessage(newMessage) { + const signer = await provider.getSigner(); + const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, signer); + const tx = await contract.updateMessage(newMessage); + const receipt = await tx.wait(); + console.log('Updated in block:', receipt.blockNumber); + return receipt; + } + ``` + + + +## 7. Listen for Events + + + + + ```javascript title="events.js" + import Web3 from 'web3'; + import { XDC_APOTHEM } from './networks.js'; + + const web3 = new Web3(XDC_APOTHEM.rpc); + + // Subscribe to new blocks + const subscription = web3.eth.subscribe('newBlockHeaders') + .on('data', block => { + console.log('New block:', block.number); + }) + .on('error', err => console.error(err)); + + // Stop after 60 seconds + setTimeout(() => subscription.unsubscribe(), 60000); + ``` + + + + + + + + ```javascript title="events.js" + import { ethers } from 'ethers'; + import { XDC_APOTHEM } from './networks.js'; + + const provider = new ethers.WebSocketProvider( + 'wss://rpc.xinfin.network' + ); + + provider.on('block', blockNumber => { + console.log('New block:', blockNumber); + }); + + // Stop after 60 seconds + setTimeout(() => provider.destroy(), 60000); + ``` + + + +Expected output: + +```text +New block: 87654321 +New block: 87654322 +New block: 87654323 +``` + +!!! warning "WebSocket endpoint differs from HTTP" + Replace `https://` with `wss://` for WebSocket connections to the same RPC host. + +## 8. React Integration + +```jsx title="XdcProvider.jsx" +import React, { createContext, useContext, useState, useEffect } from 'react'; +import { ethers } from 'ethers'; +import { XDC_APOTHEM } from './networks.js'; + +const XdcContext = createContext(null); + +export function XdcProvider({ children }) { + const [provider, setProvider] = useState(null); + const [signer, setSigner] = useState(null); + const [address, setAddress] = useState(null); + + async function connect() { + if (!window.ethereum) { + alert('Install MetaMask'); + return; + } + + await window.ethereum.request({ + method: 'wallet_addEthereumChain', + params: [{ + chainId: '0x' + XDC_APOTHEM.chainId.toString(16), + chainName: XDC_APOTHEM.name, + rpcUrls: [XDC_APOTHEM.rpc], + nativeCurrency: XDC_APOTHEM.nativeCurrency, + blockExplorerUrls: [XDC_APOTHEM.explorer] + }] + }); + + const browserProvider = new ethers.BrowserProvider(window.ethereum); + const newSigner = await browserProvider.getSigner(); + const newAddress = await newSigner.getAddress(); + + setProvider(browserProvider); + setSigner(newSigner); + setAddress(newAddress); + } + + return ( + + {children} + + ); +} + +export const useXdc = () => useContext(XdcContext); +``` + +Usage: + +```jsx title="App.jsx" +import { useXdc } from './XdcProvider'; + +function App() { + const { address, connect } = useXdc(); + + return ( +
+ {address ? ( +

Connected: {address}

+ ) : ( + + )} +
+ ); +} +``` + +## Configuration Reference + +| Parameter | Mainnet | Apothem Testnet | Devnet | +| --- | --- | --- | --- | +| Chain ID | 50 | 51 | 551 | +| RPC URL | https://rpc.xinfin.network | https://rpc.apothem.network | https://devnetrpc.xinfin.network | +| WebSocket | wss://rpc.xinfin.network | wss://rpc.apothem.network | — | +| Explorer | https://xdcscan.com | https://testnet.xdcscan.com | — | +| Currency | XDC | TXDC | XDC | +| Block Time | ~2 seconds | ~2 seconds | ~2 seconds | + +## Troubleshooting + +| Error | Cause | Fix | +| --- | --- | --- | +| `invalid chain id` | Used chain 1 instead of 50/51 | Set chainId to 51 for Apothem in wallet_addEthereumChain | +| `invalid address` | Used `0x` prefix with XDCScan | XDCScan uses `xdc` prefix; convert with `"xdc" + addr.slice(2)` | +| `insufficient funds` | Wrong network or empty wallet | Get testnet XDC from faucet.apothem.network | +| `nonce too low` | Stuck pending transaction | Reset account in MetaMask: Settings > Advanced > Reset | +| `gas required exceeds allowance` | Default gas limit too low | Explicitly set gasLimit to 500000 for contract calls | +| `contract verification failed` | Wrong API endpoint | Use https://testnet.xdcscan.com/api for Apothem verification | + +## Next Steps + +* [Deploy Your First Smart Contract](/smartcontract/deploy) +* [Token Standards Reference](/smartcontract/tokens) +* [JSON-RPC API Reference](/api/json-rpc) diff --git a/website/docs/xdcchain/developers/sdks/xdc3js.md b/website/docs/xdcchain/developers/sdks/xdc3js.md new file mode 100644 index 00000000..81258a5d --- /dev/null +++ b/website/docs/xdcchain/developers/sdks/xdc3js.md @@ -0,0 +1,1382 @@ +--- +title: "xdc3.js SDK Guide +description: Complete guide to xdc3.js, the official XDC Network JavaScript SDK. Installation, providers, accounts, transactions, contract interactions, events, and framework integration with copy-pasteable code." +--- + +**Difficulty:** Beginner | **Time:** ~25 minutes | **Tools:** Node.js `v18+`, npm + +# xdc3.js SDK Guide + +xdc3.js is the official JavaScript SDK for XDC Network. It is a fork of web3.js with additional utilities for XDC-specific address formatting (`xdc` prefix). This guide covers everything from installation to production deployment. + +## Table of Contents + +1. [What is xdc3.js](#what-is-xdc3js) +2. [Installation](#installation) +3. [Provider Configuration](#provider-configuration) +4. [Account Management](#account-management) +5. [Reading On-Chain Data](#reading-on-chain-data) +6. [Sending Transactions](#sending-transactions) +7. [Smart Contract Interaction](#smart-contract-interaction) +8. [Event Listening](#event-listening) +9. [XDC-Specific Utilities](#xdc-specific-utilities) +10. [Error Handling](#error-handling) +11. [Migration from web3.js](#migration-from-web3js) +12. [Framework Integration](#framework-integration) +13. [Testing Utilities](#testing-utilities) +14. [TypeScript Support](#typescript-support) +15. [Related Topics](#related-topics) + +--- + +## What is xdc3.js + +xdc3.js is the official JavaScript API for XDC Network, maintained by XinFinOrg. It extends web3.js with XDC-specific address formatting utilities. + +### Key Differences from web3.js + +| Feature | web3.js | xdc3.js | +|---------|---------|---------| +| Address prefix | `0x` only | `0x` and `xdc` support | +| `toXdcAddress()` | Not available | Built-in utility | +| `fromXdcAddress()` | Not available | Built-in utility | +| `isXdcAddress()` | Not available | Built-in utility | +| RPC compatibility | Ethereum | XDC + Ethereum | + +### Package Structure + +``` +xdc3 +├── xdc3 # Main package (includes all modules) +├── xdc3-utils # Utility functions +├── xdc3-eth # Ethereum-compatible modules +├── xdc3-eth-contract # Contract interaction +├── xdc3-eth-accounts # Account management +├── xdc3-eth-personal # Personal sign operations +└── xdc3-net # Network utilities +``` + +--- + +## Installation + +### npm + +```bash +npm install xdc3 +``` + +### yarn + +```bash +yarn add xdc3 +``` + +### CDN (Browser) + +```html + + +``` + +### Version Check + +```javascript +import Xdc3 from 'xdc3'; + +console.log(Xdc3.version); // "1.3.13416" +``` + +--- + +## Provider Configuration + +### HTTP Provider + +```javascript +import Xdc3 from 'xdc3'; + +// Mainnet +const xdcMainnet = new Xdc3('https://rpc.xinfin.network'); + +// Apothem Testnet +const xdcTestnet = new Xdc3('https://rpc.apothem.network'); + +// Devnet +const xdcDevnet = new Xdc3('https://devnetrpc.xinfin.network'); + +// With options +const xdcWithTimeout = new Xdc3( + new Xdc3.providers.HttpProvider('https://rpc.xinfin.network', { + timeout: 30000, + headers: [{ name: 'X-API-Key', value: 'your-api-key' }] + }) +); +``` + +### WebSocket Provider + +```javascript +import Xdc3 from 'xdc3'; + +// Real-time subscriptions +const wsProvider = new Xdc3.providers.WebsocketProvider( + 'wss://rpc.xinfin.network' +); + +const xdcWs = new Xdc3(wsProvider); + +// Reconnection options +const wsWithReconnect = new Xdc3.providers.WebsocketProvider( + 'wss://rpc.xinfin.network', + { + timeout: 30000, + clientConfig: { + keepalive: true, + keepaliveInterval: 60000 + }, + reconnect: { + auto: true, + delay: 5000, + maxAttempts: 5, + onTimeout: false + } + } +); +``` + +### MetaMask / Browser Provider + +```javascript +import Xdc3 from 'xdc3'; + +// Detect MetaMask or other injected wallet +if (window.ethereum) { + const xdc = new Xdc3(window.ethereum); + + // Request account access + await window.ethereum.request({ method: 'eth_requestAccounts' }); + + // Get connected accounts + const accounts = await xdc.eth.getAccounts(); + console.log('Connected:', accounts[0]); +} +``` + +### Network Configuration Reference + +| Parameter | Mainnet | Apothem Testnet | Devnet | +|-----------|---------|-----------------|--------| +| Chain ID | 50 | 51 | 551 | +| RPC URL | `https://rpc.xinfin.network` | `https://rpc.apothem.network` | `https://devnetrpc.xinfin.network` | +| WebSocket | `wss://rpc.xinfin.network` | `wss://rpc.apothem.network` | — | +| Explorer | `https://xdcscan.com` | `https://testnet.xdcscan.com` | — | +| Currency | XDC | TXDC | XDC | +| Block Time | ~2 seconds | ~2 seconds | ~2 seconds | + +--- + +## Account Management + +### Creating Accounts + +```javascript +import Xdc3 from 'xdc3'; + +// Create a new random account +const newAccount = Xdc3.eth.accounts.create(); +console.log('Address:', newAccount.address); // 0x... +console.log('Private Key:', newAccount.privateKey); + +// Create from entropy +const accountFromEntropy = Xdc3.eth.accounts.create('extra entropy here'); +``` + +### Importing Private Keys + +```javascript +import Xdc3 from 'xdc3'; + +// Add account to wallet +const privateKey = '0x...'; +const account = Xdc3.eth.accounts.privateKeyToAccount(privateKey); + +// Add to wallet for transaction signing +xdc.eth.accounts.wallet.add(account); + +// Wallet can hold multiple accounts +xdc.eth.accounts.wallet.add('0xprivatekey1'); +xdc.eth.accounts.wallet.add('0xprivatekey2'); + +console.log('Wallet size:', xdc.eth.accounts.wallet.length); +``` + +### HD Wallet Support + +```javascript +import Xdc3 from 'xdc3'; + +// Create from mnemonic +const mnemonic = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; + +// Note: xdc3 uses same HD path as Ethereum (BIP44) +const hdwallet = Xdc3.eth.accounts.create(); + +// For full HD wallet support, use ethers.js alongside xdc3 +import { ethers } from 'ethers'; +const hdNode = ethers.HDNodeWallet.fromPhrase(mnemonic); +console.log('HD Address:', hdNode.address); +``` + +### Account Balance Queries + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('https://rpc.xinfin.network'); + +async function getBalance(address) { + // Handles both 0x and xdc prefixes automatically + const balanceWei = await xdc.eth.getBalance(address); + const balanceXdc = xdc.utils.fromWei(balanceWei, 'ether'); + + return { + wei: balanceWei, + xdc: balanceXdc + }; +} + +// Query with xdc prefix +const bal1 = await getBalance('xdc3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB'); + +// Query with 0x prefix +const bal2 = await getBalance('0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB'); +``` + +### Account Information + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('https://rpc.xinfin.network'); + +async function getAccountInfo(address) { + const [balance, txCount, code] = await Promise.all([ + xdc.eth.getBalance(address), + xdc.eth.getTransactionCount(address), + xdc.eth.getCode(address) + ]); + + return { + address, + balance: xdc.utils.fromWei(balance, 'ether'), + transactionCount: txCount, + isContract: code !== '0x' + }; +} +``` + +--- + +## Reading On-Chain Data + +### Block Information + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('https://rpc.xinfin.network'); + +async function getBlockInfo() { + // Latest block + const latest = await xdc.eth.getBlock('latest'); + console.log('Latest block:', latest.number); + console.log('Timestamp:', new Date(latest.timestamp * 1000)); + console.log('Transactions:', latest.transactions.length); + + // Block by number + const block100 = await xdc.eth.getBlock(100); + + // Block transaction count + const txCount = await xdc.eth.getBlockTransactionCount('latest'); +} +``` + +### Transaction Details + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('https://rpc.xinfin.network'); + +async function getTransactionInfo(txHash) { + const tx = await xdc.eth.getTransaction(txHash); + const receipt = await xdc.eth.getTransactionReceipt(txHash); + + return { + from: tx.from, + to: tx.to, + value: xdc.utils.fromWei(tx.value, 'ether'), + gasPrice: xdc.utils.fromWei(tx.gasPrice, 'gwei'), + status: receipt.status ? 'Success' : 'Failed', + blockNumber: receipt.blockNumber, + gasUsed: receipt.gasUsed + }; +} +``` + +### Chain State + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('https://rpc.xinfin.network'); + +async function getChainState() { + const [chainId, gasPrice, blockNumber] = await Promise.all([ + xdc.eth.getChainId(), + xdc.eth.getGasPrice(), + xdc.eth.getBlockNumber() + ]); + + return { + chainId, + gasPriceGwei: xdc.utils.fromWei(gasPrice, 'gwei'), + blockNumber + }; +} +``` + +--- + +## Sending Transactions + +### Basic XDC Transfer + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('https://rpc.apothem.network'); + +async function sendXdc(toAddress, amountXdc) { + // Add sender account + const sender = xdc.eth.accounts.privateKeyToAccount('0xPRIVATE_KEY'); + xdc.eth.accounts.wallet.add(sender); + + // Convert amount to wei + const amountWei = xdc.utils.toWei(amountXdc.toString(), 'ether'); + + // Build transaction + const tx = { + from: sender.address, + to: toAddress, + value: amountWei, + gas: 21000, + gasPrice: await xdc.eth.getGasPrice() + }; + + // Sign and send + const receipt = await xdc.eth.sendTransaction(tx); + + console.log('Transaction hash:', receipt.transactionHash); + console.log('Block:', receipt.blockNumber); + console.log('Gas used:', receipt.gasUsed); + + return receipt; +} + +// Send 1.5 XDC +sendXdc('xdc3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB', 1.5); +``` + +### With MetaMask (Browser) + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3(window.ethereum); + +async function sendWithMetaMask(toAddress, amountXdc) { + const accounts = await xdc.eth.getAccounts(); + const from = accounts[0]; + + const receipt = await xdc.eth.sendTransaction({ + from, + to: toAddress, + value: xdc.utils.toWei(amountXdc.toString(), 'ether') + }); + + return receipt; +} +``` + +### Gas Estimation + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('https://rpc.apothem.network'); + +async function estimateGas(txObject) { + try { + const gasEstimate = await xdc.eth.estimateGas(txObject); + const gasPrice = await xdc.eth.getGasPrice(); + + const estimatedCost = gasEstimate * gasPrice; + + return { + gasEstimate, + gasPrice, + estimatedCostXdc: xdc.utils.fromWei(estimatedCost.toString(), 'ether') + }; + } catch (error) { + console.error('Gas estimation failed:', error.message); + throw error; + } +} + +// Example usage +const gasInfo = await estimateGas({ + from: '0x...', + to: '0x...', + value: xdc.utils.toWei('1', 'ether') +}); +``` + +### Nonce Management + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('https://rpc.apothem.network'); + +async function getNonce(address) { + // Current transaction count = next nonce + const nonce = await xdc.eth.getTransactionCount(address); + + // For pending transactions, use 'pending' + const pendingNonce = await xdc.eth.getTransactionCount(address, 'pending'); + + return { nonce, pendingNonce }; +} + +// Manual nonce for transaction batching +async function sendMultipleTransactions(from, to, amounts) { + let nonce = await xdc.eth.getTransactionCount(from); + + const receipts = []; + for (const amount of amounts) { + const receipt = await xdc.eth.sendTransaction({ + from, + to, + value: xdc.utils.toWei(amount.toString(), 'ether'), + nonce: nonce++ // Increment for each tx + }); + receipts.push(receipt); + } + + return receipts; +} +``` + +--- + +## Smart Contract Interaction + +### Read Operations (Call) + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('https://rpc.xinfin.network'); + +const ABI = [ + { + "inputs": [], + "name": "totalSupply", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{"internalType": "address", "name": "account", "type": "address"}], + "name": "balanceOf", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function" + } +]; + +const CONTRACT_ADDRESS = '0x...'; + +const contract = new xdc.eth.Contract(ABI, CONTRACT_ADDRESS); + +async function readContractData() { + // Call totalSupply + const totalSupply = await contract.methods.totalSupply().call(); + console.log('Total Supply:', xdc.utils.fromWei(totalSupply, 'ether')); + + // Call balanceOf + const balance = await contract.methods.balanceOf('0x...').call(); + console.log('Balance:', xdc.utils.fromWei(balance, 'ether')); +} +``` + +### Write Operations (Send) + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('https://rpc.apothem.network'); + +const ABI = [ + { + "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" + } +]; + +const TOKEN_ADDRESS = '0x...'; + +const contract = new xdc.eth.Contract(ABI, TOKEN_ADDRESS); + +async function transferTokens(recipient, amount) { + const sender = xdc.eth.accounts.privateKeyToAccount('0xPRIVATE_KEY'); + xdc.eth.accounts.wallet.add(sender); + + const amountWei = xdc.utils.toWei(amount.toString(), 'ether'); + + const receipt = await contract.methods.transfer(recipient, amountWei) + .send({ + from: sender.address, + gas: 100000 + }); + + console.log('Transfer confirmed:', receipt.transactionHash); + return receipt; +} +``` + +### Deploy Contract + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('https://rpc.apothem.network'); + +const BYTECODE = '0x608060405234801561001057600080fd5b50...'; +const ABI = [/* ... */]; + +async function deployContract(constructorArgs) { + const deployer = xdc.eth.accounts.privateKeyToAccount('0xPRIVATE_KEY'); + xdc.eth.accounts.wallet.add(deployer); + + const contract = new xdc.eth.Contract(ABI); + + const deployTx = contract.deploy({ + data: BYTECODE, + arguments: constructorArgs + }); + + const gas = await deployTx.estimateGas({ from: deployer.address }); + + const receipt = await deployTx.send({ + from: deployer.address, + gas + }); + + console.log('Contract deployed at:', receipt.options.address); + return receipt; +} +``` + +--- + +## Event Listening + +### Subscribe to Contract Events + +```javascript +import Xdc3 from 'xdc3'; + +// Use WebSocket for real-time events +const wsProvider = new Xdc3.providers.WebsocketProvider( + 'wss://rpc.xinfin.network' +); +const xdc = new Xdc3(wsProvider); + +const ABI = [ + { + "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" + } +]; + +const TOKEN_ADDRESS = '0x...'; +const contract = new xdc.eth.Contract(ABI, TOKEN_ADDRESS); + +// Listen for all Transfer events +const subscription = contract.events.Transfer({ + fromBlock: 'latest' +}) + .on('data', event => { + console.log('Transfer detected:'); + console.log(' From:', event.returnValues.from); + console.log(' To:', event.returnValues.to); + console.log(' Value:', xdc.utils.fromWei(event.returnValues.value, 'ether')); + console.log(' Block:', event.blockNumber); + }) + .on('error', error => { + console.error('Event error:', error); + }); + +// Stop listening after 5 minutes +setTimeout(() => { + subscription.unsubscribe(); + console.log('Unsubscribed from events'); +}, 300000); +``` + +### Filter Events + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('wss://rpc.xinfin.network'); + +const contract = new xdc.eth.Contract(ABI, TOKEN_ADDRESS); + +// Filter by sender +contract.events.Transfer({ + filter: { from: '0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB' }, + fromBlock: 'latest' +}) + .on('data', event => { + console.log('Outgoing transfer:', event.returnValues); + }); + +// Filter by recipient +contract.events.Transfer({ + filter: { to: '0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB' }, + fromBlock: 'latest' +}) + .on('data', event => { + console.log('Incoming transfer:', event.returnValues); + }); +``` + +### Past Events + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('https://rpc.xinfin.network'); + +const contract = new xdc.eth.Contract(ABI, TOKEN_ADDRESS); + +async function getPastEvents() { + // Get all Transfer events in block range + const events = await contract.getPastEvents('Transfer', { + fromBlock: 87654000, + toBlock: 87655000 + }); + + console.log(`Found ${events.length} events`); + + events.forEach(event => { + console.log(`Block ${event.blockNumber}: ${event.returnValues.from} -> ${event.returnValues.to}`); + }); +} +``` + +### New Block Headers + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('wss://rpc.xinfin.network'); + +// Subscribe to new blocks +const blockSubscription = xdc.eth.subscribe('newBlockHeaders') + .on('data', block => { + console.log('New block:', block.number); + console.log('Hash:', block.hash); + console.log('Timestamp:', new Date(block.timestamp * 1000)); + console.log('Transactions:', block.transactionsRoot); + }) + .on('error', error => { + console.error('Block subscription error:', error); + }); + +// Unsubscribe +// blockSubscription.unsubscribe(); +``` + +--- + +## XDC-Specific Utilities + +### Address Conversion + +```javascript +import Xdc3 from 'xdc3'; + +const ethAddress = '0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB'; +const xdcAddress = 'xdc3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB'; + +// Convert 0x to xdc +const converted = Xdc3.utils.toXdcAddress(ethAddress); +console.log(converted); // xdc3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB + +// Convert xdc to 0x +const reverted = Xdc3.utils.fromXdcAddress(xdcAddress); +console.log(reverted); // 0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB + +// Check if xdc address +console.log(Xdc3.utils.isXdcAddress(xdcAddress)); // true +console.log(Xdc3.utils.isXdcAddress(ethAddress)); // false +``` + +### Address Validation + +```javascript +import Xdc3 from 'xdc3'; + +function validateAddress(address) { + // Check if valid Ethereum address + const isEthAddress = Xdc3.utils.isAddress(address); + + // Check if valid XDC address + const isXdcAddr = Xdc3.utils.isXdcAddress(address); + + return { + valid: isEthAddress || isXdcAddr, + type: isXdcAddr ? 'xdc' : (isEthAddress ? 'eth' : 'invalid'), + normalized: isXdcAddr ? Xdc3.utils.fromXdcAddress(address) : address + }; +} + +console.log(validateAddress('xdc3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB')); +// { valid: true, type: 'xdc', normalized: '0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB' } +``` + +### Unit Conversion + +```javascript +import Xdc3 from 'xdc3'; + +// Wei to XDC +const wei = '1000000000000000000'; +console.log(Xdc3.utils.fromWei(wei, 'ether')); // "1" + +// XDC to Wei +const xdc = '1.5'; +console.log(Xdc3.utils.toWei(xdc, 'ether')); // "1500000000000000000" + +// Gwei conversions +const gwei = '20'; +console.log(Xdc3.utils.toWei(gwei, 'gwei')); // "20000000000" + +// Custom units +console.log(Xdc3.utils.fromWei('1000000', 'mwei')); // "1" (1 MXDC) +``` + +--- + +## Error Handling + +### Common Errors + +```javascript +import Xdc3 from 'xdc3'; + +const xdc = new Xdc3('https://rpc.apothem.network'); + +async function safeTransaction(txObject) { + try { + const receipt = await xdc.eth.sendTransaction(txObject); + return { success: true, receipt }; + } catch (error) { + // Parse xdc3 error types + if (error.message.includes('insufficient funds')) { + return { + success: false, + error: 'INSUFFICIENT_FUNDS', + message: 'Account balance too low for transaction' + }; + } + + if (error.message.includes('nonce too low')) { + return { + success: false, + error: 'NONCE_TOO_LOW', + message: 'Transaction nonce already used' + }; + } + + if (error.message.includes('gas required exceeds allowance')) { + return { + success: false, + error: 'GAS_LIMIT_EXCEEDED', + message: 'Transaction requires more gas than limit' + }; + } + + if (error.message.includes('invalid chain id')) { + return { + success: false, + error: 'WRONG_CHAIN', + message: 'Connected to wrong network. Use XDC Mainnet (50) or Apothem (51)' + }; + } + + return { + success: false, + error: 'UNKNOWN', + message: error.message + }; + } +} +``` + +### Retry Logic + +```javascript +import Xdc3 from 'xdc3'; + +async function sendWithRetry(xdc, txObject, maxRetries = 3) { + let lastError; + + for (let attempt = 1; attempt <= maxRetries; attempt++) { + try { + return await xdc.eth.sendTransaction(txObject); + } catch (error) { + lastError = error; + + // Don't retry on fatal errors + if (error.message.includes('insufficient funds') || + error.message.includes('nonce too low')) { + throw error; + } + + // Exponential backoff + const delay = Math.pow(2, attempt) * 1000; + console.log(`Attempt ${attempt} failed. Retrying in ${delay}ms...`); + await new Promise(resolve => setTimeout(resolve, delay)); + } + } + + throw lastError; +} +``` + +### Timeout Handling + +```javascript +import Xdc3 from 'xdc3'; + +function sendWithTimeout(xdc, txObject, timeoutMs = 60000) { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + reject(new Error('Transaction timeout after ' + timeoutMs + 'ms')); + }, timeoutMs); + + xdc.eth.sendTransaction(txObject) + .on('receipt', receipt => { + clearTimeout(timer); + resolve(receipt); + }) + .on('error', error => { + clearTimeout(timer); + reject(error); + }); + }); +} +``` + +--- + +## Migration from web3.js + +### Drop-in Replacement + +```javascript +// Before (web3.js) +import Web3 from 'web3'; +const web3 = new Web3('https://rpc.xinfin.network'); + +// After (xdc3.js) +import Xdc3 from 'xdc3'; +const xdc = new Xdc3('https://rpc.xinfin.network'); + +// Same API for most operations +const balance = await xdc.eth.getBalance(address); +``` + +### Address Handling Differences + +```javascript +// web3.js - manual conversion +const xdcAddr = 'xdc3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bB'; +const ethAddr = '0x' + xdcAddr.slice(3); + +// xdc3.js - built-in utilities +const ethAddr2 = Xdc3.utils.fromXdcAddress(xdcAddr); +const xdcAddr2 = Xdc3.utils.toXdcAddress(ethAddr2); +``` + +### Package Comparison + +| web3.js | xdc3.js | Purpose | +|---------|---------|---------| +| `web3` | `xdc3` | Main package | +| `web3-utils` | `xdc3-utils` | Utilities | +| `web3-eth` | `xdc3-eth` | Ethereum modules | +| `web3-eth-contract` | `xdc3-eth-contract` | Contract interaction | + +--- + +## Framework Integration + +### React Integration + +```jsx +// XdcContext.jsx +import React, { createContext, useContext, useState, useEffect } from 'react'; +import Xdc3 from 'xdc3'; + +const XdcContext = createContext(null); + +export function XdcProvider({ children, rpcUrl = 'https://rpc.apothem.network' }) { + const [xdc, setXdc] = useState(null); + const [account, setAccount] = useState(null); + const [chainId, setChainId] = useState(null); + + useEffect(() => { + const instance = new Xdc3(rpcUrl); + setXdc(instance); + }, [rpcUrl]); + + async function connect() { + if (!window.ethereum) { + throw new Error('MetaMask not installed'); + } + + await window.ethereum.request({ method: 'eth_requestAccounts' }); + + const browserXdc = new Xdc3(window.ethereum); + const accounts = await browserXdc.eth.getAccounts(); + const id = await browserXdc.eth.getChainId(); + + setXdc(browserXdc); + setAccount(accounts[0]); + setChainId(id); + } + + return ( + + {children} + + ); +} + +export const useXdc = () => useContext(XdcContext); +``` + +```jsx +// App.jsx +import { XdcProvider, useXdc } from './XdcContext'; + +function WalletButton() { + const { account, connect } = useXdc(); + + return ( + + ); +} + +function App() { + return ( + + + + ); +} +``` + +### Vue 3 Integration + +```javascript +// composables/useXdc.js +import { ref, onMounted } from 'vue'; +import Xdc3 from 'xdc3'; + +export function useXdc(rpcUrl = 'https://rpc.apothem.network') { + const xdc = ref(null); + const account = ref(null); + const balance = ref('0'); + + onMounted(() => { + xdc.value = new Xdc3(rpcUrl); + }); + + async function connect() { + if (!window.ethereum) throw new Error('MetaMask not installed'); + + await window.ethereum.request({ method: 'eth_requestAccounts' }); + + const browserXdc = new Xdc3(window.ethereum); + const accounts = await browserXdc.eth.getAccounts(); + + xdc.value = browserXdc; + account.value = accounts[0]; + + // Get balance + const bal = await browserXdc.eth.getBalance(accounts[0]); + balance.value = browserXdc.utils.fromWei(bal, 'ether'); + } + + return { xdc, account, balance, connect }; +} +``` + +```vue + + + + +``` + +### Node.js / Backend + +```javascript +// server.js +import Xdc3 from 'xdc3'; +import express from 'express'; + +const app = express(); +const xdc = new Xdc3('https://rpc.xinfin.network'); + +// API endpoint to check balance +app.get('/balance/:address', async (req, res) => { + try { + const { address } = req.params; + const balance = await xdc.eth.getBalance(address); + + res.json({ + address, + balance: xdc.utils.fromWei(balance, 'ether'), + currency: 'XDC' + }); + } catch (error) { + res.status(400).json({ error: error.message }); + } +}); + +// API endpoint to get transaction status +app.get('/tx/:hash', async (req, res) => { + try { + const receipt = await xdc.eth.getTransactionReceipt(req.params.hash); + + if (!receipt) { + return res.json({ status: 'pending' }); + } + + res.json({ + status: receipt.status ? 'success' : 'failed', + blockNumber: receipt.blockNumber, + gasUsed: receipt.gasUsed, + transactionHash: receipt.transactionHash + }); + } catch (error) { + res.status(400).json({ error: error.message }); + } +}); + +app.listen(3000, () => console.log('XDC API running on port 3000')); +``` + +--- + +## Testing Utilities + +### Local Testing Setup + +```javascript +// test/setup.js +import Xdc3 from 'xdc3'; + +// Use Apothem for testing +export const TEST_RPC = 'https://rpc.apothem.network'; +export const testXdc = new Xdc3(TEST_RPC); + +// Test account (use a faucet-funded account) +export const TEST_ACCOUNT = { + address: '0x...', + privateKey: '0x...' +}; + +// Add to wallet before each test +beforeEach(() => { + testXdc.eth.accounts.wallet.add(TEST_ACCOUNT.privateKey); +}); +``` + +### Contract Testing + +```javascript +// test/contract.test.js +import { testXdc, TEST_ACCOUNT } from './setup.js'; + +const ABI = [/* ... */]; +const BYTECODE = '0x...'; + +describe('Token Contract', () => { + let contract; + + beforeAll(async () => { + const Contract = new testXdc.eth.Contract(ABI); + const deployTx = Contract.deploy({ data: BYTECODE }); + + const gas = await deployTx.estimateGas({ from: TEST_ACCOUNT.address }); + contract = await deployTx.send({ + from: TEST_ACCOUNT.address, + gas + }); + }); + + test('should have correct initial supply', async () => { + const totalSupply = await contract.methods.totalSupply().call(); + expect(totalSupply).toBe('1000000000000000000000000'); + }); + + test('should transfer tokens', async () => { + const receipt = await contract.methods.transfer('0x...', '1000') + .send({ from: TEST_ACCOUNT.address }); + + expect(receipt.status).toBe(true); + }); +}); +``` + +--- + +## TypeScript Support + +### Type Definitions + +```typescript +// types/xdc3.d.ts +declare module 'xdc3' { + import { EventEmitter } from 'events'; + + export default class Xdc3 { + static version: string; + static utils: Xdc3Utils; + static providers: { + HttpProvider: new (url: string, options?: any) => any; + WebsocketProvider: new (url: string, options?: any) => any; + }; + + constructor(provider: string | any); + + eth: { + accounts: { + create(entropy?: string): Account; + privateKeyToAccount(privateKey: string): Account; + wallet: { + add(account: string | Account): Account; + remove(index: number): boolean; + clear(): void; + length: number; + }; + }; + getBalance(address: string): Promise; + getTransactionCount(address: string, block?: string): Promise; + getBlock(blockHashOrNumber: string | number): Promise; + getTransaction(hash: string): Promise; + getTransactionReceipt(hash: string): Promise; + sendTransaction(tx: TransactionConfig): Promise; + getGasPrice(): Promise; + getChainId(): Promise; + getBlockNumber(): Promise; + estimateGas(tx: TransactionConfig): Promise; + getCode(address: string): Promise; + subscribe(type: string, options?: any): EventEmitter; + Contract: new (abi: any[], address?: string) => Contract; + }; + } + + interface Xdc3Utils { + toXdcAddress(address: string): string; + fromXdcAddress(address: string): string; + isXdcAddress(address: string): boolean; + isAddress(address: string): boolean; + toWei(value: string, unit: string): string; + fromWei(value: string, unit: string): string; + sha3(value: string): string; + keccak256(value: string): string; + soliditySha3(...values: any[]): string; + encodePacked(...values: any[]): string; + } + + interface Account { + address: string; + privateKey: string; + signTransaction(tx: TransactionConfig): Promise; + sign(data: string): Signature; + } + + interface TransactionConfig { + from?: string; + to?: string; + value?: string | number; + gas?: number; + gasPrice?: string; + data?: string; + nonce?: number; + } + + interface Transaction { + hash: string; + nonce: number; + from: string; + to: string | null; + value: string; + gasPrice: string; + gas: number; + input: string; + } + + interface Receipt { + transactionHash: string; + blockNumber: number; + status: boolean; + gasUsed: number; + logs: Log[]; + } + + interface Block { + number: number; + hash: string; + timestamp: number; + transactions: string[]; + } + + interface Log { + address: string; + topics: string[]; + data: string; + } + + interface Contract { + methods: { + [methodName: string]: (...args: any[]) => ContractMethod; + }; + events: { + [eventName: string]: (options?: any) => EventEmitter; + }; + deploy(options: { data: string; arguments?: any[] }): ContractDeployer; + options: { + address: string; + }; + } + + interface ContractMethod { + call(options?: any): Promise; + send(options: TransactionConfig): Promise; + estimateGas(options?: any): Promise; + encodeABI(): string; + } + + interface ContractDeployer { + send(options: TransactionConfig): Promise; + estimateGas(options?: any): Promise; + encodeABI(): string; + } + + interface SignedTransaction { + messageHash: string; + rawTransaction: string; + transactionHash: string; + } + + interface Signature { + message: string; + messageHash: string; + v: string; + r: string; + s: string; + signature: string; + } +} +``` + +### Typed Usage Example + +```typescript +import Xdc3 from 'xdc3'; + +const xdc: Xdc3 = new Xdc3('https://rpc.xinfin.network'); + +async function getBalanceTyped(address: string): Promise { + const balance: string = await xdc.eth.getBalance(address); + return xdc.utils.fromWei(balance, 'ether'); +} +``` + +--- + +## Troubleshooting + +| Error | Cause | Fix | +|-------|-------|-----| +| `invalid chain id` | Wrong network in MetaMask | Set chainId to 50 (Mainnet) or 51 (Apothem) | +| `insufficient funds` | Empty wallet or wrong network | Get testnet XDC from faucet.apothem.network | +| `nonce too low` | Stuck pending transaction | Reset account in MetaMask or manually set nonce | +| `gas required exceeds allowance` | Gas limit too low | Set gas limit to 500000+ for contract calls | +| `connection not open` | WebSocket disconnected | Check network, add reconnection logic | +| `invalid address` | Mixed `0x`/`xdc` prefixes | Use `Xdc3.utils.fromXdcAddress()` to normalize | +| `Contract has not been deployed` | Wrong contract address | Verify address on XDCScan | +| `Transaction was not mined within 50 blocks` | Network congestion | Increase gas price or retry | + +--- + +## Related Topics + +- [JavaScript SDK Guide](./javascript.md): General web3.js and ethers.js guide +- [JSON-RPC API Reference](/api/json-rpc): Raw RPC methods +- [Smart Contract Development](/smartcontract): Contract writing and deployment +- [Wallet Configuration](/xdcchain/developers/wallet-configuration): MetaMask setup +- [Account Abstraction](/smartcontract/account-abstraction): Advanced wallet patterns diff --git a/website/docs/xdcchain/developers/subgraphs/best-practices.md b/website/docs/xdcchain/developers/subgraphs/best-practices.md new file mode 100644 index 00000000..ad5c1c7c --- /dev/null +++ b/website/docs/xdcchain/developers/subgraphs/best-practices.md @@ -0,0 +1,40 @@ +--- +title: Best Practices +--- + +## Best Practices + +### Schema Design + +1. **Normalize Entities:** Separate concerns into distinct entities with relationships +2. **Use IDs Strategically:** Composite IDs prevent collisions (e.g., `token-address`) +3. **Index Frequently Queried Fields:** Add `@index` directive for performance +4. **Avoid Deep Nesting:** Limit entity relationships to 2-3 levels +5. **Document Fields:** Add comments explaining non-obvious fields + +### Mapping Development + +1. **Handle Edge Cases:** Zero values, self-transfers, reverted transactions +2. **Validate Inputs:** Check addresses and values before processing +3. **Minimize Storage:** Only store data your application needs +4. **Use Constants:** Define magic numbers as named constants +5. **Test Thoroughly:** Unit tests for all event handlers + +### Deployment + +1. **Version Control:** Tag subgraph versions for reproducibility +2. **Monitor Indexing:** Track sync status and error rates +3. **Backup Manifests:** Store subgraph.yaml in version control +4. **Document Changes:** Maintain changelog for schema updates +5. **Plan Migrations:** Schema changes require new deployments + +### Querying + +1. **Paginate Results:** Never request unbounded lists +2. **Cache Responses:** Implement client-side caching for static data +3. **Batch Requests:** Combine multiple queries when possible +4. **Handle Errors:** Implement retry logic for failed queries +5. **Optimize Complexity:** Simplify queries to reduce load + +--- + diff --git a/website/docs/xdcchain/developers/subgraphs/concepts.md b/website/docs/xdcchain/developers/subgraphs/concepts.md new file mode 100644 index 00000000..04a1d40a --- /dev/null +++ b/website/docs/xdcchain/developers/subgraphs/concepts.md @@ -0,0 +1,185 @@ +--- +title: Concepts +--- + +## Subgraph Concepts + +### GraphQL Schema Design + +The schema defines the data structure that your subgraph will expose. It uses GraphQL schema definition language (SDL) with The Graph-specific directives. + +**Entity Definition:** + +```graphql +type Transfer @entity { + id: ID! + from: Bytes! + to: Bytes! + value: BigInt! + timestamp: BigInt! + blockNumber: BigInt! + transactionHash: Bytes! +} +``` + +**Schema Directives:** + +| Directive | Purpose | +|-----------|---------| +| `@entity` | Marks a type as indexable entity | +| `@id` | Primary key field (mandatory for entities) | +| `@derivedFrom` | Defines reverse lookup relationships | + +**Relationship Patterns:** + +```graphql +type Token @entity { + id: ID! + symbol: String! + name: String! + decimals: Int! + totalSupply: BigInt! + transfers: [Transfer!]! @derivedFrom(field: "token") + holders: [Holder!]! @derivedFrom(field: "token") +} + +type Holder @entity { + id: ID! + address: Bytes! + token: Token! + balance: BigInt! +} +``` + +**Data Types:** + +| Type | Description | Example | +|------|-------------|---------| +| `ID` | Unique identifier string | `"0x123..."` | +| `String` | UTF-8 string | `"XDC Token"` | +| `Int` | 32-bit signed integer | `42` | +| `BigInt` | Arbitrary precision integer | `10^18` | +| `Float` | 64-bit floating point | `3.14` | +| `Boolean` | True/false | `true` | +| `Bytes` | Byte array (hex) | `0xabcd...` | +| `BigDecimal` | High precision decimal | `1.0000000001` | + +### Subgraph Manifest + +The `subgraph.yaml` manifest defines the subgraph configuration, including data sources, entities, and mapping handlers. + +**Manifest Structure:** + +```yaml +specVersion: 0.0.4 +schema: + file: ./schema.graphql +dataSources: + - kind: ethereum + name: XRC20Token + network: xdc + source: + address: "0x1234..." + abi: XRC20 + startBlock: 12345678 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Transfer + - Approval + abis: + - name: XRC20 + file: ./abis/XRC20.json + eventHandlers: + - event: Transfer(indexed address,indexed address,uint256) + handler: handleTransfer + - event: Approval(indexed address,indexed address,uint256) + handler: handleApproval + file: ./src/mapping.ts +``` + +**Configuration Fields:** + +| Field | Description | +|-------|-------------| +| `specVersion` | Subgraph specification version | +| `schema.file` | Path to GraphQL schema | +| `dataSources` | Array of blockchain data sources | +| `source.address` | Contract address to monitor | +| `source.abi` | ABI reference name | +| `source.startBlock` | Block to start indexing from | +| `mapping.language` | Only `wasm/assemblyscript` supported | +| `eventHandlers` | Event-to-handler mappings | + +### AssemblyScript Mappings + +Mappings are TypeScript-like functions that transform blockchain events into entities. They run in a WebAssembly sandbox with blockchain-specific APIs. + +**Basic Mapping Structure:** + +```typescript +import { + Transfer as TransferEvent, + Approval as ApprovalEvent +} from "../generated/XRC20Token/XRC20"; +import { Transfer, Approval } from "../generated/schema"; + +export function handleTransfer(event: TransferEvent): void { + let transfer = new Transfer( + event.transaction.hash.toHex() + "-" + event.logIndex.toString() + ); + transfer.from = event.params.from; + transfer.to = event.params.to; + transfer.value = event.params.value; + transfer.timestamp = event.block.timestamp; + transfer.blockNumber = event.block.number; + transfer.transactionHash = event.transaction.hash; + transfer.save(); +} +``` + +**Available APIs:** + +| API | Purpose | +|-----|---------| +| `ethereum.Event` | Event parameters and metadata | +| `ethereum.Block` | Block header information | +| `ethereum.Transaction` | Transaction details | +| `store.get/load` | Entity retrieval | +| `store.set/save` | Entity persistence | +| `log.info/debug/error` | Logging for debugging | +| `ipfs.cat/map` | IPFS data access | +| `crypto.keccak256` | Cryptographic hashing | + +### Indexing Mechanics + +**Block Processing:** + +1. Graph Node receives new block from XDC network +2. Scans block for events matching manifest filters +3. Executes corresponding mapping handlers +4. Stores resulting entities in database +5. Updates indexing progress marker + +**Reorganization Handling:** + +If the XDC chain reorganizes, the Graph Node automatically: + +1. Detects the reorganization depth +2. Rolls back affected entities +3. Reprocesses blocks from the common ancestor +4. Ensures data consistency + +**Indexing Status:** + +Monitor indexing progress via the Graph CLI or Subgraph Studio dashboard. Full indexing time depends on: + +- Number of events to process +- Complexity of mapping logic +- Network block time +- Graph Node resources + +--- + diff --git a/website/docs/xdcchain/developers/subgraphs/deployment.md b/website/docs/xdcchain/developers/subgraphs/deployment.md new file mode 100644 index 00000000..107aa4b9 --- /dev/null +++ b/website/docs/xdcchain/developers/subgraphs/deployment.md @@ -0,0 +1,128 @@ +--- +title: Deployment +--- + +## Deployment + +### Subgraph Studio + +Subgraph Studio is the recommended platform for creating, testing, and publishing subgraphs to The Graph Network. + +**Setup:** + +1. Visit https://thegraph.com/studio/ +2. Connect your wallet (MetaMask or WalletConnect) +3. Create a new subgraph +4. Note your deployment key + +**Authenticate CLI:** + +```bash +graph auth --studio YOUR_DEPLOY_KEY +``` + +**Deploy:** + +```bash +graph deploy --studio xdc-token-indexer +``` + +**Version Management:** + +- Each deployment creates a new version +- Versions are identified by IPFS hash +- Query URL remains stable across versions +- Previous versions remain accessible + +### Hosted Service + +The hosted service provides free subgraph indexing with API access. + +**Create Subgraph:** + +1. Visit https://thegraph.com/hosted-service/ +2. Sign in with GitHub +3. Click "Add Subgraph" +4. Enter name and description + +**Authenticate:** + +```bash +graph auth --product hosted-service YOUR_ACCESS_TOKEN +``` + +**Deploy:** + +```bash +graph deploy --product hosted-service YOUR_GITHUB_USERNAME/xdc-token-indexer +``` + +**XDC Network Configuration:** + +Ensure your `subgraph.yaml` specifies: + +```yaml +network: xdc +``` + +For testnet deployment: + +```yaml +network: apothem +``` + +### Decentralized Network + +Publishing to The Graph Network requires GRT tokens and follows a curation model. + +**Requirements:** + +- GRT tokens for curation signaling +- Subgraph published to Subgraph Studio +- Indexers available for XDC network + +**Publish:** + +```bash +graph publish --studio xdc-token-indexer +``` + +**Signal Curation:** + +- Deposit GRT to signal quality to indexers +- Higher curation attracts more indexers +- Earn query fee rewards from usage + +### XDC-Specific Configuration + +**Network Names:** + +| Environment | Network Value | +|-------------|--------------| +| Mainnet | `xdc` | +| Testnet | `apothem` | + +**RPC Configuration:** + +For self-hosted Graph Nodes, configure XDC RPC: + +```bash +ethereum="xdc:https://rpc.xinfin.network" +``` + +For WebSocket support: + +```bash +ethereum="xdc:wss://rpc.xinfin.network" +``` + +**Block Time Considerations:** + +XDC's 2-second block time requires Graph Node tuning: + +- Reduce `ETHEREUM_POLLING_INTERVAL` for faster detection +- Increase `GRAPH_ETHEREUM_TARGET_TRIGGERS_PER_BLOCK` for throughput +- Monitor `eth_getLogs` batch sizes for RPC provider limits + +--- + diff --git a/website/docs/xdcchain/developers/subgraphs/development.md b/website/docs/xdcchain/developers/subgraphs/development.md new file mode 100644 index 00000000..bf585646 --- /dev/null +++ b/website/docs/xdcchain/developers/subgraphs/development.md @@ -0,0 +1,251 @@ +--- +title: Development +--- + +## Development Workflow + +### Project Initialization + +**Create New Subgraph:** + +```bash +graph init --product subgraph-studio xdc-token-indexer +``` + +**From Contract Example:** + +```bash +graph init \ + --product subgraph-studio \ + --from-contract 0xContractAddress \ + --network xdc \ + --abi ./path/to/abi.json \ + xdc-token-indexer +``` + +**Project Structure:** + +``` +xdc-token-indexer/ +├── abis/ +│ └── XRC20.json # Contract ABI +├── src/ +│ └── mapping.ts # Mapping logic +├── tests/ +│ └── .gitkeep # Unit tests (optional) +├── schema.graphql # GraphQL schema +├── subgraph.yaml # Subgraph manifest +├── package.json # Dependencies +└── tsconfig.json # TypeScript config +``` + +### Schema Definition + +Define your data model in `schema.graphql`: + +```graphql +type Token @entity { + id: ID! + symbol: String! + name: String! + decimals: Int! + totalSupply: BigInt! + transferCount: BigInt! + holderCount: BigInt! +} + +type Account @entity { + id: ID! + balances: [TokenBalance!]! @derivedFrom(field: "account") + sentTransfers: [Transfer!]! @derivedFrom(field: "from") + receivedTransfers: [Transfer!]! @derivedFrom(field: "to") +} + +type TokenBalance @entity { + id: ID! + token: Token! + account: Account! + balance: BigInt! +} + +type Transfer @entity { + id: ID! + token: Token! + from: Account! + to: Account! + value: BigInt! + timestamp: BigInt! + blockNumber: BigInt! + transactionHash: Bytes! +} +``` + +### ABI Preparation + +Obtain the contract ABI from: + +- Compiler output (Hardhat, Foundry, Remix) +- Verified contract on XDCScan +- Etherscan equivalent for EVM-compatible contracts + +**ABI Format:** + +```json +[ + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "from", "type": "address" }, + { "indexed": true, "name": "to", "type": "address" }, + { "indexed": false, "name": "value", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + } +] +``` + +### Mapping Implementation + +Implement transformation logic in `src/mapping.ts`: + +```typescript +import { + Transfer as TransferEvent, + XRC20 +} from "../generated/XRC20Token/XRC20"; +import { + Token, + Account, + TokenBalance, + Transfer +} from "../generated/schema"; +import { Address, BigInt } from "@graphprotocol/graph-ts"; + +function getOrCreateAccount(address: Address): Account { + let account = Account.load(address.toHex()); + if (!account) { + account = new Account(address.toHex()); + account.save(); + } + return account; +} + +function getOrCreateTokenBalance( + token: Token, + account: Account +): TokenBalance { + let id = token.id + "-" + account.id; + let balance = TokenBalance.load(id); + if (!balance) { + balance = new TokenBalance(id); + balance.token = token.id; + balance.account = account.id; + balance.balance = BigInt.zero(); + token.holderCount = token.holderCount.plus(BigInt.fromI32(1)); + token.save(); + } + return balance; +} + +export function handleTransfer(event: TransferEvent): void { + let token = Token.load(event.address.toHex()); + if (!token) return; + + let fromAccount = getOrCreateAccount(event.params.from); + let toAccount = getOrCreateAccount(event.params.to); + + // Update balances + if (event.params.from.toHex() != "0x0000000000000000000000000000000000000000") { + let fromBalance = getOrCreateTokenBalance(token, fromAccount); + fromBalance.balance = fromBalance.balance.minus(event.params.value); + fromBalance.save(); + } + + let toBalance = getOrCreateTokenBalance(token, toAccount); + toBalance.balance = toBalance.balance.plus(event.params.value); + toBalance.save(); + + // Create transfer record + let transfer = new Transfer( + event.transaction.hash.toHex() + "-" + event.logIndex.toString() + ); + transfer.token = token.id; + transfer.from = fromAccount.id; + transfer.to = toAccount.id; + transfer.value = event.params.value; + transfer.timestamp = event.block.timestamp; + transfer.blockNumber = event.block.number; + transfer.transactionHash = event.transaction.hash; + transfer.save(); + + // Update token stats + token.transferCount = token.transferCount.plus(BigInt.fromI32(1)); + token.save(); +} +``` + +### Local Testing + +**Generate Code:** + +```bash +graph codegen +``` + +This generates TypeScript types from your schema and ABI. + +**Build Subgraph:** + +```bash +graph build +``` + +Compiles mappings to WebAssembly and validates the manifest. + +**Local Graph Node (Docker):** + +```yaml +version: "3" +services: + graph-node: + image: graphprotocol/graph-node + ports: + - "8000:8000" + - "8001:8001" + - "8020:8020" + - "8030:8030" + - "8040:8040" + environment: + postgres_host: postgres + postgres_user: graph-node + postgres_pass: let-me-in + postgres_db: graph-node + ipfs: "ipfs:5001" + ethereum: "xdc:https://rpc.xinfin.network" + RUST_LOG: info + + ipfs: + image: ipfs/kubo:latest + ports: + - "5001:5001" + + postgres: + image: postgres:latest + environment: + POSTGRES_USER: graph-node + POSTGRES_PASSWORD: let-me-in + POSTGRES_DB: graph-node +``` + +**Deploy Locally:** + +```bash +graph create xdc-token-indexer --node http://localhost:8020 +graph deploy xdc-token-indexer \ + --ipfs http://localhost:5001 \ + --node http://localhost:8020 +``` + +--- + diff --git a/website/docs/xdcchain/developers/subgraphs/examples.md b/website/docs/xdcchain/developers/subgraphs/examples.md new file mode 100644 index 00000000..efe7b70c --- /dev/null +++ b/website/docs/xdcchain/developers/subgraphs/examples.md @@ -0,0 +1,96 @@ +--- +title: "Good: Minimal fields" +--- + +## Performance Optimization + +### Indexing Optimization + +**Selective Indexing:** + +Set `startBlock` to the contract deployment block to avoid processing unnecessary history: + +```yaml +source: + startBlock: 61580000 # Contract deployment block +``` + +**Event Filtering:** + +Index only relevant events. Avoid indexing common events like `Approval` if not needed. + +**Batch Processing:** + +Process multiple entities in a single handler when possible: + +```typescript +export function handleBatchTransfer(event: BatchTransferEvent): void { + let recipients = event.params.recipients; + let amounts = event.params.amounts; + + for (let i = 0; i < recipients.length; i++) { + // Process each transfer in batch + createTransfer(recipients[i], amounts[i]); + } +} +``` + +### Query Optimization + +**Field Selection:** + +Request only needed fields to reduce response size: + +```graphql +# Good: Minimal fields +query { + transfers(first: 10) { + id + value + } +} + +# Avoid: Unnecessary nested data +query { + transfers(first: 10) { + id + from { id balances { id token { id symbol name decimals } } } + to { id balances { id token { id symbol name decimals } } } + } +} +``` + +**Query Complexity:** + +The Graph limits query complexity. Deep nesting and large `first` values may be rejected. + +### Caching Strategies + +**Client-Side Caching:** + +```javascript +import { ApolloClient, InMemoryCache } from '@apollo/client'; + +const client = new ApolloClient({ + uri: 'https://api.thegraph.com/subgraphs/name/username/xdc-indexer', + cache: new InMemoryCache() +}); +``` + +**CDN Caching:** + +Configure cache headers for repeated queries: + +```javascript +fetch(subgraphUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Cache-Control': 'max-age=60' + }, + body: JSON.stringify({ query }) +}); +``` + +--- + diff --git a/website/docs/xdcchain/developers/subgraphs/index.md b/website/docs/xdcchain/developers/subgraphs/index.md new file mode 100644 index 00000000..45278b1d --- /dev/null +++ b/website/docs/xdcchain/developers/subgraphs/index.md @@ -0,0 +1,1183 @@ +--- +title: The Graph Subgraph Development Guide for XDC +--- + +# The Graph Subgraph Development Guide for XDC + +Subgraphs are open APIs that extract, process, and index blockchain data, making it queryable via GraphQL. For XDC developers, subgraphs eliminate the need for complex direct RPC indexing, enabling efficient data retrieval for decentralized applications at scale. + +--- + +## Overview + +### What Is a Subgraph + +A subgraph is a custom indexing specification that defines which blockchain events to listen to, how to transform that data, and what GraphQL schema to expose for querying. It acts as a middleware layer between the blockchain and your application, providing structured, indexed data with powerful query capabilities. + +**Key Benefits:** + +- **Indexed Data:** Query blockchain data in milliseconds instead of scanning blocks +- **GraphQL Interface:** Flexible, typed queries with exactly the data you need +- **Real-Time Updates:** Automatic indexing of new blocks and events +- **Cost Efficiency:** Reduce RPC call volume and infrastructure costs +- **Reliability:** Hosted indexing with redundancy and uptime guarantees +- **Composability:** Multiple subgraphs can be combined for complex dApp requirements + +### How Subgraphs Work + +The subgraph indexing pipeline follows this architecture: + +``` +Blockchain Events → Graph Node → Mapping Functions → Store → GraphQL API +``` + +**Indexing Pipeline:** + +1. **Event Detection:** Graph Node monitors XDC blocks for configured events +2. **Data Extraction:** Matching events trigger mapping functions (AssemblyScript) +3. **Transformation:** Mappings process raw event data into entities +4. **Storage:** Transformed entities are stored in a PostgreSQL database +5. **Query Serving:** GraphQL API exposes indexed data with filtering and pagination + +### XDC Network Compatibility + +The Graph supports XDC Mainnet and Apothem Testnet through the hosted service and Subgraph Studio. XDC's EVM compatibility means Ethereum subgraphs require minimal or no modifications to work on XDC. + +**Network Identifiers:** + +| Network | Chain ID | Subgraph Network Name | +|---------|----------|----------------------| +| XDC Mainnet | 50 | `xdc` | +| Apothem Testnet | 51 | `apothem` | + +--- + +## Prerequisites + +### Development Environment + +Before building subgraphs, ensure you have the following tools installed: + +**Required:** + +- **Node.js:** Version 18 or higher +- **npm or yarn:** Package manager for Graph CLI +- **Git:** Version control for subgraph deployment + +**Recommended:** + +- **Docker:** For local Graph Node testing +- **PostgreSQL:** Local database for self-hosted indexing +- **IPFS Node:** For local subgraph deployment + +### Installing Graph CLI + +The Graph CLI is the primary tool for creating, building, and deploying subgraphs. + +**Global Installation:** + +```bash +npm install -g @graphprotocol/graph-cli +``` + +**Verify Installation:** + +```bash +graph --version +# Expected output: @graphprotocol/graph-cli 0.60.x or higher +``` + +**Project-Level Installation (Recommended):** + +```bash +npm install --save-dev @graphprotocol/graph-cli +``` + +This ensures consistent CLI versions across team members and CI/CD pipelines. + +### XDC Network Access + +For indexing XDC, you need reliable RPC access: + +**Public RPC Endpoints:** + +| Network | HTTP RPC | WebSocket RPC | +|---------|----------|---------------| +| Mainnet | https://rpc.xinfin.network | wss://rpc.xinfin.network | +| Testnet | https://rpc.apothem.network | wss://rpc.apothem.network | + +**Recommended:** Use dedicated RPC providers (Ankr, QuickNode, or self-hosted) for production subgraphs to ensure reliability and avoid rate limits. + +--- + +## Subgraph Concepts + +### GraphQL Schema Design + +The schema defines the data structure that your subgraph will expose. It uses GraphQL schema definition language (SDL) with The Graph-specific directives. + +**Entity Definition:** + +```graphql +type Transfer @entity { + id: ID! + from: Bytes! + to: Bytes! + value: BigInt! + timestamp: BigInt! + blockNumber: BigInt! + transactionHash: Bytes! +} +``` + +**Schema Directives:** + +| Directive | Purpose | +|-----------|---------| +| `@entity` | Marks a type as indexable entity | +| `@id` | Primary key field (mandatory for entities) | +| `@derivedFrom` | Defines reverse lookup relationships | + +**Relationship Patterns:** + +```graphql +type Token @entity { + id: ID! + symbol: String! + name: String! + decimals: Int! + totalSupply: BigInt! + transfers: [Transfer!]! @derivedFrom(field: "token") + holders: [Holder!]! @derivedFrom(field: "token") +} + +type Holder @entity { + id: ID! + address: Bytes! + token: Token! + balance: BigInt! +} +``` + +**Data Types:** + +| Type | Description | Example | +|------|-------------|---------| +| `ID` | Unique identifier string | `"0x123..."` | +| `String` | UTF-8 string | `"XDC Token"` | +| `Int` | 32-bit signed integer | `42` | +| `BigInt` | Arbitrary precision integer | `10^18` | +| `Float` | 64-bit floating point | `3.14` | +| `Boolean` | True/false | `true` | +| `Bytes` | Byte array (hex) | `0xabcd...` | +| `BigDecimal` | High precision decimal | `1.0000000001` | + +### Subgraph Manifest + +The `subgraph.yaml` manifest defines the subgraph configuration, including data sources, entities, and mapping handlers. + +**Manifest Structure:** + +```yaml +specVersion: 0.0.4 +schema: + file: ./schema.graphql +dataSources: + - kind: ethereum + name: XRC20Token + network: xdc + source: + address: "0x1234..." + abi: XRC20 + startBlock: 12345678 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Transfer + - Approval + abis: + - name: XRC20 + file: ./abis/XRC20.json + eventHandlers: + - event: Transfer(indexed address,indexed address,uint256) + handler: handleTransfer + - event: Approval(indexed address,indexed address,uint256) + handler: handleApproval + file: ./src/mapping.ts +``` + +**Configuration Fields:** + +| Field | Description | +|-------|-------------| +| `specVersion` | Subgraph specification version | +| `schema.file` | Path to GraphQL schema | +| `dataSources` | Array of blockchain data sources | +| `source.address` | Contract address to monitor | +| `source.abi` | ABI reference name | +| `source.startBlock` | Block to start indexing from | +| `mapping.language` | Only `wasm/assemblyscript` supported | +| `eventHandlers` | Event-to-handler mappings | + +### AssemblyScript Mappings + +Mappings are TypeScript-like functions that transform blockchain events into entities. They run in a WebAssembly sandbox with blockchain-specific APIs. + +**Basic Mapping Structure:** + +```typescript +import { + Transfer as TransferEvent, + Approval as ApprovalEvent +} from "../generated/XRC20Token/XRC20"; +import { Transfer, Approval } from "../generated/schema"; + +export function handleTransfer(event: TransferEvent): void { + let transfer = new Transfer( + event.transaction.hash.toHex() + "-" + event.logIndex.toString() + ); + transfer.from = event.params.from; + transfer.to = event.params.to; + transfer.value = event.params.value; + transfer.timestamp = event.block.timestamp; + transfer.blockNumber = event.block.number; + transfer.transactionHash = event.transaction.hash; + transfer.save(); +} +``` + +**Available APIs:** + +| API | Purpose | +|-----|---------| +| `ethereum.Event` | Event parameters and metadata | +| `ethereum.Block` | Block header information | +| `ethereum.Transaction` | Transaction details | +| `store.get/load` | Entity retrieval | +| `store.set/save` | Entity persistence | +| `log.info/debug/error` | Logging for debugging | +| `ipfs.cat/map` | IPFS data access | +| `crypto.keccak256` | Cryptographic hashing | + +### Indexing Mechanics + +**Block Processing:** + +1. Graph Node receives new block from XDC network +2. Scans block for events matching manifest filters +3. Executes corresponding mapping handlers +4. Stores resulting entities in database +5. Updates indexing progress marker + +**Reorganization Handling:** + +If the XDC chain reorganizes, the Graph Node automatically: + +1. Detects the reorganization depth +2. Rolls back affected entities +3. Reprocesses blocks from the common ancestor +4. Ensures data consistency + +**Indexing Status:** + +Monitor indexing progress via the Graph CLI or Subgraph Studio dashboard. Full indexing time depends on: + +- Number of events to process +- Complexity of mapping logic +- Network block time +- Graph Node resources + +--- + +## Development Workflow + +### Project Initialization + +**Create New Subgraph:** + +```bash +graph init --product subgraph-studio xdc-token-indexer +``` + +**From Contract Example:** + +```bash +graph init \ + --product subgraph-studio \ + --from-contract 0xContractAddress \ + --network xdc \ + --abi ./path/to/abi.json \ + xdc-token-indexer +``` + +**Project Structure:** + +``` +xdc-token-indexer/ +├── abis/ +│ └── XRC20.json # Contract ABI +├── src/ +│ └── mapping.ts # Mapping logic +├── tests/ +│ └── .gitkeep # Unit tests (optional) +├── schema.graphql # GraphQL schema +├── subgraph.yaml # Subgraph manifest +├── package.json # Dependencies +└── tsconfig.json # TypeScript config +``` + +### Schema Definition + +Define your data model in `schema.graphql`: + +```graphql +type Token @entity { + id: ID! + symbol: String! + name: String! + decimals: Int! + totalSupply: BigInt! + transferCount: BigInt! + holderCount: BigInt! +} + +type Account @entity { + id: ID! + balances: [TokenBalance!]! @derivedFrom(field: "account") + sentTransfers: [Transfer!]! @derivedFrom(field: "from") + receivedTransfers: [Transfer!]! @derivedFrom(field: "to") +} + +type TokenBalance @entity { + id: ID! + token: Token! + account: Account! + balance: BigInt! +} + +type Transfer @entity { + id: ID! + token: Token! + from: Account! + to: Account! + value: BigInt! + timestamp: BigInt! + blockNumber: BigInt! + transactionHash: Bytes! +} +``` + +### ABI Preparation + +Obtain the contract ABI from: + +- Compiler output (Hardhat, Foundry, Remix) +- Verified contract on XDCScan +- Etherscan equivalent for EVM-compatible contracts + +**ABI Format:** + +```json +[ + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "from", "type": "address" }, + { "indexed": true, "name": "to", "type": "address" }, + { "indexed": false, "name": "value", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + } +] +``` + +### Mapping Implementation + +Implement transformation logic in `src/mapping.ts`: + +```typescript +import { + Transfer as TransferEvent, + XRC20 +} from "../generated/XRC20Token/XRC20"; +import { + Token, + Account, + TokenBalance, + Transfer +} from "../generated/schema"; +import { Address, BigInt } from "@graphprotocol/graph-ts"; + +function getOrCreateAccount(address: Address): Account { + let account = Account.load(address.toHex()); + if (!account) { + account = new Account(address.toHex()); + account.save(); + } + return account; +} + +function getOrCreateTokenBalance( + token: Token, + account: Account +): TokenBalance { + let id = token.id + "-" + account.id; + let balance = TokenBalance.load(id); + if (!balance) { + balance = new TokenBalance(id); + balance.token = token.id; + balance.account = account.id; + balance.balance = BigInt.zero(); + token.holderCount = token.holderCount.plus(BigInt.fromI32(1)); + token.save(); + } + return balance; +} + +export function handleTransfer(event: TransferEvent): void { + let token = Token.load(event.address.toHex()); + if (!token) return; + + let fromAccount = getOrCreateAccount(event.params.from); + let toAccount = getOrCreateAccount(event.params.to); + + // Update balances + if (event.params.from.toHex() != "0x0000000000000000000000000000000000000000") { + let fromBalance = getOrCreateTokenBalance(token, fromAccount); + fromBalance.balance = fromBalance.balance.minus(event.params.value); + fromBalance.save(); + } + + let toBalance = getOrCreateTokenBalance(token, toAccount); + toBalance.balance = toBalance.balance.plus(event.params.value); + toBalance.save(); + + // Create transfer record + let transfer = new Transfer( + event.transaction.hash.toHex() + "-" + event.logIndex.toString() + ); + transfer.token = token.id; + transfer.from = fromAccount.id; + transfer.to = toAccount.id; + transfer.value = event.params.value; + transfer.timestamp = event.block.timestamp; + transfer.blockNumber = event.block.number; + transfer.transactionHash = event.transaction.hash; + transfer.save(); + + // Update token stats + token.transferCount = token.transferCount.plus(BigInt.fromI32(1)); + token.save(); +} +``` + +### Local Testing + +**Generate Code:** + +```bash +graph codegen +``` + +This generates TypeScript types from your schema and ABI. + +**Build Subgraph:** + +```bash +graph build +``` + +Compiles mappings to WebAssembly and validates the manifest. + +**Local Graph Node (Docker):** + +```yaml +version: "3" +services: + graph-node: + image: graphprotocol/graph-node + ports: + - "8000:8000" + - "8001:8001" + - "8020:8020" + - "8030:8030" + - "8040:8040" + environment: + postgres_host: postgres + postgres_user: graph-node + postgres_pass: let-me-in + postgres_db: graph-node + ipfs: "ipfs:5001" + ethereum: "xdc:https://rpc.xinfin.network" + RUST_LOG: info + + ipfs: + image: ipfs/kubo:latest + ports: + - "5001:5001" + + postgres: + image: postgres:latest + environment: + POSTGRES_USER: graph-node + POSTGRES_PASSWORD: let-me-in + POSTGRES_DB: graph-node +``` + +**Deploy Locally:** + +```bash +graph create xdc-token-indexer --node http://localhost:8020 +graph deploy xdc-token-indexer \ + --ipfs http://localhost:5001 \ + --node http://localhost:8020 +``` + +--- + +## Deployment + +### Subgraph Studio + +Subgraph Studio is the recommended platform for creating, testing, and publishing subgraphs to The Graph Network. + +**Setup:** + +1. Visit https://thegraph.com/studio/ +2. Connect your wallet (MetaMask or WalletConnect) +3. Create a new subgraph +4. Note your deployment key + +**Authenticate CLI:** + +```bash +graph auth --studio YOUR_DEPLOY_KEY +``` + +**Deploy:** + +```bash +graph deploy --studio xdc-token-indexer +``` + +**Version Management:** + +- Each deployment creates a new version +- Versions are identified by IPFS hash +- Query URL remains stable across versions +- Previous versions remain accessible + +### Hosted Service + +The hosted service provides free subgraph indexing with API access. + +**Create Subgraph:** + +1. Visit https://thegraph.com/hosted-service/ +2. Sign in with GitHub +3. Click "Add Subgraph" +4. Enter name and description + +**Authenticate:** + +```bash +graph auth --product hosted-service YOUR_ACCESS_TOKEN +``` + +**Deploy:** + +```bash +graph deploy --product hosted-service YOUR_GITHUB_USERNAME/xdc-token-indexer +``` + +**XDC Network Configuration:** + +Ensure your `subgraph.yaml` specifies: + +```yaml +network: xdc +``` + +For testnet deployment: + +```yaml +network: apothem +``` + +### Decentralized Network + +Publishing to The Graph Network requires GRT tokens and follows a curation model. + +**Requirements:** + +- GRT tokens for curation signaling +- Subgraph published to Subgraph Studio +- Indexers available for XDC network + +**Publish:** + +```bash +graph publish --studio xdc-token-indexer +``` + +**Signal Curation:** + +- Deposit GRT to signal quality to indexers +- Higher curation attracts more indexers +- Earn query fee rewards from usage + +### XDC-Specific Configuration + +**Network Names:** + +| Environment | Network Value | +|-------------|--------------| +| Mainnet | `xdc` | +| Testnet | `apothem` | + +**RPC Configuration:** + +For self-hosted Graph Nodes, configure XDC RPC: + +```bash +ethereum="xdc:https://rpc.xinfin.network" +``` + +For WebSocket support: + +```bash +ethereum="xdc:wss://rpc.xinfin.network" +``` + +**Block Time Considerations:** + +XDC's 2-second block time requires Graph Node tuning: + +- Reduce `ETHEREUM_POLLING_INTERVAL` for faster detection +- Increase `GRAPH_ETHEREUM_TARGET_TRIGGERS_PER_BLOCK` for throughput +- Monitor `eth_getLogs` batch sizes for RPC provider limits + +--- + +## Querying Subgraphs + +### GraphQL Queries + +Subgraphs expose a GraphQL endpoint for flexible data retrieval. + +**Query Structure:** + +```graphql +query GetTransfers($first: Int!, $skip: Int!) { + transfers( + first: $first + skip: $skip + orderBy: timestamp + orderDirection: desc + ) { + id + from { + id + } + to { + id + } + value + timestamp + transactionHash + } +} +``` + +**Variables:** + +```json +{ + "first": 10, + "skip": 0 +} +``` + +### Pagination + +Use `first` and `skip` for offset-based pagination: + +```graphql +query PaginatedTransfers($first: Int!, $skip: Int!) { + transfers(first: $first, skip: $skip) { + id + value + } +} +``` + +**Best Practice:** Limit `first` to 1000 maximum. For large datasets, use cursor-based pagination with `id` filtering: + +```graphql +query CursorPagination($lastId: ID!) { + transfers( + first: 1000 + where: { id_gt: $lastId } + orderBy: id + orderDirection: asc + ) { + id + value + } +} +``` + +### Filtering + +Apply `where` clauses for precise data selection: + +```graphql +query FilteredTransfers { + transfers( + where: { + value_gt: "1000000000000000000" + timestamp_gt: "1700000000" + } + ) { + id + from { + id + } + to { + id + } + value + } +} +``` + +**Available Operators:** + +| Operator | Description | +|----------|-------------| +| `_eq` | Equal | +| `_gt` | Greater than | +| `_lt` | Less than | +| `_gte` | Greater than or equal | +| `_lte` | Less than or equal | +| `_in` | In array | +| `_not_in` | Not in array | +| `_contains` | Contains substring | +| `_starts_with` | Starts with | +| `_ends_with` | Ends with | + +### Sorting + +Order results with `orderBy` and `orderDirection`: + +```graphql +query SortedTransfers { + transfers( + orderBy: timestamp + orderDirection: desc + first: 50 + ) { + id + timestamp + value + } +} +``` + +### Time-Travel Queries + +Query historical state at a specific block: + +```graphql +query HistoricalState { + token(id: "0x...", block: { number: 50000000 }) { + totalSupply + holderCount + } +} +``` + +### Real-Time Subscriptions + +WebSocket subscriptions for live data updates: + +```javascript +import { createClient } from 'graphql-ws'; + +const client = createClient({ + url: 'wss://api.thegraph.com/subgraphs/name/username/xdc-token-indexer' +}); + +const subscription = client.subscribe( + { + query: ` + subscription OnNewTransfer { + transfers(orderBy: timestamp, orderDirection: desc, first: 1) { + id + from { id } + to { id } + value + } + } + ` + }, + { + next: (data) => console.log('New transfer:', data), + error: (err) => console.error(err), + complete: () => console.log('Done') + } +); +``` + +--- + +## Performance Optimization + +### Indexing Optimization + +**Selective Indexing:** + +Set `startBlock` to the contract deployment block to avoid processing unnecessary history: + +```yaml +source: + startBlock: 61580000 # Contract deployment block +``` + +**Event Filtering:** + +Index only relevant events. Avoid indexing common events like `Approval` if not needed. + +**Batch Processing:** + +Process multiple entities in a single handler when possible: + +```typescript +export function handleBatchTransfer(event: BatchTransferEvent): void { + let recipients = event.params.recipients; + let amounts = event.params.amounts; + + for (let i = 0; i < recipients.length; i++) { + // Process each transfer in batch + createTransfer(recipients[i], amounts[i]); + } +} +``` + +### Query Optimization + +**Field Selection:** + +Request only needed fields to reduce response size: + +```graphql +# Good: Minimal fields +query { + transfers(first: 10) { + id + value + } +} + +# Avoid: Unnecessary nested data +query { + transfers(first: 10) { + id + from { id balances { id token { id symbol name decimals } } } + to { id balances { id token { id symbol name decimals } } } + } +} +``` + +**Query Complexity:** + +The Graph limits query complexity. Deep nesting and large `first` values may be rejected. + +### Caching Strategies + +**Client-Side Caching:** + +```javascript +import { ApolloClient, InMemoryCache } from '@apollo/client'; + +const client = new ApolloClient({ + uri: 'https://api.thegraph.com/subgraphs/name/username/xdc-indexer', + cache: new InMemoryCache() +}); +``` + +**CDN Caching:** + +Configure cache headers for repeated queries: + +```javascript +fetch(subgraphUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Cache-Control': 'max-age=60' + }, + body: JSON.stringify({ query }) +}); +``` + +--- + +## Example Subgraphs + +### XRC20 Token Tracker + +A complete subgraph for indexing any XRC20 token with holder balances and transfer history. + +**Schema:** + +```graphql +type Token @entity { + id: ID! + symbol: String! + name: String! + decimals: Int! + totalSupply: BigInt! + transferCount: BigInt! + holderCount: BigInt! +} + +type Account @entity { + id: ID! + balances: [TokenBalance!]! @derivedFrom(field: "account") +} + +type TokenBalance @entity { + id: ID! + token: Token! + account: Account! + balance: BigInt! +} + +type Transfer @entity { + id: ID! + token: Token! + from: Account! + to: Account! + value: BigInt! + timestamp: BigInt! + blockNumber: BigInt! +} +``` + +**Mapping:** + +```typescript +import { Transfer } from "../generated/XRC20/XRC20"; +import { Token, Account, TokenBalance, Transfer as TransferEntity } from "../generated/schema"; + +export function handleTransfer(event: Transfer): void { + // Implementation as shown in previous sections +} +``` + +### NFT Marketplace Indexer + +Index NFT mints, transfers, sales, and marketplace listings. + +**Key Entities:** + +- `Collection`: NFT contract metadata +- `Token`: Individual NFT with metadata +- `Transfer`: Ownership changes +- `Sale`: Marketplace transactions with price +- `Listing`: Active marketplace listings + +### DeFi Protocol Tracker + +Index liquidity pools, swaps, deposits, and yield farming positions. + +**Key Entities:** + +- `Pool`: Liquidity pool with reserves +- `Swap`: Token exchange transactions +- `LiquidityPosition`: User LP token balances +- `YieldPosition`: Staking and farming positions + +--- + +## Testing Procedures + +### Unit Testing + +The Graph provides a Matchstick testing framework for AssemblyScript mappings. + +**Installation:** + +```bash +npm install --save-dev matchstick-as +``` + +**Test Example:** + +```typescript +import { assert, test, describe } from "matchstick-as"; +import { handleTransfer } from "../src/mapping"; +import { createTransferEvent } from "./utils"; + +describe("Transfer Handler", () => { + test("Should create transfer entity", () => { + let event = createTransferEvent( + "0x123...", + "0x456...", + "1000000000000000000" + ); + + handleTransfer(event); + + assert.fieldEquals( + "Transfer", + event.transaction.hash.toHex() + "-0", + "value", + "1000000000000000000" + ); + }); +}); +``` + +**Run Tests:** + +```bash +graph test +``` + +### Integration Testing + +**Local Deployment Testing:** + +1. Deploy to local Graph Node +2. Query indexed data via GraphQL playground +3. Verify entity counts and relationships +4. Test edge cases (zero transfers, self-transfers) + +**Staging Deployment:** + +1. Deploy to Subgraph Studio +2. Monitor indexing progress +3. Run query validation suite +4. Compare results with direct RPC calls + +--- + +## Troubleshooting + +### Common Issues + +**Indexing Failures:** + +| Symptom | Cause | Solution | +|---------|-------|----------| +| "Failed to run hosted service" | Invalid manifest | Validate YAML syntax | +| "ABI mismatch" | Wrong ABI version | Regenerate ABI from deployment | +| "Entity not found" | Missing `save()` call | Ensure all entities are saved | +| "Null pointer" | Uninitialized entity | Check for null before accessing | +| "Out of gas" | Infinite loop in mapping | Add iteration limits | + +**Slow Indexing:** + +- Reduce `startBlock` to contract deployment +- Remove unnecessary event handlers +- Optimize mapping logic complexity +- Upgrade to paid Graph Node resources + +**Query Timeouts:** + +- Reduce `first` parameter +- Simplify nested queries +- Add filtering to limit result sets +- Implement client-side pagination + +### Debugging Mappings + +**Logging:** + +```typescript +import { log } from "@graphprotocol/graph-ts"; + +log.info("Processing transfer from {} to {}", [ + event.params.from.toHex(), + event.params.to.toHex() +]); + +log.debug("Transfer value: {}", [event.params.value.toString()]); +``` + +View logs in Subgraph Studio or Graph Node console. + +**Local Debugging:** + +Use `console.log` equivalent and run tests with Matchstick for rapid iteration. + +### Migration from Direct RPC + +**Comparison:** + +| Approach | Latency | Cost | Complexity | Real-Time | +|----------|---------|------|------------|-----------| +| Direct RPC | High | High | Low | Yes | +| Subgraph | Low | Low | Medium | Yes | +| Database | Low | Medium | High | No | + +**Migration Steps:** + +1. Identify all RPC queries in your application +2. Design subgraph schema to serve equivalent data +3. Implement mappings for required events +4. Deploy and index historical data +5. Replace RPC calls with GraphQL queries +6. Implement fallback to RPC for unindexed data + +--- + +## Best Practices + +### Schema Design + +1. **Normalize Entities:** Separate concerns into distinct entities with relationships +2. **Use IDs Strategically:** Composite IDs prevent collisions (e.g., `token-address`) +3. **Index Frequently Queried Fields:** Add `@index` directive for performance +4. **Avoid Deep Nesting:** Limit entity relationships to 2-3 levels +5. **Document Fields:** Add comments explaining non-obvious fields + +### Mapping Development + +1. **Handle Edge Cases:** Zero values, self-transfers, reverted transactions +2. **Validate Inputs:** Check addresses and values before processing +3. **Minimize Storage:** Only store data your application needs +4. **Use Constants:** Define magic numbers as named constants +5. **Test Thoroughly:** Unit tests for all event handlers + +### Deployment + +1. **Version Control:** Tag subgraph versions for reproducibility +2. **Monitor Indexing:** Track sync status and error rates +3. **Backup Manifests:** Store subgraph.yaml in version control +4. **Document Changes:** Maintain changelog for schema updates +5. **Plan Migrations:** Schema changes require new deployments + +### Querying + +1. **Paginate Results:** Never request unbounded lists +2. **Cache Responses:** Implement client-side caching for static data +3. **Batch Requests:** Combine multiple queries when possible +4. **Handle Errors:** Implement retry logic for failed queries +5. **Optimize Complexity:** Simplify queries to reduce load + +--- + +## Related Topics + +- [Smart Contract Development](/smartcontract): Building contracts to emit indexed events +- [XDC3.js SDK](../sdks/xdc3js.md): JavaScript SDK for contract interaction +- [API Reference](/api): Direct RPC API documentation +- [Block Explorer Guide](../explorers/index.md): Verifying indexed data on explorers +- [Token Standards](/smartcontract/tokens): XRC20, XRC721, and XRC1155 specifications +- [Developer Quick Start](/xdcchain/developers/quick-guide): Getting started with XDC development