How can I validate a Solana wallet address with web3js?
Asked Answered
P

6

11

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...

Papke answered 21/2, 2022 at 3:37 Comment(0)
B
4

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.

Balanchine answered 21/2, 2022 at 4:2 Comment(3)
Thank you Jacob, I wasn't sure I was doing it rightPapke
this returns false for some addresses like "4ig5eTKvBefXB9Pqwq2rCJTGFRNATEa7geNzeuVQGmAE", any idea why?Kohima
yup i tried with a wallet address "Eej78Z5E4w5sSreb8w8esQqTVwBuyT8La2ypa8jiY3Tw". but it returns false. Although this is correct wallet address.Propertied
H
9

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
Harrell answered 28/7, 2022 at 12:29 Comment(0)
B
4

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.

Balanchine answered 21/2, 2022 at 4:2 Comment(3)
Thank you Jacob, I wasn't sure I was doing it rightPapke
this returns false for some addresses like "4ig5eTKvBefXB9Pqwq2rCJTGFRNATEa7geNzeuVQGmAE", any idea why?Kohima
yup i tried with a wallet address "Eej78Z5E4w5sSreb8w8esQqTVwBuyT8La2ypa8jiY3Tw". but it returns false. Although this is correct wallet address.Propertied
C
3

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));
Choose answered 19/4, 2022 at 15:39 Comment(0)
L
1

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

Lossa answered 6/3, 2022 at 20:14 Comment(3)
Thx Vicente for your comment. In fact, in my code, the address you provide results in true. You can test it on a Replit I set up here: replit.com/@cdelalama/VerifyAddress1?v=1#index.js (fork it and edit it on a workspace). I've noticed that depending on how I import the web3.js module it behaves differently: import {PublicKey} from '@solana/web3.js' returns true, but import PublicKey from '@solana/web3.js' or import web3 from '@solana/web3.js' returns false. I'm not an expert javascript developer so I don't know what the difference is, maybe someone can explainPapke
I also tried yours and set up another replit here: replit.com/@cdelalama/VerifyAdress2?v=1#index.js But I can't understand the first part of your code var connection = new web3.Connection( web3.clusterApiUrl('devote'), 'confirmed', ); Without it is very similar to mine, and can't make it work with that blockPapke
Same issue, it returns false for a bunch of addresses such as 4ig5eTKvBefXB9Pqwq2rCJTGFRNATEa7geNzeuVQGmAEKohima
B
1

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;
        }
      };
Bitterroot answered 30/3, 2022 at 8:18 Comment(0)
C
0
import { Connection, LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js";

const suppliedPublicKey = process.argv[2];
if (!suppliedPublicKey) {
    throw new Error("Provide a public key to check the balance of!");
} else {
    console.log(PublicKey.isOnCurve(suppliedPublicKey));
}

const connection = new Connection("https://api.mainnet.solana.com", "confirmed");

const publicKey = new PublicKey(suppliedPublicKey);

const balanceInLamports = await connection.getBalance(publicKey);

const balanceInSOL = balanceInLamports / LAMPORTS_PER_SOL;

console.log(
    `✅ Finished! The balance for the wallet at address ${publicKey} is ${balanceInSOL}!`
);
Carnatic answered 23/5 at 9:33 Comment(1)
the isOnCurve() returns true if the wallet address is validCarnatic

© 2022 - 2024 — McMap. All rights reserved.