solana-age-verify-sdk 2.0.0-beta.5 → 2.0.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,7 +7,7 @@ Solana Age Verify is a client-side biometric SDK that estimates user age and per
7
7
  - **Privacy First**: No facial images are ever stored or transmitted. All AI inference happens in the user's browser (client-side).
8
8
  - **On-Chain**: Verification results are immutable and publicly verifiable via the Solana blockchain (MemoSq4gqABAXib96qFbncnscymPme7yS4AtGf4Vb7).
9
9
  - **Biometric**: Uses geometric face landmarks and texture analysis for liveness.
10
- - **Sybil Resistance**: A flat protocol fee (0.001 SOL base) is required for each successful verification to prevent spam and fund the decentralized registry.
10
+ - **Sybil Resistance**: A minimal protocol fee (0.001 SOL) is required for each successful verification to prevent spam and fund the decentralized registry.
11
11
 
12
12
  ## Security Architecture
13
13
 
@@ -183,7 +183,7 @@ interface VerifyResult {
183
183
  ### "Protocol fee payment failed"
184
184
  - User must approve the protocol fee transaction.
185
185
  - Ensure the wallet has sufficient SOL (typically 0.001 - 0.01 SOL depending on app configuration).
186
- - The default SDK fee is 0.001 SOL.
186
+ - The default SDK fee is **0.001 SOL** (approx. $0.15).
187
187
 
188
188
  ### "SafeToAutoRun" errors
189
189
  - This is an internal AI error, disregard.
package/dist/security.js CHANGED
@@ -18,7 +18,8 @@ export function getPlatformPublicKey() {
18
18
  return _cachedPlatformPubKey;
19
19
  // In a production build, this would be swapped or populated from env
20
20
  // For now, we use the VITE environment variable if available (Vite/Vercel)
21
- const envKey = import.meta.env?.VITE_PLATFORM_PUBLIC_KEY;
21
+ // We check VITE_TREASURY_ADDRESS first as per configuration, then fallback to legacy VITE_PLATFORM_PUBLIC_KEY
22
+ const envKey = import.meta.env?.VITE_TREASURY_ADDRESS || import.meta.env?.VITE_PLATFORM_PUBLIC_KEY;
22
23
  if (envKey) {
23
24
  _cachedPlatformPubKey = new PublicKey(envKey);
24
25
  return _cachedPlatformPubKey;
package/dist/verify.js CHANGED
@@ -664,82 +664,128 @@ export async function verifyHost18Plus(options) {
664
664
  }
665
665
  try {
666
666
  const fromPubkey = options.wallet.publicKey;
667
- // ONLY compute facehash right before signing - ensures it's tied to wallet consent
668
- if (embedding.length > 0) {
669
- facehash = await computeFaceHash(options.walletPubkeyBase58, salt, embedding);
667
+ // Debug checks exposed to UI via error message
668
+ try {
669
+ new PublicKey(fromPubkey);
670
+ }
671
+ catch (e) {
672
+ throw new Error(`Invalid Wallet Public Key: ${e.message}`);
673
+ }
674
+ try {
675
+ new PublicKey(platformPubKey);
676
+ }
677
+ catch (e) {
678
+ throw new Error(`Invalid Treasury Public Key (Check VITE_TREASURY_ADDRESS): ${e.message}`);
679
+ }
680
+ // Step 1: FaceHash
681
+ try {
682
+ if (embedding.length > 0) {
683
+ facehash = await computeFaceHash(options.walletPubkeyBase58, salt, embedding);
684
+ }
685
+ }
686
+ catch (e) {
687
+ throw new Error(`FaceHash Computation Failed: ${e.message}`);
670
688
  }
671
689
  const transaction = new Transaction();
672
- // 0. Prioritization Fees & Compute Limits (Crucial for Mainnet reliability)
673
- transaction.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 50000 }), ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 100000 }) // Priority fee
674
- );
675
- // 1. Protocol Fee Transfer
676
- transaction.add(SystemProgram.transfer({
677
- fromPubkey,
678
- toPubkey: platformPubKey,
679
- lamports: protocolFeeSol * LAMPORTS_PER_SOL,
680
- }));
681
- // 2. Add Verification Memo (signed by both User and Platform)
690
+ transaction.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 50000 }), ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 100000 }));
691
+ // Step 2: Protocol Fee Instruction
692
+ try {
693
+ transaction.add(SystemProgram.transfer({
694
+ fromPubkey,
695
+ toPubkey: platformPubKey,
696
+ lamports: protocolFeeSol * LAMPORTS_PER_SOL,
697
+ }));
698
+ }
699
+ catch (e) {
700
+ throw new Error(`Fee Transfer Instruction Failed: ${e.message}`);
701
+ }
682
702
  const statusStr = isOver18 ? 'OVER18' : (isFinalStrike ? 'FINAL_FAILURE' : 'UNDER18');
