Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
I
interface
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
LuckySwap
interface
Commits
9b2fe0bd
Unverified
Commit
9b2fe0bd
authored
May 08, 2020
by
Moody Salem
Committed by
GitHub
May 08, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use best trade to get the best route (#731)
parent
cb00e0ba
Changes
8
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
286 additions
and
321 deletions
+286
-321
index.tsx
src/components/ExchangePage/index.tsx
+158
-189
swap-store.ts
src/components/ExchangePage/swap-store.ts
+36
-0
Application.tsx
src/contexts/Application.tsx
+28
-12
Routes.tsx
src/contexts/Routes.tsx
+0
-110
Transactions.tsx
src/contexts/Transactions.tsx
+9
-3
Trades.ts
src/hooks/Trades.ts
+51
-0
index.tsx
src/index.tsx
+3
-6
index.ts
src/utils/index.ts
+1
-1
No files found.
src/components/ExchangePage/index.tsx
View file @
9b2fe0bd
This diff is collapsed.
Click to expand it.
src/components/ExchangePage/swap-store.ts
View file @
9b2fe0bd
import
{
WETH
}
from
'
@uniswap/sdk
'
import
{
useReducer
}
from
'
react
'
import
{
useWeb3React
}
from
'
../../hooks
'
import
{
QueryParams
}
from
'
../../utils
'
export
enum
Field
{
INPUT
,
OUTPUT
...
...
@@ -93,3 +98,34 @@ export function reducer(
}
}
}
export
function
useSwapStateReducer
(
params
:
QueryParams
)
{
const
{
chainId
}
=
useWeb3React
()
return
useReducer
(
reducer
,
{
independentField
:
params
.
outputTokenAddress
&&
!
params
.
inputTokenAddress
?
Field
.
OUTPUT
:
Field
.
INPUT
,
inputTokenAddress
:
params
.
inputTokenAddress
?
params
.
inputTokenAddress
:
WETH
[
chainId
].
address
,
outputTokenAddress
:
params
.
outputTokenAddress
?
params
.
outputTokenAddress
:
''
,
typedValue
:
params
.
inputTokenAddress
&&
!
params
.
outputTokenAddress
?
params
.
inputTokenAmount
?
params
.
inputTokenAmount
:
''
:
!
params
.
inputTokenAddress
&&
params
.
outputTokenAddress
?
params
.
outputTokenAmount
?
params
.
outputTokenAmount
:
''
:
params
.
inputTokenAddress
&&
params
.
outputTokenAddress
?
params
.
inputTokenAmount
?
params
.
inputTokenAmount
:
''
:
''
?
''
:
''
?
''
:
''
},
initializeSwapState
)
}
src/contexts/Application.
js
→
src/contexts/Application.
tsx
View file @
9b2fe0bd
...
...
@@ -16,13 +16,29 @@ const ADD_POPUP = 'ADD_POPUP'
const
USER_ADVANCED
=
'
USER_ADVANCED
'
const
TOGGLE_USER_ADVANCED
=
'
TOGGLE_USER_ADVANCED
'
const
ApplicationContext
=
createContext
()
interface
ApplicationState
{
BLOCK_NUMBER
:
{},
USD_PRICE
:
{},
POPUP_LIST
:
Array
<
{
key
:
number
;
show
:
boolean
;
content
:
React
.
ReactElement
}
>
,
POPUP_KEY
:
number
,
WALLET_MODAL_OPEN
:
boolean
,
USER_ADVANCED
:
boolean
}
const
ApplicationContext
=
createContext
<
[
ApplicationState
,
{
[
updater
:
string
]:
(...
args
:
any
[])
=>
void
}]
>
([{
[
BLOCK_NUMBER
]:
{},
[
USD_PRICE
]:
{},
[
POPUP_LIST
]:
[],
[
POPUP_KEY
]:
0
,
[
WALLET_MODAL_OPEN
]:
false
,
[
USER_ADVANCED
]:
false
},
{}])
function
useApplicationContext
()
{
return
useContext
(
ApplicationContext
)
}
function
reducer
(
state
,
{
type
,
payload
})
{
function
reducer
(
state
:
ApplicationState
,
{
type
,
payload
}):
ApplicationState
{
switch
(
type
)
{
case
UPDATE_BLOCK_NUMBER
:
{
const
{
networkId
,
blockNumber
}
=
payload
...
...
@@ -66,19 +82,19 @@ export default function Provider({ children }) {
const
updateBlockNumber
=
useCallback
((
networkId
,
blockNumber
)
=>
{
dispatch
({
type
:
UPDATE_BLOCK_NUMBER
,
payload
:
{
networkId
,
blockNumber
}
})
},
[])
},
[
dispatch
])
const
toggleWalletModal
=
useCallback
(()
=>
{
dispatch
({
type
:
TOGGLE_WALLET_MODAL
})
},
[])
dispatch
({
type
:
TOGGLE_WALLET_MODAL
,
payload
:
null
})
},
[
dispatch
])
const
toggleUserAdvanced
=
useCallback
(()
=>
{
dispatch
({
type
:
TOGGLE_USER_ADVANCED
})
},
[])
dispatch
({
type
:
TOGGLE_USER_ADVANCED
,
payload
:
null
})
},
[
dispatch
])
const
setPopups
=
useCallback
(
newList
=>
{
dispatch
({
type
:
ADD_POPUP
,
payload
:
{
newList
}
})
},
[])
},
[
dispatch
])
return
(
<
ApplicationContext
.
Provider
...
...
@@ -105,7 +121,7 @@ export function Updater() {
if
(
library
)
{
let
stale
=
false
function
update
()
{
const
update
=
()
=>
{
library
.
getBlockNumber
()
.
then
(
blockNumber
=>
{
...
...
@@ -164,13 +180,13 @@ export function useToggleUserAdvanced() {
return
toggleUserAdvanced
}
export
function
usePopups
()
{
export
function
usePopups
()
:
[
ApplicationState
[
'
POPUP_LIST
'
],
(
content
:
React
.
ReactElement
)
=>
void
,
(
key
:
number
)
=>
void
]
{
const
[
state
,
{
setPopups
}]
=
useApplicationContext
()
const
index
=
state
[
POPUP_KEY
]
const
currentPopups
=
state
[
POPUP_LIST
]
function
addPopup
(
content
)
{
function
addPopup
(
content
:
React
.
ReactElement
):
void
{
const
newItem
=
{
show
:
true
,
key
:
index
,
...
...
@@ -180,7 +196,7 @@ export function usePopups() {
setPopups
(
currentPopups
)
}
function
removePopup
(
key
)
{
function
removePopup
(
key
:
number
):
void
{
currentPopups
.
map
(
item
=>
{
if
(
key
===
item
.
key
)
{
item
.
show
=
false
...
...
src/contexts/Routes.tsx
deleted
100644 → 0
View file @
cb00e0ba
import
React
,
{
createContext
,
useContext
,
useReducer
,
useMemo
,
useCallback
,
useEffect
}
from
'
react
'
import
{
WETH
,
Token
,
Route
,
JSBI
}
from
'
@uniswap/sdk
'
import
{
useWeb3React
}
from
'
../hooks
'
import
{
usePair
}
from
'
../contexts/Pairs
'
import
{
isWETH
}
from
'
../utils
'
const
UPDATE
=
'
UPDATE
'
interface
RouteState
{
[
chainId
:
number
]:
{
[
tokenAddress
:
string
]:
{
[
tokenAddress
:
string
]:
{
route
:
Route
}
}
}
}
const
RouteContext
=
createContext
<
[
RouteState
,
{
[
k
:
string
]:
(...
args
:
any
)
=>
void
}]
>
([{},
{}])
function
useRouteContext
()
{
return
useContext
(
RouteContext
)
}
function
reducer
(
state
:
RouteState
,
{
type
,
payload
})
{
switch
(
type
)
{
case
UPDATE
:
{
const
{
tokens
,
route
,
chainId
}
=
payload
return
{
...
state
,
[
chainId
]:
{
...
state
[
chainId
],
[
tokens
[
0
]]:
{
...
state
[
chainId
]?.[
tokens
[
0
]],
[
tokens
[
1
]]:
{
route
}
}
}
}
}
default
:
{
throw
Error
(
`Unexpected action type in ExchangesContext reducer: '
${
type
}
'.`
)
}
}
}
export
default
function
Provider
({
children
})
{
const
[
state
,
dispatch
]
=
useReducer
(
reducer
,
{})
const
update
=
useCallback
((
tokens
,
route
,
chainId
)
=>
{
dispatch
({
type
:
UPDATE
,
payload
:
{
tokens
,
route
,
chainId
}
})
},
[])
return
(
<
RouteContext
.
Provider
value=
{
useMemo
(()
=>
[
state
,
{
update
}],
[
state
,
update
])
}
>
{
children
}
</
RouteContext
.
Provider
>
)
}
/**
* @param tokenA input to token to be sold
* @param tokenB output token to be bought
*
* This hook finds either a direct pair between tokenA and tokenB or,
* a one-hop route that goes through token<->WETH pairs
*
* if neither exists returns null
*/
export
function
useRoute
(
tokenA
:
Token
,
tokenB
:
Token
)
{
const
[
state
,
{
update
}]
=
useRouteContext
()
const
{
chainId
}
=
useWeb3React
()
let
route
:
Route
=
state
?.[
chainId
]?.[
tokenA
?.
address
]?.[
tokenB
?.
address
]?.
route
// check for direct pair between tokens
const
defaultPair
=
usePair
(
tokenA
,
tokenB
)
// get token<->WETH pairs
const
aToETH
=
usePair
(
tokenA
&&
!
isWETH
(
tokenA
)
?
tokenA
:
null
,
WETH
[
chainId
])
const
bToETH
=
usePair
(
tokenB
&&
!
isWETH
(
tokenB
)
?
tokenB
:
null
,
WETH
[
chainId
])
// needs to route through WETH
const
requiresHop
=
defaultPair
&&
JSBI
.
equal
(
defaultPair
?.
reserve0
?.
raw
,
JSBI
.
BigInt
(
0
))
&&
JSBI
.
equal
(
defaultPair
?.
reserve1
?.
raw
,
JSBI
.
BigInt
(
0
))
useEffect
(()
=>
{
if
(
!
route
&&
tokenA
&&
tokenB
)
{
if
(
!
requiresHop
&&
defaultPair
)
{
update
([
tokenA
.
address
,
tokenB
.
address
],
new
Route
([
defaultPair
],
tokenA
),
chainId
)
}
if
(
requiresHop
&&
aToETH
&&
bToETH
&&
// check there is liquidity in both token<->ETH pairs
JSBI
.
notEqual
(
JSBI
.
BigInt
(
0
),
aToETH
.
reserve0
.
raw
)
&&
JSBI
.
notEqual
(
JSBI
.
BigInt
(
0
),
bToETH
.
reserve0
.
raw
)
)
{
const
routeThroughETH
=
new
Route
([
aToETH
,
bToETH
],
tokenA
)
update
([
tokenA
.
address
,
tokenB
.
address
],
routeThroughETH
,
chainId
)
}
}
},
[
route
,
requiresHop
,
update
,
chainId
,
tokenA
,
tokenB
,
defaultPair
,
aToETH
,
bToETH
])
return
useMemo
(()
=>
route
,
[
route
])
}
src/contexts/Transactions.
js
→
src/contexts/Transactions.
tsx
View file @
9b2fe0bd
...
...
@@ -16,7 +16,11 @@ const ADD = 'ADD'
const
CHECK
=
'
CHECK
'
const
FINALIZE
=
'
FINALIZE
'
const
TransactionsContext
=
createContext
()
interface
TransactionState
{
}
const
TransactionsContext
=
createContext
<
[
TransactionState
,
{
[
updater
:
string
]:
(...
args
:
any
[])
=>
void
}]
>
([{},
{}])
export
function
useTransactionsContext
()
{
return
useContext
(
TransactionsContext
)
...
...
@@ -134,10 +138,12 @@ export function Updater() {
finalize
(
chainId
,
hash
,
receipt
)
// add success or failure popup
if
(
receipt
.
status
===
1
)
{
addPopup
(
<
TxnPopup
hash
=
{
hash
}
success
=
{
true
}
summary
=
{
allTransactions
[
hash
]?.
response
?.
summary
}
/>
)
addPopup
(<
TxnPopup
popKey=
{
1
}
hash=
{
hash
}
success=
{
true
}
summary=
{
allTransactions
[
hash
]?.
response
?.
summary
}
/>)
}
else
{
addPopup
(
<
TxnPopup
hash
=
{
hash
}
success
=
{
false
}
summary
=
{
allTransactions
[
hash
]?.
response
?.
summary
}
/
>
<
TxnPopup
popKey=
{
2
}
hash=
{
hash
}
success=
{
false
}
summary=
{
allTransactions
[
hash
]?.
response
?.
summary
}
/>
)
}
}
...
...
src/hooks/Trades.ts
0 → 100644
View file @
9b2fe0bd
import
{
useMemo
}
from
'
react
'
import
{
WETH
,
Token
,
TokenAmount
,
Trade
}
from
'
@uniswap/sdk
'
import
{
useWeb3React
}
from
'
./index
'
import
{
usePair
}
from
'
../contexts/Pairs
'
import
{
isWETH
}
from
'
../utils
'
/**
* Returns the best trade for the exact amount of tokens in to the given token out
*/
export
function
useTradeExactIn
(
amountIn
?:
TokenAmount
,
tokenOut
?:
Token
):
Trade
|
null
{
const
{
chainId
}
=
useWeb3React
()
// check for direct pair between tokens
const
pairBetween
=
usePair
(
amountIn
?.
token
,
tokenOut
)
// get token<->WETH pairs
const
aToETH
=
usePair
(
amountIn
&&
!
isWETH
(
amountIn
.
token
)
?
amountIn
.
token
:
null
,
WETH
[
chainId
])
const
bToETH
=
usePair
(
tokenOut
&&
!
isWETH
(
tokenOut
)
?
tokenOut
:
null
,
WETH
[
chainId
])
return
useMemo
(()
=>
{
const
allPairs
=
[
pairBetween
,
aToETH
,
bToETH
].
filter
(
p
=>
!!
p
)
if
(
amountIn
&&
allPairs
.
length
>
0
&&
tokenOut
)
{
return
Trade
.
bestTradeExactIn
(
allPairs
,
amountIn
,
tokenOut
)[
0
]
??
null
}
return
null
},
[
aToETH
,
bToETH
,
pairBetween
,
amountIn
,
tokenOut
])
}
/**
* Returns the best trade for the token in to the exact amount of token out
*/
export
function
useTradeExactOut
(
tokenIn
?:
Token
,
amountOut
?:
TokenAmount
):
Trade
|
null
{
const
{
chainId
}
=
useWeb3React
()
// check for direct pair between tokens
const
pairBetween
=
usePair
(
amountOut
?.
token
,
tokenIn
)
// get token<->WETH pairs
const
aToETH
=
usePair
(
amountOut
&&
!
isWETH
(
amountOut
.
token
)
?
amountOut
.
token
:
null
,
WETH
[
chainId
])
const
bToETH
=
usePair
(
tokenIn
&&
!
isWETH
(
tokenIn
)
?
tokenIn
:
null
,
WETH
[
chainId
])
return
useMemo
(()
=>
{
const
allPairs
=
[
pairBetween
,
aToETH
,
bToETH
].
filter
(
p
=>
!!
p
)
if
(
amountOut
&&
allPairs
.
length
>
0
&&
tokenIn
)
{
return
Trade
.
bestTradeExactOut
(
allPairs
,
tokenIn
,
amountOut
)[
0
]
??
null
}
return
null
},
[
pairBetween
,
aToETH
,
bToETH
,
amountOut
,
tokenIn
])
}
src/index.tsx
View file @
9b2fe0bd
...
...
@@ -12,7 +12,6 @@ import TransactionContextProvider, { Updater as TransactionContextUpdater } from
import
BalancesContextProvider
,
{
Updater
as
BalancesContextUpdater
}
from
'
./contexts/Balances
'
import
ExchangesContextProvider
from
'
./contexts/Pairs
'
import
AllowancesContextProvider
from
'
./contexts/Allowances
'
import
RoutesContextProvider
from
'
./contexts/Routes
'
import
App
from
'
./pages/App
'
import
ThemeProvider
,
{
GlobalStyle
}
from
'
./theme
'
import
'
./i18n
'
...
...
@@ -42,11 +41,9 @@ function ContextProviders({ children }) {
<
ApplicationContextProvider
>
<
TransactionContextProvider
>
<
ExchangesContextProvider
>
<
RoutesContextProvider
>
<
BalancesContextProvider
>
<
AllowancesContextProvider
>
{
children
}
</
AllowancesContextProvider
>
</
BalancesContextProvider
>
</
RoutesContextProvider
>
<
BalancesContextProvider
>
<
AllowancesContextProvider
>
{
children
}
</
AllowancesContextProvider
>
</
BalancesContextProvider
>
</
ExchangesContextProvider
>
</
TransactionContextProvider
>
</
ApplicationContextProvider
>
...
...
src/utils/index.ts
View file @
9b2fe0bd
...
...
@@ -69,7 +69,7 @@ function parseUrlTokenAmount(paramName: string): string {
return
value
}
interface
QueryParams
{
export
interface
QueryParams
{
readonly
inputTokenAddress
:
string
readonly
outputTokenAddress
:
string
readonly
inputTokenAmount
:
string
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment