Allow setting payment amount without decimals

This commit is contained in:
Shreerang Kale 2025-07-21 17:52:56 +05:30
parent 0e23e2f3dc
commit 5fccab228b
5 changed files with 243 additions and 17 deletions

View File

@ -9,7 +9,7 @@ NEXT_PUBLIC_SOLANA_TOKEN_MINT_ADDRESS=71Jvq4Epe2FCJ7JFSF7jLXdNk1Wy4Bhqd9iL6bEFEL
NEXT_PUBLIC_SOLANA_TOKEN_RECIPIENT_ADDRESS=FFDx3SdAEeXrp6BTmStB4BDHpctGsaasZq4FFcowRobY NEXT_PUBLIC_SOLANA_TOKEN_RECIPIENT_ADDRESS=FFDx3SdAEeXrp6BTmStB4BDHpctGsaasZq4FFcowRobY
NEXT_PUBLIC_SOLANA_TOKEN_SYMBOL=GOR NEXT_PUBLIC_SOLANA_TOKEN_SYMBOL=GOR
NEXT_PUBLIC_SOLANA_TOKEN_DECIMALS=6 NEXT_PUBLIC_SOLANA_TOKEN_DECIMALS=6
NEXT_PUBLIC_SOLANA_PAYMENT_AMOUNT=400000000 # Approx. 5 USD NEXT_PUBLIC_SOLANA_PAYMENT_AMOUNT=400 # Approx. 5 USD
# UI Configuration # UI Configuration
NEXT_PUBLIC_EXAMPLE_URL=https://git.vdb.to/cerc-io/test-progressive-web-app NEXT_PUBLIC_EXAMPLE_URL=https://git.vdb.to/cerc-io/test-progressive-web-app
@ -20,10 +20,10 @@ NEXT_PUBLIC_EXAMPLE_URL=https://git.vdb.to/cerc-io/test-progressive-web-app
REGISTRY_CHAIN_ID=laconic-mainnet REGISTRY_CHAIN_ID=laconic-mainnet
REGISTRY_RPC_ENDPOINT=https://laconicd-mainnet-1.laconic.com REGISTRY_RPC_ENDPOINT=https://laconicd-mainnet-1.laconic.com
REGISTRY_GQL_ENDPOINT=https://laconicd-mainnet-1.laconic.com/graphql REGISTRY_GQL_ENDPOINT=https://laconicd-mainnet-1.laconic.com/graphql
REGISTRY_GAS_PRICE=0.001
REGISTRY_BOND_ID= REGISTRY_BOND_ID=
REGISTRY_AUTHORITY= REGISTRY_AUTHORITY=
REGISTRY_USER_KEY= REGISTRY_USER_KEY=
REGISTRY_GAS_PRICE=0.001
# Application Configuration # Application Configuration
DEPLOYER_LRN= DEPLOYER_LRN=

231
CLAUDE.md Normal file
View File

