Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/components/TransactionPool/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const TransactionProvider = ({ children } : { children: ReactNode}) => {
const [pendingTransactions, setPendingTransactions] = useState<Transaction[]>([]);
const [lastAddress, setLastAddress] = useState<string>('');
const [viemClient, setClient] = useState<PublicClient | null>(null)
const { selectedOption, bridgeProgram, eclipseRpc, withdrawApi, legacyAddress } = useNetwork();
const { selectedOption, bridgeProgram, eclipseRpc, withdrawApi } = useNetwork();

const { evmWallet } = useWallets();
const fetchDeposits = async () => {
Expand All @@ -43,7 +43,7 @@ export const TransactionProvider = ({ children } : { children: ReactNode}) => {
}

try {
const withdrawalsData = await getWithdrawalsByAddress(evmWallet?.address || '', withdrawApi, legacyAddress);
const withdrawalsData = await getWithdrawalsByAddress(evmWallet?.address || '', withdrawApi);
setWithdrawals(withdrawalsData)
withdrawalsData.forEach(async (item, index) => {
await delay(index * 300);
Expand Down
53 changes: 6 additions & 47 deletions app/components/WithdrawDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { Transport, Chain, Account } from "viem";
import { useTransaction } from "../TransactionPool";
import { createPublicClient, http, WalletClient } from "viem";
import { mainnet, sepolia } from "viem/chains";
import { getGasPrice } from "viem/actions";
import { CONTRACT_ABI, WITHDRAW_TX_FEE } from "../constants";
import {
composeEclipsescanUrl,
Expand Down Expand Up @@ -117,11 +116,7 @@ export const WithdrawDetails: React.FC<TransactionDetailsProps> = ({
ethStatus,
ethAmount,
}) => {
const [gasPrice, ethPrice, blockNumber] = useContext(EthereumDataContext) ?? [
null,
null,
null,
];
const [_, ethPrice] = useContext(EthereumDataContext) ?? [0, 0];
const {
transactions,
deposits,
Expand Down Expand Up @@ -201,56 +196,20 @@ export const WithdrawDetails: React.FC<TransactionDetailsProps> = ({
feeReceiver: tx[0].message.fee_receiver,
feeWei: tx[0].message.fee_wei,
};
// Use the contract address from the withdrawal data (V2 API provides this)
const targetContractAddress = tx[0].bridge;

try {
// Setup gas price for configured gas parameters
//
// message.feeWei (exact calculation from relayer)
//
// pub const CANONICAL_BRIDGE_AUTHORIZE_WITHDRAW_GAS_AMOUNT: u64 = 106_800_u64;
//
// pub async fn estimate_authorize_withdraw_fees(&self) -> eyre::Result<U256> {
// let gas_price = self
// .provider
// .estimate_gas_price()
// .await
// .wrap_err("failed to query CanonicalBridge provider estimate_gas_price")?;
//
// Ok((U256::from(CANONICAL_BRIDGE_AUTHORIZE_WITHDRAW_GAS_AMOUNT) * gas_price * 12) / 10)
// }
//
// let eth_fee_wei = self
// .canonical_bridge
// .estimate_authorize_withdraw_fees()
// .await?;
//

// Calculate auth gas price from message.feeWei (deterministic)
let canonicalBridgeGasEstimate = (BigInt(106_800) * BigInt(12)) / BigInt(10);
let authGasPrice = BigInt(message.feeWei) / canonicalBridgeGasEstimate;

// Get market gas price
let nodeGasPriceWei = await getGasPrice(client); // Should return bigint
let marketGasPriceWei = nodeGasPriceWei > ONE_GWEI ? nodeGasPriceWei : ONE_GWEI // 1 gwei

// Determine use gas price: max(authGasPrice, marketPrice)
const useGasPrice = authGasPrice > marketGasPriceWei ? authGasPrice : marketGasPriceWei;

// claimWithdraw is about 75k gas
let txResponse = await walletClient!.writeContract({
// simulate transaction and send
const { request } = await client.simulateContract({
//@ts-ignore
address: targetContractAddress,
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "claimWithdraw",
args: [message],
account,
gas: BigInt(100_000), // Set a 100k gas limit for the claim transaction
gasPrice: (useGasPrice * BigInt(12)) / BigInt(10), // Bid slightly more than formula
value: BigInt(0),
chain: isMainnet ? mainnet : sepolia,
});
let txResponse = await walletClient!.writeContract(request);
if (!txResponse.startsWith("0x")) txResponse = `0x${txResponse}`;

setButtonText("Confirming");
Expand All @@ -269,7 +228,7 @@ export const WithdrawDetails: React.FC<TransactionDetailsProps> = ({
);
setWithdrawals(updatedWithdrawals);
} catch (error) {
console.log(`❌ Failed to claim from contract ${targetContractAddress}:`, error);
console.log(`❌ Failed to claim from contract ${contractAddress}:`, error);
}
setIsClaimFlowOpen(false);
setButtonText("Claim Now");
Expand Down
5 changes: 1 addition & 4 deletions app/contexts/NetworkContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ type NetworkContextType = {
bridgeProgram: string;
eclipseRpc: string;
contractAddress: string;
legacyAddress: string; // V1 contract address for backward compatibility
relayerAddress: string;
configAccount: string;
withdrawApi: string;
Expand All @@ -66,8 +65,7 @@ export const NetworkProvider = ({ selectedOption, setSelectedOption, children }:
const isMainnet = (selectedOption === Options.Mainnet);
const bridgeProgram = isMainnet ? "br1xwubggTiEZ6b7iNZUwfA3psygFfaXGfZ1heaN9AW" : "br1t2MBNdtVRZk3taADwNLt142cVNkekXe1hn3qJVYb"
const eclipseRpc = isMainnet ? "https://eclipse.lgns.net/" : "https://testnet.dev2.eclipsenetwork.xyz"
const contractAddress = isMainnet ? "0x867A8FcD5Bb6774d4d37fb342D669A35FF789a51" : "0x568a5e1Ad8F6FA834C0d28c9D29Fb3eB86fe84E9"
const legacyAddress = isMainnet ? "0x2B08D7cF7EafF0f5f6623d9fB09b080726D4be11" : "0xe49aaa25a10fd6e15dd7ddcb50904ca1e91f6e01" // V1 contract address for backward compatibility
const contractAddress = isMainnet ? "0x867A8FcD5Bb6774d4d37fb342D669A35FF789a51" : "0x21c6AAB98a41560df325F74055d11d79ECae7139"
const relayerAddress = isMainnet ? "CrfbABN2sSvmoZLu9eDDfXpaC2nHg42R7AXbHs9eg4S9" : "ec1vCnQKsQSnTbcTyc3SH2azcDXZquiFB3QqtRvm3Px"
const configAccount = isMainnet ? "B6UA9rd6Qrx9chsrcMWPV3EFnSb1cbnf7AA2wdkhkpqw" : "A3jHKVwNvrvTjnUPGKYei9jbPn7NcraD6H94ewWyfVMY"
const withdrawApi = isMainnet ? "https://withdraw.api.prod.eclipse.xyz" : "https://withdraw.api.dev2.eclipsenetwork.xyz"
Expand All @@ -80,7 +78,6 @@ export const NetworkProvider = ({ selectedOption, setSelectedOption, children }:
bridgeProgram,
eclipseRpc,
contractAddress,
legacyAddress,
relayerAddress,
configAccount,
withdrawApi,
Expand Down
66 changes: 21 additions & 45 deletions lib/withdrawUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ export type WithdrawObject = [MessageEntry, Status];
export async function getWithdrawalsByAddress(
address: string,
withdrawApi: string,
legacyAddress: string, // V1 contract address for backward compatibility
): Promise<WithdrawObject[]> {
if (!withdrawApi) {
return [];
Expand All @@ -108,7 +107,7 @@ export async function getWithdrawalsByAddress(
}

const serverData = LosslessJSON.parse(await response.text());
const result = parseWithdrawData(serverData, legacyAddress);
const result = parseWithdrawData(serverData);
result.reverse();
return result;
}
Expand All @@ -132,50 +131,27 @@ export async function getWithdrawalPda(
}
}

function parseWithdrawData(data: any[], legacyAddress: string): WithdrawObject[] {
// New V3 format: { bridge, auth: { sender, message, message_hash, start_time }, status }
function parseWithdrawData(data: any[]): WithdrawObject[] {
return data.map((entry) => {
// Check if this is the new V2 format (object with bridge and auth properties)
if (entry.bridge && entry.auth) {
// New V2 format: { bridge, auth: { sender, message, message_hash, start_time }, status }
const message: Message = {
from: entry.auth.message.from,
destination: entry.auth.message.destination,
amount_wei: entry.auth.message.amount_wei,
withdraw_id: BigInt(entry.auth.message.withdraw_id),
fee_receiver: entry.auth.message.fee_receiver,
fee_wei: entry.auth.message.fee_wei,
};

const messageEntry: MessageEntry = {
sender: entry.auth.sender,
message,
message_hash: entry.auth.message_hash,
start_time: entry.auth.start_time,
bridge: entry.bridge,
};

return [messageEntry, entry.status as Status];
} else {
// Old V1 format: [entry, status] where entry has direct properties
const message: Message = {
from: entry[0].message.from,
destination: entry[0].message.destination,
amount_wei: entry[0].message.amount_wei,
withdraw_id: BigInt(entry[0].message.withdraw_id),
fee_receiver: entry[0].message.fee_receiver,
fee_wei: entry[0].message.fee_wei,
};

const messageEntry: MessageEntry = {
sender: entry[0].sender,
message,
message_hash: entry[0].message_hash,
start_time: entry[0].start_time,
bridge: legacyAddress, // Use config address for V1 backward compatibility
};

return [messageEntry, entry[1] as Status];
}
const message: Message = {
from: entry.auth.message.from,
destination: entry.auth.message.destination,
amount_wei: entry.auth.message.amount_wei,
withdraw_id: BigInt(entry.auth.message.withdraw_id),
fee_receiver: entry.auth.message.fee_receiver,
fee_wei: entry.auth.message.fee_wei,
};

const messageEntry: MessageEntry = {
sender: entry.auth.sender,
message,
message_hash: entry.auth.message_hash,
start_time: entry.auth.start_time,
bridge: entry.bridge,
};

return [messageEntry, entry.status as Status];
});
}

Expand Down