Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
e4dffb9
tmp
viet-nv Sep 14, 2025
394183a
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
viet-nv Sep 14, 2025
1393682
feat: create smart exit order
viet-nv Sep 17, 2025
300998a
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
viet-nv Sep 17, 2025
b1ed55b
Smart exit list
viet-nv Sep 17, 2025
3c0f7e8
feat: smart exit
viet-nv Sep 19, 2025
de0f8c3
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
viet-nv Sep 19, 2025
7f0ab47
chore: navigate to smart exit list
viet-nv Sep 21, 2025
b0c1681
feat: cancel order
viet-nv Sep 23, 2025
8526d23
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
viet-nv Sep 24, 2025
5e3f5eb
fix: change network before remove
viet-nv Sep 24, 2025
3f23f01
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
viet-nv Sep 24, 2025
0034ca7
feat: smart exit mobile
viet-nv Sep 24, 2025
f487293
feat: filter and paging
viet-nv Sep 25, 2025
5fb0bf0
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
viet-nv Oct 7, 2025
0e27396
fix: create smart exit order
viet-nv Oct 7, 2025
190a5a7
feat: mobile for create
viet-nv Oct 8, 2025
d5c3b91
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
viet-nv Oct 8, 2025
6d46b12
fix: smart exit filter
viet-nv Oct 8, 2025
7d3cf8a
feat: support pancake v3
viet-nv Oct 9, 2025
5a0dc90
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
viet-nv Oct 9, 2025
7fcae13
feat: pancake support
viet-nv Oct 9, 2025
c9f2090
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
viet-nv Oct 12, 2025
d0a80cf
add all status
viet-nv Oct 12, 2025
80fd23d
fix: smart exit order check
viet-nv Oct 13, 2025
e4937ed
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
tienkane Oct 13, 2025
f57c6d9
fix: time picker
viet-nv Oct 13, 2025
d897d4b
pre-release zap earn
viet-nv Oct 14, 2025
46eeb50
fix: time
viet-nv Oct 14, 2025
007ec1f
feat: remove condition
viet-nv Oct 14, 2025
183e5ce
fix: deadline
viet-nv Oct 14, 2025
7ea2199
fix: deadline
viet-nv Oct 14, 2025
f44d503
fix: status display
viet-nv Oct 14, 2025
7c9fae6
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
viet-nv Oct 15, 2025
4c73ac0
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
viet-nv Oct 16, 2025
3bbbe9f
feat: earned fee yeild
viet-nv Oct 16, 2025
693f1d0
Merge branch 'feat/smart-exit' of github.com:KyberNetwork/kyberswap-i…
viet-nv Oct 17, 2025
05859aa
fix: lint
viet-nv Oct 17, 2025
8861453
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
viet-nv Oct 22, 2025
2323529
update sc address
viet-nv Oct 22, 2025
fb96bfd
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
viet-nv Oct 24, 2025
4f36a53
env prod
viet-nv Oct 24, 2025
7105c61
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
tienkane Oct 28, 2025
da573ed
fix: user positions filter in mobile screen
tienkane Oct 29, 2025
f669ef7
fix: smart exit with staking position
tienkane Oct 29, 2025
89fe89c
fix: relative path to absolute path
tienkane Oct 29, 2025
5bef9bb
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
tienkane Oct 29, 2025
5905ee0
fix
tienkane Oct 29, 2025
e914733
fix: add supported smartexit to chain, add disabled tooltip
tienkane Oct 29, 2025
2035e22
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
tienkane Oct 30, 2025
ea2a5a3
fix: view orders icon & pagination display
tienkane Oct 30, 2025
d8c7671
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
tienkane Oct 31, 2025
9ddbc06
feat: max gas setting
tienkane Nov 3, 2025
a4edd93
fix
tienkane Nov 3, 2025
7ff8853
fix
tienkane Nov 3, 2025
128a770
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
tienkane Nov 3, 2025
204643a
fix: nonce using timestamp
tienkane Nov 4, 2025
7055097
fix: small gas
tienkane Nov 4, 2025
7179ca8
refactor
tienkane Nov 4, 2025
f63f71b
rename smart exit -> smart exit orders
tienkane Nov 4, 2025
2d91b4a
fix
tienkane Nov 4, 2025
d964701
refactor type
tienkane Nov 5, 2025
7f1d798
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
tienkane Nov 5, 2025
71cb35b
fix permit
tienkane Nov 6, 2025
52c7342
test
tienkane Nov 6, 2025
2bab51b
test
tienkane Nov 6, 2025
3cdb9bc
test
tienkane Nov 6, 2025
42902fe
feat: refactor selectedMetric & 2 price conditions
tienkane Nov 6, 2025
f9c5654
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
tienkane Nov 14, 2025
3b95a6f
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
tienkane Nov 25, 2025
cf841fe
fix
tienkane Nov 26, 2025
d4aeb27
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
tienkane Nov 27, 2025
0cff94b
feat: price slider
tienkane Dec 1, 2025
c1ab797
integrate with price slider
tienkane Dec 1, 2025
ba0fc4b
Merge branch 'main' of github.com:KyberNetwork/kyberswap-interface in…
tienkane Dec 1, 2025
50e87a8
fix(price-slider): debounce, circular update, refactor metrics
tienkane Dec 1, 2025
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
2 changes: 2 additions & 0 deletions apps/kyberswap-interface/.env.production
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,5 @@ VITE_ZAP_EARN_URL=https://zap-earn-service-v3.kyberengineering.io/api

