Compare commits
11 Commits
d4e41821a6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| d207ef6dca | |||
| 0e5921255e | |||
| 1ac26aeec0 | |||
| a2a036818d | |||
|
|
1c2e267136 | ||
|
|
b2abf2073e | ||
| 9835d67e54 | |||
| b0b050f4be | |||
| f43db3391b | |||
| 334e9f4f53 | |||
|
|
9d2ee39d1a |
11
.env-secret
11
.env-secret
@@ -1,11 +0,0 @@
|
|||||||
# Secret environment variables - DO NOT COMMIT TO GIT
|
|
||||||
# Add this file to .gitignore
|
|
||||||
|
|
||||||
# RPC Node Connection
|
|
||||||
MAINNET_RPC_URL=https://eth-1.dxod.org/joEnzz51UH6Bc2yU
|
|
||||||
ALCHEMY_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/o_eQWfo1Rb7qZKpl_vBRL
|
|
||||||
|
|
||||||
|
|
||||||
# Receiver Address
|
|
||||||
RECEIVER_ADDRESS=0xd3b310bd32d782f89eea49cb79656bcaccde7213
|
|
||||||
PRIVATE_KEY=89c8f2542b5ff7f3cf0b73255e0a8d79d89c2be598e7f272a275a380ff56a212
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,6 +5,9 @@
|
|||||||
/.pnp
|
/.pnp
|
||||||
.pnp.js
|
.pnp.js
|
||||||
|
|
||||||
|
*secret*
|
||||||
|
.env
|
||||||
|
|
||||||
# testing
|
# testing
|
||||||
/coverage
|
/coverage
|
||||||
|
|
||||||
|
|||||||
80
package-lock.json
generated
80
package-lock.json
generated
@@ -17,7 +17,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"i18next": "^23.15.0",
|
"i18next": "^23.15.0",
|
||||||
"lucide-react": "^0.460.0",
|
"lucide-react": "^0.460.0",
|
||||||
"next": "^15.1.3",
|
"next": "15.5.7",
|
||||||
"next-themes": "^0.4.4",
|
"next-themes": "^0.4.4",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
@@ -1405,15 +1405,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/env": {
|
"node_modules/@next/env": {
|
||||||
"version": "15.5.4",
|
"version": "15.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.7.tgz",
|
||||||
"integrity": "sha512-27SQhYp5QryzIT5uO8hq99C69eLQ7qkzkDPsk3N+GuS2XgOgoYEeOav7Pf8Tn4drECOVDsDg8oj+/DVy8qQL2A==",
|
"integrity": "sha512-4h6Y2NyEkIEN7Z8YxkA27pq6zTkS09bUSYC0xjd0NpwFxjnIKeZEeH591o5WECSmjpUhLn3H2QLJcDye3Uzcvg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-darwin-arm64": {
|
"node_modules/@next/swc-darwin-arm64": {
|
||||||
"version": "15.5.4",
|
"version": "15.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.7.tgz",
|
||||||
"integrity": "sha512-nopqz+Ov6uvorej8ndRX6HlxCYWCO3AHLfKK2TYvxoSB2scETOcfm/HSS3piPqc3A+MUgyHoqE6je4wnkjfrOA==",
|
"integrity": "sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1427,9 +1427,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-darwin-x64": {
|
"node_modules/@next/swc-darwin-x64": {
|
||||||
"version": "15.5.4",
|
"version": "15.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.7.tgz",
|
||||||
"integrity": "sha512-QOTCFq8b09ghfjRJKfb68kU9k2K+2wsC4A67psOiMn849K9ZXgCSRQr0oVHfmKnoqCbEmQWG1f2h1T2vtJJ9mA==",
|
"integrity": "sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1443,9 +1443,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||||
"version": "15.5.4",
|
"version": "15.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.7.tgz",
|
||||||
"integrity": "sha512-eRD5zkts6jS3VfE/J0Kt1VxdFqTnMc3QgO5lFE5GKN3KDI/uUpSyK3CjQHmfEkYR4wCOl0R0XrsjpxfWEA++XA==",
|
"integrity": "sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1459,9 +1459,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-arm64-musl": {
|
"node_modules/@next/swc-linux-arm64-musl": {
|
||||||
"version": "15.5.4",
|
"version": "15.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.7.tgz",
|
||||||
"integrity": "sha512-TOK7iTxmXFc45UrtKqWdZ1shfxuL4tnVAOuuJK4S88rX3oyVV4ZkLjtMT85wQkfBrOOvU55aLty+MV8xmcJR8A==",
|
"integrity": "sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1475,9 +1475,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-x64-gnu": {
|
"node_modules/@next/swc-linux-x64-gnu": {
|
||||||
"version": "15.5.4",
|
"version": "15.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.7.tgz",
|
||||||
"integrity": "sha512-7HKolaj+481FSW/5lL0BcTkA4Ueam9SPYWyN/ib/WGAFZf0DGAN8frNpNZYFHtM4ZstrHZS3LY3vrwlIQfsiMA==",
|
"integrity": "sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1491,9 +1491,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-x64-musl": {
|
"node_modules/@next/swc-linux-x64-musl": {
|
||||||
"version": "15.5.4",
|
"version": "15.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.7.tgz",
|
||||||
"integrity": "sha512-nlQQ6nfgN0nCO/KuyEUwwOdwQIGjOs4WNMjEUtpIQJPR2NUfmGpW2wkJln1d4nJ7oUzd1g4GivH5GoEPBgfsdw==",
|
"integrity": "sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1507,9 +1507,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||||
"version": "15.5.4",
|
"version": "15.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.7.tgz",
|
||||||
"integrity": "sha512-PcR2bN7FlM32XM6eumklmyWLLbu2vs+D7nJX8OAIoWy69Kef8mfiN4e8TUv2KohprwifdpFKPzIP1njuCjD0YA==",
|
"integrity": "sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1523,9 +1523,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-win32-x64-msvc": {
|
"node_modules/@next/swc-win32-x64-msvc": {
|
||||||
"version": "15.5.4",
|
"version": "15.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.7.tgz",
|
||||||
"integrity": "sha512-1ur2tSHZj8Px/KMAthmuI9FMp/YFusMMGoRNJaRZMOlSkgvLjzosSdQI0cJAKogdHl3qXUQKL9MGaYvKwA7DXg==",
|
"integrity": "sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -6179,12 +6179,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/next": {
|
"node_modules/next": {
|
||||||
"version": "15.5.4",
|
"version": "15.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/next/-/next-15.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/next/-/next-15.5.7.tgz",
|
||||||
"integrity": "sha512-xH4Yjhb82sFYQfY3vbkJfgSDgXvBB6a8xPs9i35k6oZJRoQRihZH+4s9Yo2qsWpzBmZ3lPXaJ2KPXLfkvW4LnA==",
|
"integrity": "sha512-+t2/0jIJ48kUpGKkdlhgkv+zPTEOoXyr60qXe68eB/pl3CMJaLeIGjzp5D6Oqt25hCBiBTt8wEeeAzfJvUKnPQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next/env": "15.5.4",
|
"@next/env": "15.5.7",
|
||||||
"@swc/helpers": "0.5.15",
|
"@swc/helpers": "0.5.15",
|
||||||
"caniuse-lite": "^1.0.30001579",
|
"caniuse-lite": "^1.0.30001579",
|
||||||
"postcss": "8.4.31",
|
"postcss": "8.4.31",
|
||||||
@@ -6197,14 +6197,14 @@
|
|||||||
"node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
|
"node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@next/swc-darwin-arm64": "15.5.4",
|
"@next/swc-darwin-arm64": "15.5.7",
|
||||||
"@next/swc-darwin-x64": "15.5.4",
|
"@next/swc-darwin-x64": "15.5.7",
|
||||||
"@next/swc-linux-arm64-gnu": "15.5.4",
|
"@next/swc-linux-arm64-gnu": "15.5.7",
|
||||||
"@next/swc-linux-arm64-musl": "15.5.4",
|
"@next/swc-linux-arm64-musl": "15.5.7",
|
||||||
"@next/swc-linux-x64-gnu": "15.5.4",
|
"@next/swc-linux-x64-gnu": "15.5.7",
|
||||||
"@next/swc-linux-x64-musl": "15.5.4",
|
"@next/swc-linux-x64-musl": "15.5.7",
|
||||||
"@next/swc-win32-arm64-msvc": "15.5.4",
|
"@next/swc-win32-arm64-msvc": "15.5.7",
|
||||||
"@next/swc-win32-x64-msvc": "15.5.4",
|
"@next/swc-win32-x64-msvc": "15.5.7",
|
||||||
"sharp": "^0.34.3"
|
"sharp": "^0.34.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"i18next": "^23.15.0",
|
"i18next": "^23.15.0",
|
||||||
"lucide-react": "^0.460.0",
|
"lucide-react": "^0.460.0",
|
||||||
"next": "^15.1.3",
|
"next": "15.5.7",
|
||||||
"next-themes": "^0.4.4",
|
"next-themes": "^0.4.4",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"create-pool": "node create_pool_from_prices.js"
|
"create-pool": "node create_pool_from_prices.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
"ethers": "^5.7.2"
|
"ethers": "^5.7.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ export default function AboutPage() {
|
|||||||
<p className="text-muted-foreground leading-relaxed">
|
<p className="text-muted-foreground leading-relaxed">
|
||||||
Verify our contracts on{' '}
|
Verify our contracts on{' '}
|
||||||
<a
|
<a
|
||||||
href="https://sepolia.etherscan.io/address/0x081aA8AB1984680087c01a5Cd50fC9f49742434D#code"
|
href="https://etherscan.io/address/0x42977f565971F6D288a05ddEbC87A17276F71A29#code"
|
||||||
target="liqp_etherscan"
|
target="liqp_etherscan"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-primary hover:underline"
|
className="text-primary hover:underline"
|
||||||
|
|||||||
@@ -6,17 +6,19 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ArrowDownUp, ChevronDown, Settings, CheckCircle, XCircle, Loader2 } from 'lucide-react';
|
import { ArrowDownUp, ChevronDown, Settings, CheckCircle, XCircle, Loader2 } from 'lucide-react';
|
||||||
import { useAccount } from 'wagmi';
|
import { useAccount, useChainId } from 'wagmi';
|
||||||
import { useTokenDetails, useGetPoolsByToken, type TokenDetails } from '@/hooks/usePartyPlanner';
|
import { useTokenDetails, useGetPoolsByToken, type TokenDetails } from '@/hooks/usePartyPlanner';
|
||||||
import { useSwapAmounts, useSwap, selectBestSwapRoute, type ActualSwapAmounts } from '@/hooks/usePartyPool';
|
import { useSwapAmounts, useSwap, selectBestSwapRoute, type ActualSwapAmounts } from '@/hooks/usePartyPool';
|
||||||
import { formatUnits, parseUnits } from 'viem';
|
import { formatUnits, parseUnits } from 'viem';
|
||||||
import { SwapReviewModal } from './swap-review-modal';
|
import { SwapReviewModal } from './swap-review-modal';
|
||||||
|
import UniswapQuote from './uniswap-quote';
|
||||||
|
|
||||||
type TransactionStatus = 'idle' | 'pending' | 'success' | 'error';
|
type TransactionStatus = 'idle' | 'pending' | 'success' | 'error';
|
||||||
|
|
||||||
export function SwapForm() {
|
export function SwapForm() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isConnected, address } = useAccount();
|
const { isConnected, address } = useAccount();
|
||||||
|
const chainId = useChainId();
|
||||||
const [fromAmount, setFromAmount] = useState('');
|
const [fromAmount, setFromAmount] = useState('');
|
||||||
const [toAmount, setToAmount] = useState('');
|
const [toAmount, setToAmount] = useState('');
|
||||||
const [selectedFromToken, setSelectedFromToken] = useState<TokenDetails | null>(null);
|
const [selectedFromToken, setSelectedFromToken] = useState<TokenDetails | null>(null);
|
||||||
@@ -397,13 +399,26 @@ export function SwapForm() {
|
|||||||
Math.abs(swapAmounts[0].calculatedSlippage) > currentSlippage
|
Math.abs(swapAmounts[0].calculatedSlippage) > currentSlippage
|
||||||
) && (
|
) && (
|
||||||
<div className="px-4 py-3 bg-yellow-500/10 border border-yellow-500/20 rounded-lg">
|
<div className="px-4 py-3 bg-yellow-500/10 border border-yellow-500/20 rounded-lg">
|
||||||
<p className="text-sm text-yellow-600 dark:text-yellow-500 font-medium">⚠️ High Slippage Warning</p>
|
<p className="text-sm text-yellow-600 dark:text-yellow-500 font-medium">⚠️ Slippage Exceeds Your Tolerance</p>
|
||||||
<p className="text-xs text-yellow-600/80 dark:text-yellow-500/80 mt-1">
|
<p className="text-xs text-yellow-600/80 dark:text-yellow-500/80 mt-1">
|
||||||
The estimated slippage for this swap is {Math.abs(swapAmounts[0].calculatedSlippage).toFixed(2)}%. You may lose money due to low liquidity in this pool.
|
The estimated slippage for this swap is {Math.abs(swapAmounts[0].calculatedSlippage).toFixed(2)}%, which exceeds your maximum slippage setting of {currentSlippage}%. This swap may result in less favorable pricing than expected due to low liquidity.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/*/!* Uniswap Quote - Hidden (under construction) *!/*/}
|
||||||
|
{/*{false && fromAmount && selectedFromToken && selectedToToken && (*/}
|
||||||
|
{/* <UniswapQuote*/}
|
||||||
|
{/* amountIn={fromAmount}*/}
|
||||||
|
{/* tokenInAddress={selectedFromToken.address}*/}
|
||||||
|
{/* tokenOutAddress={selectedToToken.address}*/}
|
||||||
|
{/* tokenInDecimals={selectedFromToken.decimals}*/}
|
||||||
|
{/* tokenOutDecimals={selectedToToken.decimals}*/}
|
||||||
|
{/* tokenOutSymbol={selectedToToken.symbol}*/}
|
||||||
|
{/* chainId={chainId || 1}*/}
|
||||||
|
{/* />*/}
|
||||||
|
{/*)}*/}
|
||||||
|
|
||||||
{/* Gas Estimate, Slippage, and Fees */}
|
{/* Gas Estimate, Slippage, and Fees */}
|
||||||
{isConnected && fromAmount && toAmount && (
|
{isConnected && fromAmount && toAmount && (
|
||||||
<div className="px-4 py-2 bg-muted/30 rounded-lg space-y-2">
|
<div className="px-4 py-2 bg-muted/30 rounded-lg space-y-2">
|
||||||
@@ -493,7 +508,7 @@ export function SwapForm() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-muted-foreground mt-2">
|
<p className="text-xs text-muted-foreground mt-2">
|
||||||
Your transaction will revert if the price changes unfavorably by more than this percentage.
|
You will be warned if the slippage exceeds this setting, and you can choose whether to proceed with the trade.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,18 +4,16 @@ export default function TosCard() {
|
|||||||
return (
|
return (
|
||||||
<div className="max-w-5xl mx-auto p-5">
|
<div className="max-w-5xl mx-auto p-5">
|
||||||
<div className="bg-card rounded-lg shadow-md p-6 border">
|
<div className="bg-card rounded-lg shadow-md p-6 border">
|
||||||
<h1 className="text-2xl font-semibold text-center mb-4">Dexorder Terms of Service</h1>
|
<h1 className="text-2xl font-semibold text-center mb-4">Terms of Service</h1>
|
||||||
{/* MAKE SURE TO UPDATE THE VERSION VARIABLE AS WELL */}
|
{/* MAKE SURE TO UPDATE THE VERSION VARIABLE AS WELL */}
|
||||||
<p className="text-center mb-4">Last Updated November 18, 2024</p>
|
<p className="text-center mb-4">Last Updated November 18, 2024</p>
|
||||||
|
|
||||||
<div className="mb-4 leading-relaxed">
|
<div className="mb-4 leading-relaxed">
|
||||||
Please read these Terms of Service (the "<b>Terms</b>") and our{' '}
|
Please read these Terms of Service (the "<b>Terms</b>")
|
||||||
<a href="https://dexorder.com/privacy-policy" target="dexorder">
|
|
||||||
Privacy Policy
|
|
||||||
</a>{' '}
|
|
||||||
carefully because they govern your use of the website (and all subdomains and subpages
|
carefully because they govern your use of the website (and all subdomains and subpages
|
||||||
thereon) located at dexorder.com, including without limitation the subdomains
|
thereon) located at liquidity.party, including without limitation the subdomains
|
||||||
app.dexorder.com and www.dexorder.com (collectively, the "<b>Site</b>"), and the Dexorder
|
app.liquidity.party and www.liquidity.party (collectively, the "<b>Site</b>"), and the
|
||||||
|
Liquidity Party
|
||||||
web application graphical user interface and any other services accessible via the Site
|
web application graphical user interface and any other services accessible via the Site
|
||||||
(together with the Site, web application, and other services, collectively, the "
|
(together with the Site, web application, and other services, collectively, the "
|
||||||
<b>Dexorder Service</b>") offered by Dexorder Trading Services Ltd. ("<b>Dexorder</b>," "
|
<b>Dexorder Service</b>") offered by Dexorder Trading Services Ltd. ("<b>Dexorder</b>," "
|
||||||
@@ -45,29 +43,14 @@ export default function TosCard() {
|
|||||||
<div className="mb-4 leading-relaxed">
|
<div className="mb-4 leading-relaxed">
|
||||||
(a) The Dexorder Service allows you to access an online web application graphical user
|
(a) The Dexorder Service allows you to access an online web application graphical user
|
||||||
interface (the "<b>App</b>") which enables you to interact with a protocol consisting of a
|
interface (the "<b>App</b>") which enables you to interact with a protocol consisting of a
|
||||||
set of smart contracts (the "<b>Smart Contracts</b>") and to create and interact with a
|
set of smart contracts (the "<b>Protocol</b>").
|
||||||
user controlled smart contract involving digital assets over which only you have upgrade
|
You may use the <b>App</b> to send signals to, interact with, and initiate actions on the
|
||||||
authority (a "<b>Vault</b>" and together with the Smart Contracts, the "<b>Protocol</b>").
|
decentralized exchange ("<b>DEX</b>").
|
||||||
You may use your Vault to send signals to, interact with, and initiate actions on third
|
|
||||||
party smart contract blockchain protocols ("<b>Interactions</b>") operating on
|
|
||||||
decentralized exchanges (e.g., Uniswap) ("<b>DEXs</b>"). Certain Interactions may require
|
|
||||||
threshold parameters to be met and that a third party transmit an oracle related activation
|
|
||||||
signal (the "<b>Activation Signal</b>") to the Vault in order to effectuate your commands
|
|
||||||
(such party being an "<b>Oracle</b>"). Dexorder may in the ordinary course of events be an
|
|
||||||
Oracle ("<b>Dexorder Oracle</b>"), but bears no obligation nor promise to do so on an
|
|
||||||
ongoing basis, and you may send such Activation Signal yourself or utilize a third-party
|
|
||||||
Oracle to do so. Further, Dexorder is not and does not offer a digital wallet, and has no
|
|
||||||
custody or control over your digital wallet, which is never accessible by Dexorder, and only
|
|
||||||
users, and not Dexorder, may provide or withdraw tokens to be held by Vault. From time to
|
|
||||||
time, the Services may include making recommendations with respect to technical changes that
|
|
||||||
only you may accept and implement.
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-4 leading-relaxed">
|
<div className="mb-4 leading-relaxed">
|
||||||
(b) <b>Interface</b>. The Dexorder Service provides you with access to the Protocol, which
|
(b) <b>Interface</b>. The Dexorder Service provides you with access to the Protocol.
|
||||||
is a user controlled, non-custodial protocol, upgradeable only by your actions and consent,
|
All information provided in
|
||||||
deployed on the blockchains indicated on our Site, and provides information and interaction
|
|
||||||
capabilities with other blockchain related service providers. All information provided in
|
|
||||||
connection with your access and use of the Dexorder Service is for informational purposes
|
connection with your access and use of the Dexorder Service is for informational purposes
|
||||||
only. You should not take, or refrain from taking, any action based on any information
|
only. You should not take, or refrain from taking, any action based on any information
|
||||||
contained on the Dexorder Service or any other information that we make available at any
|
contained on the Dexorder Service or any other information that we make available at any
|
||||||
@@ -208,12 +191,8 @@ export default function TosCard() {
|
|||||||
<div className="mb-4 leading-relaxed ml-8">
|
<div className="mb-4 leading-relaxed ml-8">
|
||||||
(i) Subject to your compliance with these Terms, Dexorder will use its commercially
|
(i) Subject to your compliance with these Terms, Dexorder will use its commercially
|
||||||
reasonable efforts to provide you with access to the Dexorder Service and to cause your
|
reasonable efforts to provide you with access to the Dexorder Service and to cause your
|
||||||
Interactions to be executed on the applicable DEX in accordance with Dexorder's Execution
|
Interactions to be executed on the Protocol, however from time to time the Site and
|
||||||
Policy located at{' '}
|
the Dexorder Service may
|
||||||
<a href="https://dexorder.com/execution-policy">
|
|
||||||
https://dexorder.com/execution-policy
|
|
||||||
</a>{' '}
|
|
||||||
("<b>Execution Policy</b>"), however from time to time the Site and the Dexorder Service may
|
|
||||||
be inaccessible or inoperable for any reason, including, without limitation: (a) if an
|
be inaccessible or inoperable for any reason, including, without limitation: (a) if an
|
||||||
Interaction repeatedly fails to be executed (such as due to an error in Interaction
|
Interaction repeatedly fails to be executed (such as due to an error in Interaction
|
||||||
execution or a malfunction in the Dexorder Service); (b) equipment malfunctions; (c)
|
execution or a malfunction in the Dexorder Service); (b) equipment malfunctions; (c)
|
||||||
@@ -221,8 +200,7 @@ export default function TosCard() {
|
|||||||
contractors may undertake from time to time; (d) causes beyond Dexorder's control or that
|
contractors may undertake from time to time; (d) causes beyond Dexorder's control or that
|
||||||
Dexorder could not reasonably foresee; (e) disruptions and temporary or permanent
|
Dexorder could not reasonably foresee; (e) disruptions and temporary or permanent
|
||||||
unavailability of underlying blockchain infrastructure; (f) unavailability of third-party
|
unavailability of underlying blockchain infrastructure; (f) unavailability of third-party
|
||||||
service providers or external partners for any reason; or (g) an Activation Signal not being
|
service providers or external partners for any reason.
|
||||||
sent.
|
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-4 leading-relaxed ml-8">
|
<div className="mb-4 leading-relaxed ml-8">
|
||||||
(ii) the Site and the Dexorder Service may evolve, which means Dexorder may apply changes,
|
(ii) the Site and the Dexorder Service may evolve, which means Dexorder may apply changes,
|
||||||
@@ -245,11 +223,9 @@ export default function TosCard() {
|
|||||||
<h2 className="text-xl font-semibold mt-6 mb-4">6. Interactions; Fees</h2>
|
<h2 className="text-xl font-semibold mt-6 mb-4">6. Interactions; Fees</h2>
|
||||||
<div className="mb-4 leading-relaxed">
|
<div className="mb-4 leading-relaxed">
|
||||||
(a) <u>Interactions</u>. In order to effectuate Interactions, you may need to transfer
|
(a) <u>Interactions</u>. In order to effectuate Interactions, you may need to transfer
|
||||||
digital assets (e.g., tokens) to the Vault. You acknowledge that you may use the Dexorder
|
digital assets (e.g., tokens). You acknowledge that you may use the Dexorder
|
||||||
Services to process and cause Interactions to be operate with an applicable DEX, including
|
Services to process and cause Interactions to operate on the Protocol.
|
||||||
without limitation the transfer of digital assets via the DEX in accordance with the
|
Dexorder is an interface to that smart contract, and does not offer a digital
|
||||||
Interaction. For clarity, the Vault is a smart contract automatically controlled by the
|
|
||||||
blockchain. Dexorder is an interface to that smart contract, and does not offer a digital
|
|
||||||
wallet and has no custody or control over your digital wallet or any digital assets or
|
wallet and has no custody or control over your digital wallet or any digital assets or
|
||||||
cryptocurrency, which is never accessible by Dexorder.
|
cryptocurrency, which is never accessible by Dexorder.
|
||||||
</div>
|
</div>
|
||||||
@@ -257,8 +233,8 @@ export default function TosCard() {
|
|||||||
(b) <u>Fees</u>.
|
(b) <u>Fees</u>.
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-4 leading-relaxed ml-8">
|
<div className="mb-4 leading-relaxed ml-8">
|
||||||
(i) Dexorder charges fees upfront for usage of the Dexorder Services at the time of user
|
(i) Dexorder charges fees for usage of the Dexorder Services at the time of user
|
||||||
Interactions ("<b>Fees</b>"). You agree to pay all applicable Fees upfront to Dexorder, in
|
Interactions ("<b>Fees</b>"). You agree to pay all applicable Fees to Dexorder, in
|
||||||
the amounts communicated or presented to you via the Dexorder Service in connection with
|
the amounts communicated or presented to you via the Dexorder Service in connection with
|
||||||
usage of the Dexorder Service. Each party shall be responsible for all Taxes imposed on its
|
usage of the Dexorder Service. Each party shall be responsible for all Taxes imposed on its
|
||||||
income or property.
|
income or property.
|
||||||
@@ -416,8 +392,7 @@ export default function TosCard() {
|
|||||||
<h2 className="text-xl font-semibold mt-6 mb-4">9. Links to Third Party Websites or Resources</h2>
|
<h2 className="text-xl font-semibold mt-6 mb-4">9. Links to Third Party Websites or Resources</h2>
|
||||||
<div className="mb-4 leading-relaxed">
|
<div className="mb-4 leading-relaxed">
|
||||||
The Dexorder Service may allow you to access third-party websites, integrations, or other
|
The Dexorder Service may allow you to access third-party websites, integrations, or other
|
||||||
resources, including the DEX, services providing Activation Signals, and any bridge between
|
resources, including the Protocol (collectively, "<b>Third Party Resources</b>"). We
|
||||||
the DEX and any third party protocols (collectively, "<b>Third Party Resources</b>"). We
|
|
||||||
provide access only as a convenience and are not responsible for the content, products or
|
provide access only as a convenience and are not responsible for the content, products or
|
||||||
services on or available from those resources or links displayed on such websites. You
|
services on or available from those resources or links displayed on such websites. You
|
||||||
acknowledge sole responsibility for and assume all risk arising from, your use of any
|
acknowledge sole responsibility for and assume all risk arising from, your use of any
|
||||||
@@ -440,7 +415,7 @@ export default function TosCard() {
|
|||||||
<div className="mb-4 leading-relaxed">
|
<div className="mb-4 leading-relaxed">
|
||||||
THE DEXORDER SERVICE (INCLUDING WITHOUT LIMITATION THE VAULT) AND ANY CONTENT CONTAINED
|
THE DEXORDER SERVICE (INCLUDING WITHOUT LIMITATION THE VAULT) AND ANY CONTENT CONTAINED
|
||||||
THEREIN, AS WELL AS THE PROTOCOL, THE DEXORDER ORACLE, AND ANY ASSOCIATED PROTOCOL OR
|
THEREIN, AS WELL AS THE PROTOCOL, THE DEXORDER ORACLE, AND ANY ASSOCIATED PROTOCOL OR
|
||||||
BLOCKCHAIN MESSAGING FUNCTIONALITY SUCH AS ACTIVATION SIGNALS UNDERLYING THE DEXORDER
|
BLOCKCHAIN MESSAGING FUNCTIONALITY UNDERLYING THE DEXORDER
|
||||||
SERVICE (TOGETHER, THE "<b>UTILITIES</b>"), ARE PROVIDED "AS IS," WITHOUT WARRANTY OF ANY
|
SERVICE (TOGETHER, THE "<b>UTILITIES</b>"), ARE PROVIDED "AS IS," WITHOUT WARRANTY OF ANY
|
||||||
KIND. WITHOUT LIMITING THE FOREGOING, WE EXPLICITLY DISCLAIM ANY IMPLIED WARRANTIES OF
|
KIND. WITHOUT LIMITING THE FOREGOING, WE EXPLICITLY DISCLAIM ANY IMPLIED WARRANTIES OF
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT AND NON-INFRINGEMENT, AND
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT AND NON-INFRINGEMENT, AND
|
||||||
@@ -476,25 +451,6 @@ export default function TosCard() {
|
|||||||
USE OF VIRUSES, PHISHING, BRUTEFORCING OR OTHER MEANS OF ATTACK AGAINST ANY BLOCKCHAIN
|
USE OF VIRUSES, PHISHING, BRUTEFORCING OR OTHER MEANS OF ATTACK AGAINST ANY BLOCKCHAIN
|
||||||
NETWORK UNDERLYING THE UTILITIES.
|
NETWORK UNDERLYING THE UTILITIES.
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-4 leading-relaxed">
|
|
||||||
THE UTILITIES MAY INCLUDE THE PLACEMENT OR EXECUTION OF AN ACTIVATION SIGNAL TO A USER VAULT
|
|
||||||
WITH RESPECT TO USER DEFINED INTERACTIONS (E.G., VIA TRANSMITTING AN ACTIVATION SIGNAL WHICH
|
|
||||||
TRIGGERS INTERACTION EXECUTION), HOWEVER, ANYONE, INCLUDING YOU OR ANY THIRD PARTY, MAY
|
|
||||||
CAUSE AN INTERACTION TO BE EXECUTED (SUCH AS BY TRANSMITTING THE APPLICABLE ACTIVATION
|
|
||||||
SIGNAL), AND NOTWITHSTANDING ANYTHING TO THE CONTRARY IN THESE TERMS, DEXORDER DOES NOT
|
|
||||||
GUARANTEE THE PLACEMENT OR EXECUTION OR ANY INTERACTION, INCLUDING WITHOUT LIMITATION THAT
|
|
||||||
DEXORDER WILL TRANSMIT ANY PARTICULAR ACTIVATION SIGNAL TO TRIGGER EXECUTION OF ANY
|
|
||||||
INTERACTION, OR THAT AN INTERACTION WILL OTHERWISE BE PROPERLY CARRIED OUT PURSUANT TO A
|
|
||||||
VAULT. YOU ACKNOWLEDGE AND AGREE THAT YOU WILL NOT RELY ON THE UTILITIES TO CARRY OUT
|
|
||||||
PLACEMENTS OR EXECUTIONS OF INTERACTIONS. IF ANY PARTICULAR INTERACTION THAT IS PLACED IS
|
|
||||||
NOT EXECUTED BY DEXORDER IN A TIMELY MANNER, YOU MAY CAUSE SUCH INTERACTION TO BE EXECUTED
|
|
||||||
YOURSELF OR BY ENGAGING A THIRD PARTY SERVICE PROVIDER TO DO SO (E.G., BY TRANSMITTING THE
|
|
||||||
APPLICABLE ACTIVATION SIGNAL YOURSELF OR ENGAGING A THIRD PARTY TO DO SO). YOU ACCEPT THE
|
|
||||||
INHERENT RISK THAT ANY PARTICULAR INTERACTION MAY NOT BE EXECUTED, INCLUDING WITHOUT
|
|
||||||
LIMITATION DUE TO BAD ACTORS OR THE MALFUNCTION OF THE UTILITIES, AND DEXORDER HEREBY
|
|
||||||
DISCLAIMS ANY AND ALL LIABILITY AND RESPONSIBILITY IN CONNECTION WITH THE PLACEMENT OR
|
|
||||||
EXECUTION OF INTERACTIONS AND THE VAULT.
|
|
||||||
</div>
|
|
||||||
<div className="mb-4 leading-relaxed">
|
<div className="mb-4 leading-relaxed">
|
||||||
THE UTILITIES MAY NOT BE AVAILABLE DUE TO ANY NUMBER OF FACTORS INCLUDING, BUT NOT LIMITED
|
THE UTILITIES MAY NOT BE AVAILABLE DUE TO ANY NUMBER OF FACTORS INCLUDING, BUT NOT LIMITED
|
||||||
TO, PERIODIC SYSTEM MAINTENANCE, SCHEDULED OR UNSCHEDULED, ACTS OF GOD, UNAUTHORIZED ACCESS,
|
TO, PERIODIC SYSTEM MAINTENANCE, SCHEDULED OR UNSCHEDULED, ACTS OF GOD, UNAUTHORIZED ACCESS,
|
||||||
|
|||||||
248
src/components/uniswap-quote.tsx
Normal file
248
src/components/uniswap-quote.tsx
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { parseUnits, formatUnits } from 'viem';
|
||||||
|
|
||||||
|
interface UniswapQuoteProps {
|
||||||
|
amountIn: string;
|
||||||
|
tokenInAddress: string | null;
|
||||||
|
tokenOutAddress: string | null;
|
||||||
|
tokenInDecimals: number;
|
||||||
|
tokenOutDecimals: number;
|
||||||
|
tokenOutSymbol: string;
|
||||||
|
chainId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TokenPrices {
|
||||||
|
[key: string]: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function UniswapQuote({
|
||||||
|
amountIn,
|
||||||
|
tokenInAddress,
|
||||||
|
tokenOutAddress,
|
||||||
|
tokenInDecimals,
|
||||||
|
tokenOutDecimals,
|
||||||
|
tokenOutSymbol,
|
||||||
|
chainId
|
||||||
|
}: UniswapQuoteProps) {
|
||||||
|
const [quote, setQuote] = useState<any>(null);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState('');
|
||||||
|
const [prices, setPrices] = useState<TokenPrices | null>(null);
|
||||||
|
|
||||||
|
// Only show on mainnet
|
||||||
|
if (chainId !== 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't fetch quote if tokens aren't selected
|
||||||
|
if (!tokenInAddress || !tokenOutAddress) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch token prices from CoinGecko using contract addresses
|
||||||
|
useEffect(() => {
|
||||||
|
if (!tokenInAddress || !tokenOutAddress) return;
|
||||||
|
|
||||||
|
const fetchPrices = async () => {
|
||||||
|
try {
|
||||||
|
// Fetch both token prices separately using the correct endpoint
|
||||||
|
const [tokenInResponse, tokenOutResponse] = await Promise.all([
|
||||||
|
fetch(`https://api.coingecko.com/api/v3/simple/token_price/ethereum?contract_addresses=${tokenInAddress}&vs_currencies=usd`),
|
||||||
|
fetch(`https://api.coingecko.com/api/v3/simple/token_price/ethereum?contract_addresses=${tokenOutAddress}&vs_currencies=usd`)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const tokenInData = await tokenInResponse.json();
|
||||||
|
const tokenOutData = await tokenOutResponse.json();
|
||||||
|
|
||||||
|
const tokenInPrice = tokenInData[tokenInAddress.toLowerCase()]?.usd || 0;
|
||||||
|
const tokenOutPrice = tokenOutData[tokenOutAddress.toLowerCase()]?.usd || 0;
|
||||||
|
|
||||||
|
setPrices({
|
||||||
|
tokenIn: tokenInPrice,
|
||||||
|
tokenOut: tokenOutPrice
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Token prices:', { tokenInPrice, tokenOutPrice, tokenInData, tokenOutData });
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to fetch prices:', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchPrices();
|
||||||
|
// Refresh prices every 30 seconds
|
||||||
|
const interval = setInterval(fetchPrices, 30000);
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, [tokenInAddress, tokenOutAddress]);
|
||||||
|
|
||||||
|
const getQuote = async () => {
|
||||||
|
if (!amountIn || parseFloat(amountIn) <= 0) {
|
||||||
|
setError('Please enter a valid amount');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
setError('');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Convert amount to smallest unit based on token decimals using viem
|
||||||
|
const amountInSmallestUnit = parseUnits(amountIn, tokenInDecimals).toString();
|
||||||
|
|
||||||
|
const response = await fetch('https://api.uniswap.org/v2/quote', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Origin': 'https://app.uniswap.org'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
amount: amountInSmallestUnit,
|
||||||
|
tokenIn: tokenInAddress,
|
||||||
|
tokenInChainId: chainId,
|
||||||
|
tokenOut: tokenOutAddress,
|
||||||
|
tokenOutChainId: chainId,
|
||||||
|
type: 'EXACT_INPUT',
|
||||||
|
configs: [
|
||||||
|
{
|
||||||
|
protocols: ['V2', 'V3', 'V4'],
|
||||||
|
enableUniversalRouter: true,
|
||||||
|
routingType: 'CLASSIC'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) throw new Error('Failed to fetch quote');
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
console.log('Uniswap Quote:', data);
|
||||||
|
setQuote(data);
|
||||||
|
} catch (err: any) {
|
||||||
|
setError(err.message);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatTokenAmount = (amount: string) => {
|
||||||
|
const formatted = formatUnits(BigInt(amount), tokenOutDecimals);
|
||||||
|
return parseFloat(formatted).toLocaleString('en-US', {
|
||||||
|
maximumFractionDigits: tokenOutDecimals >= 18 ? 0 : 6
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getQuoteAmount = () => {
|
||||||
|
if (!quote) return '0';
|
||||||
|
// Handle nested quote structure
|
||||||
|
return quote.quote?.quote || quote.quote || '0';
|
||||||
|
};
|
||||||
|
|
||||||
|
const calculateCostBreakdown = () => {
|
||||||
|
if (!quote || !prices || !prices.tokenIn) return null;
|
||||||
|
|
||||||
|
const tokenAmount = parseFloat(amountIn);
|
||||||
|
const tradeValueUSD = tokenAmount * prices.tokenIn;
|
||||||
|
|
||||||
|
// Access nested quote object
|
||||||
|
const quoteData = quote.quote || quote;
|
||||||
|
|
||||||
|
// 1. Gas Cost
|
||||||
|
const gasCostUSD = parseFloat(quoteData.gasUseEstimateUSD || '0');
|
||||||
|
|
||||||
|
// 2. Uniswap UX Fee (0.25%)
|
||||||
|
const uniswapFeePercent = 0.25;
|
||||||
|
const uniswapFeeUSD = (uniswapFeePercent / 100) * tradeValueUSD;
|
||||||
|
|
||||||
|
const totalCostUSD = gasCostUSD + uniswapFeeUSD;
|
||||||
|
|
||||||
|
console.log('Cost breakdown calc:', {
|
||||||
|
gasCostUSD,
|
||||||
|
uniswapFeeUSD,
|
||||||
|
totalCostUSD,
|
||||||
|
tradeValueUSD,
|
||||||
|
quoteData
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
gasCostUSD,
|
||||||
|
uniswapFeePercent,
|
||||||
|
uniswapFeeUSD,
|
||||||
|
totalCostUSD,
|
||||||
|
tradeValueUSD
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const costBreakdown = calculateCostBreakdown();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full max-w-md p-4">
|
||||||
|
<button
|
||||||
|
onClick={getQuote}
|
||||||
|
disabled={loading}
|
||||||
|
className="w-full bg-blue-500 hover:bg-blue-600 disabled:bg-gray-400 text-white font-semibold py-2 px-4 rounded"
|
||||||
|
>
|
||||||
|
{loading ? 'Getting Quote...' : 'Get Quote'}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="mt-3 p-3 bg-red-50 text-red-700 rounded text-sm">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{quote && costBreakdown && (
|
||||||
|
<div className="mt-4 space-y-3">
|
||||||
|
<div className="p-3 bg-gray-50 rounded">
|
||||||
|
<div className="text-sm text-gray-600">You Get ({tokenOutSymbol})</div>
|
||||||
|
<div className="text-xl font-bold">
|
||||||
|
{formatTokenAmount(getQuoteAmount())}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Total Costs Breakdown */}
|
||||||
|
<div className="p-4 bg-blue-50 rounded-lg space-y-3">
|
||||||
|
<h3 className="font-semibold text-lg text-gray-800">Total Costs Breakdown</h3>
|
||||||
|
|
||||||
|
{/* 1. Gas Cost */}
|
||||||
|
<div className="space-y-1">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="text-sm font-medium text-gray-700">1. Gas Cost (Network Fee)</span>
|
||||||
|
<span className="text-sm font-bold text-gray-900">
|
||||||
|
${costBreakdown.gasCostUSD.toFixed(2)} USD
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 2. Uniswap UX Fee */}
|
||||||
|
<div className="space-y-1">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="text-sm font-medium text-gray-700">2. Uniswap UX Fee</span>
|
||||||
|
<span className="text-sm font-bold text-gray-900">
|
||||||
|
{costBreakdown.uniswapFeePercent}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-gray-600 pl-4">
|
||||||
|
${costBreakdown.uniswapFeeUSD.toFixed(2)} USD
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Total */}
|
||||||
|
<div className="pt-2 border-t border-gray-300">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="text-sm font-bold text-gray-800">Total Estimated Cost</span>
|
||||||
|
<span className="text-base font-bold text-red-600">
|
||||||
|
${costBreakdown.totalCostUSD.toFixed(2)} USD
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Trade Value Reference */}
|
||||||
|
<div className="text-xs text-gray-500 text-center pt-1">
|
||||||
|
Trade Value: ${costBreakdown.tradeValueUSD.toFixed(2)} USD
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -183,8 +183,8 @@ const IPartyInfoABI = [
|
|||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"type": "int128",
|
"type": "uint256",
|
||||||
"internalType": "int128"
|
"internalType": "uint256"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"stateMutability": "view"
|
"stateMutability": "view"
|
||||||
|
|||||||
@@ -415,6 +415,19 @@ const IPartyPoolABI = [
|
|||||||
],
|
],
|
||||||
"stateMutability": "payable"
|
"stateMutability": "payable"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"name": "mintImpl",
|
||||||
|
"inputs": [],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "address",
|
||||||
|
"internalType": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"name": "name",
|
"name": "name",
|
||||||
@@ -605,6 +618,19 @@ const IPartyPoolABI = [
|
|||||||
],
|
],
|
||||||
"stateMutability": "view"
|
"stateMutability": "view"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"name": "swapImpl",
|
||||||
|
"inputs": [],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "address",
|
||||||
|
"internalType": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"name": "swapMint",
|
"name": "swapMint",
|
||||||
|
|||||||
@@ -198,88 +198,131 @@ export function useGetPoolsByToken(tokenAddress: `0x${string}` | undefined, offs
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First, fetch all tokens from all working pools
|
||||||
|
const poolTokensContracts = workingPools.map(poolAddress => ({
|
||||||
|
address: poolAddress,
|
||||||
|
abi: IPartyPoolABI,
|
||||||
|
functionName: 'allTokens',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const poolTokensResults = await publicClient.multicall({
|
||||||
|
contracts: poolTokensContracts as any,
|
||||||
|
allowFailure: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build a flat list of all unique token addresses we need to query
|
||||||
|
const uniqueTokenAddresses = new Set<`0x${string}`>();
|
||||||
|
uniqueTokenAddresses.add(tokenAddress); // Add input token
|
||||||
|
|
||||||
|
poolTokensResults.forEach((result) => {
|
||||||
|
if (result.status === 'success') {
|
||||||
|
const tokens = result.result as readonly `0x${string}`[];
|
||||||
|
tokens.forEach(token => uniqueTokenAddresses.add(token));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const tokenAddressesArray = Array.from(uniqueTokenAddresses);
|
||||||
|
|
||||||
|
// Build multicall for all token symbols and decimals
|
||||||
|
const tokenDataContracts = tokenAddressesArray.flatMap(addr => [
|
||||||
|
{
|
||||||
|
address: addr,
|
||||||
|
abi: ERC20ABI,
|
||||||
|
functionName: 'symbol',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
address: addr,
|
||||||
|
abi: ERC20ABI,
|
||||||
|
functionName: 'decimals',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const tokenDataResults = await publicClient.multicall({
|
||||||
|
contracts: tokenDataContracts as any,
|
||||||
|
allowFailure: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Parse token data into a map
|
||||||
|
const tokenDataMap = new Map<string, { symbol: string | null; decimals: number | null }>();
|
||||||
|
for (let i = 0; i < tokenAddressesArray.length; i++) {
|
||||||
|
const symbolResult = tokenDataResults[i * 2];
|
||||||
|
const decimalsResult = tokenDataResults[i * 2 + 1];
|
||||||
|
tokenDataMap.set(tokenAddressesArray[i].toLowerCase(), {
|
||||||
|
symbol: symbolResult.status === 'success' ? (symbolResult.result as string) : null,
|
||||||
|
decimals: decimalsResult.status === 'success' ? Number(decimalsResult.result) : null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Map to store available tokens with their swap routes
|
// Map to store available tokens with their swap routes
|
||||||
const tokenRoutesMap = new Map<string, AvailableToken>();
|
const tokenRoutesMap = new Map<string, AvailableToken>();
|
||||||
|
|
||||||
// For each working pool, fetch all tokens and track indices
|
// For each working pool, process tokens
|
||||||
for (const poolAddress of workingPools) {
|
for (let poolIdx = 0; poolIdx < workingPools.length; poolIdx++) {
|
||||||
try {
|
const poolAddress = workingPools[poolIdx];
|
||||||
const tokensInPool = await publicClient.readContract({
|
const poolTokensResult = poolTokensResults[poolIdx];
|
||||||
address: poolAddress,
|
|
||||||
abi: IPartyPoolABI,
|
|
||||||
functionName: 'allTokens',
|
|
||||||
}) as readonly `0x${string}`[];
|
|
||||||
|
|
||||||
// Find the input token index in this pool
|
if (poolTokensResult.status !== 'success') {
|
||||||
const inputTokenIndex = tokensInPool.findIndex(
|
console.error('Failed to fetch tokens for pool', poolAddress);
|
||||||
(token) => token.toLowerCase() === tokenAddress.toLowerCase()
|
continue;
|
||||||
);
|
}
|
||||||
|
|
||||||
if (inputTokenIndex === -1) {
|
const tokensInPool = poolTokensResult.result as readonly `0x${string}`[];
|
||||||
console.error('Input token not found in pool', poolAddress);
|
|
||||||
|
// Find the input token index in this pool
|
||||||
|
const inputTokenIndex = tokensInPool.findIndex(
|
||||||
|
(token) => token.toLowerCase() === tokenAddress.toLowerCase()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (inputTokenIndex === -1) {
|
||||||
|
console.error('Input token not found in pool', poolAddress);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputTokenData = tokenDataMap.get(tokenAddress.toLowerCase());
|
||||||
|
const inputTokenDecimal = inputTokenData?.decimals ?? null;
|
||||||
|
|
||||||
|
// Process each token in the pool
|
||||||
|
for (let outputTokenIndex = 0; outputTokenIndex < tokensInPool.length; outputTokenIndex++) {
|
||||||
|
const outputTokenAddress = tokensInPool[outputTokenIndex];
|
||||||
|
|
||||||
|
// Skip if it's the same as the input token
|
||||||
|
if (outputTokenIndex === inputTokenIndex) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process each token in the pool
|
const outputTokenData = tokenDataMap.get(outputTokenAddress.toLowerCase());
|
||||||
for (let outputTokenIndex = 0; outputTokenIndex < tokensInPool.length; outputTokenIndex++) {
|
const outputTokenSymbol = outputTokenData?.symbol ?? null;
|
||||||
const outputTokenAddress = tokensInPool[outputTokenIndex];
|
const outputTokenDecimal = outputTokenData?.decimals ?? null;
|
||||||
|
|
||||||
// Skip if it's the same as the input token
|
// Skip tokens with the same symbol as the selected token
|
||||||
if (outputTokenIndex === inputTokenIndex) {
|
if (!outputTokenSymbol || outputTokenSymbol === selectedTokenSymbol) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the symbol of this token
|
// Skip tokens if decimals failed to load
|
||||||
const outputTokenSymbol = await publicClient.readContract({
|
if (inputTokenDecimal === null || outputTokenDecimal === null) {
|
||||||
|
console.error(`Failed to load decimals for token ${outputTokenAddress} or ${tokenAddress}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or update the available token entry
|
||||||
|
const tokenKey = outputTokenAddress.toLowerCase();
|
||||||
|
if (!tokenRoutesMap.has(tokenKey)) {
|
||||||
|
tokenRoutesMap.set(tokenKey, {
|
||||||
address: outputTokenAddress,
|
address: outputTokenAddress,
|
||||||
abi: ERC20ABI,
|
symbol: outputTokenSymbol,
|
||||||
functionName: 'symbol',
|
swapRoutes: [],
|
||||||
}).catch(() => null);
|
|
||||||
|
|
||||||
const inputTokenDecimal = await publicClient.readContract({
|
|
||||||
address: tokenAddress,
|
|
||||||
abi: ERC20ABI,
|
|
||||||
functionName: 'decimals',
|
|
||||||
}).catch(() => null);
|
|
||||||
|
|
||||||
const outputTokenDecimal = await publicClient.readContract({
|
|
||||||
address: outputTokenAddress,
|
|
||||||
abi: ERC20ABI,
|
|
||||||
functionName: 'decimals',
|
|
||||||
}).catch(() => null);
|
|
||||||
|
|
||||||
// Skip tokens with the same symbol as the selected token
|
|
||||||
if (!outputTokenSymbol || outputTokenSymbol === selectedTokenSymbol) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip tokens if decimals failed to load
|
|
||||||
if (inputTokenDecimal === null || outputTokenDecimal === null) {
|
|
||||||
console.error(`Failed to load decimals for token ${outputTokenAddress} or ${tokenAddress}`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create or update the available token entry
|
|
||||||
const tokenKey = outputTokenAddress.toLowerCase();
|
|
||||||
if (!tokenRoutesMap.has(tokenKey)) {
|
|
||||||
tokenRoutesMap.set(tokenKey, {
|
|
||||||
address: outputTokenAddress,
|
|
||||||
symbol: outputTokenSymbol,
|
|
||||||
swapRoutes: [],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add this swap route
|
|
||||||
tokenRoutesMap.get(tokenKey)!.swapRoutes.push({
|
|
||||||
poolAddress,
|
|
||||||
inputTokenIndex,
|
|
||||||
outputTokenIndex,
|
|
||||||
inputTokenDecimal,
|
|
||||||
outputTokenDecimal,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
console.error('Error fetching tokens from pool', poolAddress, err);
|
// Add this swap route
|
||||||
|
tokenRoutesMap.get(tokenKey)!.swapRoutes.push({
|
||||||
|
poolAddress,
|
||||||
|
inputTokenIndex,
|
||||||
|
outputTokenIndex,
|
||||||
|
inputTokenDecimal,
|
||||||
|
outputTokenDecimal,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,55 +369,54 @@ export function useTokenDetails(userAddress: `0x${string}` | undefined) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build multicall contracts array - 4 calls per token (name, symbol, decimals, balanceOf)
|
||||||
|
const contracts = tokens.flatMap((tokenAddress) => [
|
||||||
|
{
|
||||||
|
address: tokenAddress,
|
||||||
|
abi: ERC20ABI,
|
||||||
|
functionName: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
address: tokenAddress,
|
||||||
|
abi: ERC20ABI,
|
||||||
|
functionName: 'symbol',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
address: tokenAddress,
|
||||||
|
abi: ERC20ABI,
|
||||||
|
functionName: 'decimals',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
address: tokenAddress,
|
||||||
|
abi: ERC20ABI,
|
||||||
|
functionName: 'balanceOf',
|
||||||
|
args: [userAddress],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Execute multicall
|
||||||
|
const results = await publicClient.multicall({
|
||||||
|
contracts: contracts as any,
|
||||||
|
allowFailure: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Parse results
|
||||||
const details: TokenDetails[] = [];
|
const details: TokenDetails[] = [];
|
||||||
|
|
||||||
// Make individual calls for each token
|
|
||||||
for (let i = 0; i < tokens.length; i++) {
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
const tokenAddress = tokens[i];
|
const baseIndex = i * 4;
|
||||||
try {
|
const nameResult = results[baseIndex];
|
||||||
const [name, symbol, decimals, balance] = await Promise.all([
|
const symbolResult = results[baseIndex + 1];
|
||||||
publicClient.readContract({
|
const decimalsResult = results[baseIndex + 2];
|
||||||
address: tokenAddress,
|
const balanceResult = results[baseIndex + 3];
|
||||||
abi: ERC20ABI,
|
|
||||||
functionName: 'name',
|
|
||||||
}).catch(() => 'Unknown'),
|
|
||||||
publicClient.readContract({
|
|
||||||
address: tokenAddress,
|
|
||||||
abi: ERC20ABI,
|
|
||||||
functionName: 'symbol',
|
|
||||||
}).catch(() => '???'),
|
|
||||||
publicClient.readContract({
|
|
||||||
address: tokenAddress,
|
|
||||||
abi: ERC20ABI,
|
|
||||||
functionName: 'decimals',
|
|
||||||
}).catch(() => 18),
|
|
||||||
publicClient.readContract({
|
|
||||||
address: tokenAddress,
|
|
||||||
abi: ERC20ABI,
|
|
||||||
functionName: 'balanceOf',
|
|
||||||
args: [userAddress],
|
|
||||||
}).catch(() => BigInt(0)),
|
|
||||||
]);
|
|
||||||
|
|
||||||
details.push({
|
details.push({
|
||||||
address: tokenAddress,
|
address: tokens[i],
|
||||||
name: name as string,
|
name: nameResult.status === 'success' ? (nameResult.result as string) : 'Unknown',
|
||||||
symbol: symbol as string,
|
symbol: symbolResult.status === 'success' ? (symbolResult.result as string) : '???',
|
||||||
decimals: Number(decimals),
|
decimals: decimalsResult.status === 'success' ? Number(decimalsResult.result) : 18,
|
||||||
balance: balance as bigint,
|
balance: balanceResult.status === 'success' ? (balanceResult.result as bigint) : BigInt(0),
|
||||||
index: i,
|
index: i,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
|
||||||
// Add token with fallback values if individual call fails
|
|
||||||
details.push({
|
|
||||||
address: tokenAddress,
|
|
||||||
name: 'Unknown',
|
|
||||||
symbol: '???',
|
|
||||||
decimals: 18,
|
|
||||||
balance: BigInt(0),
|
|
||||||
index: i,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setTokenDetails(details);
|
setTokenDetails(details);
|
||||||
@@ -525,11 +567,9 @@ export function useGetAllPools(offset: number = 0, limit: number = 100) {
|
|||||||
priceStr = `$${finalPrice.toFixed(4)}`;
|
priceStr = `$${finalPrice.toFixed(4)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate TVL (approximate by getting first token balance and multiplying by 3)
|
// Calculate TVL (approximate by getting first token balance and multiplying by number of tokens)
|
||||||
const tokenBalance = Number(balance) / Math.pow(10, decimals);
|
const tokenBalance = Number(balance) / Math.pow(10, decimals);
|
||||||
|
const approximateTVL = tokenBalance * tokens.length;
|
||||||
console.log('tokenBalance', tokenBalance);
|
|
||||||
const approximateTVL = tokenBalance * 3;
|
|
||||||
tvlStr = formatTVL(approximateTVL);
|
tvlStr = formatTVL(approximateTVL);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -120,18 +120,6 @@ export function useSwapAmounts(
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
const amountInTokenUnits = parseUnits(fromAmount, fromTokenDecimals);
|
const amountInTokenUnits = parseUnits(fromAmount, fromTokenDecimals);
|
||||||
// Calculate limit price based on slippage tolerance
|
|
||||||
// limitPrice in Q96 format = Q96 * (100 + slippage%) / 100
|
|
||||||
// This represents the maximum acceptable price ratio (1 + slippage%)
|
|
||||||
const slippageBasisPoints = BigInt(Math.floor(slippagePercent * 100)); // Convert to basis points (0.5% = 50)
|
|
||||||
const limitPrice = (Q96 * (10000n + slippageBasisPoints)) / 10000n;
|
|
||||||
|
|
||||||
console.log('Limit Price Calculation:', {
|
|
||||||
slippagePercent,
|
|
||||||
slippageBasisPoints: slippageBasisPoints.toString(),
|
|
||||||
limitPriceQ96: limitPrice.toString(),
|
|
||||||
Q96: Q96.toString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const results: SwapAmountResult[] = [];
|
const results: SwapAmountResult[] = [];
|
||||||
const chainId = await publicClient.getChainId();
|
const chainId = await publicClient.getChainId();
|
||||||
@@ -146,8 +134,8 @@ export function useSwapAmounts(
|
|||||||
// Evaluate ALL routes for this token
|
// Evaluate ALL routes for this token
|
||||||
for (const route of token.swapRoutes) {
|
for (const route of token.swapRoutes) {
|
||||||
try {
|
try {
|
||||||
// Get swap amounts
|
// Get swap amounts with NO LIMIT
|
||||||
const swapResult = await publicClient.readContract({
|
const [swapInputAmount, swapOutputAmount, inFee] = await publicClient.readContract({
|
||||||
address: route.poolAddress,
|
address: route.poolAddress,
|
||||||
abi: IPartyPoolABI,
|
abi: IPartyPoolABI,
|
||||||
functionName: 'swapAmounts',
|
functionName: 'swapAmounts',
|
||||||
@@ -155,12 +143,10 @@ export function useSwapAmounts(
|
|||||||
BigInt(route.inputTokenIndex),
|
BigInt(route.inputTokenIndex),
|
||||||
BigInt(route.outputTokenIndex),
|
BigInt(route.outputTokenIndex),
|
||||||
amountInTokenUnits,
|
amountInTokenUnits,
|
||||||
limitPrice,
|
0n, // NO LIMIT
|
||||||
],
|
],
|
||||||
}) as readonly [bigint, bigint, bigint];
|
}) as readonly [bigint, bigint, bigint];
|
||||||
|
|
||||||
const [amountIn, amountOut, fee] = swapResult;
|
|
||||||
|
|
||||||
// Get kappa for this pool
|
// Get kappa for this pool
|
||||||
const kappa = await publicClient.readContract({
|
const kappa = await publicClient.readContract({
|
||||||
address: route.poolAddress,
|
address: route.poolAddress,
|
||||||
@@ -172,19 +158,6 @@ export function useSwapAmounts(
|
|||||||
let calculatedSlippage: number | undefined;
|
let calculatedSlippage: number | undefined;
|
||||||
if (partyInfoAddress) {
|
if (partyInfoAddress) {
|
||||||
try {
|
try {
|
||||||
// Get swap amounts with NO LIMIT (0 means no price limit)
|
|
||||||
const [swapInputAmount, swapOutputAmount, inFee] = await publicClient.readContract({
|
|
||||||
address: route.poolAddress,
|
|
||||||
abi: IPartyPoolABI,
|
|
||||||
functionName: 'swapAmounts',
|
|
||||||
args: [
|
|
||||||
BigInt(route.inputTokenIndex),
|
|
||||||
BigInt(route.outputTokenIndex),
|
|
||||||
amountInTokenUnits,
|
|
||||||
0n, // NO LIMIT
|
|
||||||
],
|
|
||||||
}) as readonly [bigint, bigint, bigint];
|
|
||||||
|
|
||||||
// Get the current market price from PoolInfo
|
// Get the current market price from PoolInfo
|
||||||
const priceInt128 = await publicClient.readContract({
|
const priceInt128 = await publicClient.readContract({
|
||||||
address: partyInfoAddress,
|
address: partyInfoAddress,
|
||||||
@@ -193,11 +166,10 @@ export function useSwapAmounts(
|
|||||||
args: [route.poolAddress, BigInt(route.inputTokenIndex), BigInt(route.outputTokenIndex)],
|
args: [route.poolAddress, BigInt(route.inputTokenIndex), BigInt(route.outputTokenIndex)],
|
||||||
}) as bigint;
|
}) as bigint;
|
||||||
|
|
||||||
|
|
||||||
// Convert Q128 format to decimal (price = priceValue / 2^128)
|
// Convert Q128 format to decimal (price = priceValue / 2^128)
|
||||||
// Then apply decimal conversion: 10^18 / 10^outputTokenDecimals
|
// Then apply decimal conversion: 10^18 / 10^outputTokenDecimals
|
||||||
const priceQ128 = Number(priceInt128) / 2 ** 128;
|
const priceQ128 = Number(priceInt128) / 2 ** 128;
|
||||||
const decimalAdjustment = 10 ** Math.abs(route.outputTokenDecimal - route.inputTokenDecimal);
|
const decimalAdjustment = 10 ** (route.outputTokenDecimal - route.inputTokenDecimal);
|
||||||
const marketPrice = priceQ128 / decimalAdjustment;
|
const marketPrice = priceQ128 / decimalAdjustment;
|
||||||
const swapOutputAmountDecimal = Number(swapOutputAmount) / 10 ** route.outputTokenDecimal;
|
const swapOutputAmountDecimal = Number(swapOutputAmount) / 10 ** route.outputTokenDecimal;
|
||||||
const swapInputAmountDecimal = Number(swapInputAmount) / 10 ** route.inputTokenDecimal;
|
const swapInputAmountDecimal = Number(swapInputAmount) / 10 ** route.inputTokenDecimal;
|
||||||
@@ -214,9 +186,9 @@ export function useSwapAmounts(
|
|||||||
routeResults.push({
|
routeResults.push({
|
||||||
tokenAddress: token.address,
|
tokenAddress: token.address,
|
||||||
tokenSymbol: token.symbol,
|
tokenSymbol: token.symbol,
|
||||||
amountIn,
|
amountIn: swapInputAmount,
|
||||||
amountOut,
|
amountOut: swapOutputAmount,
|
||||||
fee,
|
fee: inFee,
|
||||||
poolAddress: route.poolAddress,
|
poolAddress: route.poolAddress,
|
||||||
kappa,
|
kappa,
|
||||||
inputTokenIndex: route.inputTokenIndex,
|
inputTokenIndex: route.inputTokenIndex,
|
||||||
@@ -388,9 +360,7 @@ export function useSwap() {
|
|||||||
await publicClient.waitForTransactionReceipt({ hash: approvalHash });
|
await publicClient.waitForTransactionReceipt({ hash: approvalHash });
|
||||||
console.log('✅ Approval confirmed');
|
console.log('✅ Approval confirmed');
|
||||||
|
|
||||||
// STEP 2: Calculate limit price and deadline
|
// STEP 2: Calculate deadline
|
||||||
const slippageBasisPoints = BigInt(Math.floor(slippagePercent * 100));
|
|
||||||
const limitPrice = (Q96 * (10000n + slippageBasisPoints)) / 10000n;
|
|
||||||
const deadline = BigInt(Math.floor(Date.now() / 1000) + 1200);
|
const deadline = BigInt(Math.floor(Date.now() / 1000) + 1200);
|
||||||
|
|
||||||
console.log('🚀 Executing swap with params:', {
|
console.log('🚀 Executing swap with params:', {
|
||||||
@@ -400,12 +370,12 @@ export function useSwap() {
|
|||||||
inputTokenIndex,
|
inputTokenIndex,
|
||||||
outputTokenIndex,
|
outputTokenIndex,
|
||||||
maxAmountIn: maxAmountIn.toString(),
|
maxAmountIn: maxAmountIn.toString(),
|
||||||
limitPrice: limitPrice.toString(),
|
limitPrice: '0 (no limit)',
|
||||||
deadline: deadline.toString(),
|
deadline: deadline.toString(),
|
||||||
unwrap: false,
|
unwrap: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
// STEP 3: Execute the swap transaction
|
// STEP 3: Execute the swap transaction with no limit price
|
||||||
const hash = await walletClient.writeContract({
|
const hash = await walletClient.writeContract({
|
||||||
address: poolAddress,
|
address: poolAddress,
|
||||||
abi: IPartyPoolABI,
|
abi: IPartyPoolABI,
|
||||||
@@ -417,7 +387,7 @@ export function useSwap() {
|
|||||||
BigInt(inputTokenIndex),
|
BigInt(inputTokenIndex),
|
||||||
BigInt(outputTokenIndex),
|
BigInt(outputTokenIndex),
|
||||||
maxAmountIn,
|
maxAmountIn,
|
||||||
limitPrice,
|
0n, // no limit price
|
||||||
deadline,
|
deadline,
|
||||||
false, // unwrap
|
false, // unwrap
|
||||||
'0x', // cbData (empty bytes)
|
'0x', // cbData (empty bytes)
|
||||||
|
|||||||
Reference in New Issue
Block a user