fix minimum rent error and lamports conversion
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
||||
} from '@solana/kit'
|
||||
import { useKitTransactionSigner, useWallet, useCluster, useSolanaClient } from '@solana/connector/react'
|
||||
import { getCreateEscrowInstructionAsync } from '@descro/sdk'
|
||||
import { lamportsFromSol } from '@/util/lamports'
|
||||
import type { Address } from '@descro/sdk'
|
||||
|
||||
function getNextEscrowId(walletAddress: string): bigint {
|
||||
@@ -66,7 +67,12 @@ export function CreateEscrowForm({ onCreated }: CreateEscrowFormProps) {
|
||||
setError('Invalid SOL amount.')
|
||||
return
|
||||
}
|
||||
const amountLamports = BigInt(Math.round(amountSolNum * 1e9))
|
||||
const amountLamports = lamportsFromSol(amountSolNum)
|
||||
// Vault is a 0-byte PDA funded entirely by the deposit; must be rent-exempt (~890,880 lamports)
|
||||
if (amountLamports < 890_880n) {
|
||||
setError('Amount too small: minimum is ~0.00089 SOL (vault must be rent-exempt).')
|
||||
return
|
||||
}
|
||||
|
||||
let resolverAddress: Address | null = null
|
||||
if (resolver.trim()) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import React from 'react'
|
||||
import { YStack, XStack, Text } from 'tamagui'
|
||||
import { StatusBadge } from './StatusBadge'
|
||||
import type { EscrowAccountWithPda } from '@descro/sdk'
|
||||
import { lamportsToSolString } from '@/util/lamports'
|
||||
function truncAddr(addr: string): string {
|
||||
return `${addr.slice(0, 4)}…${addr.slice(-4)}`
|
||||
}
|
||||
@@ -16,7 +17,7 @@ interface EscrowCardProps {
|
||||
|
||||
export function EscrowCard({ item, selected, onSelect }: EscrowCardProps) {
|
||||
const { pda, account } = item
|
||||
const solAmount = (Number(account.amount.toString()) / 1e9).toFixed(4)
|
||||
const solAmount = lamportsToSolString(account.amount, 4)
|
||||
|
||||
return (
|
||||
<YStack
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
} from '@descro/sdk'
|
||||
import type { EscrowAccountWithPda } from '@descro/sdk'
|
||||
import { useEscrowDetail } from '@/hooks/useEscrowDetail'
|
||||
import { lamportsToSolString } from '@/util/lamports'
|
||||
|
||||
interface EscrowDetailProps {
|
||||
item: EscrowAccountWithPda
|
||||
@@ -50,7 +51,7 @@ export function EscrowDetail({ item, onAction }: EscrowDetailProps) {
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [success, setSuccess] = useState<string | null>(null)
|
||||
|
||||
const solAmount = (Number(escrow.amount) / 1e9).toFixed(4)
|
||||
const solAmount = lamportsToSolString(escrow.amount, 4)
|
||||
const isSeller = address != null && address === escrow.seller
|
||||
const isBuyer = address != null && address === escrow.buyer
|
||||
const resolverAddr = isSome(escrow.disputeResolver) ? escrow.disputeResolver.value : null
|
||||
|
||||
20
app/src/util/lamports.ts
Normal file
20
app/src/util/lamports.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { lamports, type Lamports } from "@solana/kit";
|
||||
|
||||
const LAMPORTS_PER_SOL = 1_000_000_000n;
|
||||
|
||||
export function lamportsFromSol(sol: number): Lamports {
|
||||
return lamports(BigInt(Math.round(sol * Number(LAMPORTS_PER_SOL))));
|
||||
}
|
||||
|
||||
export function lamportsToSolString(amount: Lamports, maxDecimals = 2): string {
|
||||
const whole = amount / LAMPORTS_PER_SOL;
|
||||
const fractional = amount % LAMPORTS_PER_SOL;
|
||||
|
||||
if (fractional === 0n) return whole.toString();
|
||||
|
||||
const decimals = fractional.toString().padStart(9, "0").slice(0, maxDecimals);
|
||||
|
||||
if (decimals.replace(/0+$/, "") === "") return whole.toString();
|
||||
|
||||
return `${whole}.${decimals.replace(/0+$/, "")}`;
|
||||
}
|
||||
@@ -16,4 +16,6 @@ pub enum EscrowError {
|
||||
DisputeTimeoutNotReached,
|
||||
#[msg("Vault balance is insufficient for the requested escrow amount")]
|
||||
InsufficientVaultBalance,
|
||||
#[msg("Amount must be at least rent-exempt minimum for the vault (~890880 lamports)")]
|
||||
AmountBelowRentMinimum,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use anchor_lang::prelude::*;
|
||||
use crate::state::{EscrowAccount, EscrowState};
|
||||
use crate::EscrowError;
|
||||
|
||||
#[derive(Accounts)]
|
||||
#[instruction(amount: u64, dispute_resolver: Option<Pubkey>, escrow_id: u64)]
|
||||
@@ -36,6 +37,9 @@ pub fn handler(
|
||||
dispute_resolver: Option<Pubkey>,
|
||||
escrow_id: u64,
|
||||
) -> Result<()> {
|
||||
let rent_min = Rent::get()?.minimum_balance(0);
|
||||
require!(amount >= rent_min, EscrowError::AmountBelowRentMinimum);
|
||||
|
||||
let escrow = &mut ctx.accounts.escrow_account;
|
||||
escrow.seller = ctx.accounts.seller.key();
|
||||
escrow.buyer = ctx.accounts.buyer.key();
|
||||
|
||||
Reference in New Issue
Block a user