VITE_AFFILIATE_SERVICE=https://affiliate-service.kyberengineering.io/api
VITE_SOLANA_RPC=https://solana.kyberengineering.io

VITE_SMART_EXIT_API_URL=https://pre-conditional-order.kyberengineering.io/api
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ReactComponent as OverviewIcon } from 'assets/svg/earn/ic_earn_overview
import { ReactComponent as PoolsIcon } from 'assets/svg/earn/ic_earn_pools.svg'
import { ReactComponent as PositionsIcon } from 'assets/svg/earn/ic_earn_positions.svg'
import { ReactComponent as FarmingIcon } from 'assets/svg/earn/ic_farming.svg'
import { ReactComponent as ListSmartExitIcon } from 'assets/svg/earn/ic_list_smart_exit.svg'
import { ReactComponent as KemIcon } from 'assets/svg/kyber/kem.svg'
import NavGroup from 'components/Header/groups/NavGroup'
import { DropdownTextAnchor, StyledNavLink } from 'components/Header/styleds'
Expand All @@ -24,6 +25,7 @@ const EarnNavGroup = () => {
APP_PATHS.EARN_POOLS,
APP_PATHS.EARN_POSITIONS,
APP_PATHS.EARN_POSITION_DETAIL,
APP_PATHS.EARN_SMART_EXIT,
].some(path => pathname.includes(path))

return (
Expand Down Expand Up @@ -98,6 +100,12 @@ const EarnNavGroup = () => {
{t`My Positions`}
</Flex>
</StyledNavLink>
<StyledNavLink data-testid="earn-positions-nav-link" to={{ pathname: `${APP_PATHS.EARN_SMART_EXIT}` }}>
<Flex sx={{ gap: '12px' }} alignItems="center">
<ListSmartExitIcon width={16} height={16} />
{t`Smart Exit Orders`}
</Flex>
</StyledNavLink>
</Flex>
}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const highlight = keyframes`
`

//transition: transform 300ms;
const DropdownIcon = styled.div`
export const DropdownIcon = styled.div`
margin-left: 6px;
border-radius: 50%;
width: 12px;
Expand All @@ -42,7 +42,7 @@ const DropdownIcon = styled.div`
padding: 2px;

transition: all 0.2s ease-in-out;
color: ${({ theme }) => theme.subText};
color: ${({ theme }) => theme.white2};
&[data-flip='true'] {
transform: rotate(180deg);
}
Expand All @@ -51,6 +51,10 @@ const DropdownIcon = styled.div`
background: ${({ theme }) => rgba(theme.primary, 0.6)};
animation: ${highlight} 2s infinite alternate ease-in-out;
}

