Take deployment cost from published pricing record

This commit is contained in:
Shreerang Kale 2025-07-22 17:11:39 +05:30
parent cd409c38d8
commit 90eb55e9bc
5 changed files with 74 additions and 24 deletions

View File

@ -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 Token Payment Configuration
# TODO: Use different RPC URL or use browser wallet
@ -13,12 +13,11 @@ NEXT_PUBLIC_SOLANA_PAYMENT_AMOUNT_USD=5 # Payment amount in USD
# 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=

View File

@ -82,9 +82,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>

View File

@ -231,9 +231,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

View File

@ -9,9 +9,28 @@ import { Connection } from '@solana/web3.js';
import { sendSolanaTokenPayment } from '@/services/solana';
import { getRequiredTokenInfo } from '@/services/jupiter-price';
import { PaymentModalProps } from '@/types';
import { getRegistry } from '@/config';
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 SOLANA_RPC_URL = process.env.NEXT_PUBLIC_SOLANA_RPC_URL;
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,
@ -25,24 +44,56 @@ export default function PaymentModal({
const [tokenAmount, setTokenAmount] = useState<number>(0);
const [tokenDecimals, setTokenDecimals] = useState<number>(6); // Default fallback
const [loadingPrice, setLoadingPrice] = useState(true);
const [deploymentCostInfo, setDeploymentCostInfo] = useState<DeploymentCostInfo>();
const connection = useMemo(() => new Connection(SOLANA_RPC_URL), [])
const connection = useMemo(() => new Connection(SOLANA_RPC_URL), []);
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 recipientAddress = process.env.NEXT_PUBLIC_SOLANA_TOKEN_RECIPIENT_ADDRESS;
// Fetch token amount based on USD price
useEffect(() => {
if (!isOpen) return;
if (!isOpen || !deploymentCost) return;
const fetchTokenAmount = async () => {
setLoadingPrice(true);
setError('');
try {
const {requiredAmountInBaseUnits, decimals} = await getRequiredTokenInfo(targetUsdAmount, mintAddress)
const {requiredAmountInBaseUnits, decimals} = await getRequiredTokenInfo(deploymentCost, mintAddress);
setTokenAmount(requiredAmountInBaseUnits);
setTokenDecimals(decimals);
} catch (error) {
@ -54,7 +105,7 @@ export default function PaymentModal({
};
fetchTokenAmount();
}, [isOpen, targetUsdAmount, mintAddress]);
}, [isOpen, deploymentCost, mintAddress]);
const handlePayment = useCallback(async () => {
if (tokenAmount === 0 || loadingPrice) {
@ -117,7 +168,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={{

View File

@ -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!,