683
703
  const memoText = `Solana-Age-Registry | ${statusStr} | HASH: ${facehash} | ${verifiedAt}`;
684
- transaction.add(new TransactionInstruction({
685
- keys: [
686
- { pubkey: fromPubkey, isSigner: true, isWritable: false },
687
- { pubkey: platformPubKey, isSigner: true, isWritable: false } // Required platform signature
688
- ],
689
- programId: getMemoProgramId(),
690
- data: new TextEncoder().encode(memoText),
691
- }));
704
+ // Step 3: Memo Instruction
705
+ try {
706
+ transaction.add(new TransactionInstruction({
707
+ keys: [
708
+ { pubkey: fromPubkey, isSigner: true, isWritable: false },
709
+ { pubkey: platformPubKey, isSigner: true, isWritable: false }
710
+ ],
711
+ programId: getMemoProgramId(),
712
+ data: new TextEncoder().encode(memoText),
713
+ }));
714
+ }
715
+ catch (e) {
716
+ throw new Error(`Memo Instruction Failed: ${e.message}`);
717
+ }
692
718
  const { blockhash } = await options.connection.getLatestBlockhash();
693
719
  transaction.recentBlockhash = blockhash;
694
720
  transaction.feePayer = fromPubkey;
695
- // 3. SECURE SERVER-SIDE SIGNING
696
- // We send the transaction to the Vercel API to get the Platform's signature
697
- const signResponse = await fetch('/api/sign-verification', {
698
- method: 'POST',
699
- headers: { 'Content-Type': 'application/json' },
700
- body: JSON.stringify({
701
- serializedTx: transaction.serialize({
702
- requireAllSignatures: false,
703
- verifySignatures: false
704
- }).toString('base64')
705
- })
706
- });
707
- if (!signResponse.ok) {
708
- const signError = await signResponse.json();
709
- throw new Error(signError.message || 'Platform signing failed');
721
+ // Step 4: Serialization
722
+ let serializedTxBase64;
723
+ try {
724
+ serializedTxBase64 = transaction.serialize({
725
+ requireAllSignatures: false,
726
+ verifySignatures: false
727
+ }).toString('base64');
710
728
  }
711
- const { transaction: platformSignedTxBase64 } = await signResponse.json();
712
- const platformSignedTxData = atob(platformSignedTxBase64);
713
- const platformSignedTxUint8 = new Uint8Array(platformSignedTxData.length);
714
- for (let i = 0; i < platformSignedTxData.length; i++) {
715
- platformSignedTxUint8[i] = platformSignedTxData.charCodeAt(i);
729
+ catch (e) {
730
+ throw new Error(`Transaction Serialization Failed: ${e.message}`);
731
+ }
732
+ // Step 5: Server Signing
733
+ let platformSignedTx;
734
+ try {
735
+ const signResponse = await fetch('/api/sign-verification', {
736
+ method: 'POST',
737
+ headers: { 'Content-Type': 'application/json' },
738
+ body: JSON.stringify({ serializedTx: serializedTxBase64 })
739
+ });
740
+ if (!signResponse.ok) {
741
+ const signError = await signResponse.json();
742
+ throw new Error(`Server API Error: ${signError.message || signError.error}`);
743
+ }
744
+ const { transaction: txBase64 } = await signResponse.json();
745
+ const txData = atob(txBase64);
746
+ const txUint8 = new Uint8Array(txData.length);
747
+ for (let i = 0; i < txData.length; i++) {
748
+ txUint8[i] = txData.charCodeAt(i);
749
+ }
750
+ platformSignedTx = Transaction.from(txUint8);
751
+ }
752
+ catch (e) {
753
+ throw new Error(`Server Signing Sequence Failed: ${e.message}`);
754
+ }
755
+ // Step 6: User Signing
756
+ let fullSignedTx;
757
+ try {
758
+ fullSignedTx = await options.wallet.signTransaction(platformSignedTx);
759
+ }
760
+ catch (e) {
761
+ throw new Error(`User Signing Failed: ${e.message}`);
762
+ }
763
+ // Step 7: Broadcast
764
+ try {
765
+ protocolFeeTxId = await options.connection.sendRawTransaction(fullSignedTx.serialize(), {
766
+ skipPreflight: false,
767
+ preflightCommitment: 'confirmed'
768
+ });
769
+ const latestBlockhash = await options.connection.getLatestBlockhash('confirmed');
770
+ await options.connection.confirmTransaction({
771
+ signature: protocolFeeTxId,
772
+ blockhash: latestBlockhash.blockhash,
773
+ lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
774
+ }, 'confirmed');
775
+ }
776
+ catch (e) {
777
+ throw new Error(`Transaction Broadcast Failed: ${e.message}`);
716
778
  }
717
- const platformSignedTx = Transaction.from(platformSignedTxUint8);
718
- // 4. USER SIGNATURE
719
- // Now the user signs the transaction that already contains the platform's signature
720
- const fullSignedTx = await options.wallet.signTransaction(platformSignedTx);
721
- // 5. BROADCAST
722
- // Use 'confirmed' commitment for better balance of speed and reliability on Mainnet
723
- protocolFeeTxId = await options.connection.sendRawTransaction(fullSignedTx.serialize(), {
724
- skipPreflight: false,
725
- preflightCommitment: 'confirmed'
726
- });
727
- const latestBlockhash = await options.connection.getLatestBlockhash('confirmed');
728
- await options.connection.confirmTransaction({
729
- signature: protocolFeeTxId,
730
- blockhash: latestBlockhash.blockhash,
731
- lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
732
- }, 'confirmed');
733
779
  protocolFeePaid = true;
734
- console.log('✓ On-chain proof recorded with dual signatures (User + Platform)');
780
+ console.log('✓ On-chain proof recorded');
735
781
  }
736
782
  catch (e) {
737
- console.error('Protocol fee payment failed or rejected:', e);
738
- // User rejected or tx failed - clear the facehash since it wasn't recorded
783
+ console.error('Protocol fee payment failed:', e);
739
784
  facehash = '';
740
- // For Community Version, we fail the verification if payment is rejected
741
785
  isOver18 = false;
742
- failureReason = `Protocol fee payment failed: ${e.message || 'Verification rejected or network error'}`;
786
+ // Expose the EXACT error message to the user UI
787
+ failureReason = `Protocol Fee Error: ${e.message}`;
788
+ console.error('[Verify Debug Stack]', e.stack);
743
789
  }
744
790
  }
745
791
  else if (isOver18 && (!options.wallet || !options.connection)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solana-age-verify-sdk",
3
- "version": "2.0.0-beta.5",
3
+ "version": "2.0.0-beta.9",
4
4
  "type": "module",
5
5
  "description": "Solana Age Verify is a premium, client-side SDK for privacy-preserving age verification and liveness detection. It generates a deterministic Face Hash linked to a wallet without storing facial data.",
6
6
  "license": "MIT",
@@ -10,6 +10,10 @@
10
10
  "dist",
11
11
  "public"
12
12
  ],
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/TrenchChef/solana-age-verify-sdk.git"
16
+ },
13
17
  "homepage": "https://talkchain.live",
14
18
  "keywords": [
15
19
  "solana",