&[data-warning='true'] {
color: ${({ theme }) => rgba(theme.warning, 0.9)};
}
`

type Props = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import { tickToPrice } from '@kyber/utils/dist/uniswapv3'
import React, { useMemo } from 'react'

import type { PriceAxisProps } from 'components/UniswapPriceSlider/types'
import { formatAxisPrice } from 'components/UniswapPriceSlider/utils'

import { PriceAxisContainer, PriceAxisLabel, PriceAxisLine, PriceAxisTick } from './styles'

const MAX_TICK_COUNT = 11 // More ticks for small ranges
const MIN_TICK_COUNT = 2 // Just first and last for extreme ranges

/**
* Calculate the optimal number of ticks and minimum gap based on price range
* More ticks for small ranges, fewer for large ranges
*/
const getOptimalTickConfig = (minPrice: number, maxPrice: number): { tickCount: number; minGapPercent: number } => {
if (minPrice <= 0 || maxPrice <= 0) {
return { tickCount: 7, minGapPercent: 15 }
}

// Calculate how many orders of magnitude the prices span
const priceRatio = maxPrice / minPrice
const ordersOfMagnitude = Math.log10(priceRatio)

// Very small range (< 0.5 orders): many ticks, small gap
if (ordersOfMagnitude <= 0.5) {
return { tickCount: MAX_TICK_COUNT, minGapPercent: 12 }
}
// Small range (0.5 - 1 order): good amount of ticks
if (ordersOfMagnitude <= 1) {
return { tickCount: 9, minGapPercent: 14 }
}
// Medium range (1 - 2 orders)
if (ordersOfMagnitude <= 2) {
return { tickCount: 7, minGapPercent: 16 }
}
// Large range (2 - 4 orders)
if (ordersOfMagnitude <= 4) {
return { tickCount: 5, minGapPercent: 20 }
}
// Very large range (4 - 8 orders)
if (ordersOfMagnitude <= 8) {
return { tickCount: 3, minGapPercent: 30 }
}
// Extreme range (> 8 orders): just first and last
return { tickCount: MIN_TICK_COUNT, minGapPercent: 40 }
}

/**
* Calculate tick positions for the axis
* Uses tick-space for even distribution (matching the slider)
*/
const calculateAxisTicks = (
viewRange: { min: number; max: number },
token0Decimals: number,
token1Decimals: number,
count: number,
invertPrice?: boolean,
): Array<{ tick: number; price: number; position: number }> => {
const tickRange = viewRange.max - viewRange.min
if (tickRange <= 0) return []

const step = tickRange / (count - 1)
const ticks: Array<{ tick: number; price: number; position: number }> = []

for (let i = 0; i < count; i++) {
const tick = Math.round(viewRange.min + step * i)
const price = +tickToPrice(tick, token0Decimals, token1Decimals, invertPrice)
const position = ((tick - viewRange.min) / tickRange) * 100

ticks.push({ tick, price, position })
}

return ticks
}

/**
* Filter ticks to ensure minimum spacing between labels
* Only shows labels that have sufficient gap from previous label
*/
const filterOverlappingTicks = (
ticks: Array<{ tick: number; price: number; position: number }>,
minGapPercent: number,
): Array<{ tick: number; price: number; position: number; showLabel: boolean }> => {
if (ticks.length === 0) return []

const result: Array<{ tick: number; price: number; position: number; showLabel: boolean }> = []
let lastLabelPosition = -Infinity

for (let i = 0; i < ticks.length; i++) {
const tick = ticks[i]
const isFirst = i === 0
const isLast = i === ticks.length - 1
const gap = tick.position - lastLabelPosition

// First tick always shows label
if (isFirst) {
lastLabelPosition = tick.position
result.push({ ...tick, showLabel: true })
continue
}

// Last tick: only show if enough gap, otherwise hide
if (isLast) {
const showLabel = gap >= minGapPercent
if (showLabel) lastLabelPosition = tick.position
result.push({ ...tick, showLabel })
continue
}

// Middle ticks: show if enough gap from previous label
const showLabel = gap >= minGapPercent
if (showLabel) lastLabelPosition = tick.position
result.push({ ...tick, showLabel })
}

return result
}

/**
* Price axis component that displays price scale below the slider
* Uses tick-based positioning to match the slider exactly
* Dynamically reduces tick count when price range is very large
*/
function PriceAxis({ viewRange, token0Decimals, token1Decimals, invertPrice }: PriceAxisProps) {
const axisTicks = useMemo(() => {
// Get min and max prices to determine optimal tick config
const minPrice = +tickToPrice(Math.round(viewRange.min), token0Decimals, token1Decimals, invertPrice)
const maxPrice = +tickToPrice(Math.round(viewRange.max), token0Decimals, token1Decimals, invertPrice)
const { tickCount, minGapPercent } = getOptimalTickConfig(
Math.min(minPrice, maxPrice),
Math.max(minPrice, maxPrice),
)

const ticks = calculateAxisTicks(viewRange, token0Decimals, token1Decimals, tickCount, invertPrice)
return filterOverlappingTicks(ticks, minGapPercent)
}, [viewRange, token0Decimals, token1Decimals, invertPrice])

return (
<PriceAxisContainer>
<PriceAxisLine />
{axisTicks.map(({ price, position, showLabel }, index) => {
// Only render if within visible range
if (position < -2 || position > 102) return null
return (
<React.Fragment key={index}>
<PriceAxisTick $position={position} />
{showLabel && <PriceAxisLabel $position={position}>{formatAxisPrice(price)}</PriceAxisLabel>}
</React.Fragment>
)
})}
</PriceAxisContainer>
)
}

export default React.memo(PriceAxis)
Loading