import React, { useState } from "react";
import { PrivyProvider, usePrivy } from "@privy-io/react-auth";
import { useWallets, toSolanaWalletConnectors } from "@privy-io/react-auth/solana";
import { createSolanaRpc } from "@solana/kit";
import { PublicKey, Connection, VersionedTransaction } from "@solana/web3.js";
import { createPaymentHandler } from "@faremeter/payment-solana/exact";
import { wrap as wrapFetch } from "@faremeter/fetch";
import { solana } from "@faremeter/info";
const NETWORK = "mainnet-beta";
const ASSET = "USDC";
const CHAIN_ID = "solana:mainnet";
function PaymentDemo() {
const { login, logout, authenticated, ready } = usePrivy();
const { wallets } = useWallets();
const [loading, setLoading] = useState(false);
const [response, setResponse] = useState("");
const wallet = wallets?.[0]; // First Solana wallet
const handlePayment = async () => {
if (!wallet) {
setResponse("Error: No Solana wallet connected");
return;
}
try {
setLoading(true);
// Lookup USDC token info
const tokenInfo = solana.lookupKnownSPLToken(NETWORK, ASSET);
if (!tokenInfo) throw new Error(`Could not lookup ${ASSET}`);
const assetAddress = new PublicKey(tokenInfo.address);
const publicKey = new PublicKey(wallet.address);
const connection = new Connection("https://api.mainnet-beta.solana.com");
// Create wallet interface for Faremeter
const paymentWallet = {
network: NETWORK,
publicKey,
updateTransaction: async (tx: VersionedTransaction) => {
const { signedTransaction } = await wallet.signTransaction({
transaction: tx.serialize(),
chain: CHAIN_ID,
});
return VersionedTransaction.deserialize(signedTransaction);
},
};
// Create payment handler
const handler = createPaymentHandler(paymentWallet, assetAddress, connection);
const fetchWithPayment = wrapFetch(fetch, { handlers: [handler] });
// Make payment request
const res = await fetchWithPayment("https://triton.api.corbits.dev", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "getBlockHeight",
}),
});
const data = await res.json();
setResponse(JSON.stringify(data, null, 2));
} catch (error: any) {
setResponse(`Error: ${error.message}`);
} finally {
setLoading(false);
}
};
if (!ready) {
return <div>Loading Privy...</div>;
}
if (!authenticated) {
return (
<div>
<h1>Privy + Faremeter Demo</h1>
<p>Connect your wallet to create a Solana embedded wallet via Privy</p>
<button onClick={login}>Connect Wallet</button>
</div>
);
}
return (
<div>
<h1>Connected: {wallet?.address.slice(0, 8)}...</h1>
<button onClick={handlePayment} disabled={loading || !wallet}>
{loading ? "Processing..." : "Make Payment"}
</button>
<button onClick={logout}>Disconnect</button>
{response && <pre>{response}</pre>}
</div>
);
}
function App() {
return (
<PrivyProvider
appId={process.env.PRIVY_APP_ID!}
config={{
loginMethods: ["wallet", "email"],
appearance: {
theme: "light",
walletChainType: "solana-only",
walletList: ["detected_solana_wallets", "phantom", "solflare", "privy"],
},
embeddedWallets: {
solana: {
createOnLogin: "users-without-wallets",
},
},
externalWallets: {
solana: {
connectors: toSolanaWalletConnectors(),
},
},
solana: {
rpcs: {
"solana:mainnet": {
rpc: createSolanaRpc("https://api.mainnet-beta.solana.com"),
},
},
},
}}
>
<PaymentDemo />
</PrivyProvider>
);
}
export default App;