Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 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
49 changes: 29 additions & 20 deletions components/BatchReviewModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ const { chainId: addressesChainId, eulerCoreAddresses } = useEulerAddresses()
const { buildKnownSymbols, resolveSymbol } = useTokenSymbolResolver()
const { getVault, isVerifiedVault } = useVaultRegistry()
const { copied, copyToClipboard } = useClipboardCopy()
const nowMs = ref(Date.now())
const staleQuoteThresholdMs = 3 * 60 * 1000
let nowTimer: ReturnType<typeof setInterval> | undefined
const owner = computed(() => (isSpyMode.value ? spyAddress.value : walletAddress.value) || '')
const chainId = computed(() => wagmiChainId.value ?? addressesChainId.value)
const ownerSubAccountKey = computed(() => {
Expand Down Expand Up @@ -153,14 +150,6 @@ const reulUnlockWarnings = computed<Array<{ id: string, description: string }>>(
}),
)

const hasStaleSwapQuote = computed(() =>
entries.value.some((entry) => {
const quoteFetchedAt = entry.review?.quoteFetchedAt
return typeof quoteFetchedAt === 'number'
&& nowMs.value - quoteFetchedAt > staleQuoteThresholdMs
}),
)

// Sub-accounts of entries that revert mid-batch (per-item revert: vault
// liquidity, vault cap, etc.). The op rolls back so its position SHOULD be
// unchanged, but in some cases the layer's reported health factor still drifts
Expand Down Expand Up @@ -224,6 +213,19 @@ const openId = ref<string | null>(null)
const toggle = (id: string) => {
openId.value = openId.value === id ? null : id
}
const nowMs = ref(Date.now())
const staleQuoteThresholdMs = 3 * 60 * 1000
let nowTimer: ReturnType<typeof setInterval> | undefined

const getQuoteFetchedAt = (entry: { review?: Record<string, unknown> }): number | null => {
const value = entry.review?.quoteFetchedAt
return typeof value === 'number' ? value : null
}
const isEntryQuoteStale = (entry: { review?: Record<string, unknown> }) => {
const fetchedAt = getQuoteFetchedAt(entry)
return typeof fetchedAt === 'number' && nowMs.value - fetchedAt > staleQuoteThresholdMs
}
const hasStaleQuoteEntries = computed(() => entries.value.some(isEntryQuoteStale))

