fix minimum rent error and lamports conversion
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
|||||||
} from '@solana/kit'
|
} from '@solana/kit'
|
||||||
import { useKitTransactionSigner, useWallet, useCluster, useSolanaClient } from '@solana/connector/react'
|
import { useKitTransactionSigner, useWallet, useCluster, useSolanaClient } from '@solana/connector/react'
|
||||||
import { getCreateEscrowInstructionAsync } from '@descro/sdk'
|
import { getCreateEscrowInstructionAsync } from '@descro/sdk'
|
||||||
|
import { lamportsFromSol } from '@/util/lamports'
|
||||||
import type { Address } from '@descro/sdk'
|
import type { Address } from '@descro/sdk'
|
||||||
|
|
||||||
function getNextEscrowId(walletAddress: string): bigint {
|
function getNextEscrowId(walletAddress: string): bigint {
|
||||||
@@ -66,7 +67,12 @@ export function CreateEscrowForm({ onCreated }: CreateEscrowFormProps) {
|
|||||||
setError('Invalid SOL amount.')
|
setError('Invalid SOL amount.')
|
||||||
return
|
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
|
let resolverAddress: Address | null = null
|
||||||
if (resolver.trim()) {
|
if (resolver.trim()) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import React from 'react'
|
|||||||
import { YStack, XStack, Text } from 'tamagui'
|
import { YStack, XStack, Text } from 'tamagui'
|
||||||
import { StatusBadge } from './StatusBadge'
|
import { StatusBadge } from './StatusBadge'
|
||||||
import type { EscrowAccountWithPda } from '@descro/sdk'
|
import type { EscrowAccountWithPda } from '@descro/sdk'
|
||||||
|
import { lamportsToSolString } from '@/util/lamports'
|
||||||
function truncAddr(addr: string): string {
|
function truncAddr(addr: string): string {
|
||||||
return `${addr.slice(0, 4)}…${addr.slice(-4)}`
|
return `${addr.slice(0, 4)}…${addr.slice(-4)}`
|
||||||
}
|
}
|
||||||
@@ -16,7 +17,7 @@ interface EscrowCardProps {
|
|||||||
|
|
||||||
export function EscrowCard({ item, selected, onSelect }: EscrowCardProps) {
|
export function EscrowCard({ item, selected, onSelect }: EscrowCardProps) {
|
||||||
const { pda, account } = item
|
const { pda, account } = item
|
||||||
const solAmount = (Number(account.amount.toString()) / 1e9).toFixed(4)
|
const solAmount = lamportsToSolString(account.amount, 4)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<YStack
|
<YStack
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import {
|
|||||||
} from '@descro/sdk'
|
} from '@descro/sdk'
|
||||||
import type { EscrowAccountWithPda } from '@descro/sdk'
|
import type { EscrowAccountWithPda } from '@descro/sdk'
|
||||||
import { useEscrowDetail } from '@/hooks/useEscrowDetail'
|
import { useEscrowDetail } from '@/hooks/useEscrowDetail'
|
||||||
|
import { lamportsToSolString } from '@/util/lamports'
|
||||||
|
|
||||||
interface EscrowDetailProps {
|
interface EscrowDetailProps {
|
||||||
item: EscrowAccountWithPda
|
item: EscrowAccountWithPda
|
||||||
@@ -50,7 +51,7 @@ export function EscrowDetail({ item, onAction }: EscrowDetailProps) {
|
|||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
const [success, setSuccess] = 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 isSeller = address != null && address === escrow.seller
|
||||||
const isBuyer = address != null && address === escrow.buyer
|
const isBuyer = address != null && address === escrow.buyer
|
||||||
const resolverAddr = isSome(escrow.disputeResolver) ? escrow.disputeResolver.value : null
|
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,
|
DisputeTimeoutNotReached,
|
||||||
#[msg("Vault balance is insufficient for the requested escrow amount")]
|
#[msg("Vault balance is insufficient for the requested escrow amount")]
|
||||||
InsufficientVaultBalance,
|
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 anchor_lang::prelude::*;
|
||||||
use crate::state::{EscrowAccount, EscrowState};
|
use crate::state::{EscrowAccount, EscrowState};
|
||||||
|
use crate::EscrowError;
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
#[instruction(amount: u64, dispute_resolver: Option<Pubkey>, escrow_id: u64)]
|
#[instruction(amount: u64, dispute_resolver: Option<Pubkey>, escrow_id: u64)]
|
||||||
@@ -36,6 +37,9 @@ pub fn handler(
|
|||||||
dispute_resolver: Option<Pubkey>,
|
dispute_resolver: Option<Pubkey>,
|
||||||
escrow_id: u64,
|
escrow_id: u64,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
let rent_min = Rent::get()?.minimum_balance(0);
|
||||||
|
require!(amount >= rent_min, EscrowError::AmountBelowRentMinimum);
|
||||||
|
|
||||||
let escrow = &mut ctx.accounts.escrow_account;
|
let escrow = &mut ctx.accounts.escrow_account;
|
||||||
escrow.seller = ctx.accounts.seller.key();
|
escrow.seller = ctx.accounts.seller.key();
|
||||||
escrow.buyer = ctx.accounts.buyer.key();
|
escrow.buyer = ctx.accounts.buyer.key();
|
||||||
|
|||||||
Reference in New Issue
Block a user