Remove usage of gas fees config and set solana pubkey in deployment request
This commit is contained in:
parent
77981f5bfb
commit
75989d9f34
@ -8,8 +8,8 @@ NEXT_PUBLIC_SOLANA_TOKEN_MINT_ADDRESS=71Jvq4Epe2FCJ7JFSF7jLXdNk1Wy4Bhqd9iL6bEFEL
|
||||
# Multisig address
|
||||
NEXT_PUBLIC_SOLANA_TOKEN_RECIPIENT_ADDRESS=FFDx3SdAEeXrp6BTmStB4BDHpctGsaasZq4FFcowRobY
|
||||
NEXT_PUBLIC_SOLANA_TOKEN_SYMBOL=GOR
|
||||
NEXT_PUBLIC_SOLANA_TOKEN_NAME=GOR Token
|
||||
NEXT_PUBLIC_MIN_SOLANA_PAYMENT_AMOUNT=400000000
|
||||
NEXT_PUBLIC_MIN_SOLANA_PAYMENT_AMOUNT=400000000 # Approx. 5 USD
|
||||
NEXT_PUBLIC_MIN
|
||||
|
||||
# UI Configuration (optional)
|
||||
NEXT_PUBLIC_DOMAIN_SUFFIX=apps.vaasl.io
|
||||
@ -24,10 +24,7 @@ REGISTRY_RPC_ENDPOINT=
|
||||
REGISTRY_BOND_ID=
|
||||
REGISTRY_AUTHORITY=
|
||||
REGISTRY_USER_KEY=
|
||||
REGISTRY_GAS=900000
|
||||
REGISTRY_FEES=900000alnt
|
||||
REGISTRY_GAS_PRICE=0.001
|
||||
|
||||
# Application Configuration
|
||||
DEPLOYER_LRN=
|
||||
LACONIC_TRANSFER_AMOUNT=1000000alnt
|
||||
|
@ -35,7 +35,6 @@ Client-side (must be prefixed with NEXT_PUBLIC_):
|
||||
- `NEXT_PUBLIC_SOLANA_TOKEN_MINT_ADDRESS` - The mint address of the SPL token to accept
|
||||
- `NEXT_PUBLIC_SOLANA_TOKEN_RECIPIENT_ADDRESS` - The Solana address that will receive token payments
|
||||
- `NEXT_PUBLIC_SOLANA_TOKEN_SYMBOL` - The token symbol to display (e.g., "GOR")
|
||||
- `NEXT_PUBLIC_SOLANA_TOKEN_NAME` - The full token name (e.g., "GOR Token")
|
||||
- `NEXT_PUBLIC_SOLANA_TOKEN_DECIMALS` - The number of decimals for the token (e.g., 6)
|
||||
- `NEXT_PUBLIC_MIN_SOLANA_PAYMENT_AMOUNT` - The fixed payment amount required (e.g., 50)
|
||||
- `NEXT_PUBLIC_DOMAIN_SUFFIX` - Optional suffix to append to DNS names in the UI (e.g. ".example.com")
|
||||
|
@ -1,10 +1,11 @@
|
||||
import BN from 'bn.js';
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { Registry } from '@cerc-io/registry-sdk';
|
||||
import { GasPrice } from '@cosmjs/stargate';
|
||||
import axios from 'axios';
|
||||
|
||||
import { GasPrice } from '@cosmjs/stargate';
|
||||
import { verifyUnusedSolanaPayment } from '@/utils/solanaVerify';
|
||||
import { transferLNTTokens } from '@/services/laconicTransfer';
|
||||
import { getRegistry, getRegistryConfig } from '@/config';
|
||||
|
||||
// Use CAIP convention for chain ID: namespace + reference
|
||||
const SOLANA_CHAIN_ID = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'; // Solana mainnet
|
||||
@ -126,11 +127,13 @@ export const registryTransactionWithRetry = async (
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
// First check if the request body is valid JSON
|
||||
let url, txHash;
|
||||
let url, txHash, senderPublicKey;
|
||||
|
||||
try {
|
||||
const body = await request.json();
|
||||
url = body.url;
|
||||
txHash = body.txHash;
|
||||
senderPublicKey = body.senderPublicKey;
|
||||
|
||||
if (!url || !txHash) {
|
||||
return NextResponse.json({
|
||||
@ -147,7 +150,7 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
// Verify Solana payment
|
||||
console.log('Step 0: Verifying Solana token payment...');
|
||||
const paymentAmount = parseInt(process.env.NEXT_PUBLIC_MIN_SOLANA_PAYMENT_AMOUNT || '50');
|
||||
const paymentAmount = parseInt(process.env.NEXT_PUBLIC_MIN_SOLANA_PAYMENT_AMOUNT || '400000000');
|
||||
const tokenAmount = new BN(paymentAmount);
|
||||
const solanaPaymentResult = await verifyUnusedSolanaPayment(txHash, tokenAmount);
|
||||
|
||||
@ -255,19 +258,7 @@ export async function POST(request: NextRequest) {
|
||||
console.log(`Final DNS name with salt: ${cleanDnsName}`);
|
||||
|
||||
// Set up Registry config
|
||||
const config = {
|
||||
chainId: process.env.REGISTRY_CHAIN_ID!,
|
||||
rpcEndpoint: process.env.REGISTRY_RPC_ENDPOINT!,
|
||||
gqlEndpoint: process.env.REGISTRY_GQL_ENDPOINT!,
|
||||
bondId: process.env.REGISTRY_BOND_ID!,
|
||||
authority: process.env.REGISTRY_AUTHORITY!,
|
||||
privateKey: process.env.REGISTRY_USER_KEY!,
|
||||
fee: {
|
||||
gas: process.env.REGISTRY_GAS || '900000',
|
||||
fees: process.env.REGISTRY_FEES || '900000alnt',
|
||||
gasPrice: '0.001alnt', // Hardcoded valid gas price string with denomination
|
||||
},
|
||||
};
|
||||
const config = getRegistryConfig()
|
||||
|
||||
console.log('Registry config:', {
|
||||
...config,
|
||||
@ -277,14 +268,10 @@ export async function POST(request: NextRequest) {
|
||||
const deployerLrn = process.env.DEPLOYER_LRN!;
|
||||
|
||||
// Create Registry client instance
|
||||
const gasPrice = GasPrice.fromString('0.001alnt');
|
||||
const gasPrice = GasPrice.fromString(config.fee.gasPrice);
|
||||
console.log('Using manual gas price:', gasPrice);
|
||||
|
||||
const registry = new Registry(
|
||||
config.gqlEndpoint,
|
||||
config.rpcEndpoint,
|
||||
{ chainId: config.chainId, gasPrice }
|
||||
);
|
||||
const registry = getRegistry()
|
||||
|
||||
// Create LRN for the application with commit hash and salt
|
||||
// We already have the salt from earlier, so we use it directly
|
||||
@ -305,12 +292,6 @@ export async function POST(request: NextRequest) {
|
||||
app_version: '0.0.1'
|
||||
};
|
||||
|
||||
// Create fee for transaction directly
|
||||
const fee = {
|
||||
amount: [{ denom: 'alnt', amount: process.env.REGISTRY_FEES?.replace('alnt', '') || '900000' }],
|
||||
gas: process.env.REGISTRY_GAS || '900000',
|
||||
};
|
||||
|
||||
console.log('Application record data:', applicationRecord);
|
||||
|
||||
// Publish the application record
|
||||
@ -324,7 +305,6 @@ export async function POST(request: NextRequest) {
|
||||
bondId: config.bondId,
|
||||
},
|
||||
config.privateKey,
|
||||
fee
|
||||
)
|
||||
) as { id?: string };
|
||||
|
||||
@ -356,7 +336,6 @@ export async function POST(request: NextRequest) {
|
||||
lrn
|
||||
},
|
||||
config.privateKey,
|
||||
fee
|
||||
)
|
||||
);
|
||||
console.log(`Set name mapping: ${lrn} -> ${applicationRecordId}`);
|
||||
@ -369,7 +348,6 @@ export async function POST(request: NextRequest) {
|
||||
lrn: `${lrn}@${fullHash}`
|
||||
},
|
||||
config.privateKey,
|
||||
fee
|
||||
)
|
||||
);
|
||||
console.log(`Set name mapping: ${lrn}@${fullHash} -> ${applicationRecordId}`);
|
||||
@ -403,8 +381,7 @@ export async function POST(request: NextRequest) {
|
||||
external_payment: {
|
||||
chain_id: SOLANA_CHAIN_ID,
|
||||
tx_hash: txHash,
|
||||
// TODO: Take pubkey from user and add it
|
||||
// pubkey: ''
|
||||
pubkey: senderPublicKey
|
||||
}
|
||||
},
|
||||
payment: finalTxHash,
|
||||
@ -423,7 +400,6 @@ export async function POST(request: NextRequest) {
|
||||
bondId: config.bondId,
|
||||
},
|
||||
config.privateKey,
|
||||
fee
|
||||
)
|
||||
) as { id?: string };
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
import URLForm from '@/components/URLForm';
|
||||
@ -33,17 +33,6 @@ export default function Home() {
|
||||
const [shortCommitHash, setShortCommitHash] = useState<string | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const handleSolanaConnect = (walletState: SolanaWalletState) => {
|
||||
setSolanaWalletState(walletState);
|
||||
// Store wallet info globally for PaymentModal access (simplified approach)
|
||||
if (typeof window !== 'undefined') {
|
||||
(window as any).solanaWalletInfo = {
|
||||
publicKey: walletState.publicKey,
|
||||
walletType: walletState.walletType
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const handleConnectWallet = () => {
|
||||
setShowWalletConnection(true);
|
||||
};
|
||||
@ -53,50 +42,51 @@ export default function Home() {
|
||||
setShowPaymentModal(true);
|
||||
};
|
||||
|
||||
const handlePaymentComplete = async (hash: string) => {
|
||||
const handlePaymentComplete = useCallback(async (hash: string) => {
|
||||
if (!solanaWalletState.publicKey || !url) {
|
||||
return
|
||||
}
|
||||
|
||||
setTxHash(hash);
|
||||
setShowPaymentModal(false);
|
||||
setStatus('creating');
|
||||
|
||||
try {
|
||||
// Create the Laconic Registry record (payment verification is done in the API)
|
||||
if (url) {
|
||||
const result = await createApplicationDeploymentRequest(url, hash);
|
||||
|
||||
if (result.status === 'success') {
|
||||
setRecordId(result.id);
|
||||
if (result.applicationRecordId) {
|
||||
setAppRecordId(result.applicationRecordId);
|
||||
}
|
||||
if (result.lrn) {
|
||||
setLrn(result.lrn);
|
||||
}
|
||||
if (result.dns) {
|
||||
setDns(result.dns);
|
||||
}
|
||||
if (result.appName) {
|
||||
setAppName(result.appName);
|
||||
}
|
||||
if (result.repoUrl) {
|
||||
setRepoUrl(result.repoUrl);
|
||||
}
|
||||
if (result.commitHash) {
|
||||
setCommitHash(result.commitHash);
|
||||
}
|
||||
if (result.shortCommitHash) {
|
||||
setShortCommitHash(result.shortCommitHash);
|
||||
}
|
||||
setStatus('success');
|
||||
} else {
|
||||
setStatus('error');
|
||||
setError(result.message || 'Failed to create record in Laconic Registry');
|
||||
const result = await createApplicationDeploymentRequest(url, hash, solanaWalletState.publicKey);
|
||||
if (result.status === 'success') {
|
||||
setRecordId(result.id);
|
||||
if (result.applicationRecordId) {
|
||||
setAppRecordId(result.applicationRecordId);
|
||||
}
|
||||
if (result.lrn) {
|
||||
setLrn(result.lrn);
|
||||
}
|
||||
if (result.dns) {
|
||||
setDns(result.dns);
|
||||
}
|
||||
if (result.appName) {
|
||||
setAppName(result.appName);
|
||||
}
|
||||
if (result.repoUrl) {
|
||||
setRepoUrl(result.repoUrl);
|
||||
}
|
||||
if (result.commitHash) {
|
||||
setCommitHash(result.commitHash);
|
||||
}
|
||||
if (result.shortCommitHash) {
|
||||
setShortCommitHash(result.shortCommitHash);
|
||||
}
|
||||
setStatus('success');
|
||||
} else {
|
||||
setStatus('error');
|
||||
setError(result.message || 'Failed to create record in Laconic Registry');
|
||||
}
|
||||
} catch (error) {
|
||||
setStatus('error');
|
||||
setError(error instanceof Error ? error.message : 'An unknown error occurred');
|
||||
}
|
||||
};
|
||||
}, [solanaWalletState, url])
|
||||
|
||||
const handleClosePaymentModal = () => {
|
||||
setShowPaymentModal(false);
|
||||
@ -136,10 +126,9 @@ export default function Home() {
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<SolanaConnect onConnect={handleSolanaConnect} />
|
||||
<SolanaConnect onConnect={(walletState) => setSolanaWalletState(walletState)} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mb-8 p-6 rounded-lg" style={{
|
||||
background: 'var(--muted-light)',
|
||||
borderLeft: '4px solid var(--primary)',
|
||||
@ -186,6 +175,7 @@ export default function Home() {
|
||||
onClose={handleClosePaymentModal}
|
||||
url={url}
|
||||
onPaymentComplete={handlePaymentComplete}
|
||||
walletState={solanaWalletState}
|
||||
/>
|
||||
)}
|
||||
</main>
|
||||
|
@ -11,12 +11,14 @@ export default function PaymentModal({
|
||||
onClose,
|
||||
url,
|
||||
onPaymentComplete,
|
||||
walletState,
|
||||
}: PaymentModalProps) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
// Get configuration from environment variables directly
|
||||
const amount = parseInt(process.env.NEXT_PUBLIC_MIN_SOLANA_PAYMENT_AMOUNT || '50');
|
||||
const amount = parseInt(process.env.NEXT_PUBLIC_MIN_SOLANA_PAYMENT_AMOUNT || '400000000');
|
||||
|
||||
const recipientAddress = process.env.NEXT_PUBLIC_SOLANA_TOKEN_RECIPIENT_ADDRESS;
|
||||
|
||||
const handlePayment = async () => {
|
||||
@ -24,16 +26,8 @@ export default function PaymentModal({
|
||||
setError('');
|
||||
|
||||
try {
|
||||
// For Solana payments, we need wallet info from parent component
|
||||
// This is a simplified approach - in a real implementation, you'd pass wallet state
|
||||
const walletInfo = (window as any).solanaWalletInfo;
|
||||
if (!walletInfo || !walletInfo.publicKey || !walletInfo.walletType) {
|
||||
setError('Solana wallet not connected. Please connect your wallet first.');
|
||||
return;
|
||||
}
|
||||
|
||||
const tokenAmount = new BN(amount);
|
||||
const result = await sendSolanaTokenPayment(walletInfo.publicKey, tokenAmount, walletInfo.walletType);
|
||||
const result = await sendSolanaTokenPayment(walletState.publicKey!, tokenAmount, walletState.walletType!);
|
||||
|
||||
if (result.success && result.transactionSignature) {
|
||||
onPaymentComplete(result.transactionSignature);
|
||||
@ -82,7 +76,7 @@ export default function PaymentModal({
|
||||
<input
|
||||
id="amount"
|
||||
type="number"
|
||||
value={amount}
|
||||
value={amount / 1e6} // Token decimals for GOR token
|
||||
disabled={true} // Fixed amount for Solana tokens
|
||||
className="w-full p-3 pr-12 rounded-md"
|
||||
style={{
|
||||
|
@ -1,5 +1,24 @@
|
||||
import { Registry, DENOM as ALNT_DENOM } from '@cerc-io/registry-sdk';
|
||||
import { GasPrice } from '@cosmjs/stargate';
|
||||
|
||||
import { RegistryConfig } from '../types';
|
||||
|
||||
let registryInstance: Registry | null = null;
|
||||
|
||||
export const getRegistry = (): Registry => {
|
||||
if (!registryInstance) {
|
||||
const config = getRegistryConfig();
|
||||
const gasPrice = GasPrice.fromString(config.fee.gasPrice + ALNT_DENOM);
|
||||
|
||||
registryInstance = new Registry(
|
||||
config.gqlEndpoint,
|
||||
config.rpcEndpoint,
|
||||
{ chainId: config.chainId, gasPrice }
|
||||
);
|
||||
}
|
||||
return registryInstance;
|
||||
};
|
||||
|
||||
export const getRegistryConfig = (): RegistryConfig => {
|
||||
// Validate required environment variables
|
||||
const requiredEnvVars = [
|
||||
@ -25,27 +44,7 @@ export const getRegistryConfig = (): RegistryConfig => {
|
||||
authority: process.env.REGISTRY_AUTHORITY!,
|
||||
privateKey: process.env.REGISTRY_USER_KEY!,
|
||||
fee: {
|
||||
gas: process.env.REGISTRY_GAS || '900000',
|
||||
fees: process.env.REGISTRY_FEES || '900000alnt',
|
||||
gasPrice: process.env.REGISTRY_GAS_PRICE || '0.025',
|
||||
gasPrice: process.env.REGISTRY_GAS_PRICE || '0.001',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const getLaconicTransferConfig = () => {
|
||||
const requiredEnvVars = [
|
||||
'REGISTRY_USER_KEY', // Same account as the registry user
|
||||
'LACONIC_TRANSFER_AMOUNT'
|
||||
];
|
||||
|
||||
for (const envVar of requiredEnvVars) {
|
||||
if (!process.env[envVar]) {
|
||||
throw new Error(`Missing environment variable: ${envVar}`);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
prefilledPrivateKey: process.env.REGISTRY_USER_KEY!, // Use the same key as registry operations
|
||||
transferAmount: process.env.LACONIC_TRANSFER_AMOUNT!
|
||||
};
|
||||
};
|
||||
|
@ -1,28 +1,13 @@
|
||||
import { Account, DEFAULT_GAS_ESTIMATION_MULTIPLIER, parseGasAndFees, Registry } from '@cerc-io/registry-sdk';
|
||||
import { DeliverTxResponse, GasPrice } from '@cosmjs/stargate';
|
||||
import { getRegistryConfig, getLaconicTransferConfig } from '../config';
|
||||
import { LaconicTransferResult } from '../types';
|
||||
import { Account, DENOM as ALNT_DENOM } from '@cerc-io/registry-sdk';
|
||||
import { DeliverTxResponse } from '@cosmjs/stargate';
|
||||
|
||||
import { registryTransactionWithRetry } from '@/app/api/registry/route';
|
||||
|
||||
let registryInstance: Registry | null = null;
|
||||
|
||||
const getRegistry = (): Registry => {
|
||||
if (!registryInstance) {
|
||||
const config = getRegistryConfig();
|
||||
const gasPrice = GasPrice.fromString(config.fee.gasPrice + 'alnt');
|
||||
|
||||
registryInstance = new Registry(
|
||||
config.gqlEndpoint,
|
||||
config.rpcEndpoint,
|
||||
{ chainId: config.chainId, gasPrice }
|
||||
);
|
||||
}
|
||||
return registryInstance;
|
||||
};
|
||||
import { getRegistry, getRegistryConfig } from '../config';
|
||||
import { LaconicTransferResult } from '../types';
|
||||
|
||||
export const transferLNTTokens = async (): Promise<LaconicTransferResult> => {
|
||||
try {
|
||||
const transferConfig = getLaconicTransferConfig();
|
||||
const registryConfig = getRegistryConfig();
|
||||
const registry = getRegistry();
|
||||
|
||||
console.log('Resolving deployer LRN to get payment address...');
|
||||
@ -56,15 +41,18 @@ export const transferLNTTokens = async (): Promise<LaconicTransferResult> => {
|
||||
|
||||
// Find the paymentAddress attribute
|
||||
const paymentAddress = deployerRecord.attributes.paymentAddress
|
||||
const deployerMinPayment = deployerRecord.attributes.minimumPayment
|
||||
|
||||
console.log('Found payment address:', paymentAddress);
|
||||
console.log('Found minimum payment:', deployerMinPayment);
|
||||
|
||||
console.log('Initiating LNT transfer from prefilled account to payment address...');
|
||||
console.log('Initiating LNT transfer...');
|
||||
|
||||
// Send tokens from prefilled account to payment address
|
||||
const transferResult = await sendTokensToAccount(
|
||||
registryConfig.privateKey,
|
||||
paymentAddress,
|
||||
transferConfig.transferAmount
|
||||
deployerMinPayment
|
||||
);
|
||||
|
||||
console.log('LNT transfer result:', transferResult);
|
||||
@ -89,24 +77,9 @@ export const transferLNTTokens = async (): Promise<LaconicTransferResult> => {
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function to validate transfer configuration
|
||||
export const validateLaconicTransferConfig = (): { valid: boolean; error?: string } => {
|
||||
try {
|
||||
getLaconicTransferConfig();
|
||||
return { valid: true };
|
||||
} catch (error) {
|
||||
return {
|
||||
valid: false,
|
||||
error: error instanceof Error ? error.message : 'Invalid Laconic transfer configuration'
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const getAccount = async (): Promise<Account> => {
|
||||
const registryConfig = getRegistryConfig();
|
||||
|
||||
const getAccount = async (accountPrivateKey: string): Promise<Account> => {
|
||||
const account = new Account(
|
||||
Buffer.from(registryConfig.privateKey, 'hex'),
|
||||
Buffer.from(accountPrivateKey, 'hex'),
|
||||
);
|
||||
await account.init();
|
||||
|
||||
@ -115,23 +88,15 @@ const getAccount = async (): Promise<Account> => {
|
||||
|
||||
|
||||
const sendTokensToAccount = async (
|
||||
senderPrivateKey: string,
|
||||
receiverAddress: string,
|
||||
amount: string,
|
||||
): Promise<DeliverTxResponse> => {
|
||||
const registryConfig = getRegistryConfig();
|
||||
const registry = getRegistry();
|
||||
|
||||
const registry = new Registry(
|
||||
registryConfig.gqlEndpoint,
|
||||
registryConfig.rpcEndpoint,
|
||||
{ chainId: registryConfig.chainId },
|
||||
);
|
||||
|
||||
const fee = parseGasAndFees(
|
||||
registryConfig.fee.gas,
|
||||
registryConfig.fee.fees,
|
||||
);
|
||||
const account = await getAccount();
|
||||
const account = await getAccount(senderPrivateKey);
|
||||
const laconicClient = await registry.getLaconicClient(account);
|
||||
|
||||
const txResponse: DeliverTxResponse = await registryTransactionWithRetry(
|
||||
() =>
|
||||
laconicClient.sendTokens(
|
||||
@ -139,11 +104,11 @@ const sendTokensToAccount = async (
|
||||
receiverAddress,
|
||||
[
|
||||
{
|
||||
denom: 'alnt',
|
||||
denom: ALNT_DENOM,
|
||||
amount,
|
||||
},
|
||||
],
|
||||
fee || DEFAULT_GAS_ESTIMATION_MULTIPLIER,
|
||||
"auto",
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -2,7 +2,8 @@ import { CreateRecordResponse } from '../types';
|
||||
|
||||
export const createApplicationDeploymentRequest = async (
|
||||
url: string,
|
||||
txHash: string
|
||||
txHash: string,
|
||||
senderPublicKey: string,
|
||||
): Promise<CreateRecordResponse> => {
|
||||
try {
|
||||
console.log(`Creating deployment request for URL: ${url} with transaction: ${txHash} using ${process.env.NEXT_PUBLIC_SOLANA_TOKEN_SYMBOL} payment`);
|
||||
@ -13,7 +14,7 @@ export const createApplicationDeploymentRequest = async (
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ url, txHash }),
|
||||
body: JSON.stringify({ url, txHash, senderPublicKey }),
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
@ -26,8 +26,6 @@ export interface RegistryConfig {
|
||||
authority: string;
|
||||
privateKey: string;
|
||||
fee: {
|
||||
gas: string;
|
||||
fees: string;
|
||||
gasPrice: string;
|
||||
};
|
||||
}
|
||||
@ -58,6 +56,7 @@ export interface PaymentModalProps {
|
||||
onClose: () => void;
|
||||
url: string;
|
||||
onPaymentComplete: (txHash: string) => void;
|
||||
walletState: SolanaWalletState;
|
||||
}
|
||||
|
||||
export interface SolanaWalletState {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import assert from 'assert';
|
||||
import BN from 'bn.js';
|
||||
|
||||
import { Connection } from '@solana/web3.js';
|
||||
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
||||
|
||||
@ -29,18 +30,6 @@ const extractTxInfo = async (transactionSignature: string): Promise<{ authority:
|
||||
return { authority, amount };
|
||||
};
|
||||
|
||||
|
||||
// Helper to track used signatures (simple in-memory store for now)
|
||||
const usedSignatures = new Set<string>();
|
||||
|
||||
export const isSignatureUsed = (transactionSignature: string): boolean => {
|
||||
return usedSignatures.has(transactionSignature);
|
||||
};
|
||||
|
||||
export const markSignatureAsUsed = (transactionSignature: string): void => {
|
||||
usedSignatures.add(transactionSignature);
|
||||
};
|
||||
|
||||
export const verifyUnusedSolanaPayment = async (
|
||||
transactionSignature: string,
|
||||
tokenAmount: BN
|
||||
@ -51,13 +40,7 @@ export const verifyUnusedSolanaPayment = async (
|
||||
sender?: string
|
||||
}> => {
|
||||
try {
|
||||
// Check if signature is already used
|
||||
if (isSignatureUsed(transactionSignature)) {
|
||||
return {
|
||||
valid: false,
|
||||
reason: 'Transaction signature has already been used'
|
||||
};
|
||||
}
|
||||
// TODO: Check if provided signature is already used
|
||||
|
||||
// Fetch transaction details
|
||||
const transactionResult = await connection.getParsedTransaction(transactionSignature, 'confirmed');
|
||||
@ -133,9 +116,6 @@ export const verifyUnusedSolanaPayment = async (
|
||||
};
|
||||
}
|
||||
|
||||
// Mark signature as used
|
||||
markSignatureAsUsed(transactionSignature);
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
amount,
|
||||
|
Loading…
Reference in New Issue
Block a user