Take deployment cost from published pricing record
This commit is contained in:
parent
64b6b1082d
commit
6c2ee093a2
11
.env.example
11
.env.example
@ -1,4 +1,4 @@
|
||||
# Client-side environment variables (must be prefixed with NEXT_PUBLIC_)
|
||||
# Client-side environment variables must be prefixed with NEXT_PUBLIC_
|
||||
|
||||
# Solana Payment Configuration
|
||||
# TODO: Use different RPC URL or use browser wallet
|
||||
@ -17,12 +17,11 @@ NEXT_PUBLIC_SOLANA_TOKEN_RECIPIENT_ADDRESS=FFDx3SdAEeXrp6BTmStB4BDHpctGsaasZq4FF
|
||||
# UI Configuration
|
||||
NEXT_PUBLIC_EXAMPLE_URL=https://git.vdb.to/cerc-io/test-progressive-web-app
|
||||
|
||||
# Server-side environment variables
|
||||
|
||||
# Laconic Registry Configuration
|
||||
REGISTRY_CHAIN_ID=laconic-mainnet
|
||||
REGISTRY_RPC_ENDPOINT=https://laconicd-mainnet-1.laconic.com
|
||||
REGISTRY_GQL_ENDPOINT=https://laconicd-mainnet-1.laconic.com/graphql
|
||||
NEXT_PUBLIC_REGISTRY_CHAIN_ID=laconic-mainnet
|
||||
NEXT_PUBLIC_REGISTRY_RPC_ENDPOINT=https://laconicd-mainnet-1.laconic.com
|
||||
NEXT_PUBLIC_REGISTRY_GQL_ENDPOINT=https://laconicd-mainnet-1.laconic.com/graphql
|
||||
NEXT_PUBLIC_PRICING_RECORD_LRN=
|
||||
REGISTRY_GAS_PRICE=0.001
|
||||
REGISTRY_BOND_ID=
|
||||
REGISTRY_AUTHORITY=
|
||||
|
@ -106,9 +106,9 @@ NEXT_PUBLIC_EXAMPLE_URL=https://git.vdb.to/cerc-io/test-progressive-web-app
|
||||
|
||||
### Server-side Variables
|
||||
```bash
|
||||
REGISTRY_CHAIN_ID=laconic-mainnet
|
||||
REGISTRY_GQL_ENDPOINT=https://laconicd-mainnet-1.laconic.com/api
|
||||
REGISTRY_RPC_ENDPOINT=https://laconicd-mainnet-1.laconic.com
|
||||
NEXT_PUBLIC_REGISTRY_CHAIN_ID=laconic-mainnet
|
||||
NEXT_PUBLIC_REGISTRY_GQL_ENDPOINT=https://laconicd-mainnet-1.laconic.com/api
|
||||
NEXT_PUBLIC_REGISTRY_RPC_ENDPOINT=https://laconicd-mainnet-1.laconic.com
|
||||
REGISTRY_BOND_ID=<BOND_ID>
|
||||
REGISTRY_AUTHORITY=<AUTHORITY_NAME>
|
||||
REGISTRY_USER_KEY=<PRIVATE_KEY>
|
||||
|
@ -284,9 +284,9 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
// Validate required environment variables for Solana payments
|
||||
const requiredEnvVars = [
|
||||
'REGISTRY_CHAIN_ID',
|
||||
'REGISTRY_GQL_ENDPOINT',
|
||||
'REGISTRY_RPC_ENDPOINT',
|
||||
'NEXT_PUBLIC_REGISTRY_CHAIN_ID',
|
||||
'NEXT_PUBLIC_REGISTRY_GQL_ENDPOINT',
|
||||
'NEXT_PUBLIC_REGISTRY_RPC_ENDPOINT',
|
||||
'REGISTRY_BOND_ID',
|
||||
'REGISTRY_AUTHORITY',
|
||||
'REGISTRY_USER_KEY', // This is the same as the prefilled account for LNT transfers
|
||||
|
@ -1,11 +1,12 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useState, useEffect } from 'react';
|
||||
import { useCallback, useState, useEffect, useMemo } from 'react';
|
||||
import assert from 'assert';
|
||||
|
||||
import { Connection } from '@solana/web3.js';
|
||||
import { useConnection, useWallet } from '@solana/wallet-adapter-react';
|
||||
|
||||
import { getRegistry } from '@/config';
|
||||
import { sendSolanaPayment } from '@/services/solana';
|
||||
import { getRequiredTokenInfo, RequiredTokenInfo } from '@/services/jupiter-price';
|
||||
import { PaymentMethod, PaymentModalProps, PaymentRequest } from '@/types';
|
||||
@ -16,6 +17,26 @@ assert(!IS_NAT_GOR_TRANSFER_ENABLED || process.env.NEXT_PUBLIC_GORBAGANA_RPC_URL
|
||||
|
||||
const GORBAGANA_RPC_URL = process.env.NEXT_PUBLIC_GORBAGANA_RPC_URL;
|
||||
|
||||
assert(process.env.NEXT_PUBLIC_SOLANA_RPC_URL, 'SOLANA_RPC_URL is required');
|
||||
assert(process.env.NEXT_PUBLIC_PRICING_RECORD_LRN, 'DEPLOYMENT_RECORD_LRN is required');
|
||||
|
||||
const PRICING_RECORD_LRN = process.env.NEXT_PUBLIC_PRICING_RECORD_LRN;
|
||||
const SUPPORTED_CURRENCY = "USD";
|
||||
const VALID_PRICING_RECORD_TYPE = "webapp-deployment";
|
||||
|
||||
interface DeploymentCostInfo {
|
||||
amount: string;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
interface PricingRecordAttributes {
|
||||
amount: string;
|
||||
currency: string;
|
||||
for: string;
|
||||
type: string;
|
||||
version: string;
|
||||
}
|
||||
|
||||
export default function PaymentModal({
|
||||
isOpen,
|
||||
onClose,
|
||||
@ -23,28 +44,55 @@ export default function PaymentModal({
|
||||
onPaymentComplete,
|
||||
}: PaymentModalProps) {
|
||||
const { selectedPaymentMethod: paymentMethod } = usePaymentMethod();
|
||||
|
||||
const { connection: solanaConnection } = useConnection();
|
||||
const { wallet, publicKey } = useWallet();
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const [tokenAmount, setTokenAmount] = useState<number>(0);
|
||||
const [tokenDecimals, setTokenDecimals] = useState<number>(6); // Default fallback
|
||||
const [loadingPrice, setLoadingPrice] = useState(false);
|
||||
const [loadingPrice, setLoadingPrice] = useState(true);
|
||||
const [deploymentCostInfo, setDeploymentCostInfo] = useState<DeploymentCostInfo>();
|
||||
|
||||
const { wallet, publicKey } = useWallet();
|
||||
useEffect(() => {
|
||||
const registry = getRegistry();
|
||||
|
||||
const resolveDeploymentCostInfo = async () => {
|
||||
const result = await registry.resolveNames([PRICING_RECORD_LRN!])
|
||||
const PricingRecordAttributes: PricingRecordAttributes = result[0].attributes;
|
||||
|
||||
if (PricingRecordAttributes.type !== VALID_PRICING_RECORD_TYPE) {
|
||||
throw new Error(`Incorrect pricing record type: ${PricingRecordAttributes.type}. Please provide correct pricing record lrn`)
|
||||
}
|
||||
|
||||
if (PricingRecordAttributes.currency !== SUPPORTED_CURRENCY) {
|
||||
throw new Error(`Unsupported currency found in pricing record: ${PricingRecordAttributes.currency}`)
|
||||
}
|
||||
|
||||
setDeploymentCostInfo({
|
||||
amount: PricingRecordAttributes.amount,
|
||||
currency:PricingRecordAttributes.currency
|
||||
})
|
||||
}
|
||||
|
||||
resolveDeploymentCostInfo();
|
||||
}, []);
|
||||
|
||||
// Get configuration from environment variables
|
||||
const targetUsdAmount = parseFloat(process.env.NEXT_PUBLIC_SOLANA_PAYMENT_AMOUNT_USD!);
|
||||
const deploymentCost = useMemo(() => {
|
||||
if (!deploymentCostInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
return parseInt(deploymentCostInfo.amount, 10);
|
||||
}, [deploymentCostInfo])
|
||||
|
||||
const mintAddress = process.env.NEXT_PUBLIC_SOLANA_TOKEN_MINT_ADDRESS!;
|
||||
const tokenSymbol = process.env.NEXT_PUBLIC_SOLANA_TOKEN_SYMBOL;
|
||||
|
||||
// Fetch payment amount based on USD price for both payment methods
|
||||
useEffect(() => {
|
||||
if (!isOpen || !paymentMethod) {
|
||||
setLoadingPrice(false);
|
||||
return;
|
||||
}
|
||||
if (!isOpen || !deploymentCost || !paymentMethod) return;
|
||||
|
||||
const fetchPaymentAmount = async () => {
|
||||
setLoadingPrice(true);
|
||||
@ -54,10 +102,10 @@ export default function PaymentModal({
|
||||
let requiredTokenInfo: RequiredTokenInfo
|
||||
if (paymentMethod === PaymentMethod.NAT_GOR) {
|
||||
// Fetch native GOR amount using solana GOR token price
|
||||
requiredTokenInfo = await getRequiredTokenInfo(targetUsdAmount, SOLANA_GOR_MINT_ADDRESS);
|
||||
requiredTokenInfo = await getRequiredTokenInfo(deploymentCost, SOLANA_GOR_MINT_ADDRESS);
|
||||
} else if (paymentMethod === PaymentMethod.SPL_TOKEN) {
|
||||
// Fetch SPL token amount using token mint price
|
||||
requiredTokenInfo = await getRequiredTokenInfo(targetUsdAmount, mintAddress);
|
||||
requiredTokenInfo = await getRequiredTokenInfo(deploymentCost, mintAddress);
|
||||
} else {
|
||||
setError('Invalid payment method');
|
||||
return;
|
||||
@ -74,7 +122,7 @@ export default function PaymentModal({
|
||||
};
|
||||
|
||||
fetchPaymentAmount();
|
||||
}, [isOpen, paymentMethod, targetUsdAmount, mintAddress]);
|
||||
}, [isOpen, paymentMethod, deploymentCost, mintAddress]);
|
||||
|
||||
// Initialize state when modal opens
|
||||
useEffect(() => {
|
||||
@ -186,7 +234,7 @@ export default function PaymentModal({
|
||||
<div className="relative">
|
||||
<input
|
||||
type="text"
|
||||
value={targetUsdAmount}
|
||||
value={`$${deploymentCost}`}
|
||||
disabled={true}
|
||||
className="w-full p-3 pr-12 rounded-md"
|
||||
style={{
|
||||
|
@ -22,9 +22,9 @@ export const getRegistry = (): Registry => {
|
||||
export const getRegistryConfig = (): RegistryConfig => {
|
||||
// Validate required environment variables
|
||||
const requiredEnvVars = [
|
||||
'REGISTRY_CHAIN_ID',
|
||||
'REGISTRY_GQL_ENDPOINT',
|
||||
'REGISTRY_RPC_ENDPOINT',
|
||||
'NEXT_PUBLIC_REGISTRY_CHAIN_ID',
|
||||
'NEXT_PUBLIC_REGISTRY_GQL_ENDPOINT',
|
||||
'NEXT_PUBLIC_REGISTRY_RPC_ENDPOINT',
|
||||
'REGISTRY_BOND_ID',
|
||||
'REGISTRY_AUTHORITY',
|
||||
'REGISTRY_USER_KEY'
|
||||
@ -37,9 +37,9 @@ export const getRegistryConfig = (): RegistryConfig => {
|
||||
}
|
||||
|
||||
return {
|
||||
chainId: process.env.REGISTRY_CHAIN_ID!,
|
||||
rpcEndpoint: process.env.REGISTRY_RPC_ENDPOINT!,
|
||||
gqlEndpoint: process.env.REGISTRY_GQL_ENDPOINT!,
|
||||
chainId: process.env.NEXT_PUBLIC_REGISTRY_CHAIN_ID!,
|
||||
rpcEndpoint: process.env.NEXT_PUBLIC_REGISTRY_RPC_ENDPOINT!,
|
||||
gqlEndpoint: process.env.NEXT_PUBLIC_REGISTRY_GQL_ENDPOINT!,
|
||||
bondId: process.env.REGISTRY_BOND_ID!,
|
||||
authority: process.env.REGISTRY_AUTHORITY!,
|
||||
privateKey: process.env.REGISTRY_USER_KEY!,
|
||||
|
Loading…
Reference in New Issue
Block a user