diff --git a/src/app/liquidity-party.json b/src/app/liquidity-party.json
index 4e427c0..ce32b17 100644
--- a/src/app/liquidity-party.json
+++ b/src/app/liquidity-party.json
@@ -1,6 +1,6 @@
{
"31337": {
- "IPartyPlanner": "0xB35D3C9b9f2Fd72FAAb282E8Dd56da31FAA30E3d",
- "IPartyPoolViewer": "0x238213078DbD09f2D15F4c14c02300FA1b2A81BB"
+ "IPartyPlanner": "0x536F14E49e1Bb927003E83aDEBF295F3682ff121",
+ "IPartyPoolViewer": "0xd85BdcdaE4db1FAEB8eF93331525FE68D7C8B3f0"
}
}
\ No newline at end of file
diff --git a/src/components/swap-form.tsx b/src/components/swap-form.tsx
index 5596941..779e89f 100644
--- a/src/components/swap-form.tsx
+++ b/src/components/swap-form.tsx
@@ -7,7 +7,7 @@ import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { ArrowDownUp, ChevronDown } from 'lucide-react';
import { useAccount } from 'wagmi';
-import { useTokenDetails, type TokenDetails } from '@/hooks/usePartyPlanner';
+import { useTokenDetails, useGetPoolsByToken, type TokenDetails } from '@/hooks/usePartyPlanner';
import { formatUnits } from 'viem';
export function SwapForm() {
@@ -28,6 +28,9 @@ export function SwapForm() {
// Use the custom hook to get all token details with a single batched RPC call
const { tokenDetails, loading, error } = useTokenDetails(address);
+ // Get available tokens for the selected "from" token
+ const { availableTokens } = useGetPoolsByToken(selectedFromToken?.address);
+
// Trigger the hook to fetch data when address is available
useEffect(() => {
if (tokenDetails) {
@@ -165,12 +168,14 @@ export function SwapForm() {
value={toAmount}
onChange={(e) => setToAmount(e.target.value)}
className="text-2xl h-16"
+ disabled={!selectedFromToken}
/>
{isToDropdownOpen && (
- {tokenDetails && tokenDetails.length > 0 ? (
- tokenDetails.map((token) => (
-
- ))
+ {availableTokens && availableTokens.length > 0 && tokenDetails ? (
+ // Filter tokenDetails to only show tokens in availableTokens
+ tokenDetails
+ .filter((token) =>
+ availableTokens.some((availToken) =>
+ availToken.toLowerCase() === token.address.toLowerCase()
+ )
+ )
+ .map((token) => (
+
+ ))
+ ) : selectedFromToken ? (
+
+ {loading ? 'Loading available tokens...' : 'No tokens available for swap'}
+
) : (
- {loading ? 'Loading tokens...' : 'No tokens available'}
+ Select a token in "You Pay" first
)}
diff --git a/src/contracts/IPartyPlannerABI.ts b/src/contracts/IPartyPlannerABI.ts
index 22619a5..0d33dc2 100644
--- a/src/contracts/IPartyPlannerABI.ts
+++ b/src/contracts/IPartyPlannerABI.ts
@@ -317,7 +317,7 @@ const IPartyPlannerABI = [
},
{
"type": "function",
- "name": "swapMintImpl",
+ "name": "swapImpl",
"inputs": [],
"outputs": [
{
diff --git a/src/contracts/IPartyPoolABI.ts b/src/contracts/IPartyPoolABI.ts
index b4c4dbd..fe19721 100644
--- a/src/contracts/IPartyPoolABI.ts
+++ b/src/contracts/IPartyPoolABI.ts
@@ -147,6 +147,11 @@ const IPartyPoolABI = [
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
+ },
+ {
+ "name": "unwrap",
+ "type": "bool",
+ "internalType": "bool"
}
],
"outputs": [
@@ -186,6 +191,11 @@ const IPartyPoolABI = [
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
+ },
+ {
+ "name": "unwrap",
+ "type": "bool",
+ "internalType": "bool"
}
],
"outputs": [
@@ -318,7 +328,7 @@ const IPartyPoolABI = [
"internalType": "uint256"
}
],
- "stateMutability": "nonpayable"
+ "stateMutability": "payable"
},
{
"type": "function",
@@ -365,7 +375,7 @@ const IPartyPoolABI = [
"internalType": "uint256"
}
],
- "stateMutability": "nonpayable"
+ "stateMutability": "payable"
},
{
"type": "function",
@@ -457,6 +467,11 @@ const IPartyPoolABI = [
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
+ },
+ {
+ "name": "unwrap",
+ "type": "bool",
+ "internalType": "bool"
}
],
"outputs": [
@@ -476,7 +491,51 @@ const IPartyPoolABI = [
"internalType": "uint256"
}
],
- "stateMutability": "nonpayable"
+ "stateMutability": "payable"
+ },
+ {
+ "type": "function",
+ "name": "swapAmounts",
+ "inputs": [
+ {
+ "name": "inputTokenIndex",
+ "type": "uint256",
+ "internalType": "uint256"
+ },
+ {
+ "name": "outputTokenIndex",
+ "type": "uint256",
+ "internalType": "uint256"
+ },
+ {
+ "name": "maxAmountIn",
+ "type": "uint256",
+ "internalType": "uint256"
+ },
+ {
+ "name": "limitPrice",
+ "type": "int128",
+ "internalType": "int128"
+ }
+ ],
+ "outputs": [
+ {
+ "name": "amountIn",
+ "type": "uint256",
+ "internalType": "uint256"
+ },
+ {
+ "name": "amountOut",
+ "type": "uint256",
+ "internalType": "uint256"
+ },
+ {
+ "name": "fee",
+ "type": "uint256",
+ "internalType": "uint256"
+ }
+ ],
+ "stateMutability": "view"
},
{
"type": "function",
@@ -528,7 +587,7 @@ const IPartyPoolABI = [
"internalType": "uint256"
}
],
- "stateMutability": "nonpayable"
+ "stateMutability": "payable"
},
{
"type": "function",
@@ -563,6 +622,11 @@ const IPartyPoolABI = [
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
+ },
+ {
+ "name": "unwrap",
+ "type": "bool",
+ "internalType": "bool"
}
],
"outputs": [
@@ -582,7 +646,7 @@ const IPartyPoolABI = [
"internalType": "uint256"
}
],
- "stateMutability": "nonpayable"
+ "stateMutability": "payable"
},
{
"type": "function",
@@ -663,6 +727,19 @@ const IPartyPoolABI = [
],
"stateMutability": "nonpayable"
},
+ {
+ "type": "function",
+ "name": "wrapperToken",
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "",
+ "type": "address",
+ "internalType": "contract IWETH9"
+ }
+ ],
+ "stateMutability": "view"
+ },
{
"type": "event",
"name": "Approval",
diff --git a/src/hooks/usePartyPlanner.ts b/src/hooks/usePartyPlanner.ts
index 342f510..83f51b4 100644
--- a/src/hooks/usePartyPlanner.ts
+++ b/src/hooks/usePartyPlanner.ts
@@ -4,6 +4,7 @@ import { useState, useEffect } from 'react';
import { usePublicClient } from 'wagmi';
import chainInfo from '@/app/liquidity-party.json';
import IPartyPlannerABI from '@/contracts/IPartyPlannerABI';
+import IPartyPoolABI from '@/contracts/IPartyPoolABI';
import { ERC20ABI } from '@/contracts/ERC20ABI';
export function useGetAllTokens(offset: number = 0, limit: number = 100) {
@@ -73,7 +74,127 @@ export interface TokenDetails {
name: string;
symbol: string;
decimals: number;
- balance: bigint;P
+ balance: bigint;
+ index: number;
+}
+
+export function useGetPoolsByToken(tokenAddress: `0x${string}` | undefined, offset: number = 0, limit: number = 100) {
+ const publicClient = usePublicClient();
+ const [mounted, setMounted] = useState(false);
+ const [availableTokens, setAvailableTokens] = useState<`0x${string}`[] | null>(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState
(null);
+
+ // Handle hydration for Next.js static export
+ useEffect(() => {
+ setMounted(true);
+ }, []);
+
+ useEffect(() => {
+ if (!mounted || !tokenAddress) {
+ setLoading(false);
+ return;
+ }
+
+ const fetchPoolsFromTokens = async () => {
+ if (!publicClient) {
+ setLoading(false);
+ return;
+ }
+
+ try {
+ setLoading(true);
+ setError(null);
+
+ // Get chain ID and contract address
+ const chainId = await publicClient.getChainId();
+ const address = (chainInfo as Record)[chainId.toString()]?.IPartyPlanner;
+
+ if (!address) {
+ setError('IPartyPlanner contract not found for current chain');
+ setAvailableTokens([]);
+ return;
+ }
+
+ // Call getPoolsByToken function
+ const poolsResult = await publicClient.readContract({
+ address: address as `0x${string}`,
+ abi: IPartyPlannerABI,
+ functionName: 'getPoolsByToken',
+ args: [tokenAddress, BigInt(offset), BigInt(limit)],
+ });
+
+ console.log('Pools for token', tokenAddress, ':', poolsResult);
+
+ // Get the symbol of the originally selected token
+ const selectedTokenSymbol = await publicClient.readContract({
+ address: tokenAddress,
+ abi: ERC20ABI,
+ functionName: 'symbol',
+ }).catch(() => null);
+
+ if (!selectedTokenSymbol) {
+ setAvailableTokens([]);
+ return;
+ }
+
+ // For each pool, fetch all tokens in that pool
+ const allTokensInPools: `0x${string}`[] = [];
+ for (const poolAddress of poolsResult) {
+ try {
+ const tokensInPool = await publicClient.readContract({
+ address: poolAddress,
+ abi: IPartyPoolABI,
+ functionName: 'allTokens',
+ }) as readonly `0x${string}`[];
+
+ // Add all tokens from this pool
+ allTokensInPools.push(...tokensInPool);
+ } catch (err) {
+ console.error('Error fetching tokens from pool', poolAddress, err);
+ }
+ }
+
+ // Remove duplicates by address
+ const uniqueTokenAddresses = Array.from(new Set(allTokensInPools));
+
+ // Fetch symbols for all tokens and filter out those matching the selected token's symbol
+ const filteredTokens: `0x${string}`[] = [];
+ for (const token of uniqueTokenAddresses) {
+ try {
+ const tokenSymbol = await publicClient.readContract({
+ address: token,
+ abi: ERC20ABI,
+ functionName: 'symbol',
+ }).catch(() => null);
+
+ // Only include tokens with different symbols
+ if (tokenSymbol && tokenSymbol !== selectedTokenSymbol) {
+ filteredTokens.push(token);
+ }
+ } catch (err) {
+ console.error('Error fetching symbol for token', token, err);
+ }
+ }
+
+ console.log('Available tokens to swap to (excluding', selectedTokenSymbol, '):', filteredTokens);
+ setAvailableTokens(filteredTokens);
+ } catch (err) {
+ setError(err instanceof Error ? err.message : 'Failed to fetch pools and tokens');
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchPoolsFromTokens();
+ }, [publicClient, mounted, tokenAddress, offset, limit]);
+
+ return {
+ availableTokens,
+ loading,
+ error,
+ isReady: mounted,
+ };
}
export function useTokenDetails(userAddress: `0x${string}` | undefined) {
@@ -102,7 +223,8 @@ export function useTokenDetails(userAddress: `0x${string}` | undefined) {
const details: TokenDetails[] = [];
// Make individual calls for each token
- for (const tokenAddress of tokens) {
+ for (let i = 0; i < tokens.length; i++) {
+ const tokenAddress = tokens[i];
try {
const [name, symbol, decimals, balance] = await Promise.all([
publicClient.readContract({
@@ -134,6 +256,7 @@ export function useTokenDetails(userAddress: `0x${string}` | undefined) {
symbol: symbol as string,
decimals: Number(decimals),
balance: balance as bigint,
+ index: i,
});
} catch (err) {
// Add token with fallback values if individual call fails
@@ -143,6 +266,7 @@ export function useTokenDetails(userAddress: `0x${string}` | undefined) {
symbol: '???',
decimals: 18,
balance: BigInt(0),
+ index: i,
});
}
}