-
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.
Merge pull request #5000 from cowprotocol/release/17-10-2024
Release 17-10-2024
- Loading branch information
Showing
58 changed files
with
1,075 additions
and
474 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
63 changes: 63 additions & 0 deletions
63
apps/cowswap-frontend/src/common/updaters/FeesUpdater/isRefetchQuoteRequired.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,63 @@ | ||
import ms from 'ms.macro' | ||
|
||
import { QuoteInformationObject } from 'legacy/state/price/reducer' | ||
import { LegacyFeeQuoteParams } from 'legacy/state/price/types' | ||
|
||
import { quoteUsingSameParameters } from './quoteUsingSameParameters' | ||
|
||
const RENEW_FEE_QUOTES_BEFORE_EXPIRATION_TIME = ms`30s` // Will renew the quote if there's less than 30 seconds left for the quote to expire | ||
const WAITING_TIME_BETWEEN_EQUAL_REQUESTS = ms`5s` // Prevents from sending the same request to often (max, every 5s) | ||
|
||
type FeeQuoteParams = Omit<LegacyFeeQuoteParams, 'validTo'> | ||
|
||
/** | ||
* Returns if the quote has been recently checked | ||
*/ | ||
function wasQuoteCheckedRecently(lastQuoteCheck: number): boolean { | ||
return lastQuoteCheck + WAITING_TIME_BETWEEN_EQUAL_REQUESTS > Date.now() | ||
} | ||
|
||
/** | ||
* Returns true if the fee quote expires soon (in less than RENEW_FEE_QUOTES_BEFORE_EXPIRATION_TIME milliseconds) | ||
*/ | ||
function isExpiringSoon(quoteExpirationIsoDate: string, threshold: number): boolean { | ||
const feeExpirationDate = Date.parse(quoteExpirationIsoDate) | ||
return feeExpirationDate <= Date.now() + threshold | ||
} | ||
|
||
/** | ||
* Decides if we need to refetch the fee information given the current parameters (selected by the user), and the current feeInfo (in the state) | ||
*/ | ||
export function isRefetchQuoteRequired( | ||
isLoading: boolean, | ||
currentParams: FeeQuoteParams, | ||
quoteInformation?: QuoteInformationObject, | ||
): boolean { | ||
// If there's no quote/fee information, we always re-fetch | ||
if (!quoteInformation) { | ||
return true | ||
} | ||
|
||
if (!quoteUsingSameParameters(currentParams, quoteInformation)) { | ||
// If the current parameters don't match the fee, the fee information is invalid and needs to be re-fetched | ||
return true | ||
} | ||
|
||
// The query params are the same, so we only ask for a new quote if: | ||
// - If the quote was not queried recently | ||
// - There's not another price query going on right now | ||
// - The quote will expire soon | ||
if (wasQuoteCheckedRecently(quoteInformation.lastCheck)) { | ||
// Don't Re-fetch if it was queried recently | ||
return false | ||
} else if (isLoading) { | ||
// Don't Re-fetch if there's another quote going on with the same params | ||
// It's better to wait for the timeout or resolution. Also prevents an issue of refreshing too fast with slow APIs | ||
return false | ||
} else if (quoteInformation.fee) { | ||
// Re-fetch if the fee is expiring soon | ||
return isExpiringSoon(quoteInformation.fee.expirationDate, RENEW_FEE_QUOTES_BEFORE_EXPIRATION_TIME) | ||
} | ||
|
||
return false | ||
} |
70 changes: 70 additions & 0 deletions
70
apps/cowswap-frontend/src/common/updaters/FeesUpdater/quoteUsingSameParameters.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,70 @@ | ||
import { QuoteInformationObject } from 'legacy/state/price/reducer' | ||
import { LegacyFeeQuoteParams } from 'legacy/state/price/types' | ||
|
||
import { decodeAppData } from 'modules/appData' | ||
|
||
type FeeQuoteParams = Omit<LegacyFeeQuoteParams, 'validTo'> | ||
|
||
/** | ||
* Checks if the parameters for the current quote are correct | ||
* | ||
* Quotes are only valid for a given token-pair and amount. If any of these parameter change, the fee needs to be re-fetched | ||
*/ | ||
export function quoteUsingSameParameters(currentParams: FeeQuoteParams, quoteInfo: QuoteInformationObject): boolean { | ||
const { | ||
amount: currentAmount, | ||
sellToken: currentSellToken, | ||
buyToken: currentBuyToken, | ||
kind: currentKind, | ||
userAddress: currentUserAddress, | ||
receiver: currentReceiver, | ||
appData: currentAppData, | ||
} = currentParams | ||
const { amount, buyToken, sellToken, kind, userAddress, receiver, appData } = quoteInfo | ||
const hasSameReceiver = currentReceiver && receiver ? currentReceiver === receiver : true | ||
const hasSameAppData = compareAppDataWithoutQuoteData(appData, currentAppData) | ||
|
||
// cache the base quote params without quoteInfo user address to check | ||
const paramsWithoutAddress = | ||
sellToken === currentSellToken && | ||
buyToken === currentBuyToken && | ||
amount === currentAmount && | ||
kind === currentKind && | ||
hasSameAppData && | ||
hasSameReceiver | ||
// 2 checks: if there's a quoteInfo user address (meaning quote was already calculated once) and one without | ||
// in case user is not connected | ||
return userAddress ? currentUserAddress === userAddress && paramsWithoutAddress : paramsWithoutAddress | ||
} | ||
|
||
/** | ||
* Compares appData without taking into account the `quote` metadata | ||
*/ | ||
function compareAppDataWithoutQuoteData<T extends string | undefined>(a: T, b: T): boolean { | ||
if (a === b) { | ||
return true | ||
} | ||
const cleanedA = removeQuoteMetadata(a) | ||
const cleanedB = removeQuoteMetadata(b) | ||
|
||
return cleanedA === cleanedB | ||
} | ||
|
||
/** | ||
* If appData is set and is valid, remove `quote` metadata from it | ||
*/ | ||
function removeQuoteMetadata(appData: string | undefined): string | undefined { | ||
if (!appData) { | ||
return | ||
} | ||
|
||
const decoded = decodeAppData(appData) | ||
|
||
if (!decoded) { | ||
return | ||
} | ||
|
||
const { metadata: fullMetadata, ...rest } = decoded | ||
const { quote: _, ...metadata } = fullMetadata | ||
return JSON.stringify({ ...rest, metadata }) | ||
} |
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
Oops, something went wrong.