How can I validate a Solana wallet address with web3js?

Viewed 3752

I'm trying to validate that the input text I get from a user is a valid Solana address.

According to the web3.js documentation, the method .isOnCurve() does that:

https://solana-labs.github.io/solana-web3.js/classes/PublicKey.html#isOnCurve

I've managed to make it work with this code:

import {PublicKey} from '@solana/web3.js'

function validateSolAddress(address:string){
    try {
        let pubkey = new PublicKey(address)
        let  isSolana =  PublicKey.isOnCurve(pubkey.toBuffer())
        return isSolana
    } catch (error) {
        return false
    }
} 

function modalSubmit(modal: any){

  const firstResponse = modal.getTextInputValue(walletQuestFields.modal.componentsList[0].id)
 
  let isSolAddress = validateSolAddress(firstResponse)

  if (isSolAddress) {
    console.log('The address is valid')
  }else{
    console.log('The address is NOT valid')
  }
}

But when I pass let pubkey = new PublicKey(address) a string that is not similar to a solana address, it throws the exception Error: Invalid public key input (PublikKey expects a PublicKeyInitData: number | string | Buffer | Uint8Array | number[] | PublicKeyData)

That is why I had to out it into a try-catch block.

Is there any other (better) way to achieve this? It looks ugly...

5 Answers

To validate a Solana public key may be a wallet address, you should both use isOnCurve() and the PublicKey constructor like you are doing.

The error thrown makes sense. If the address is not a public key, it should not be able to be instantiated.

Perhaps there could be another function made native to @solana/web3.js that takes care of validating wallet addresses for you in the future.

PublicKey.isOnCurve() return true only if the address is on ed25519 curve such addresses generated from Keypair and returns false for off-curve addresses such as derived addresses from PublicKey.findProgramAddress() though they can be valid public key.

const owner = new PublicKey("DS2tt4BX7YwCw7yrDNwbAdnYrxjeCPeGJbHmZEYC8RTb");
console.log(PublicKey.isOnCurve(owner.toBytes())); // true
console.log(PublicKey.isOnCurve(owner.toString())); // true

const ownerPda = PublicKey.findProgramAddressSync(
    [owner.toBuffer()],
    new PublicKey("worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth"),
)[0];
console.log(PublicKey.isOnCurve(ownerPda.toString())); // false

console.log(PublicKey.isOnCurve([owner, 18])); // false

const RAY_MINT = new PublicKey("4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R");
console.log(PublicKey.isOnCurve(new PublicKey(RAY_MINT))); // true

console.log(PublicKey.isOnCurve("fasddfasevase")); // throws error

I'm trying to do the same (validate a solana wallet address) and works for me.

isOnCurve return true if the public key has a valid format, but I think this is not sufficient for verify a wallet address because I'm tested some public keys from devnet and mainnet-beta and ever return true (without care about the env) unless I used invalid key.

This is a public key from devnet, you can try with this to test:

8B9wLUXGFQQJ6VpzhDMpmHxByAvQBXhwSsZUwjLz971x

My code looks like:

var connection = new web3.Connection(
   web3.clusterApiUrl('devote'),
   'confirmed',
  );

const publicKey = new web3.PublicKey("8B9wLUXGFQQJ6VpzhDMpmHxByAvQBXhwSsZUwjLz971x");

console.log(await web3.PublicKey.isOnCurve(publicKey))

Should print true

isOnCurve expects a Uint8Array format for publicKey argument. So you must do publicKey.toBytes() to get byte array representation of the publicKey.

 const validateSolanaAddress = async (addr: string) => {
      let publicKey: PublicKey;
      try {
          publicKey = new PublicKey(addr);
          return await PublicKey.isOnCurve(publicKey.toBytes());
        } catch (err) {
          return false;
        }
      };

You don't have to use Connection only to validate wallet address. A minimum working example should be something like this:

import { PublicKey } from '@solana/web3.js'

const address = new PublicKey("8B9wLUXGFQQJ6VpzhDMpmHxByAvQBXhwSsZUwjLz971x");
console.log(PublicKey.isOnCurve(address));
Related