-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(hook-store): create bundle hooks tenderly simulation (#4943)
* chore: init tenderly module * feat: enable bundle simulations * refactor: change bundle simulation to use SWR * chore: consider custom recipient * chore: remove goldrush sdk * fix: error on post hooks get simulation * refactor: use bff on bundle simulation feature * chore: remove console.logs * chore: fix leandro comments * chore: remove unused tenderly consts * refactor: rename tenderly simulation hook * chore: refactor top token holder swr to jotai with cache * chore: rename hook to match file name * refactor: use seconds for cache time in toptokenholder state
- Loading branch information
1 parent
f6f6f8c
commit 435bfdf
Showing
13 changed files
with
448 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,4 +30,4 @@ | |
"dependencies": {}, | ||
"devDependencies": {}, | ||
"nx": {} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
apps/cowswap-frontend/src/modules/tenderly/hooks/useGetTopTokenHolders.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { useAtom } from 'jotai' | ||
import { useCallback } from 'react' | ||
|
||
import { topTokenHoldersAtom } from '../state/topTokenHolders' | ||
import { GetTopTokenHoldersParams } from '../types' | ||
|
||
export function useGetTopTokenHolders() { | ||
const [cachedData, fetchTopTokenHolders] = useAtom(topTokenHoldersAtom) | ||
|
||
return useCallback( | ||
async (params: GetTopTokenHoldersParams) => { | ||
const key = `${params.chainId}-${params.tokenAddress}` | ||
if (cachedData[key]?.value) { | ||
return cachedData[key].value | ||
} | ||
return fetchTopTokenHolders(params) | ||
}, | ||
[cachedData, fetchTopTokenHolders], | ||
) | ||
} |
106 changes: 106 additions & 0 deletions
106
apps/cowswap-frontend/src/modules/tenderly/hooks/useTenderlyBundleSimulation.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { useCallback } from 'react' | ||
|
||
import { useWalletInfo } from '@cowprotocol/wallet' | ||
|
||
import useSWR from 'swr' | ||
|
||
import { useHooks } from 'modules/hooksStore' | ||
import { useOrderParams } from 'modules/hooksStore/hooks/useOrderParams' | ||
|
||
import { useTokenContract } from 'common/hooks/useContract' | ||
|
||
import { useGetTopTokenHolders } from './useGetTopTokenHolders' | ||
|
||
import { completeBundleSimulation, preHooksBundleSimulation } from '../utils/bundleSimulation' | ||
import { generateNewSimulationData, generateSimulationDataToError } from '../utils/generateSimulationData' | ||
import { getTokenTransferInfo } from '../utils/getTokenTransferInfo' | ||
|
||
export function useTenderlyBundleSimulation() { | ||
const { account, chainId } = useWalletInfo() | ||
const { preHooks, postHooks } = useHooks() | ||
const orderParams = useOrderParams() | ||
const tokenSell = useTokenContract(orderParams?.sellTokenAddress) | ||
const tokenBuy = useTokenContract(orderParams?.buyTokenAddress) | ||
const buyAmount = orderParams?.buyAmount | ||
const sellAmount = orderParams?.sellAmount | ||
const orderReceiver = orderParams?.receiver || account | ||
|
||
const getTopTokenHolder = useGetTopTokenHolders() | ||
|
||
const simulateBundle = useCallback(async () => { | ||
if (postHooks.length === 0 && preHooks.length === 0) return | ||
|
||
if (!postHooks.length) | ||
return preHooksBundleSimulation({ | ||
chainId, | ||
preHooks, | ||
}) | ||
|
||
if (!account || !tokenBuy || !tokenSell || !buyAmount || !sellAmount || !orderReceiver) { | ||
return | ||
} | ||
|
||
const buyTokenTopHolders = await getTopTokenHolder({ | ||
tokenAddress: tokenBuy.address, | ||
chainId, | ||
}) | ||
|
||
if (!buyTokenTopHolders) return | ||
|
||
const tokenBuyTransferInfo = getTokenTransferInfo({ | ||
tokenHolders: buyTokenTopHolders, | ||
amountToTransfer: buyAmount, | ||
}) | ||
|
||
const paramsComplete = { | ||
postHooks, | ||
preHooks, | ||
tokenBuy, | ||
tokenBuyTransferInfo, | ||
sellAmount, | ||
orderReceiver, | ||
tokenSell, | ||
account, | ||
chainId, | ||
} | ||
|
||
return completeBundleSimulation(paramsComplete) | ||
}, [ | ||
account, | ||
chainId, | ||
getTopTokenHolder, | ||
tokenBuy, | ||
postHooks, | ||
preHooks, | ||
buyAmount, | ||
sellAmount, | ||
orderReceiver, | ||
tokenSell, | ||
]) | ||
|
||
const getNewSimulationData = useCallback(async () => { | ||
try { | ||
const simulationData = await simulateBundle() | ||
|
||
if (!simulationData) { | ||
return {} | ||
} | ||
|
||
return generateNewSimulationData(simulationData, { preHooks, postHooks }) | ||
} catch { | ||
return generateSimulationDataToError({ preHooks, postHooks }) | ||
} | ||
}, [preHooks, postHooks, simulateBundle]) | ||
|
||
const { data, isValidating: isBundleSimulationLoading } = useSWR( | ||
['tenderly-bundle-simulation', postHooks, preHooks, orderParams?.sellTokenAddress, orderParams?.buyTokenAddress], | ||
getNewSimulationData, | ||
{ | ||
revalidateOnFocus: false, | ||
revalidateOnReconnect: false, | ||
refreshWhenOffline: false, | ||
}, | ||
) | ||
|
||
return { data, isValidating: isBundleSimulationLoading } | ||
} |
55 changes: 55 additions & 0 deletions
55
apps/cowswap-frontend/src/modules/tenderly/state/topTokenHolders.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { atom } from 'jotai' | ||
import { atomWithStorage } from 'jotai/utils' | ||
|
||
import { BFF_BASE_URL } from '@cowprotocol/common-const' | ||
import { SupportedChainId } from '@cowprotocol/cow-sdk' | ||
|
||
export interface GetTopTokenHoldersParams { | ||
tokenAddress?: string | ||
chainId: SupportedChainId | ||
} | ||
|
||
export interface TokenHolder { | ||
address: string | ||
balance: string | ||
} | ||
|
||
export async function getTopTokenHolder({ tokenAddress, chainId }: GetTopTokenHoldersParams) { | ||
if (!tokenAddress) return | ||
|
||
return (await fetch(`${BFF_BASE_URL}/${chainId}/tokens/${tokenAddress}/topHolders`, { | ||
method: 'GET', | ||
}).then((res) => res.json())) as TokenHolder[] | ||
} | ||
|
||
interface CachedValue<T> { | ||
value: T | ||
timestamp: number | ||
} | ||
|
||
const baseTopTokenHolderAtom = atomWithStorage<Record<string, CachedValue<TokenHolder[] | undefined>>>( | ||
'topTokenHolders:v1', | ||
{}, | ||
) | ||
|
||
export const topTokenHoldersAtom = atom( | ||
(get) => get(baseTopTokenHolderAtom), | ||
async (get, set, params: GetTopTokenHoldersParams) => { | ||
const key = `${params.chainId}:${params.tokenAddress?.toLowerCase()}` | ||
const cachedData = get(baseTopTokenHolderAtom) | ||
const currentTime = Date.now() / 1000 | ||
|
||
// 1 hour in seconds | ||
if (cachedData[key] && currentTime - cachedData[key].timestamp <= 3600) { | ||
return cachedData[key].value | ||
} | ||
|
||
const newValue = await getTopTokenHolder(params) | ||
set(baseTopTokenHolderAtom, { | ||
...cachedData, | ||
[key]: { value: newValue, timestamp: currentTime }, | ||
}) | ||
|
||
return newValue | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { SupportedChainId } from '@cowprotocol/cow-sdk' | ||
|
||
export interface SimulationInput { | ||
input: string | ||
from: string | ||
to: string | ||
value?: string | ||
gas?: number | ||
gas_price?: string | ||
} | ||
|
||
export interface SimulationData { | ||
link: string | ||
status: boolean | ||
id: string | ||
} | ||
|
||
export interface GetTopTokenHoldersParams { | ||
tokenAddress?: string | ||
chainId: SupportedChainId | ||
} | ||
|
||
export interface TokenHolder { | ||
address: string | ||
balance: string | ||
} |
Oops, something went wrong.