import {
createPublicClient,
createParaViemClient,
createParaAccount,
http,
parseEther,
formatEther,
parseGwei,
isAddress
} from "viem";
import { holesky } from "viem/chains";
class ViemTransferService {
private publicClient: any;
private walletClient: any;
constructor(rpcUrl: string, paraClient: any) {
this.publicClient = createPublicClient({
chain: holesky,
transport: http(rpcUrl)
});
const account = createParaAccount(paraClient);
this.walletClient = createParaViemClient(paraClient, {
account,
chain: holesky,
transport: http(rpcUrl)
});
}
async transfer(
toAddress: `0x${string}`,
ethAmount: string,
fromAddress: `0x${string}`
) {
try {
// Validate inputs
if (!isAddress(toAddress)) {
throw new Error("Invalid recipient address");
}
// Check balance and estimate gas
const balance = await this.publicClient.getBalance({ address: fromAddress });
const amount = parseEther(ethAmount);
const estimatedGas = await this.publicClient.estimateGas({
account: fromAddress,
to: toAddress,
value: amount
});
const gasPrice = await this.publicClient.getGasPrice();
const estimatedGasCost = estimatedGas * gasPrice;
if (balance < amount + estimatedGasCost) {
throw new Error("Insufficient balance for transfer and gas");
}
// Send transaction
const hash = await this.walletClient.sendTransaction({
account: fromAddress,
to: toAddress,
value: amount,
chain: holesky,
maxFeePerGas: parseGwei("100"),
maxPriorityFeePerGas: parseGwei("3")
});
const receipt = await this.publicClient.waitForTransactionReceipt({ hash });
return {
success: true,
hash: receipt.transactionHash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString()
};
} catch (error) {
console.error("Transfer failed:", error);
throw error;
}
}
}