# Monad

## Introduction

{% hint style="info" %}
Currently, the Monad RPC only supports the `eth_sendRawTransaction` method
{% endhint %}

This API is used to send signed raw transactions on Monad mainnet, supporting HTTP/HTTPS protocol.

## Endpoint

{% tabs %}
{% tab title="HTTP" %}

<table><thead><tr><th width="122.00390625">Region</th><th>Endpoint</th></tr></thead><tbody><tr><td>Frankfurt</td><td>http://frankfurt-monad.blockrazor.io</td></tr><tr><td>Virginia</td><td>http://virginia-monad.blockrazor.io</td></tr><tr><td>Tokyo</td><td>http://tokyo-monad.blockrazor.io</td></tr></tbody></table>
{% endtab %}

{% tab title="HTTPS" %}

<table><thead><tr><th width="113.75">Region</th><th>Endpoint</th></tr></thead><tbody><tr><td>Frankfurt</td><td>https://frankfurt-monad.blockrazor.io</td></tr><tr><td>Virginia</td><td>https://virginia-monad.blockrazor.io</td></tr><tr><td>Tokyo</td><td>https://tokyo-monad.blockrazor.io</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

## Rate Limit

{% hint style="warning" %}
Monad's transaction sending service is not bound to the subscription plan. If you need to use the service, please [contact](https://discord.com/invite/qqJuwRb8Nh) us and we will handle it as soon as possible.
{% endhint %}

## Request Example

{% tabs %}
{% tab title="CURL" %}
{% code overflow="wrap" %}

```shellscript
curl -X POST http://frankfurt-monad.blockrazor.io \
  -H "Authorization: <auth-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_sendRawTransaction",
    "params": [
      "0xd46e……e8b2c1"
    ]
  }'
  
  ## To maintain a persistent TCP connection, implementing a keep-alive mechanism is recommended
```

{% endcode %}
{% endtab %}

{% tab title="Go" %}

```go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
)

type JsonRpcRequest struct {
	JsonRpc string        `json:"jsonrpc"`
	ID      int           `json:"id"`
	Method  string        `json:"method"`
	Params  []interface{} `json:"params"`
}

func main() {
	// Define request parameters and configuration
	url := "http://frankfurt-monad.blockrazor.io"
	authToken := "<auth-token>"        // Replace with your actual authorization token
	rawTransaction := "0xd46e……e8b2c1" // Replace with your actual raw transaction data

	// Construct the JSON-RPC request body
	requestBody := JsonRpcRequest{
		JsonRpc: "2.0",
		ID:      1,
		Method:  "eth_sendRawTransaction",
		Params:  []interface{}{rawTransaction},
	}

	// Marshal the struct into JSON format
	jsonBody, err := json.Marshal(requestBody)
	if err != nil {
		log.Fatalf("Error marshaling JSON: %v", err)
	}

	// Create HTTP client (Keep-Alive is supported by default)
	client := &http.Client{}

	// Create a new POST request
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
	if err != nil {
		log.Fatalf("Error creating request: %v", err)
	}

	// Set request Headers
	req.Header.Set("Authorization", authToken)
	req.Header.Set("Content-Type", "application/json")
	// Go's http.Client uses Keep-Alive by default when the connection can be reused.
	// Explicitly setting 'Connection: keep-alive' is optional,
	// but can be kept if the server has strict requirements for connection behavior.
	// The default Go behavior is usually sufficient in this case.
	// req.Header.Set("Connection", "keep-alive")

	// Send the request
	resp, err := client.Do(req)
	if err != nil {
		log.Fatalf("Error sending request: %v", err)
	}
	defer resp.Body.Close()

	// Process the response
	bodyBytes, _ := io.ReadAll(resp.Body)
	fmt.Printf("Status Code: %d\n", resp.StatusCode)
	fmt.Printf("Response Body: %s\n", bodyBytes)
	fmt.Printf("Connection Header: %s\n", resp.Header.Get("Connection"))
	fmt.Printf("Keep-Alive successful (requires server support).\n")

	// Second request
	// The client will attempt to use the same underlying TCP connection
	// established by the first request, thus implementing Keep-Alive.
	fmt.Println("\n--- Sending Request 2 (Connection Reuse Test) ---")

	// Reset the request body to prepare for resending
	req2, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
	if err != nil {
		log.Fatalf("Error creating request 2: %v", err)
	}

	// Copy the same Headers
	req2.Header.Set("Authorization", authToken)
	req2.Header.Set("Content-Type", "application/json")

	// ⚠️ Crucial: Continue using the existing client, do not create a new one.
	resp2, err := client.Do(req2)
	if err != nil {
		log.Fatalf("Error sending request 2: %v", err)
	}
	defer resp2.Body.Close()

	bodyBytes2, _ := io.ReadAll(resp2.Body)
	fmt.Printf("Status Code 2: %d\n", resp2.StatusCode)
	fmt.Printf("Response Body 2: %s\n", bodyBytes2)
	fmt.Printf("Connection Header 2: %s\n", resp2.Header.Get("Connection"))
}
```

