x401 use cases
Sample Use Cases
Token Gating [without any backend changes]
Copy
"use client";
import { useState, useEffect } from 'react';
import { detectWallets, VelocityAuth } from "velocitytunedx401"
function GatedContent() {
const [wallets, setWallets] = useState([]);
const [showPopup, setShowPopup] = useState(false);
useEffect(() => {
let wallets = detectWallets();
setWallets(wallets);
}, []);
const getWalletIcon = (walletName) => {
const icons = {
metamask: "",
phantom: "/plogo.png",
solflare: "/solflare.svg"
};
return icons[walletName];
}
const GATING = async (wallet) => {
const config = {
wallet: wallet,
required_mint: "TOKEN CA HERE",
mint_amount: "1",
geo_code: "false",
geo_code_locs: "",
coords: {
latitude:""
longitude:""
}
}
const result = await VelocityAuth(config);
if (result.success) {
if (result.alreadyAuthenticated) {
alert("Welcome back to premium content!");
console.log(result.token);
// no re authentication for already authenticated client
} else {
console.log(result.token);
localStorage.setItem("vjwt", result.token);
alert("Access granted! Enjoy premium content")
// Redirect to app
}
} else {
switch(result.error) {
case "INSUFFICIENT_TOKENS":
alert(`You need tokens to access`);
break;
// custom logic to deny access
}
}
}
return (
<div className="items-center justify-center p-20" style={{ background: '', minHeight: '90vh' }}>
<button
onClick={() => setShowPopup(true)}
className="px-10 py-1 text-lg font-bold uppercase tracking-widest rounded-lg transition duration-300 ease-in-out bg-white/10 backdrop-blur-md border border-purple-500/50 text-white shadow-[0_0_15px_rgba(168,85,247,0.7)] hover:bg-white/20 hover:border-fuchsia-500/70 transform hover:scale-[1.02]"
>
Access Premium Content
</button>
{showPopup && (
<div
className="fixed inset-0 z-50 bg-black bg-opacity-80 flex items-center justify-center p-2 backdrop-blur-sm"
onClick={() => setShowPopup(false)}
>
<div
className="bg-gray-900/95 p-6 rounded-xl shadow-[0_0_40px_rgba(124,58,237,0.9)] w-full max-w-sm border border-purple-700/70"
onClick={(e) => e.stopPropagation()}
>
<div className="flex justify-between items-center mb-2">
<h2 className="text-2xl font-bold text-white tracking-wide">
Connect Wallet
</h2>
<button
onClick={() => setShowPopup(false)}
className="text-gray-400 hover:text-white transition duration-200 p-1"
>
</button>
</div>
<div className="space-y-3">
{wallets.map((wallet, index) => (
<button
key={wallet.address || index}
onClick={() => GATING(wallet)}
className="flex items-center justify-start gap-3 w-full p-3 rounded-lg transition duration-200 bg-gray-800/80 border border-transparent hover:bg-purple-600/30 hover:border-fuchsia-500 shadow-md hover:scale-[1.02]"
>
<img
src={getWalletIcon(wallet)}
alt={`${wallet.wallet} icon`}
className="w-8 h-8 rounded-md"
/>
<span className="text-lg font-semibold text-white font-mono">
{wallet == "phantom" ? ("PHANTOM") : ("SOLFLARE")}
</span>
</button>
))}
</div>
{wallets.length === 0 && (
<p className="text-center text-gray-400 pt-4">No wallets detected.</p>
)}
</div>
</div>
)}
</div>
);
}
export default GatedContent;
DAO Voting Access [ without any backend changes]
Copy
"use client";
import { useState, useEffect } from 'react';
import { detectWallets,VelocityAuth } from "velocitytunedx401"
function DAOVoting() {
const [wallets, setWallets] = useState([]);
const [showPopup, setShowPopup] = useState(false);
useEffect(() => {
let wallets = detectWallets();
setWallets(wallets);
}, []);
const getWalletIcon = (walletName) => {
const icons = {
metamask: "",
phantom: "/plogo.png",
solflare: "/solflare.svg"
};
return icons[walletName];
}
const DAOACCESS = async (wallet) => {
const config = {
wallet: wallet,
required_mint: "DAO_TOKEN_CA",
mint_amount: "100.0",
geo_code: "false",
geo_code_locs: "",
coords: {
latitude: "",
longitude:""
}
}
const result = await VelocityAuth(config);
if (result.success) {
if (result.alreadyAuthenticated) {
alert("already authenticated");
console.log(result.token);
// Show voting interface
} else {
console.log(result.token);
localStorage.setItem("vjwt", result.token);
alert("authenticated - you can now vote");
// Load proposals
}
} else {
switch(result.error) {
case "INSUFFICIENT_TOKENS":
alert(`You need ${result.required} tokens to vote`);
break;
}
}
return (
<div className="items-center justify-center p-20" style={{ background: '', minHeight: '90vh' }}>
<button
onClick={() => setShowPopup(true)}
className="px-10 py-1 text-lg font-bold uppercase tracking-widest rounded-lg transition duration-300 ease-in-out bg-white/10 backdrop-blur-md border border-purple-500/50 text-white shadow-[0_0_15px_rgba(168,85,247,0.7)] hover:bg-white/20 hover:border-fuchsia-500/70 transform hover:scale-[1.02]"
>
Connect to Vote
</button>
{showPopup && (
<div
className="fixed inset-0 z-50 bg-black bg-opacity-80 flex items-center justify-center p-2 backdrop-blur-sm"
onClick={() => setShowPopup(false)}
>
<div
className="bg-gray-900/95 p-6 rounded-xl shadow-[0_0_40px_rgba(124,58,237,0.9)] w-full max-w-sm border border-purple-700/70"
onClick={(e) => e.stopPropagation()}
>
<div className="flex justify-between items-center mb-2">
<h2 className="text-2xl font-bold text-white tracking-wide">
Connect Wallet
</h2>
<button
onClick={() => setShowPopup(false)}
className="text-gray-400 hover:text-white transition duration-200 p-1"
>
</button>
</div>
<div className="space-y-3">
{wallets.map((wallet, index) => (
<button
key={wallet.address || index}
onClick={() => DAOACCESS(wallet)}
className="flex items-center justify-start gap-3 w-full p-3 rounded-lg transition duration-200 bg-gray-800/80 border border-transparent hover:bg-purple-600/30 hover:border-fuchsia-500 shadow-md hover:scale-[1.02]"
>
<img
src={getWalletIcon(wallet)}
alt={`${wallet.wallet} icon`}
className="w-8 h-8 rounded-md"
/>
<span className="text-lg font-semibold text-white font-mono">
{wallet == "phantom" ? ("PHANTOM") : ("SOLFLARE")}
</span>
</button>
))}
</div>
{wallets.length === 0 && (
<p className="text-center text-gray-400 pt-4">No wallets detected.</p>
)}
</div>
</div>
)}
</div>
);
}
export default DAOVoting;
Geo Restricted Access [without any backend changes]
Copy
"use client";
import { useState, useEffect } from 'react';
import { detectWallets, getGeolocationData, VelocityAuth } from "velocitytunedx401"
function GeoRestrictedEntry() {
const [wallets, setWallets] = useState([]);
const [showPopup, setShowPopup] = useState(false);
const [location, setLocation] = useState({
latitude: null,
longitude: null,
error: null,
isFetching: false,
});
useEffect(() => {
async function fetchLocation() {
const locationdata = await getGeolocationData();
setLocation({
latitude: locationdata.latitude || null,
longitude: locationdata.longitude || null,
error: locationdata.error || null,
isFetching: false,
});
}
fetchLocation();
}, []);
useEffect(() => {
let wallets = detectWallets();
setWallets(wallets);
}, []);
const getWalletIcon = (walletName) => {
const icons = {
metamask: "",
phantom: "/plogo.png",
solflare: "/solflare.svg"
};
return icons[walletName];
}
const RUN = async (wallet) => {
const config = {
wallet: wallet,
required_mint: "TOURNAMENT_TOKEN_CA",
mint_amount: "50.0",
geo_code: "true",
geo_code_locs: "US",
coords: {
latitude: location.latitude,
longitude: location.longitude
}
}
const result = await VelocityAuth(config);
if (result.success) {
if (result.alreadyAuthenticated) {
alert("already registered for tournament");
console.log(result.token);
} else {
console.log(result.token);
localStorage.setItem("vjwt", result.token);
alert("entry approved!");
// Enter
}
} else {
switch(result.error) {
case "INSUFFICIENT_TOKENS":
alert(`You need ${result.required} tokens to enter`);
break;
case "LOCATION_DENIED":
alert("Tournament only available in US, CA, MX");
break;
case "LOCATION_ERROR":
alert("Location permission denied");
break;
}
}
}
return (
<div className="items-center justify-center p-20" style={{ background: '', minHeight: '90vh' }}>
<button
onClick={() => setShowPopup(true)}
className="px-10 py-1 text-lg font-bold uppercase tracking-widest rounded-lg transition duration-300 ease-in-out bg-white/10 backdrop-blur-md border border-purple-500/50 text-white shadow-[0_0_15px_rgba(168,85,247,0.7)] hover:bg-white/20 hover:border-fuchsia-500/70 transform hover:scale-[1.02]"
>
Join Tournament
</button>
{showPopup && (
<div
className="fixed inset-0 z-50 bg-black bg-opacity-80 flex items-center justify-center p-2 backdrop-blur-sm"
onClick={() => setShowPopup(false)}
>
<div
className="bg-gray-900/95 p-6 rounded-xl shadow-[0_0_40px_rgba(124,58,237,0.9)] w-full max-w-sm border border-purple-700/70"
onClick={(e) => e.stopPropagation()}
>
<div className="flex justify-between items-center mb-2">
<h2 className="text-2xl font-bold text-white tracking-wide">
Connect Wallet
</h2>
<button
onClick={() => setShowPopup(false)}
className="text-gray-400 hover:text-white transition duration-200 p-1"
>
</button>
</div>
<div className="space-y-3">
{wallets.map((wallet, index) => (
<button
key={wallet.address || index}
onClick={() => RUN(wallet)}
className="flex items-center justify-start gap-3 w-full p-3 rounded-lg transition duration-200 bg-gray-800/80 border border-transparent hover:bg-purple-600/30 hover:border-fuchsia-500 shadow-md hover:scale-[1.02]"
>
<img
src={getWalletIcon(wallet)}
alt={`${wallet.wallet} icon`}
className="w-8 h-8 rounded-md"
/>
<span className="text-lg font-semibold text-white font-mono">
{wallet == "phantom" ? ("PHANTOM") : ("SOLFLARE")}
</span>
</button>
))}
</div>
{wallets.length === 0 && (
<p className="text-center text-gray-400 pt-4">No wallets detected.</p>
)}
</div>
</div>
)}
</div>
);
}
export default GeoRestrictedEntry;