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
b69f08cb
Unverified
Commit
b69f08cb
authored
Apr 23, 2021
by
Moody Salem
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
allow fetching multiple pools via usePools.ts
parent
644ecdbd
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
97 additions
and
112 deletions
+97
-112
staking-rewards.ts
src/abis/staking-rewards.ts
+1
-4
index.tsx
src/components/PositionListItem/index.tsx
+1
-1
index.ts
src/constants/index.ts
+2
-2
Pools.ts
src/data/Pools.ts
+0
-97
useDerivedPositionInfo.ts
src/hooks/useDerivedPositionInfo.ts
+1
-1
usePools.ts
src/hooks/usePools.ts
+85
-0
MigrateV2Pair.tsx
src/pages/MigrateV2/MigrateV2Pair.tsx
+1
-1
PositionPage.tsx
src/pages/Pool/PositionPage.tsx
+1
-1
hooks.ts
src/state/burn/v3/hooks.ts
+1
-1
hooks.ts
src/state/claim/hooks.ts
+2
-2
hooks.ts
src/state/mint/hooks.ts
+2
-2
No files found.
src/abis/staking-rewards.ts
View file @
b69f08cb
import
{
Interface
}
from
'
@ethersproject/abi
'
import
{
Interface
}
from
'
@ethersproject/abi
'
import
{
abi
as
STAKING_REWARDS_ABI
}
from
'
@uniswap/liquidity-staker/build/StakingRewards.json
'
import
{
abi
as
STAKING_REWARDS_ABI
}
from
'
@uniswap/liquidity-staker/build/StakingRewards.json
'
import
{
abi
as
STAKING_REWARDS_FACTORY_ABI
}
from
'
@uniswap/liquidity-staker/build/StakingRewardsFactory.json
'
const
STAKING_REWARDS_INTERFACE
=
new
Interface
(
STAKING_REWARDS_ABI
)
const
STAKING_REWARDS_INTERFACE
=
new
Interface
(
STAKING_REWARDS_ABI
)
const
STAKING_REWARDS_FACTORY_INTERFACE
=
new
Interface
(
STAKING_REWARDS_FACTORY_ABI
)
export
{
STAKING_REWARDS_INTERFACE
}
export
{
STAKING_REWARDS_FACTORY_INTERFACE
,
STAKING_REWARDS_INTERFACE
}
src/components/PositionListItem/index.tsx
View file @
b69f08cb
...
@@ -2,7 +2,7 @@ import React, { useMemo } from 'react'
...
@@ -2,7 +2,7 @@ import React, { useMemo } from 'react'
import
{
Position
}
from
'
@uniswap/v3-sdk
'
import
{
Position
}
from
'
@uniswap/v3-sdk
'
import
Badge
,
{
BadgeVariant
}
from
'
components/Badge
'
import
Badge
,
{
BadgeVariant
}
from
'
components/Badge
'
import
DoubleCurrencyLogo
from
'
components/DoubleLogo
'
import
DoubleCurrencyLogo
from
'
components/DoubleLogo
'
import
{
PoolState
,
usePool
}
from
'
data/
Pools
'
import
{
PoolState
,
usePool
}
from
'
hooks/use
Pools
'
import
{
useToken
}
from
'
hooks/Tokens
'
import
{
useToken
}
from
'
hooks/Tokens
'
import
{
AlertTriangle
}
from
'
react-feather
'
import
{
AlertTriangle
}
from
'
react-feather
'
import
{
useTranslation
}
from
'
react-i18next
'
import
{
useTranslation
}
from
'
react-i18next
'
...
...
src/constants/index.ts
View file @
b69f08cb
...
@@ -85,8 +85,8 @@ export const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = {
...
@@ -85,8 +85,8 @@ export const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = {
export
const
ADDITIONAL_BASES
:
{
[
chainId
in
ChainId
]?:
{
[
tokenAddress
:
string
]:
Token
[]
}
}
=
{
export
const
ADDITIONAL_BASES
:
{
[
chainId
in
ChainId
]?:
{
[
tokenAddress
:
string
]:
Token
[]
}
}
=
{
[
ChainId
.
MAINNET
]:
{
[
ChainId
.
MAINNET
]:
{
'
0xA948E86885e12Fb09AfEF8C52142EBDbDf73cD18
'
:
[
new
Token
(
ChainId
.
MAINNET
,
UNI_ADDRESS
,
18
,
'
UNI
'
,
'
Uniswap
'
)
],
'
0xA948E86885e12Fb09AfEF8C52142EBDbDf73cD18
'
:
[
UNI
[
ChainId
.
MAINNET
]
],
'
0x561a4717537ff4AF5c687328c0f7E90a319705C0
'
:
[
new
Token
(
ChainId
.
MAINNET
,
UNI_ADDRESS
,
18
,
'
UNI
'
,
'
Uniswap
'
)
],
'
0x561a4717537ff4AF5c687328c0f7E90a319705C0
'
:
[
UNI
[
ChainId
.
MAINNET
]
],
[
FEI
.
address
]:
[
TRIBE
],
[
FEI
.
address
]:
[
TRIBE
],
[
TRIBE
.
address
]:
[
FEI
],
[
TRIBE
.
address
]:
[
FEI
],
[
FRAX
.
address
]:
[
FXS
],
[
FRAX
.
address
]:
[
FXS
],
...
...
src/data/Pools.ts
deleted
100644 → 0
View file @
644ecdbd
import
{
computePoolAddress
}
from
'
@uniswap/v3-sdk
'
import
{
ZERO_ADDRESS
}
from
'
./../constants/index
'
import
{
Currency
}
from
'
@uniswap/sdk-core
'
import
{
useMemo
}
from
'
react
'
import
{
useActiveWeb3React
}
from
'
../hooks
'
import
{
useSingleCallResult
}
from
'
../state/multicall/hooks
'
import
{
wrappedCurrency
}
from
'
../utils/wrappedCurrency
'
import
{
Pool
,
FeeAmount
}
from
'
@uniswap/v3-sdk
'
import
{
useV3Factory
,
useV3Pool
}
from
'
hooks/useContract
'
import
{
V3_CORE_FACTORY_ADDRESSES
}
from
'
constants/v3
'
export
enum
PoolState
{
LOADING
=
'
LOADING
'
,
NOT_EXISTS
=
'
NOT_EXISTS
'
,
EXISTS
=
'
EXISTS
'
,
INVALID
=
'
INVALID
'
,
}
export
function
usePool
(
currencyA
?:
Currency
,
currencyB
?:
Currency
,
feeAmount
?:
FeeAmount
):
[
PoolState
,
Pool
|
null
]
{
const
{
chainId
}
=
useActiveWeb3React
()
const
factoryContract
=
useV3Factory
()
const
tokenA
=
wrappedCurrency
(
currencyA
,
chainId
)
const
tokenB
=
wrappedCurrency
(
currencyB
,
chainId
)
// sorted version
const
[
token0
,
token1
]
=
useMemo
(
()
=>
tokenA
&&
tokenB
&&
!
tokenA
.
equals
(
tokenB
)
?
tokenA
.
sortsBefore
(
tokenB
)
?
[
tokenA
,
tokenB
]
:
[
tokenB
,
tokenA
]
:
[
undefined
,
undefined
],
[
tokenA
,
tokenB
]
)
// fetch all generated addresses for pools
const
poolAddress
=
useMemo
(()
=>
{
try
{
const
addr
=
chainId
&&
V3_CORE_FACTORY_ADDRESSES
[
chainId
]
return
addr
&&
tokenA
&&
tokenB
&&
feeAmount
&&
!
tokenA
.
equals
(
tokenB
)
?
computePoolAddress
({
factoryAddress
:
addr
,
tokenA
,
tokenB
,
fee
:
feeAmount
,
})
:
undefined
}
catch
{
return
undefined
}
},
[
chainId
,
feeAmount
,
tokenA
,
tokenB
])
// check factory if pools exists
const
addressParams
=
token0
&&
token1
&&
feeAmount
?
[
token0
.
address
,
token1
.
address
,
feeAmount
]
:
undefined
const
addressFromFactory
=
useSingleCallResult
(
addressParams
?
factoryContract
:
undefined
,
'
getPool
'
,
addressParams
)
const
{
result
:
addressesResult
,
loading
:
addressesLoading
}
=
addressFromFactory
const
poolAddressFromFactory
=
addressesResult
?.[
0
]
const
poolContract
=
useV3Pool
(
poolAddress
)
// attempt to fetch pool metadata
const
slot0Datas
=
useSingleCallResult
(
poolContract
,
'
slot0
'
)
// fetch additional data to instantiate pools
const
liquidityDatas
=
useSingleCallResult
(
poolContract
,
'
liquidity
'
)
const
{
result
:
slot0
,
loading
:
slot0Loading
}
=
slot0Datas
const
{
result
:
liquidityResult
,
loading
:
liquidityLoading
}
=
liquidityDatas
const
liquidity
=
liquidityResult
?.[
0
]
return
useMemo
(()
=>
{
// still loading data
if
(
slot0Loading
||
addressesLoading
||
liquidityLoading
)
return
[
PoolState
.
LOADING
,
null
]
// invalid pool setup
if
(
!
tokenA
||
!
tokenB
||
!
feeAmount
||
tokenA
.
equals
(
tokenB
))
return
[
PoolState
.
INVALID
,
null
]
// pool has not been created or not initialized yet
if
(
poolAddressFromFactory
===
ZERO_ADDRESS
||
!
slot0
||
!
liquidity
||
slot0
.
sqrtPriceX96
===
0
)
{
return
[
PoolState
.
NOT_EXISTS
,
null
]
}
return
[
PoolState
.
EXISTS
,
new
Pool
(
tokenA
,
tokenB
,
feeAmount
,
slot0
.
sqrtPriceX96
,
liquidity
,
slot0
.
tick
)]
},
[
addressesLoading
,
feeAmount
,
liquidity
,
liquidityLoading
,
poolAddressFromFactory
,
slot0
,
slot0Loading
,
tokenA
,
tokenB
,
])
}
src/hooks/useDerivedPositionInfo.ts
View file @
b69f08cb
import
{
Pool
,
Position
}
from
'
@uniswap/v3-sdk
'
import
{
Pool
,
Position
}
from
'
@uniswap/v3-sdk
'
import
{
usePool
}
from
'
data/
Pools
'
import
{
usePool
}
from
'
hooks/use
Pools
'
import
{
PositionDetails
}
from
'
types/position
'
import
{
PositionDetails
}
from
'
types/position
'
import
{
useCurrency
}
from
'
./Tokens
'
import
{
useCurrency
}
from
'
./Tokens
'
...
...
src/hooks/usePools.ts
0 → 100644
View file @
b69f08cb
import
{
computePoolAddress
}
from
'
@uniswap/v3-sdk
'
import
{
IUniswapV3PoolStateInterface
}
from
'
../types/v3/IUniswapV3PoolState
'
import
{
Token
,
Currency
}
from
'
@uniswap/sdk-core
'
import
{
useMemo
}
from
'
react
'
import
{
useActiveWeb3React
}
from
'
./index
'
import
{
useMultipleContractSingleData
}
from
'
../state/multicall/hooks
'
import
{
wrappedCurrency
}
from
'
../utils/wrappedCurrency
'
import
{
Pool
,
FeeAmount
}
from
'
@uniswap/v3-sdk
'
import
{
V3_CORE_FACTORY_ADDRESSES
}
from
'
constants/v3
'
import
{
abi
as
IUniswapV3PoolStateABI
}
from
'
@uniswap/v3-core/artifacts/contracts/interfaces/pool/IUniswapV3PoolState.sol/IUniswapV3PoolState.json
'
import
{
Interface
}
from
'
@ethersproject/abi
'
const
POOL_STATE_INTERFACE
=
new
Interface
(
IUniswapV3PoolStateABI
)
as
IUniswapV3PoolStateInterface
export
enum
PoolState
{
LOADING
=
'
LOADING
'
,
NOT_EXISTS
=
'
NOT_EXISTS
'
,
EXISTS
=
'
EXISTS
'
,
INVALID
=
'
INVALID
'
,
}
export
function
usePools
(
poolKeys
:
[
Currency
|
undefined
,
Currency
|
undefined
,
FeeAmount
|
undefined
][]
):
[
PoolState
,
Pool
|
null
][]
{
const
{
chainId
}
=
useActiveWeb3React
()
const
transformed
:
([
Token
,
Token
,
FeeAmount
]
|
null
)[]
=
useMemo
(()
=>
{
return
poolKeys
.
map
(([
currencyA
,
currencyB
,
feeAmount
])
=>
{
if
(
!
chainId
||
!
currencyA
||
!
currencyB
||
!
feeAmount
)
return
null
const
tokenA
=
wrappedCurrency
(
currencyA
,
chainId
)
const
tokenB
=
wrappedCurrency
(
currencyB
,
chainId
)
if
(
!
tokenA
||
!
tokenB
||
tokenA
.
equals
(
tokenB
))
return
null
const
[
token0
,
token1
]
=
tokenA
.
sortsBefore
(
tokenB
)
?
[
tokenA
,
tokenB
]
:
[
tokenB
,
tokenA
]
return
[
token0
,
token1
,
feeAmount
]
})
},
[
chainId
,
poolKeys
])
const
poolAddresses
:
(
string
|
undefined
)[]
=
useMemo
(()
=>
{
const
v3CoreFactoryAddress
=
chainId
&&
V3_CORE_FACTORY_ADDRESSES
[
chainId
]
return
transformed
.
map
((
value
)
=>
{
if
(
!
v3CoreFactoryAddress
||
!
value
)
return
undefined
return
computePoolAddress
({
factoryAddress
:
v3CoreFactoryAddress
,
tokenA
:
value
[
0
],
tokenB
:
value
[
1
],
fee
:
value
[
2
],
})
})
},
[
chainId
,
transformed
])
const
slot0s
=
useMultipleContractSingleData
(
poolAddresses
,
POOL_STATE_INTERFACE
,
'
slot0
'
)
const
liquidities
=
useMultipleContractSingleData
(
poolAddresses
,
POOL_STATE_INTERFACE
,
'
liquidity
'
)
return
useMemo
(()
=>
{
return
poolKeys
.
map
((
_key
,
index
)
=>
{
const
[
token0
,
token1
,
fee
]
=
transformed
[
index
]
??
[]
if
(
!
token0
||
!
token1
||
!
fee
)
return
[
PoolState
.
INVALID
,
null
]
const
{
result
:
slot0
,
loading
:
slot0Loading
,
valid
:
slot0Valid
}
=
slot0s
[
index
]
const
{
result
:
liquidity
,
loading
:
liquidityLoading
,
valid
:
liquidityValid
}
=
liquidities
[
index
]
if
(
!
slot0Valid
||
!
liquidityValid
)
return
[
PoolState
.
INVALID
,
null
]
if
(
slot0Loading
||
liquidityLoading
)
return
[
PoolState
.
LOADING
,
null
]
if
(
!
slot0
||
!
liquidity
)
return
[
PoolState
.
NOT_EXISTS
,
null
]
return
[
PoolState
.
EXISTS
,
new
Pool
(
token0
,
token1
,
fee
,
slot0
.
sqrtPriceX96
,
liquidity
[
0
],
slot0
.
tick
)]
})
},
[
liquidities
,
poolKeys
,
slot0s
,
transformed
])
}
export
function
usePool
(
currencyA
:
Currency
|
undefined
,
currencyB
:
Currency
|
undefined
,
feeAmount
:
FeeAmount
|
undefined
):
[
PoolState
,
Pool
|
null
]
{
const
poolKeys
:
[
Currency
|
undefined
,
Currency
|
undefined
,
FeeAmount
|
undefined
][]
=
useMemo
(
()
=>
[[
currencyA
,
currencyB
,
feeAmount
]],
[
currencyA
,
currencyB
,
feeAmount
]
)
return
usePools
(
poolKeys
)[
0
]
}
src/pages/MigrateV2/MigrateV2Pair.tsx
View file @
b69f08cb
...
@@ -18,7 +18,7 @@ import { BackArrow, ExternalLink, TYPE } from '../../theme'
...
@@ -18,7 +18,7 @@ import { BackArrow, ExternalLink, TYPE } from '../../theme'
import
{
getEtherscanLink
,
isAddress
}
from
'
../../utils
'
import
{
getEtherscanLink
,
isAddress
}
from
'
../../utils
'
import
{
BodyWrapper
}
from
'
../AppBody
'
import
{
BodyWrapper
}
from
'
../AppBody
'
import
{
V2_MIGRATOR_ADDRESSES
}
from
'
constants/v3
'
import
{
V2_MIGRATOR_ADDRESSES
}
from
'
constants/v3
'
import
{
PoolState
,
usePool
}
from
'
data/
Pools
'
import
{
PoolState
,
usePool
}
from
'
hooks/use
Pools
'
import
{
FeeAmount
,
Pool
,
Position
,
priceToClosestTick
,
TickMath
}
from
'
@uniswap/v3-sdk
'
import
{
FeeAmount
,
Pool
,
Position
,
priceToClosestTick
,
TickMath
}
from
'
@uniswap/v3-sdk
'
import
{
LightCard
,
PinkCard
,
YellowCard
}
from
'
components/Card
'
import
{
LightCard
,
PinkCard
,
YellowCard
}
from
'
components/Card
'
import
{
ApprovalState
,
useApproveCallback
}
from
'
hooks/useApproveCallback
'
import
{
ApprovalState
,
useApproveCallback
}
from
'
hooks/useApproveCallback
'
...
...
src/pages/Pool/PositionPage.tsx
View file @
b69f08cb
import
React
,
{
useCallback
,
useMemo
,
useState
}
from
'
react
'
import
React
,
{
useCallback
,
useMemo
,
useState
}
from
'
react
'
import
{
Position
}
from
'
@uniswap/v3-sdk
'
import
{
Position
}
from
'
@uniswap/v3-sdk
'
import
{
PoolState
,
usePool
}
from
'
data/
Pools
'
import
{
PoolState
,
usePool
}
from
'
hooks/use
Pools
'
import
{
useToken
}
from
'
hooks/Tokens
'
import
{
useToken
}
from
'
hooks/Tokens
'
import
{
useV3PositionFromTokenId
}
from
'
hooks/useV3Positions
'
import
{
useV3PositionFromTokenId
}
from
'
hooks/useV3Positions
'
import
{
Link
,
RouteComponentProps
}
from
'
react-router-dom
'
import
{
Link
,
RouteComponentProps
}
from
'
react-router-dom
'
...
...
src/state/burn/v3/hooks.ts
View file @
b69f08cb
import
{
BigNumber
}
from
'
@ethersproject/bignumber
'
import
{
BigNumber
}
from
'
@ethersproject/bignumber
'
import
{
TokenAmount
}
from
'
@uniswap/sdk-core
'
import
{
TokenAmount
}
from
'
@uniswap/sdk-core
'
import
{
Position
}
from
'
@uniswap/v3-sdk
'
import
{
Position
}
from
'
@uniswap/v3-sdk
'
import
{
usePool
}
from
'
data/
Pools
'
import
{
usePool
}
from
'
hooks/use
Pools
'
import
{
useActiveWeb3React
}
from
'
hooks
'
import
{
useActiveWeb3React
}
from
'
hooks
'
import
{
useToken
}
from
'
hooks/Tokens
'
import
{
useToken
}
from
'
hooks/Tokens
'
import
{
useV3PositionFees
}
from
'
hooks/useV3PositionFees
'
import
{
useV3PositionFees
}
from
'
hooks/useV3PositionFees
'
...
...
src/state/claim/hooks.ts
View file @
b69f08cb
...
@@ -97,7 +97,7 @@ export function useClaimCallback(
...
@@ -97,7 +97,7 @@ export function useClaimCallback(
const
claimData
=
useUserClaimData
(
account
)
const
claimData
=
useUserClaimData
(
account
)
// used for popup summary
// used for popup summary
const
un
C
laimedAmount
:
TokenAmount
|
undefined
=
useUserUnclaimedAmount
(
account
)
const
un
c
laimedAmount
:
TokenAmount
|
undefined
=
useUserUnclaimedAmount
(
account
)
const
addTransaction
=
useTransactionAdder
()
const
addTransaction
=
useTransactionAdder
()
const
distributorContract
=
useMerkleDistributorContract
()
const
distributorContract
=
useMerkleDistributorContract
()
...
@@ -111,7 +111,7 @@ export function useClaimCallback(
...
@@ -111,7 +111,7 @@ export function useClaimCallback(
.
claim
(...
args
,
{
value
:
null
,
gasLimit
:
calculateGasMargin
(
estimatedGasLimit
)
})
.
claim
(...
args
,
{
value
:
null
,
gasLimit
:
calculateGasMargin
(
estimatedGasLimit
)
})
.
then
((
response
:
TransactionResponse
)
=>
{
.
then
((
response
:
TransactionResponse
)
=>
{
addTransaction
(
response
,
{
addTransaction
(
response
,
{
summary
:
`Claimed
${
un
C
laimedAmount
?.
toSignificant
(
4
)}
UNI
`,
summary
:
`Claimed
${
un
c
laimedAmount
?.
toSignificant
(
4
)}
UNI
`,
claim: { recipient: account },
claim: { recipient: account },
})
})
return response.hash
return response.hash
...
...
src/state/mint/hooks.ts
View file @
b69f08cb
import
{
BIG_INT_ZERO
}
from
'
./../../constants/index
'
import
{
BIG_INT_ZERO
}
from
'
./../../constants/index
'
import
{
getTickToPrice
}
from
'
utils/getTickToPrice
'
import
{
getTickToPrice
}
from
'
utils/getTickToPrice
'
import
JSBI
from
'
jsbi
'
import
JSBI
from
'
jsbi
'
import
{
PoolState
}
from
'
.
/../../data/
Pools
'
import
{
PoolState
}
from
'
.
./../hooks/use
Pools
'
import
{
Pool
,
FeeAmount
,
Position
,
priceToClosestTick
,
TickMath
}
from
'
@uniswap/v3-sdk/dist/
'
import
{
Pool
,
FeeAmount
,
Position
,
priceToClosestTick
,
TickMath
}
from
'
@uniswap/v3-sdk/dist/
'
import
{
Currency
,
CurrencyAmount
,
ETHER
,
Price
}
from
'
@uniswap/sdk-core
'
import
{
Currency
,
CurrencyAmount
,
ETHER
,
Price
}
from
'
@uniswap/sdk-core
'
import
{
useCallback
,
useMemo
}
from
'
react
'
import
{
useCallback
,
useMemo
}
from
'
react
'
...
@@ -13,7 +13,7 @@ import { tryParseAmount } from '../swap/hooks'
...
@@ -13,7 +13,7 @@ import { tryParseAmount } from '../swap/hooks'
import
{
useCurrencyBalances
}
from
'
../wallet/hooks
'
import
{
useCurrencyBalances
}
from
'
../wallet/hooks
'
import
{
Field
,
Bound
,
typeInput
,
typeLowerRangeInput
,
typeUpperRangeInput
,
typeStartPriceInput
}
from
'
./actions
'
import
{
Field
,
Bound
,
typeInput
,
typeLowerRangeInput
,
typeUpperRangeInput
,
typeStartPriceInput
}
from
'
./actions
'
import
{
tryParseTick
}
from
'
./utils
'
import
{
tryParseTick
}
from
'
./utils
'
import
{
usePool
}
from
'
data/
Pools
'
import
{
usePool
}
from
'
hooks/use
Pools
'
export
function
useMintState
():
AppState
[
'
mint
'
]
{
export
function
useMintState
():
AppState
[
'
mint
'
]
{
return
useSelector
<
AppState
,
AppState
[
'
mint
'
]
>
((
state
)
=>
state
.
mint
)
return
useSelector
<
AppState
,
AppState
[
'
mint
'
]
>
((
state
)
=>
state
.
mint
)
...
...
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