Reputation: 151
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...
Upvotes: 14
Views: 17873
Reputation: 123
READ THIS FIRST. All the solutions using isOnCurve
will fail if you pass a pumpfun token address and will return it as a "valid" wallet address. The following code will return true even though 7oBYdEhV4GkXC19ZfgAvXpJWp2Rn9pm1Bx2cVNxFpump
is not a wallet.
import { PublicKey } from '@solana/web3.js';
function isValidSolanaWalletAddress(walletAddress: string) {
try {
const key = new PublicKey(walletAddress);
if (PublicKey.isOnCurve(key.toBytes())) {
return true;
}
return false;
} catch (error) {
return false;
}
}
console.log(isValidSolanaWalletAddress("7oBYdEhV4GkXC19ZfgAvXpJWp2Rn9pm1Bx2cVNxFpump"))
No where does the Solana documentation mention this is how you check whether the address is a wallet. It only checks if it is suitable for end users.
Upvotes: 1
Reputation: 11
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}!`
);
Upvotes: 1
Reputation: 111
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
Upvotes: 11
Reputation: 41
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));
Upvotes: 4
Reputation: 901
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;
}
};
Upvotes: 3
Reputation: 966
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
Upvotes: 2
Reputation: 2107
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.
Upvotes: 6