// Approvals the user will be asked to sign, decoded from the prepared plan.
interface ResolvedApproval { type: string, token: string }
Expand All @@ -240,7 +242,6 @@ onMounted(async () => {
nowTimer = setInterval(() => {
nowMs.value = Date.now()
}, 1000)

void fetchTenderlyEnabled()
isPreparing.value = true
prepareError.value = ''
Expand Down Expand Up @@ -382,6 +383,14 @@ const handleClose = () => {
description="You are granting the Permit2 contract an unlimited token allowance. Permit2 is a Uniswap contract that lets you approve once, then sign per-action permissions without new onchain approvals."
/>

<UiAlert
v-if="hasStaleQuoteEntries"
variant="warning"
size="compact"
title="Stale swap quote"
description="This batch includes a swap quote which is more than 3 minutes old. Consider refreshing it to get the best execution price"
/>

<!-- Operations -->
<div>
<p class="text-p3 text-content-tertiary uppercase tracking-[0.04em] mb-8">
Expand Down Expand Up @@ -431,6 +440,14 @@ const handleClose = () => {
:market="marketByEntryId[entry.id]"
class="mt-6 px-12"
/>
<UiAlert
v-if="isEntryQuoteStale(entry)"
class="mt-6"
variant="warning"
size="compact"
title="Stale swap quote"
description="This operation uses a swap quote that is more than 3 minutes old."
/>
<!-- Same decoded operation steps the per-op review modal shows
(the builder row's (i) icon). -->
<div
Expand Down Expand Up @@ -465,14 +482,6 @@ const handleClose = () => {
:description="warning.description"
/>

<UiAlert
v-if="hasStaleSwapQuote"
variant="warning"
size="compact"
title="Stale swap quote"
description="This batch includes a swap quote which is more than 3 minutes old. Consider refreshing it to get the best execution price"
/>

<!-- Wallet changes -->
<BatchWalletChanges
v-if="walletChanges.length"
Expand Down
6 changes: 3 additions & 3 deletions components/entities/asset/AssetInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ watch(() => props.collateralOptions, (options) => {
const firstEnabled = options.findIndex(o => !o.disabled)
if (firstEnabled >= 0) {
selectedIdx.value = firstEnabled
emits('change-collateral', firstEnabled)
emits('change-collateral', firstEnabled, options[firstEnabled])
}
}
})
Expand Down Expand Up @@ -184,9 +184,9 @@ const openChooseCollateralModal = () => {
selected: selectedIdx.value,
title: props.collateralModalTitle,
apyLabel: props.collateralModalApyLabel,
onSave: (selectedIndex: number) => {
onSave: (selectedIndex: number, selectedOption: CollateralOption) => {
selectedIdx.value = selectedIndex
emits('change-collateral', selectedIndex)
emits('change-collateral', selectedIndex, selectedOption)
modal.close()
},
},
Expand Down
11 changes: 8 additions & 3 deletions components/entities/operation/OperationReviewModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ interface REULUnlockInfo {
daysUntilMaturity: number
}

const { type, asset, assetIconUrl, reulUnlockInfo, amount, onConfirm, plan, prepared, swapToAsset, swapToAmount, swapMode, swapEstimatedSide, supplyingAssetForBorrow, supplyingAmount, transferAmounts, submittingLabel, quoteFetchedAt, hideExecute, subAccount, marketLabel } = defineProps<{
type?: 'supply' | 'withdraw' | 'borrow' | 'repay' | 'swap' | 'transfer' | 'reward' | 'brevis-reward' | 'fuul-reward' | 'turtle-reward' | 'reul-unlock' | 'disableCollateral' | 'swap-supply' | 'swap-withdraw' | 'swap-borrow'
const { type, asset, assetIconUrl, reulUnlockInfo, amount, onConfirm, plan, prepared, swapFromAsset, swapFromAmount, swapToAsset, swapToAmount, swapMode, swapEstimatedSide, supplyingAssetForBorrow, supplyingAmount, transferAmounts, vaultAmounts, submittingLabel, quoteFetchedAt, hideExecute, subAccount, marketLabel } = defineProps<{
type?: 'supply' | 'withdraw' | 'borrow' | 'repay' | 'swap' | 'transfer' | 'refinance' | 'reward' | 'brevis-reward' | 'fuul-reward' | 'turtle-reward' | 'reul-unlock' | 'disableCollateral' | 'swap-supply' | 'swap-withdraw' | 'swap-borrow'
asset: VaultAsset
assetIconUrl?: string
amount: number | string
Expand All @@ -35,6 +35,8 @@ const { type, asset, assetIconUrl, reulUnlockInfo, amount, onConfirm, plan, prep
prepared?: TransactionPlanPrepared
supplyingAssetForBorrow?: VaultAsset
supplyingAmount?: number | string
swapFromAsset?: VaultAsset
swapFromAmount?: number | string
swapToAsset?: VaultAsset
swapToAmount?: number | string
swapMode?: SwapperMode
Expand All @@ -44,6 +46,7 @@ const { type, asset, assetIconUrl, reulUnlockInfo, amount, onConfirm, plan, prep
subAccount?: string
hasBorrows?: boolean
transferAmounts?: Record<string, string>
vaultAmounts?: Record<string, string>
submittingLabel?: string
/** Milliseconds since epoch when the active swap quote was fetched */
quoteFetchedAt?: number | null
Expand Down Expand Up @@ -200,7 +203,7 @@ const displaySteps = computed((): DisplayStep[] => {
const ctx: StepDecodingContext = {
type, asset, assetIconUrl, amount,
supplyingAssetForBorrow, supplyingAmount,
swapToAsset, swapToAmount, swapMode, swapEstimatedSide, transferAmounts,
swapFromAsset, swapFromAmount, swapToAsset, swapToAmount, swapMode, swapEstimatedSide, transferAmounts, vaultAmounts,
}
return buildTransactionPlanDisplaySteps(currentPlan, ctx, getVault, getAssetLogoUrl)
})
Expand Down Expand Up @@ -293,6 +296,8 @@ const btnLabel = computed(() => {
return 'Swap'
case 'transfer':
return 'Transfer'
case 'refinance':
return 'Refinance'
case 'reul-unlock':
return 'Unlock'
case 'reward':
Expand Down
Loading