@ -0,0 +1,231 @@
# CLAUDE.md - GOR Deploy Development Guide
## Project Overview
**GOR Deploy** is a Next.js application that bridges Solana blockchain token payments with Laconic Registry deployments. Users pay with GOR tokens (or any configurable Solana SPL token) and the app creates deployment records in the Laconic Registry for frontend applications.
## Quick Commands
```bash
# Development
npm run dev # Start development server (http://localhost:3000)
npm run build # Build for production
npm start # Start production server
npm run lint # Run ESLint
# Testing
# No test framework configured - check README for testing approach
```
## Project Architecture
### Tech Stack
- **Frontend**: Next.js 15.3.1 with React 19
- **Styling**: TailwindCSS 4
- **Blockchain**:
- Solana Web3.js for payments
- @cerc-io/registry-sdk for Laconic Registry
- CosmJS for Cosmos blockchain interactions
- **Wallet Integration**: Phantom & Solflare
- **Language**: TypeScript
### Key Dependencies
- `@solana/web3.js` - Solana blockchain interactions
- `@solana/spl-token` - SPL token handling
- `@cerc-io/registry-sdk` - Laconic Registry operations
- `@cosmjs/stargate` - Cosmos blockchain operations
- `axios` - HTTP requests for GitHub API
- `bn.js` - Big number arithmetic
- `big.js` - Decimal arithmetic
## Application Flow
1. **Wallet Connection**: User connects Phantom or Solflare wallet
2. **URL Input**: User enters repository URL to deploy
3. **Payment**: Fixed amount payment in GOR/SPL tokens to configured recipient
4. **Verification**: Server verifies Solana transaction (5-minute window)
5. **LNT Transfer**: Server transfers LNT tokens for registry fees
6. **Registry Records**: Creates ApplicationRecord and ApplicationDeploymentRequest
7. **Name Mapping**: Sets LRN mappings in Laconic Registry
## Key Files and Components
### Frontend Components
- `src/app/page.tsx` - Main application page with 3-step flow
- `src/components/PaymentModal.tsx` - Solana payment interface
- `src/components/SolanaConnect.tsx` - Wallet connection UI
- `src/components/URLForm.tsx` - URL input form
- `src/components/StatusDisplay.tsx` - Deployment status display
### Services and Utils
- `src/services/solana.ts` - Solana wallet and payment operations
- `src/services/registry.ts` - Client-side registry service wrapper
- `src/services/laconicTransfer.ts` - LNT token transfer logic
- `src/utils/solanaVerify.ts` - Payment verification with replay protection
- `src/config/index.ts` - Registry configuration management
### API Routes
- `src/app/api/registry/route.ts` - Main server-side registry operations
## Environment Configuration
### Client-side Variables (NEXT_PUBLIC_*)
```bash
NEXT_PUBLIC_SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
NEXT_PUBLIC_SOLANA_TOKEN_MINT_ADDRESS=<SPL_TOKEN_MINT>
NEXT_PUBLIC_SOLANA_TOKEN_RECIPIENT_ADDRESS=<RECIPIENT_WALLET>
NEXT_PUBLIC_SOLANA_TOKEN_SYMBOL=GOR
NEXT_PUBLIC_SOLANA_TOKEN_DECIMALS=6
NEXT_PUBLIC_SOLANA_PAYMENT_AMOUNT=400
NEXT_PUBLIC_DOMAIN_SUFFIX=.example.com
NEXT_PUBLIC_EXAMPLE_URL=https://github.com/cerc-io/laconic-registry-cli
```
### 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
REGISTRY_BOND_ID=<BOND_ID>
REGISTRY_AUTHORITY=<AUTHORITY_NAME>
REGISTRY_USER_KEY=<PRIVATE_KEY>
APP_NAME=gor-deploy
DEPLOYER_LRN=<DEPLOYER_LRN>
```
## Code Patterns and Conventions
### State Management
- Uses React `useState` for component state
- No global state management library
- Dynamic imports to avoid SSR issues with browser APIs
### Error Handling
- Comprehensive try-catch blocks in all async operations
- User-friendly error messages in UI
- Server-side error logging with detailed context
### Security Best Practices
- Environment variables for sensitive data
- Transaction verification with replay protection
- Proper SPL token account creation and validation
- Private key never exposed to client-side
## Development Workflow
### Adding New Features
1. **Client Components**: Add to `src/components/`
2. **Services**: Add to `src/services/`
3. **API Routes**: Add to `src/app/api/`
4. **Types**: Update `src/types/index.ts`
### Payment Integration
- All payment logic in `src/services/solana.ts`
- Verification logic in `src/utils/solanaVerify.ts`
- Transaction signing via wallet adapters
### Registry Integration
- Registry operations in `src/app/api/registry/route.ts`
- Configuration in `src/config/index.ts`
- LRN format: `lrn://{authority}/applications/{app-name}-{commit-hash}`
## DNS and Resource Naming
### DNS Name Generation
Format: `{sanitized-repo-name}-{7-char-commit-hash}`
- Sanitized to be DNS-compatible (alphanumeric + dashes)
- Max 63 characters per DNS label
- Always lowercase
- Random salt removed (commit hash provides uniqueness)
### LRN (Laconic Resource Name) Format
Format: `lrn://{authority}/applications/{app-name}-{commit-hash}`
- Matches DNS naming for consistency
- Includes both versioned and unversioned mappings
## Transaction Flow Details
### Solana Payment Verification
- 5-minute transaction window
- Amount verification against configured payment
- Recipient address validation
- Replay attack protection (TODO: implement used transaction tracking)
### Laconic Registry Operations
1. **ApplicationRecord**: Repository metadata and commit info
2. **Name Mappings**: LRN pointing to application record
3. **ApplicationDeploymentRequest**: Deployment configuration with payment proof
## Common Development Tasks
### Adding New Wallet Support
1. Update `SolanaWalletType` in `src/types/index.ts`
2. Add wallet logic to `src/services/solana.ts`
3. Update `SolanaConnect.tsx` component
### Modifying Payment Verification
- Update logic in `src/utils/solanaVerify.ts`
- Consider replay protection requirements
- Test with various transaction types
### Registry Schema Changes
- Update record structures in `src/app/api/registry/route.ts`
- Ensure compatibility with Laconic Registry schema
- Test with registry validation
## Deployment Considerations
### Production Setup
- All environment variables must be set
- HTTPS required for wallet connections
- Consider rate limiting for API routes
- Monitor gas fees and LNT transfer costs
### Docker Deployment
- Dockerfile provided in project root
- Build optimization for Next.js production
- Environment variables via docker-compose or k8s secrets
## Troubleshooting
### Common Issues
- **Wallet connection fails**: Check HTTPS and wallet extension
- **Transaction verification fails**: Check RPC URL and transaction timing
- **Registry errors**: Verify all REGISTRY_* environment variables
- **LNT transfer fails**: Check private key balance and permissions
### Debug Tools
- Browser console for client-side debugging
- Server logs for API route debugging
- Solana Explorer for transaction verification
- Registry CLI for direct registry interactions
## Testing Strategy
- Manual testing with real wallets and tokens
- Use testnet/devnet for development
- Test transaction verification edge cases
- Verify registry record creation and name mappings
## Related Projects
This application references:
- `snowballtools-base/packages/backend/src/registry.ts`
- Original `hosted-frontends/deploy-atom.sh`
- Laconic Registry CLI tools
## Security Considerations
- Private keys stored securely server-side only
- Transaction replay protection implemented
- Input validation on all user inputs
- Secure RPC endpoint usage
- Wallet signature verification
## Future Enhancements
- Implement transaction replay protection database
- Add support for custom deployment configurations
- Enhanced error recovery and retry logic
- Monitoring and analytics integration
- Multi-chain payment support

