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
d4011f73
Unverified
Commit
d4011f73
authored
May 29, 2020
by
Moody Salem
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(multicall): return loading states from the multicall hooks #842
parent
6fc31579
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
91 additions
and
36 deletions
+91
-36
Allowances.ts
src/data/Allowances.ts
+1
-1
Reserves.ts
src/data/Reserves.ts
+3
-3
TotalSupply.ts
src/data/TotalSupply.ts
+1
-1
V1.ts
src/data/V1.ts
+6
-2
hooks.ts
src/state/multicall/hooks.ts
+78
-27
hooks.ts
src/state/wallet/hooks.ts
+2
-2
No files found.
src/data/Allowances.ts
View file @
d4011f73
...
@@ -8,7 +8,7 @@ export function useTokenAllowance(token?: Token, owner?: string, spender?: strin
...
@@ -8,7 +8,7 @@ export function useTokenAllowance(token?: Token, owner?: string, spender?: strin
const
contract
=
useTokenContract
(
token
?.
address
,
false
)
const
contract
=
useTokenContract
(
token
?.
address
,
false
)
const
inputs
=
useMemo
(()
=>
[
owner
,
spender
],
[
owner
,
spender
])
const
inputs
=
useMemo
(()
=>
[
owner
,
spender
],
[
owner
,
spender
])
const
allowance
=
useSingleCallResult
(
contract
,
'
allowance
'
,
inputs
)
const
allowance
=
useSingleCallResult
(
contract
,
'
allowance
'
,
inputs
)
.
result
return
useMemo
(()
=>
(
token
&&
allowance
?
new
TokenAmount
(
token
,
allowance
.
toString
())
:
undefined
),
[
return
useMemo
(()
=>
(
token
&&
allowance
?
new
TokenAmount
(
token
,
allowance
.
toString
())
:
undefined
),
[
token
,
token
,
...
...
src/data/Reserves.ts
View file @
d4011f73
...
@@ -12,13 +12,13 @@ import { useSingleCallResult } from '../state/multicall/hooks'
...
@@ -12,13 +12,13 @@ import { useSingleCallResult } from '../state/multicall/hooks'
export
function
usePair
(
tokenA
?:
Token
,
tokenB
?:
Token
):
undefined
|
Pair
|
null
{
export
function
usePair
(
tokenA
?:
Token
,
tokenB
?:
Token
):
undefined
|
Pair
|
null
{
const
pairAddress
=
tokenA
&&
tokenB
&&
!
tokenA
.
equals
(
tokenB
)
?
Pair
.
getAddress
(
tokenA
,
tokenB
)
:
undefined
const
pairAddress
=
tokenA
&&
tokenB
&&
!
tokenA
.
equals
(
tokenB
)
?
Pair
.
getAddress
(
tokenA
,
tokenB
)
:
undefined
const
contract
=
usePairContract
(
pairAddress
,
false
)
const
contract
=
usePairContract
(
pairAddress
,
false
)
const
reserves
=
useSingleCallResult
(
contract
,
'
getReserves
'
)
const
{
result
:
reserves
,
loading
}
=
useSingleCallResult
(
contract
,
'
getReserves
'
)
return
useMemo
(()
=>
{
return
useMemo
(()
=>
{
if
(
!
pairAddress
||
!
contract
||
!
tokenA
||
!
tokenB
)
return
undefined
if
(
loading
||
!
tokenA
||
!
tokenB
)
return
undefined
if
(
!
reserves
)
return
null
if
(
!
reserves
)
return
null
const
{
reserve0
,
reserve1
}
=
reserves
const
{
reserve0
,
reserve1
}
=
reserves
const
[
token0
,
token1
]
=
tokenA
.
sortsBefore
(
tokenB
)
?
[
tokenA
,
tokenB
]
:
[
tokenB
,
tokenA
]
const
[
token0
,
token1
]
=
tokenA
.
sortsBefore
(
tokenB
)
?
[
tokenA
,
tokenB
]
:
[
tokenB
,
tokenA
]
return
new
Pair
(
new
TokenAmount
(
token0
,
reserve0
.
toString
()),
new
TokenAmount
(
token1
,
reserve1
.
toString
()))
return
new
Pair
(
new
TokenAmount
(
token0
,
reserve0
.
toString
()),
new
TokenAmount
(
token1
,
reserve1
.
toString
()))
},
[
contract
,
pairAddress
,
reserves
,
tokenA
,
tokenB
])
},
[
loading
,
reserves
,
tokenA
,
tokenB
])
}
}
src/data/TotalSupply.ts
View file @
d4011f73
...
@@ -8,7 +8,7 @@ import { useSingleCallResult } from '../state/multicall/hooks'
...
@@ -8,7 +8,7 @@ import { useSingleCallResult } from '../state/multicall/hooks'
export
function
useTotalSupply
(
token
?:
Token
):
TokenAmount
|
undefined
{
export
function
useTotalSupply
(
token
?:
Token
):
TokenAmount
|
undefined
{
const
contract
=
useTokenContract
(
token
?.
address
,
false
)
const
contract
=
useTokenContract
(
token
?.
address
,
false
)
const
totalSupply
:
BigNumber
=
useSingleCallResult
(
contract
,
'
totalSupply
'
)?.[
0
]
const
totalSupply
:
BigNumber
=
useSingleCallResult
(
contract
,
'
totalSupply
'
)?.
result
?.
[
0
]
return
token
&&
totalSupply
?
new
TokenAmount
(
token
,
totalSupply
.
toString
())
:
undefined
return
token
&&
totalSupply
?
new
TokenAmount
(
token
,
totalSupply
.
toString
())
:
undefined
}
}
src/data/V1.ts
View file @
d4011f73
...
@@ -12,7 +12,11 @@ function useV1PairAddress(tokenAddress?: string): string | undefined {
...
@@ -12,7 +12,11 @@ function useV1PairAddress(tokenAddress?: string): string | undefined {
return
useSingleCallResult
(
contract
,
'
getExchange
'
,
inputs
)?.[
0
]
return
useSingleCallResult
(
contract
,
'
getExchange
'
,
inputs
)?.[
0
]
}
}
function
useMockV1Pair
(
token
?:
Token
)
{
class
MockV1Pair
extends
Pair
{
readonly
isV1
:
true
=
true
}
function
useMockV1Pair
(
token
?:
Token
):
MockV1Pair
|
undefined
{
const
isWETH
=
token
?.
equals
(
WETH
[
token
?.
chainId
])
const
isWETH
=
token
?.
equals
(
WETH
[
token
?.
chainId
])
// will only return an address on mainnet, and not for WETH
// will only return an address on mainnet, and not for WETH
...
@@ -21,7 +25,7 @@ function useMockV1Pair(token?: Token) {
...
@@ -21,7 +25,7 @@ function useMockV1Pair(token?: Token) {
const
ETHBalance
=
useETHBalances
([
v1PairAddress
])[
v1PairAddress
??
''
]
const
ETHBalance
=
useETHBalances
([
v1PairAddress
])[
v1PairAddress
??
''
]
return
tokenBalance
&&
ETHBalance
&&
token
return
tokenBalance
&&
ETHBalance
&&
token
?
new
Pair
(
tokenBalance
,
new
TokenAmount
(
WETH
[
token
.
chainId
],
ETHBalance
.
toString
()))
?
new
MockV1
Pair
(
tokenBalance
,
new
TokenAmount
(
WETH
[
token
.
chainId
],
ETHBalance
.
toString
()))
:
undefined
:
undefined
}
}
...
...
src/state/multicall/hooks.ts
View file @
d4011f73
import
{
Interface
}
from
'
@ethersproject/abi
'
import
{
Interface
,
FunctionFragment
}
from
'
@ethersproject/abi
'
import
{
BigNumber
}
from
'
@ethersproject/bignumber
'
import
{
BigNumber
}
from
'
@ethersproject/bignumber
'
import
{
Contract
}
from
'
@ethersproject/contracts
'
import
{
Contract
}
from
'
@ethersproject/contracts
'
import
{
useEffect
,
useMemo
}
from
'
react
'
import
{
useEffect
,
useMemo
}
from
'
react
'
import
{
useDispatch
,
useSelector
}
from
'
react-redux
'
import
{
useDispatch
,
useSelector
}
from
'
react-redux
'
import
{
useActiveWeb3React
}
from
'
../../hooks
'
import
{
useActiveWeb3React
}
from
'
../../hooks
'
import
useDebounce
from
'
../../hooks/useDebounce
'
import
useDebounce
from
'
../../hooks/useDebounce
'
import
{
useBlockNumber
}
from
'
../application/hooks
'
import
{
AppDispatch
,
AppState
}
from
'
../index
'
import
{
AppDispatch
,
AppState
}
from
'
../index
'
import
{
addMulticallListeners
,
Call
,
removeMulticallListeners
,
parseCallKey
,
toCallKey
}
from
'
./actions
'
import
{
addMulticallListeners
,
Call
,
removeMulticallListeners
,
parseCallKey
,
toCallKey
}
from
'
./actions
'
...
@@ -27,8 +28,16 @@ function isValidMethodArgs(x: unknown): x is MethodArgs | undefined {
...
@@ -27,8 +28,16 @@ function isValidMethodArgs(x: unknown): x is MethodArgs | undefined {
)
)
}
}
interface
CallResult
{
readonly
valid
:
boolean
readonly
data
:
string
|
undefined
readonly
blockNumber
:
number
|
undefined
}
const
INVALID_RESULT
:
CallResult
=
{
valid
:
false
,
blockNumber
:
undefined
,
data
:
undefined
}
// the lowest level call for subscribing to contract data
// the lowest level call for subscribing to contract data
function
useCallsData
(
calls
:
(
Call
|
undefined
)[]):
(
string
|
undefined
)
[]
{
function
useCallsData
(
calls
:
(
Call
|
undefined
)[]):
CallResult
[]
{
const
{
chainId
}
=
useActiveWeb3React
()
const
{
chainId
}
=
useActiveWeb3React
()
const
callResults
=
useSelector
<
AppState
,
AppState
[
'
multicall
'
][
'
callResults
'
]
>
(
state
=>
state
.
multicall
.
callResults
)
const
callResults
=
useSelector
<
AppState
,
AppState
[
'
multicall
'
][
'
callResults
'
]
>
(
state
=>
state
.
multicall
.
callResults
)
const
dispatch
=
useDispatch
<
AppDispatch
>
()
const
dispatch
=
useDispatch
<
AppDispatch
>
()
...
@@ -68,25 +77,64 @@ function useCallsData(calls: (Call | undefined)[]): (string | undefined)[] {
...
@@ -68,25 +77,64 @@ function useCallsData(calls: (Call | undefined)[]): (string | undefined)[] {
}
}
},
[
chainId
,
dispatch
,
debouncedSerializedCallKeys
])
},
[
chainId
,
dispatch
,
debouncedSerializedCallKeys
])
return
useMemo
(()
=>
{
return
useMemo
(
return
calls
.
map
<
string
|
undefined
>
(
call
=>
{
()
=>
if
(
!
chainId
||
!
call
)
return
undefined
calls
.
map
<
CallResult
>
(
call
=>
{
if
(
!
chainId
||
!
call
)
return
INVALID_RESULT
const
result
=
callResults
[
chainId
]?.[
toCallKey
(
call
)]
let
data
if
(
result
?.
data
&&
result
?.
data
!==
'
0x
'
)
{
data
=
result
.
data
}
return
{
valid
:
true
,
data
,
blockNumber
:
result
?.
blockNumber
}
}),
[
callResults
,
calls
,
chainId
]
)
}
const
result
=
callResults
[
chainId
]?.[
toCallKey
(
call
)]
interface
CallState
{
if
(
!
result
||
!
result
.
data
||
result
.
data
===
'
0x
'
)
{
readonly
valid
:
boolean
return
undefined
// the result, or undefined if loading or errored/no data
}
readonly
result
:
Result
|
undefined
// true if the result has never been fetched
readonly
loading
:
boolean
// true if the result is not for the latest block
readonly
syncing
:
boolean
// true if the call was made and is synced, but the return data is invalid
readonly
error
:
boolean
}
return
result
.
data
const
INVALID_CALL_STATE
:
CallState
=
{
valid
:
false
,
result
:
undefined
,
loading
:
false
,
syncing
:
false
,
error
:
false
}
})
const
LOADING_CALL_STATE
:
CallState
=
{
valid
:
true
,
result
:
undefined
,
loading
:
true
,
syncing
:
true
,
error
:
false
}
},
[
callResults
,
calls
,
chainId
])
function
toCallState
(
result
:
CallResult
|
undefined
,
contractInterface
:
Interface
|
undefined
,
fragment
:
FunctionFragment
|
undefined
,
latestBlockNumber
:
number
|
undefined
):
CallState
{
if
(
!
result
)
return
INVALID_CALL_STATE
const
{
valid
,
data
,
blockNumber
}
=
result
if
(
!
valid
)
return
INVALID_CALL_STATE
if
(
valid
&&
!
blockNumber
)
return
LOADING_CALL_STATE
if
(
!
contractInterface
||
!
fragment
||
!
latestBlockNumber
)
return
LOADING_CALL_STATE
const
success
=
data
&&
data
.
length
>
2
return
{
valid
:
true
,
loading
:
false
,
syncing
:
(
blockNumber
??
0
)
<
latestBlockNumber
,
result
:
success
&&
data
?
contractInterface
.
decodeFunctionResult
(
fragment
,
data
)
:
undefined
,
error
:
!
success
}
}
}
export
function
useSingleContractMultipleData
(
export
function
useSingleContractMultipleData
(
contract
:
Contract
|
null
|
undefined
,
contract
:
Contract
|
null
|
undefined
,
methodName
:
string
,
methodName
:
string
,
callInputs
:
OptionalMethodInputs
[]
callInputs
:
OptionalMethodInputs
[]
):
(
Result
|
undefined
)
[]
{
):
CallState
[]
{
const
fragment
=
useMemo
(()
=>
contract
?.
interface
?.
getFunction
(
methodName
),
[
contract
,
methodName
])
const
fragment
=
useMemo
(()
=>
contract
?.
interface
?.
getFunction
(
methodName
),
[
contract
,
methodName
])
const
calls
=
useMemo
(
const
calls
=
useMemo
(
...
@@ -102,12 +150,13 @@ export function useSingleContractMultipleData(
...
@@ -102,12 +150,13 @@ export function useSingleContractMultipleData(
[
callInputs
,
contract
,
fragment
]
[
callInputs
,
contract
,
fragment
]
)
)
const
data
=
useCallsData
(
calls
)
const
results
=
useCallsData
(
calls
)
const
latestBlockNumber
=
useBlockNumber
()
return
useMemo
(()
=>
{
return
useMemo
(()
=>
{
if
(
!
fragment
||
!
contract
)
return
[]
return
results
.
map
(
result
=>
toCallState
(
result
,
contract
?.
interface
,
fragment
,
latestBlockNumber
))
return
data
.
map
(
data
=>
(
data
?
contract
.
interface
.
decodeFunctionResult
(
fragment
,
data
)
:
undefined
))
},
[
fragment
,
contract
,
results
,
latestBlockNumber
])
},
[
contract
,
data
,
fragment
])
}
}
export
function
useMultipleContractSingleData
(
export
function
useMultipleContractSingleData
(
...
@@ -115,7 +164,7 @@ export function useMultipleContractSingleData(
...
@@ -115,7 +164,7 @@ export function useMultipleContractSingleData(
contractInterface
:
Interface
,
contractInterface
:
Interface
,
methodName
:
string
,
methodName
:
string
,
callInputs
?:
OptionalMethodInputs
callInputs
?:
OptionalMethodInputs
):
(
Result
|
undefined
)
[]
{
):
CallState
[]
{
const
fragment
=
useMemo
(()
=>
contractInterface
.
getFunction
(
methodName
),
[
contractInterface
,
methodName
])
const
fragment
=
useMemo
(()
=>
contractInterface
.
getFunction
(
methodName
),
[
contractInterface
,
methodName
])
const
callData
:
string
|
undefined
=
useMemo
(
const
callData
:
string
|
undefined
=
useMemo
(
()
=>
()
=>
...
@@ -140,19 +189,20 @@ export function useMultipleContractSingleData(
...
@@ -140,19 +189,20 @@ export function useMultipleContractSingleData(
[
addresses
,
callData
,
fragment
]
[
addresses
,
callData
,
fragment
]
)
)
const
data
=
useCallsData
(
calls
)
const
results
=
useCallsData
(
calls
)
const
latestBlockNumber
=
useBlockNumber
()
return
useMemo
(()
=>
{
return
useMemo
(()
=>
{
if
(
!
fragment
)
return
[]
return
results
.
map
(
result
=>
toCallState
(
result
,
contractInterface
,
fragment
,
latestBlockNumber
))
return
data
.
map
(
data
=>
(
data
?
contractInterface
.
decodeFunctionResult
(
fragment
,
data
)
:
undefined
))
},
[
fragment
,
results
,
contractInterface
,
latestBlockNumber
])
},
[
contractInterface
,
data
,
fragment
])
}
}
export
function
useSingleCallResult
(
export
function
useSingleCallResult
(
contract
:
Contract
|
null
|
undefined
,
contract
:
Contract
|
null
|
undefined
,
methodName
:
string
,
methodName
:
string
,
inputs
?:
OptionalMethodInputs
inputs
?:
OptionalMethodInputs
):
Result
|
undefined
{
):
CallState
{
const
fragment
=
useMemo
(()
=>
contract
?.
interface
?.
getFunction
(
methodName
),
[
contract
,
methodName
])
const
fragment
=
useMemo
(()
=>
contract
?.
interface
?.
getFunction
(
methodName
),
[
contract
,
methodName
])
const
calls
=
useMemo
<
Call
[]
>
(()
=>
{
const
calls
=
useMemo
<
Call
[]
>
(()
=>
{
...
@@ -166,9 +216,10 @@ export function useSingleCallResult(
...
@@ -166,9 +216,10 @@ export function useSingleCallResult(
:
[]
:
[]
},
[
contract
,
fragment
,
inputs
])
},
[
contract
,
fragment
,
inputs
])
const
data
=
useCallsData
(
calls
)[
0
]
const
result
=
useCallsData
(
calls
)[
0
]
const
latestBlockNumber
=
useBlockNumber
()
return
useMemo
(()
=>
{
return
useMemo
(()
=>
{
if
(
!
contract
||
!
fragment
||
!
data
)
return
undefined
return
toCallState
(
result
,
contract
?.
interface
,
fragment
,
latestBlockNumber
)
return
contract
.
interface
.
decodeFunctionResult
(
fragment
,
data
)
},
[
result
,
contract
,
fragment
,
latestBlockNumber
])
},
[
data
,
fragment
,
contract
])
}
}
src/state/wallet/hooks.ts
View file @
d4011f73
...
@@ -33,7 +33,7 @@ export function useETHBalances(uncheckedAddresses?: (string | undefined)[]): { [
...
@@ -33,7 +33,7 @@ export function useETHBalances(uncheckedAddresses?: (string | undefined)[]): { [
return
useMemo
(
return
useMemo
(
()
=>
()
=>
addresses
.
reduce
<
{
[
address
:
string
]:
JSBI
|
undefined
}
>
((
memo
,
address
,
i
)
=>
{
addresses
.
reduce
<
{
[
address
:
string
]:
JSBI
|
undefined
}
>
((
memo
,
address
,
i
)
=>
{
const
value
=
results
?.[
i
]?.[
0
]
const
value
=
results
?.[
i
]?.
result
?.
[
0
]
if
(
value
)
memo
[
address
]
=
JSBI
.
BigInt
(
value
.
toString
())
if
(
value
)
memo
[
address
]
=
JSBI
.
BigInt
(
value
.
toString
())
return
memo
return
memo
},
{}),
},
{}),
...
@@ -61,7 +61,7 @@ export function useTokenBalances(
...
@@ -61,7 +61,7 @@ export function useTokenBalances(
()
=>
()
=>
address
&&
validatedTokens
.
length
>
0
address
&&
validatedTokens
.
length
>
0
?
validatedTokens
.
reduce
<
{
[
tokenAddress
:
string
]:
TokenAmount
|
undefined
}
>
((
memo
,
token
,
i
)
=>
{
?
validatedTokens
.
reduce
<
{
[
tokenAddress
:
string
]:
TokenAmount
|
undefined
}
>
((
memo
,
token
,
i
)
=>
{
const
value
=
balances
?.[
i
]?.[
0
]
const
value
=
balances
?.[
i
]?.
result
?.
[
0
]
const
amount
=
value
?
JSBI
.
BigInt
(
value
.
toString
())
:
undefined
const
amount
=
value
?
JSBI
.
BigInt
(
value
.
toString
())
:
undefined
if
(
amount
)
{
if
(
amount
)
{
memo
[
token
.
address
]
=
new
TokenAmount
(
token
,
amount
)
memo
[
token
.
address
]
=
new
TokenAmount
(
token
,
amount
)
...
...
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