solana-age-verify-sdk 2.0.0-beta.4 → 2.0.0-beta.7
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 +2 -2
- package/dist/security.js +2 -1
- package/dist/ui/spinner.d.ts +5 -0
- package/dist/ui/spinner.js +36 -0
- package/dist/verify.js +13 -11
- package/package.json +5 -1
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
|
|
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
|
-
|
|
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;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a premium gradient spinner HTML string for use in SDK UI overlays
|
|
3
|
+
* Matches Solana brand colors (purple to cyan gradient)
|
|
4
|
+
*/
|
|
5
|
+
export function createSpinnerHTML() {
|
|
6
|
+
return `
|
|
7
|
+
<div style="display: flex; align-items: center; justify-content: center; padding: 20px;">
|
|
8
|
+
<div style="
|
|
9
|
+
width: 64px;
|
|
10
|
+
height: 64px;
|
|
11
|
+
border: 4px solid transparent;
|
|
12
|
+
border-radius: 50%;
|
|
13
|
+
background: linear-gradient(#0f172a, #0f172a) padding-box, linear-gradient(135deg, #a78bfa 0%, #60a5fa 50%, #14b8a6 100%) border-box;
|
|
14
|
+
animation: spin 0.8s linear infinite;
|
|
15
|
+
position: relative;
|
|
16
|
+
" aria-label="Loading">
|
|
17
|
+
<div style="
|
|
18
|
+
position: absolute;
|
|
19
|
+
top: 50%;
|
|
20
|
+
left: 50%;
|
|
21
|
+
transform: translate(-50%, -50%);
|
|
22
|
+
width: 48px;
|
|
23
|
+
height: 48px;
|
|
24
|
+
border-radius: 50%;
|
|
25
|
+
background: #0f172a;
|
|
26
|
+
"></div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<style>
|
|
30
|
+
@keyframes spin {
|
|
31
|
+
from { transform: rotate(0deg); }
|
|
32
|
+
to { transform: rotate(360deg); }
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
35
|
+
`;
|
|
36
|
+
}
|
package/dist/verify.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
// The public treasury address is provided via the environment variable VITE_TREASURY_ADDRESS.
|
|
2
|
+
// This address is used by the SDK to direct fee payments to the platform's treasury.
|
|
1
3
|
import { DEFAULT_CONFIG } from './types';
|
|
2
4
|
import { Transaction, SystemProgram, LAMPORTS_PER_SOL, PublicKey, TransactionInstruction, ComputeBudgetProgram } from '@solana/web3.js';
|
|
3
5
|
import { Camera } from './camera';
|
|
4
6
|
import { computeFaceHash, generateSalt, toHex } from './hashing/facehash';
|
|
5
7
|
import { generateChallengeSequence } from './liveness/challenges';
|
|
6
8
|
import { getPlatformPublicKey, getProtocolFee } from './security';
|
|
9
|
+
import { createSpinnerHTML } from './ui/spinner';
|
|
7
10
|
// Lazy getter to avoid top-level PublicKey construction before polyfills load
|
|
8
11
|
let _memoProgramId = null;
|
|
9
12
|
function getMemoProgramId() {
|
|
@@ -205,7 +208,7 @@ export async function verifyHost18Plus(options) {
|
|
|
205
208
|
// Load Models
|
|
206
209
|
if (options.onChallenge)
|
|
207
210
|
options.onChallenge('Loading models...');
|
|
208
|
-
// Show loading screen
|
|
211
|
+
// Show loading screen with premium spinner
|
|
209
212
|
if (options.uiMountEl) {
|
|
210
213
|
options.uiMountEl.innerHTML = `
|
|
211
214
|
<div style="position: relative; height: 100%; width: 100%; pointer-events: none; display: flex; flex-direction: column; align-items: center; justify-content: center; background: rgba(15, 23, 42, 0.85);">
|
|
@@ -213,15 +216,11 @@ export async function verifyHost18Plus(options) {
|
|
|
213
216
|
<div style="font-size: 24px; font-weight: 600; background: linear-gradient(to right, #e2e8f0, #94a3b8); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 32px; letter-spacing: -0.01em;">
|
|
214
217
|
Initializing Neural Engine...
|
|
215
218
|
</div>
|
|
216
|
-
|
|
217
|
-
<div style="position: absolute; top: 0; left: 0; height: 100%; width: 100%; background: linear-gradient(90deg, transparent, #3b82f6, transparent); animation: shimmer 1.5s infinite;">
|
|
218
|
-
</div>
|
|
219
|
-
</div>
|
|
219
|
+
${createSpinnerHTML()}
|
|
220
220
|
</div>
|
|
221
221
|
</div>
|
|
222
222
|
<style>
|
|
223
223
|
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
224
|
-
@keyframes shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }
|
|
225
224
|
</style>
|
|
226
225
|
`;
|
|
227
226
|
}
|
|
@@ -655,15 +654,12 @@ export async function verifyHost18Plus(options) {
|
|
|
655
654
|
To record your verification on-chain, a minimal protocol fee of <b>${protocolFeeSol} SOL</b> is required.<br>
|
|
656
655
|
Please approve the transaction in your wallet.
|
|
657
656
|
</div>
|
|
658
|
-
|
|
659
|
-
|
|
657
|
+
${createSpinnerHTML()}
|
|
658
|
+
<div style="color: #60a5fa; font-weight: 600; margin-top: 16px;">
|
|
660
659
|
Waiting for signature...
|
|
661
660
|
</div>
|
|
662
661
|
</div>
|
|
663
662
|
</div>
|
|
664
|
-
<style>
|
|
665
|
-
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
|
666
|
-
</style>
|
|
667
663
|
`;
|
|
668
664
|
}
|
|
669
665
|
try {
|
|
@@ -672,6 +668,11 @@ export async function verifyHost18Plus(options) {
|
|
|
672
668
|
if (embedding.length > 0) {
|
|
673
669
|
facehash = await computeFaceHash(options.walletPubkeyBase58, salt, embedding);
|
|
674
670
|
}
|
|
671
|
+
console.log('[DEBUG] Fee Payment Init', {
|
|
672
|
+
fromPubkey: fromPubkey?.toString(),
|
|
673
|
+
platformPubKey: platformPubKey?.toString(),
|
|
674
|
+
protocolFeeSol
|
|
675
|
+
});
|
|
675
676
|
const transaction = new Transaction();
|
|
676
677
|
// 0. Prioritization Fees & Compute Limits (Crucial for Mainnet reliability)
|
|
677
678
|
transaction.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 50000 }), ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 100000 }) // Priority fee
|
|
@@ -710,6 +711,7 @@ export async function verifyHost18Plus(options) {
|
|
|
710
711
|
});
|
|
711
712
|
if (!signResponse.ok) {
|
|
712
713
|
const signError = await signResponse.json();
|
|
714
|
+
console.error('[DEBUG] Sign API Error:', signError);
|
|
713
715
|
throw new Error(signError.message || 'Platform signing failed');
|
|
714
716
|
}
|
|
715
717
|
const { transaction: platformSignedTxBase64 } = await signResponse.json();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solana-age-verify-sdk",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.7",
|
|
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",
|