Secure Your Web3 Project Finances with Endpoint Armor: Control Access and Set Rate Limits
In the early stages of the Web3 ecosystem, managing access control and rate limits for our endpoint was quite cumbersome. Nowadays, these issues have solutions that can save our project money and prevent looping problems. If you're in finance and don't understand why your Web3 teams exceed the allocated credits in your plan, this is an effective way to address the issue.
What You Will Need
An account on QuickNode
$5 USD in funds to test on the Polygon Mainnet Network.
An ERC20 contract generated using the Open Zepellin Wizard.
What We Will Do
Create an endpoint on QuickNode.
Activating the Endpoint Armor.
What is QuickNode?
QuickNode is your partner in the Web3 space, helping you search for NFTs across different blockchains and build token-gated communities. By using various nodes, you can make your Web3 setup simpler and better.
What is Endpoint Armor?
In simple terms, this plugin lets you customize your RPC usage. For example, you can limit operations to a specific smart contract or set rate limits to prevent abuse, making sure it fits your exact needs.
Understanding how Endpoint Armor works.
First, we need an active RPC on QuickNode.
After that, go to the "Add-ons" tab and search for the "Endpoint Armor" add-on.
Now, activate the plugin by clicking on the "Explore" button.
As a result, you will see details about "Endpoint Armor" ,please click on "Install for Free".
Then, wait a few minutes for endpoint armor to be installed. Refresh the "Add-ons" tab to see the update.
You should now see the "Dashboard" option. Click on it.
After that, you will see the next page. Please click on the dropdown menu labeled "Select an endpoint".
Then, search for your endpoint and click on "Enable Endpoint Armor".
After that, select the endpoint again, and Endpoint Armor will be activated.
Now you can see the configuration options where you can restrict your endpoint and save money!
According to the documentation:
"At least one method name must be specified in the configuration when setting up rate limits. This is because Endpoint Armor, by default, blocks all methods that are not explicitly mentioned in the settings. Therefore, to ensure that your endpoint allows access to the required methods, you must list each method you intend to use."
For example, we have two URLs:
QuickNode's public URLs offer general security, but Endpoint Armor provides more specific customization for your solution and budget.
To use this configuration, you need to copy the RPC URL from Endpoint Armor.
In my case, this is my URL:
dry-methodical-sea.secure.quiknode.pro
Configuring our secure RPC on MetaMask
To begin testing our endpoint, please configure an endpoint in your wallet provider. In my case, it’s MetaMask.
Next, paste your secured endpoint into the RPC URL field, click on "Save", and fill in the network details according to your needs.
Testing on Remix
Please create a new contract.
After that, paste the code from the Open Zepellin Wizard.
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.20;
import "@openzeppelin/contracts@5.0.2/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts@5.0.2/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts@5.0.2/token/ERC20/extensions/ERC20Pausable.sol";
import "@openzeppelin/contracts@5.0.2/access/AccessControl.sol";
import "@openzeppelin/contracts@5.0.2/token/ERC20/extensions/ERC20Permit.sol";
contract Coin is ERC20, ERC20Burnable, ERC20Pausable, AccessControl, ERC20Permit {
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
constructor(address defaultAdmin, address pauser, address minter)
ERC20("Coin", "MXN")
ERC20Permit("Coin")
{
_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
_grantRole(PAUSER_ROLE, pauser);
_grantRole(MINTER_ROLE, minter);
}
function pause() public onlyRole(PAUSER_ROLE) {
_pause();
}
function unpause() public onlyRole(PAUSER_ROLE) {
_unpause();
}
function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
_mint(to, amount);
}
// The following functions are overrides required by Solidity.
function _update(address from, address to, uint256 value)
internal
override(ERC20, ERC20Pausable)
{
super._update(from, to, value);
}
}
Now please compile your contract.
After that, we need to go to our Endpoint Armor dashboard to manage the rules for our endpoint
And please paste these configuration rules.
{
"methods": {
"eth_getBalance": "enabled",
"eth_call": "enabled",
"web3_sha3": "enabled",
"eth_chainId": "enabled",
"eth_getCode": "enabled",
"eth_getLogs": {
"latestBlocks": 100
},
"net_version": "enabled",
"eth_gasPrice": "enabled",
"eth_newFilter": "enabled",
"eth_subscribe": "enabled",
"eth_blockNumber": "enabled",
"eth_estimateGas": "enabled",
"eth_unsubscribe": "enabled",
"eth_getFilterLogs": "enabled",
"eth_getBlockByHash": "enabled",
"web3_clientVersion": "enabled",
"eth_sendTransaction": "enabled",
"eth_uninstallFilter": "enabled",
"eth_getBlockByNumber": "enabled",
"eth_getFilterChanges": "enabled",
"eth_getTransactionCount": "enabled",
"eth_getTransactionByHash": "enabled",
"eth_getTransactionReceipt": "enabled",
"net_peerCount": "enabled",
"net_listening": "enabled",
"eth_protocolVersion": "enabled",
"eth_syncing": "enabled",
"eth_coinbase": "enabled",
"eth_mining": "enabled",
"eth_hashrate": "enabled",
"eth_accounts": "enabled",
"eth_getStorageAt": "enabled",
"eth_getBlockTransactionCountByHash": "enabled",
"eth_getBlockTransactionCountByNumber": "enabled",
"eth_getUncleCountByBlockHash": "enabled",
"eth_getUncleCountByBlockNumber": "enabled",
"eth_sign": "enabled",
"eth_signTransaction": "enabled",
"eth_sendRawTransaction": "enabled",
"eth_getTransactionByBlockHashAndIndex": "enabled",
"eth_getTransactionByBlockNumberAndIndex": "enabled",
"eth_getUncleByBlockHashAndIndex": "enabled",
"eth_getUncleByBlockNumberAndIndex": "enabled",
"eth_getCompilers": "enabled",
"eth_compileLLL": "enabled",
"eth_compileSolidity": "enabled",
"eth_compileSerpent": "enabled",
"eth_newBlockFilter": "enabled",
"eth_newPendingTransactionFilter": "enabled"
},
"visitorRateLimits": {
"reqPerSecond": 3
},
"endpointRateLimits": {
"reqPerMinute": 100,
"reqPerSecond": 5
}
}
Then deploy your contract.
Let's break down these rules!
For instance, to use the "balanceOf" method, we need to make a JSON-RPC call using "eth_call".
In our rules, this method is configured as follows:
"eth_call": "enabled"
We have different types of value to be filled in the method "eth_call"
enabled: No limits on the number of requests.
Optional values:
reqPerHour: Maximum number of requests allowed per hour.
reqPerMinute: Maximum number of requests allowed per minute.
reqPerSecond: Maximum number of requests allowed per second.
Now, you might notice that there are many JSON-RPC methods listed. This is because, by default, not all methods are enabled.
Let's test the balanceOf method to ensure everything works as expected.
After understanding how the rules work, let's delete the line.
"eth_call": "enabled"
Now, let’s test the balanceOf method again.
You can see the error:
call to Irwing.balanceOf errored: Error occurred: Non-200 status code: '404'.
Non-200 status code: '404'
You may want to cautiously increase the gas limit if the transaction went out of gas.
This is because we restrict the method "eth_call" , we need to include the method and the options for the limits.
For example, if you want to ensure that your endpoint is only interacting with your smart contract, you need to modify this line:
"eth_call": {
"contractAllowlist": [
"0xdAC17F958D2ee523a2206206994597C13D831ec7"
]
}
Here’s how the line looks in the entire code:
Don’t forget to submit the changes after each modification.
Now, let’s test the method again.
You should see that everything works! ,but what happens if we change the contract and interact with the same method?
We encountered an error:
If we encounter an error, it means the rule is working as expected.
Use Case Example
Now, imagine you are only using your endpoint to fetch balance in the backend, but you want to ensure to only execute this, but you don't know how to do this,or you are not too technical,you can use AI.
In my case i will use ChatGPT.
Rules:
{
"methods": {
"eth_getBalance": "enabled",
"eth_call": "enabled",
"web3_sha3": "enabled",
"eth_chainId": "enabled",
"eth_getCode": "enabled",
"eth_getLogs": {
"latestBlocks": 100
},
"net_version": "enabled",
"eth_gasPrice": "enabled",
"eth_newFilter": "enabled",
"eth_subscribe": "enabled",
"eth_blockNumber": "enabled",
"eth_estimateGas": "enabled",
"eth_unsubscribe": "enabled",
"eth_getFilterLogs": "enabled",
"eth_getBlockByHash": "enabled",
"web3_clientVersion": "enabled",
"eth_sendTransaction": "enabled",
"eth_uninstallFilter": "enabled",
"eth_getBlockByNumber": "enabled",
"eth_getFilterChanges": "enabled",
"eth_getTransactionCount": "enabled",
"eth_getTransactionByHash": "enabled",
"eth_getTransactionReceipt": "enabled",
"net_peerCount": "enabled",
"net_listening": "enabled",
"eth_protocolVersion": "enabled",
"eth_syncing": "enabled",
"eth_coinbase": "enabled",
"eth_mining": "enabled",
"eth_hashrate": "enabled",
"eth_accounts": "enabled",
"eth_getStorageAt": "enabled",
"eth_getBlockTransactionCountByHash": "enabled",
"eth_getBlockTransactionCountByNumber": "enabled",
"eth_getUncleCountByBlockHash": "enabled",
"eth_getUncleCountByBlockNumber": "enabled",
"eth_sign": "enabled",
"eth_signTransaction": "enabled",
"eth_sendRawTransaction": "enabled",
"eth_getTransactionByBlockHashAndIndex": "enabled",
"eth_getTransactionByBlockNumberAndIndex": "enabled",
"eth_getUncleByBlockHashAndIndex": "enabled",
"eth_getUncleByBlockNumberAndIndex": "enabled",
"eth_getCompilers": "enabled",
"eth_compileLLL": "enabled",
"eth_compileSolidity": "enabled",
"eth_compileSerpent": "enabled",
"eth_newBlockFilter": "enabled",
"eth_newPendingTransactionFilter": "enabled"
},
"visitorRateLimits": {
"reqPerSecond": 3
},
"endpointRateLimits": {
"reqPerMinute": 100,
"reqPerSecond": 5
}
}
Instruction:
I want to fetch only the balance from the backend.
Please refer to the following documentation and use only Ethereum JSON-RPC methods:
https://www.quicknode.com/docs/ethereum/endpoint-armor
https://www.quicknode.com/guides/quicknode-products/endpoint-security/how-to-secure-your-endpoint-using-endpoint-armor
Now you can use test these rules and improve your project finances!
Conclusion
I'm proud of you!. You stand out from other teams by protecting your endpoints and reducing the risk of endpoint abuse.
I encourage you to implement this in your product and monitor your dapp workflow to ensure you have the optimal settings as you scale your project.
We are here to support you ❤️ .
We ❤️ Feedback!
If you have any feedback or questions on this guide, let us know.
Or, feel free to reach out to us via Twitter or our Discord community server.
We’d love to hear from you!
Author: Irwing Tello
Discord: discord.com/invite/ADjtsHVreT
Twitter: twitter.com/irwingtello
LinkedIn: linkedin.com/in/irwingtello
Email: irwing@dfhcommunity.com
Youtube: youtube.com/@irwingtellomx
You can support my work here:
BTC: 34kXK9CpTJP1PyHKw2kUD2bt6rtGcG5CHY
EVM Address: 0x8B98F8Ff69d2A720120eD6C71A9Bc5072b8Eb46D
Solana: Ey9oVFHW79giacRZaKxigYjeihMsY7ox8jxc7Hp1sJmS