import { ProofStatus, SignatureProof } from "@notabene/javascript-sdk"; import { AccountTxTransaction, Client } from "xrpl"; import { verify } from "ripple-keypairs"; export function verifyXRPL( message: string, publicKey: string, proof: string ): boolean { return verify(Buffer.from(message).toString("hex"), proof, publicKey); } export const xrplTestnetWs = [ "wss://s.altnet.rippletest.net:51233", "wss://testnet.xrpl-labs.com/", ]; export const xrplMainnetWs = [ "wss://s1.ripple.com", "wss://xrplcluster.com/", // full node "wss://s2.ripple.com/", ]; // If the public key is not provided, we need to get it directly async function getPublicKey( address: string, isTest?: boolean ): Promise { const servers = isTest ? xrplTestnetWs : xrplMainnetWs; for (const server of servers) { try { const client = new Client(server); await client.connect(); const response = await client.request({ command: "account_tx", account: address, binary: false, limit: 2, forward: false, }); await client.disconnect(); return getSigningPubkeyFromLatestTx(response.result?.transactions); } catch (error) { let errorMessage = "Connection to XRPL server failed"; if (error instanceof Error) { errorMessage += `: ${error.message}`; } console.error(errorMessage); // Continue to next server } } } function getSigningPubkeyFromLatestTx( latestTx: AccountTxTransaction[] ): string { for (let i = 0; i < latestTx.length; i++) { // Check if the Account in the .tx is the address derived from the pubkey const signingPubKey = latestTx[i]?.tx_json?.SigningPubKey ?? "0x"; // TODO: https://github.com/Cypher-Laboratory/xrpl-publickey-getter/blob/main/src/pubKeyGetter.ts#L98 // Check the public key matches the address properly return signingPubKey; } throw new Error("No valid pubkey found in the latest transactions"); } export async function verifyPersonalSignXRPL( proof: SignatureProof, publicKey?: string, isTest?: boolean ): Promise { const [ns, , address] = proof.address.split(/:/); if (ns !== "xrpl") return { ...proof, status: ProofStatus.FAILED }; if (!publicKey) { publicKey = await getPublicKey(address, isTest); } if (!publicKey) { return { ...proof, status: ProofStatus.FAILED }; } const verified = verifyXRPL(proof.attestation, publicKey, proof.proof); return { ...proof, status: verified ? ProofStatus.VERIFIED : ProofStatus.FAILED, }; }