View File

@ -179,7 +179,10 @@ export async function POST(request: NextRequest) {
// Verify Solana payment // Verify Solana payment
console.log('Step 0: Verifying Solana token payment...'); console.log('Step 0: Verifying Solana token payment...');
const paymentAmount = parseInt(process.env.NEXT_PUBLIC_SOLANA_PAYMENT_AMOUNT!); const paymentAmount = parseInt(process.env.NEXT_PUBLIC_SOLANA_PAYMENT_AMOUNT!);
const tokenAmount = new BN(paymentAmount); const decimals = parseInt(process.env.NEXT_PUBLIC_SOLANA_TOKEN_DECIMALS!);
const fullAmount = paymentAmount * Math.pow(10, decimals);
const tokenAmount = new BN(fullAmount);
const solanaPaymentResult = await verifyUnusedSolanaPayment(connection, txHash, tokenAmount); const solanaPaymentResult = await verifyUnusedSolanaPayment(connection, txHash, tokenAmount);
if (!solanaPaymentResult.valid) { if (!solanaPaymentResult.valid) {

View File

@ -26,16 +26,7 @@ export default function PaymentModal({
// Get configuration from environment variables directly // Get configuration from environment variables directly
const amount = parseInt(process.env.NEXT_PUBLIC_SOLANA_PAYMENT_AMOUNT!); const amount = parseInt(process.env.NEXT_PUBLIC_SOLANA_PAYMENT_AMOUNT!);
const decimals = parseInt(process.env.NEXT_PUBLIC_SOLANA_TOKEN_DECIMALS!);
const divisor = useMemo(() => {
const decimalsEnv = process.env.NEXT_PUBLIC_SOLANA_TOKEN_DECIMALS;
const decimals = parseInt(decimalsEnv!, 10);
if (isNaN(decimals)) {
console.warn("Invalid NEXT_PUBLIC_SOLANA_TOKEN_DECIMALS; defaulting to 6.");
return 1e6;
}
return 10 ** decimals;
}, []);
const recipientAddress = process.env.NEXT_PUBLIC_SOLANA_TOKEN_RECIPIENT_ADDRESS; const recipientAddress = process.env.NEXT_PUBLIC_SOLANA_TOKEN_RECIPIENT_ADDRESS;
@ -44,7 +35,9 @@ export default function PaymentModal({
setError(''); setError('');
try { try {
const tokenAmount = new BN(amount); const fullAmount = amount * Math.pow(10, decimals);
const tokenAmount = new BN(fullAmount);
const result = await sendSolanaTokenPayment(connection, walletState.publicKey!, tokenAmount, walletState.walletType!); const result = await sendSolanaTokenPayment(connection, walletState.publicKey!, tokenAmount, walletState.walletType!);
if (result.success && result.transactionSignature) { if (result.success && result.transactionSignature) {
@ -57,7 +50,7 @@ export default function PaymentModal({
} finally { } finally {
setLoading(false); setLoading(false);
} }
}, [connection, walletState, amount, onPaymentComplete]); }, [connection, walletState, amount, decimals, onPaymentComplete]);
if (!isOpen) return null; if (!isOpen) return null;
@ -94,7 +87,7 @@ export default function PaymentModal({
<input <input
id="amount" id="amount"
type="number" type="number"
value={amount / divisor} value={amount}
disabled={true} // Fixed amount for Solana tokens disabled={true} // Fixed amount for Solana tokens
className="w-full p-3 pr-12 rounded-md" className="w-full p-3 pr-12 rounded-md"
style={{ style={{

View File

@ -1,4 +1,3 @@
import assert from 'assert';
import BN from 'bn.js'; import BN from 'bn.js';
import { Connection, PublicKey } from '@solana/web3.js'; import { Connection, PublicKey } from '@solana/web3.js';