{% endtab %}

{% tab title="JS" %}

```javascript
// Import Node.js built-in modules
const http = require('http');

// --- Configuration ---
const url = "http://frankfurt-monad.blockrazor.io";
const authToken = "<auth-token>";         // Replace with your actual authorization token
const rawTransaction = "0xd46e……e8b2c1"; // Replace with your actual raw transaction data

// Define the JSON-RPC request body
const requestBody = {
    jsonrpc: "2.0",
    id: 1,
    method: "eth_sendRawTransaction",
    params: [rawTransaction]
};

// Stringify the request body into a JSON string
const jsonBody = JSON.stringify(requestBody);

// Create an HTTP Agent to control the connection pool, Keep-Alive is enabled by default
// Similar to the default http.Client in Go
const keepAliveAgent = new http.Agent({
    keepAlive: true,
    maxSockets: 5, // Max number of sockets can be adjusted as needed
});

async function sendJsonRpcRequest(requestUrl, body, token, agent, requestNumber) {
    console.log(`\n--- Sending Request ${requestNumber} ---`);
    try {
        const response = await fetch(requestUrl, {
            method: 'POST',
            // Note: fetch in Node.js requires explicit specification of the agent for connection reuse control
            agent: agent,
            headers: {
                'Authorization': token,
                'Content-Type': 'application/json',
                // 'Connection': 'keep-alive' is enabled by default, but can be explicitly added
            },
            body: body
        });

        // Check response status
        if (!response.ok) {
            console.error(`Request ${requestNumber} failed with status: ${response.status}`);
        }

        const responseText = await response.text();
        
        console.log(`Status Code ${requestNumber}: ${response.status}`);
        console.log(`Response Body ${requestNumber}: ${responseText}`);
        console.log(`Connection Header ${requestNumber}: ${response.headers.get('connection') || 'N/A'}`);
        // ⚠️ It's hard to directly confirm underlying TCP connection reuse in Node.js like in Go,
        // we rely on the Agent and server support.
        console.log(`Keep-Alive successful (requires server support and Agent configuration).`);

        return response;

    } catch (error) {
        console.error(`Error sending request ${requestNumber}:`, error.message);
        // Exit program or handle error
        process.exit(1); 
    }
}

// Main execution function
async function main() {
    // First request
    await sendJsonRpcRequest(url, jsonBody, authToken, keepAliveAgent, 1);

    // Second request
    // The client will attempt to use the same underlying TCP connection established by the first request,
    // thus implementing Keep-Alive.
    // ⚠️ Note: We reuse the keepAliveAgent object, not the request object itself.
    await sendJsonRpcRequest(url, jsonBody, authToken, keepAliveAgent, 2);

    // After completion, destroy the Agent to free up resources
    keepAliveAgent.destroy();
}

// Execute the main function
main();
```

{% endtab %}
{% endtabs %}

## Response

**Normal**

{% code overflow="wrap" %}

```go
{"jsonrpc":"2.0","id":0,"result":"0xfb2c5fc7d7b92e2b8ba43f079ce68b67c66e42633f6bf10ab762ace2b5ec47f6"}
```

{% endcode %}

**Abnormal**

{% code overflow="wrap" %}

```go
{"jsonrpc":"2.0","error":{"code":-32603,"message":"Transaction nonce too low"},"id":1}
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

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

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

```
GET https://docs.blockrazor.io/transaction-submission/rpc/monad.md?ask=<question>
```

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

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