6

In some countries, Solana RPC endpoints are blocked.

"https://api.mainnet-beta.solana.com" and "https://api.devnet.solana.com/" are both blocked in China.

When I'm trying to connect, I'm getting this error:

 https://api.devnet.solana.com/ failed, reason: connect ETIMEDOUT 103.240.182.55:443

How to get @solana/web3.js to access the RPC endpoints through a proxy?

1
  • 1
    In some countries, solana nodes cannot be accessed, how to set solana web3.js to access through proxy
    – ghost chen
    Commented Jul 20, 2022 at 13:24

2 Answers 2

8

First you'd need to find/buy a proxy server you can use. Once you've got one, add it to your projects .env file like this:

HTTP_PROXY=http://user:pass@ip:port

You should then be able to to use it like this:

import { clusterApiUrl, Connection } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import { TokenListProvider} from '@solana/spl-token-registry';
import { log } from 'console';
import { HttpsProxyAgent } from 'hpagent';
import fetch from 'node-fetch';
import { config } from 'dotenv';
config();

const proxy = process.env.HTTP_PROXY;
const proxyAgent = new HttpsProxyAgent ({ proxy });

const solanaConnection = new Connection(clusterApiUrl("mainnet-beta"), {
  commitment: 'confirmed',
  fetch: async (input, options) => {
    const processedInput =
    typeof input === 'string' && input.slice(0, 2) === '//'
      ? 'https:' + input
      : input;    

    const result = await fetch(processedInput, {
      ...options,
      agent: proxyAgent,
    });

    log('RESPONSE STATUS', result.status);
    return result;
  },
});

const walletToQuery = process?.argv[2];
if(!walletToQuery) {
  throw new Error('No wallet address given');
}

// An example taken from some article online
async function getTokenRegistry(){
    const tokenListProvider =  new TokenListProvider;
    const tokens = await tokenListProvider.resolve();
    const tokenList = tokens.filterByClusterSlug('mainnet-beta').getList();
    return(tokenList);
}

async function getTokenAccounts(wallet, solanaConnection) {
    const filters = [
        {
          dataSize: 165,    // size of account (bytes)
        },
        {
          memcmp: {
            offset: 32,     // location of our query in the account (bytes)
            bytes: wallet,  // our search criteria, a base58 encoded string
          },            
        }];
    const accounts = await solanaConnection.getParsedProgramAccounts(
        TOKEN_PROGRAM_ID, // new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
        {filters: filters}
    );
    console.log(`Found ${accounts.length} token account(s) for wallet ${wallet}.`);
    const tokenList = await getTokenRegistry();
    accounts.forEach((account, i) => {
        // Parse the account data
        const parsedAccountInfo = account.account.data;
        const mintAddress = parsedAccountInfo["parsed"]["info"]["mint"];
        const tokenBalance = parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"];
        // Find this token in the Token Registry
        const tokenName = tokenList.find(token=>token.address === mintAddress);
        // Log results
        console.log(`Token Account No. ${i + 1}: ${account.pubkey.toString()}`);
        console.log(`--Token Mint: ${mintAddress}`);
        if(tokenName) {console.log(`--Name: ${tokenName.name}`)}
        console.log(`--Token Balance: ${tokenBalance}`);
    });
}
getTokenAccounts(walletToQuery, solanaConnection);

Note: To run the above you'd need to install the required packages:

 - @solana/spl-token
 - @solana/spl-token-registry
 - @solana/web3.js
 - dotenv
 - hpagent
 - node-fetch

And then pass in a wallet address.

Example:

yarn install
node <FILENAME> <WALLET_ADDRESS>
2
  • 1
    This is a great answer (adding a custom agent to a connection). I'd only suggest using the built in getTokenAccountsByOwner() on Connection vs rolling your own with filtered program accounts. Less confusing for new users.
    – yamen
    Commented Jul 21, 2022 at 0:15
  • Thanks :) That's probably a better suggestion. If you have time would you mind editing my answer and adding the implementation how you imagine in? :)
    – 8bithero
    Commented Jul 21, 2022 at 10:05
0
import { Connection, clusterApiUrl, Keypair, PublicKey,} from "@solana/web3.js";
import { HttpsProxyAgent } from 'hpagent';
import fetch from 'node-fetch';
import { config } from 'dotenv';
config();
(async () => {
    const proxy = process.env.HTTP_PROXY || "";
    console.log("proxy:", proxy)
    const proxyAgent = new HttpsProxyAgent ({ proxy });
    const connection = new Connection(clusterApiUrl("mainnet-beta"), {
        commitment: 'confirmed',
        fetch: async (input, options) => {
            const processedInput =
                typeof input === 'string' && input.slice(0, 2) === '//'
                    ? 'https:' + input
                    : input;

            const result = await fetch(processedInput, {
                ...options,
                agent: proxyAgent,
            });

            console.log('RESPONSE STATUS', result.status);
            return result;
        },
    });

    let latestBlockhash = await connection.getLatestBlockhash();//
    console.log("latestBlockhash:", latestBlockhash)

    let base58publicKey = new PublicKey('9nEBir5mYz5yAnAtuZsuBxwfC7SayWZTMnyCmmTsUknf');
    console.log(base58publicKey.toBase58());

    let nonceAccountInfo = await connection.getAccountInfo(
        base58publicKey,
        'confirmed'
    );

    console.log("nonceAccountInfo:", nonceAccountInfo)

})()
1
  • 3
    to improve the quality of this answer, consider annotating this code to describe the changes you needed to make from your original to make it work
    – trent.sol
    Commented Jul 21, 2022 at 18:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.