Skip to content
This repository was archived by the owner on Jun 24, 2022. It is now read-only.

Commit

Permalink
prototype position data hook (#32)
Browse files Browse the repository at this point in the history
Co-authored-by: Jordan Frankfurt <[email protected]>
  • Loading branch information
JFrankfurt and Jordan Frankfurt authored Mar 24, 2021
1 parent 59164f8 commit 32e679c
Show file tree
Hide file tree
Showing 12 changed files with 163 additions and 64 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@uniswap/token-lists": "^1.0.0-beta.19",
"@uniswap/v2-core": "1.0.0",
"@uniswap/v2-periphery": "^1.1.0-beta.0",
"@uniswap/v3-periphery": "^1.0.0-beta.7",
"@web3-react/core": "^6.0.9",
"@web3-react/fortmatic-connector": "^6.0.9",
"@web3-react/injected-connector": "^6.0.7",
Expand Down
10 changes: 1 addition & 9 deletions src/components/PositionList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { unwrappedToken } from 'utils/wrappedCurrency'
import styled, { keyframes } from 'styled-components'
import { Link } from 'react-router-dom'
import { MEDIA_WIDTHS } from 'theme'
import { Position } from 'types/v3'

const ActiveDot = styled.span`
background-color: ${({ theme }) => theme.success};
Expand Down Expand Up @@ -175,15 +176,6 @@ const DataText = styled.div`
font-weight: 500;
`

interface Position {
feeLevel: Percent
feesEarned: Record<string, number>
tokenAmount0: TokenAmount
tokenAmount1: TokenAmount
tickLower: number
tickUpper: number
}

export type PositionListProps = React.PropsWithChildren<{
loading: boolean
positions: Position[]
Expand Down
2 changes: 1 addition & 1 deletion src/connectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function getNetworkLibrary(): Web3Provider {
}

export const injected = new InjectedConnector({
supportedChainIds: [1, 3, 4, 5, 42],
supportedChainIds: [1, 3, 4, 5, 42, 1337],
})

// mainnet only
Expand Down
28 changes: 28 additions & 0 deletions src/constants/v3/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ChainId } from '@uniswap/sdk'

export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: { [chainId in ChainId | 1337]: string } = {
[ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '',
[ChainId.RINKEBY]: '',
[ChainId.GÖRLI]: '',
[ChainId.KOVAN]: '',
[1337]: '0xee9e30637f84Bbf929042A9118c6E20023dab833',
}

export const NONFUNGIBLE_TOKEN_POSITION_DESCRIPTOR_ADDRESSES: { [chainId in ChainId | 1337]: string } = {
[ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '',
[ChainId.RINKEBY]: '',
[ChainId.GÖRLI]: '',
[ChainId.KOVAN]: '',
[1337]: '0x3431b9Ed12e3204bC6f7039e1c576417B70fdD67',
}

export const SWAP_ROUTER_ADDRESSES: { [chainId in ChainId | 1337]: string } = {
[ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '',
[ChainId.RINKEBY]: '',
[ChainId.GÖRLI]: '',
[ChainId.KOVAN]: '',
[1337]: '0xa0588c89Fe967e66533aB1A0504C30989f90156f',
}
9 changes: 9 additions & 0 deletions src/hooks/useContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import { abi as STAKING_REWARDS_ABI } from '@uniswap/liquidity-staker/build/Stak
import { abi as MERKLE_DISTRIBUTOR_ABI } from '@uniswap/merkle-distributor/build/MerkleDistributor.json'
import { ChainId, WETH } from '@uniswap/sdk'
import { abi as IUniswapV2PairABI } from '@uniswap/v2-core/build/IUniswapV2Pair.json'
import { abi as NFTPositionManagerABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES } from 'constants/v3'
import { useMemo } from 'react'
import { NonfungiblePositionManager } from 'types/v3/contracts/NonfungiblePositionManager'
import { GOVERNANCE_ADDRESS, MERKLE_DISTRIBUTOR_ADDRESS, UNI } from '../constants'
import {
ARGENT_WALLET_DETECTOR_ABI,
Expand Down Expand Up @@ -128,3 +131,9 @@ export function useSocksController(): Contract | null {
false
)
}

export function useV3NFTPositionManagerContract(): NonfungiblePositionManager | null {
const { chainId } = useActiveWeb3React()
const address = chainId ? NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId] : undefined
return useContract(address, NFTPositionManagerABI) as NonfungiblePositionManager | null
}
63 changes: 63 additions & 0 deletions src/hooks/useV3PositionManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { OptionalMethodInputs, useSingleCallResult, useSingleContractMultipleData } from 'state/multicall/hooks'
import { Position } from 'types/v3'
import { useV3NFTPositionManagerContract } from './useContract'

interface UseV3PositionsResults {
error?: (string | boolean) | (string | boolean)[]
loading: boolean
positions: Position[]
}
export function useV3Positions(account: string | null | undefined): UseV3PositionsResults {
const positionManager = useV3NFTPositionManagerContract()
let loading = false
let error: any
const {
error: balanceOfError,
loading: balanceOfLoading,
result: balanceOfResult,
} = useSingleCallResult(positionManager, 'balanceOf', [account || undefined])

loading = balanceOfLoading
error = balanceOfError

const tokenOfOwnerByIndexArgs: OptionalMethodInputs[] = balanceOfResult
? balanceOfResult.filter((x) => Boolean(x)).map((index) => [account, index])
: []
const tokensCallResults = useSingleContractMultipleData(
positionManager,
'tokenOfOwnerByIndex',
tokenOfOwnerByIndexArgs
)

const callData: any[] = []
tokensCallResults.forEach(({ error: e, loading: l, result: data }) => {
if (e && !error) {
error = e
}
loading = loading || l
if (data) {
callData.push([account, data])
}
})

const positionsCallResults = useSingleContractMultipleData(positionManager, 'positions', callData)

const positions: any[] = []
positionsCallResults.forEach(({ error: e, loading: l, result: data }) => {
if (e) {
if (!error) {
error = e
}
if (error && Array.isArray(error)) {
error = [...error, error]
}
}
loading = loading || l

if (data) {
positions.push(data)
}
})

return { error, loading, positions }
}
67 changes: 15 additions & 52 deletions src/pages/Pool/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { TokenAmount } from '@uniswap/sdk'
import Badge, { BadgeVariant } from 'components/Badge'
import { ButtonGray, ButtonPrimary } from 'components/Button'
import { AutoColumn } from 'components/Column'
Expand All @@ -7,15 +6,14 @@ import { SwapPoolTabs } from 'components/NavigationTabs'
import PositionList from 'components/PositionList'
import { RowBetween, RowFixed } from 'components/Row'
import { useActiveWeb3React } from 'hooks'
import { useV3Positions } from 'hooks/useV3PositionManager'
import React, { useContext, useMemo } from 'react'
import { BookOpen, ChevronDown, Download, Inbox, Info, PlusCircle } from 'react-feather'
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
import { useWalletModalToggle } from 'state/application/hooks'
import styled, { ThemeContext } from 'styled-components'
import { HideSmall, MEDIA_WIDTHS, TYPE } from 'theme'
import { basisPointsToPercent } from 'utils'
import { DAI, WBTC } from '../../constants'

const PageWrapper = styled(AutoColumn)`
max-width: 870px;
Expand Down Expand Up @@ -91,64 +89,29 @@ const MainContentWrapper = styled.main`
display: flex;
flex-direction: column;
`
const FEE_BIPS = {
FIVE: basisPointsToPercent(5),
THIRTY: basisPointsToPercent(30),
ONE_HUNDRED: basisPointsToPercent(100),
}

function useV3Positions() {
const positions = [
{
feesEarned: {
DAI: 1000,
WBTC: 0.005,
},
feeLevel: FEE_BIPS.FIVE,
tokenAmount0: new TokenAmount(DAI, BigInt(0) * BigInt(10e18)),
tokenAmount1: new TokenAmount(WBTC, BigInt(1) * BigInt(10e7)),
tickLower: 40000,
tickUpper: 60000,
},
{
feesEarned: {
DAI: 1000,
WBTC: 0.005,
},
feeLevel: FEE_BIPS.THIRTY,
tokenAmount0: new TokenAmount(DAI, BigInt(5000) * BigInt(10e18)),
tokenAmount1: new TokenAmount(WBTC, BigInt(1) * BigInt(10e7)),
tickLower: 45000,
tickUpper: 55000,
},
]
const error = undefined
const loading = false
return { error, loading, positions }
}
export default function Pool() {
const { error, loading, positions } = useV3Positions()
const { account } = useActiveWeb3React()
const { error, loading, positions } = useV3Positions(account)
const toggleWalletModal = useWalletModalToggle()
const { t } = useTranslation()
const theme = useContext(ThemeContext)
const { account } = useActiveWeb3React()

if (error) {
console.error(error)
console.error('error fetching v3 positions', error)
}

const numInactivePositions = useMemo(
() =>
positions.reduce((acc: any, position: any) => {
const { tokenAmount0, tokenAmount1 } = position
const limitCrossed = tokenAmount0.equalTo(BigInt(0)) || tokenAmount1.equalTo(BigInt(0))
return limitCrossed ? acc + 1 : acc
}, 0),
[positions]
)
const hasPositions = Boolean(positions?.length > 0)

const numInactivePositions = useMemo(() => {
return positions.reduce((acc: any, position: any) => {
const { tokenAmount0, tokenAmount1 } = position
const limitCrossed = tokenAmount0.equalTo(BigInt(0)) || tokenAmount1.equalTo(BigInt(0))
return limitCrossed ? acc + 1 : acc
}, 0)
}, [positions])

const hasV2Liquidity = true
const showMigrateHeaderLink = hasV2Liquidity && positions.length > 0
const showMigrateHeaderLink = Boolean(hasV2Liquidity && hasPositions)

const menuItems = [
{
Expand Down Expand Up @@ -219,7 +182,7 @@ export default function Pool() {
</TitleRow>

<MainContentWrapper>
{positions?.length > 0 ? (
{hasPositions ? (
<PositionList loading={loading} positions={positions} />
) : (
<NoLiquidity>
Expand Down
4 changes: 3 additions & 1 deletion src/state/lists/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class WrappedTokenInfo extends Token {
}

export type TokenAddressMap = Readonly<
{ [chainId in ChainId]: Readonly<{ [tokenAddress: string]: { token: WrappedTokenInfo; list: TokenList } }> }
{ [chainId in ChainId | 1337]: Readonly<{ [tokenAddress: string]: { token: WrappedTokenInfo; list: TokenList } }> }
>

/**
Expand All @@ -42,6 +42,7 @@ const EMPTY_LIST: TokenAddressMap = {
[ChainId.ROPSTEN]: {},
[ChainId.GÖRLI]: {},
[ChainId.MAINNET]: {},
[1337]: {},
}

const listCache: WeakMap<TokenList, TokenAddressMap> | null =
Expand Down Expand Up @@ -97,6 +98,7 @@ function combineMaps(map1: TokenAddressMap, map2: TokenAddressMap): TokenAddress
4: { ...map1[4], ...map2[4] },
5: { ...map1[5], ...map2[5] },
42: { ...map1[42], ...map2[42] },
1337: { ...map1[1337], ...map2[1337] },
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/state/multicall/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface Result extends ReadonlyArray<any> {
type MethodArg = string | number | BigNumber
type MethodArgs = Array<MethodArg | MethodArg[]>

type OptionalMethodInputs = Array<MethodArg | MethodArg[] | undefined> | undefined
export type OptionalMethodInputs = Array<MethodArg | MethodArg[] | undefined> | undefined

function isMethodArg(x: unknown): x is MethodArg {
return ['string', 'number'].indexOf(typeof x) !== -1
Expand Down
6 changes: 6 additions & 0 deletions src/types/v3/contracts/NonfungiblePositionManager.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Contract } from '@ethersproject/contracts'

export interface NonfungiblePositionManager extends Contract {
balanceOf(address: string): Promise<BigNumber>
tokenOfOwnerByIndex(address: string, index: BigNumber): Promise<BigNumber>
}
17 changes: 17 additions & 0 deletions src/types/v3/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { BigNumberish } from '@ethersproject/bignumber'
import { basisPointsToPercent } from 'utils'

const FEE_BIPS = {
FIVE: basisPointsToPercent(5),
THIRTY: basisPointsToPercent(30),
ONE_HUNDRED: basisPointsToPercent(100),
}

export interface Position {
feesEarned: Record<string, BigNumberish>
feeLevel: FEE_BIPS
tokenAmount0: TokenAmount
tokenAmount1: TokenAmount
tickLower: BigNumberish
tickUpper: BigNumberish
}
18 changes: 18 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2257,6 +2257,11 @@
mkdirp "^1.0.4"
rimraf "^3.0.2"

"@openzeppelin/[email protected]":
version "3.4.1-solc-0.7-2"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.1-solc-0.7-2.tgz#371c67ebffe50f551c3146a9eec5fe6ffe862e92"
integrity sha512-tAG9LWg8+M2CMu7hIsqHPaTyG4uDzjr6mhvH96LvOpLZZj6tgzTluBt+LsCf1/QaYrlis6pITvpIaIhE+iZB+Q==

"@pedrouid/iso-crypto@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@pedrouid/iso-crypto/-/iso-crypto-1.0.0.tgz#cf06b40ef3da3d7ca7363bd7a521ed59fa2fd13d"
Expand Down Expand Up @@ -3984,6 +3989,19 @@
"@uniswap/lib" "1.1.1"
"@uniswap/v2-core" "1.0.0"

"@uniswap/v3-core@^1.0.0-beta.10":
version "1.0.0-beta.10"
resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.0-beta.10.tgz#c0fa1169e4a7fd0e5b33efb827c95c9bd05be071"
integrity sha512-Z23ikJr3sWIYQrvsRMrzDCeDXfQtRQMIyGsgHtfx4UAXc4jjUzNfDxNdAcBcgFH0u0ekt1RJ0gXUVcH0NjPfKQ==

"@uniswap/v3-periphery@^1.0.0-beta.7":
version "1.0.0-beta.7"
resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.0.0-beta.7.tgz#d110308f8f8d0d645ad541ebe0f62721ade0dbd8"
integrity sha512-tvOYdjVgrYzIuxIjUHCyYv8C0UYwa0PFkn0xM0FALU2TNYy7BP4ITrozu6KmUBqEVZf9hAs2HlmomhMoSa/WtA==
dependencies:
"@openzeppelin/contracts" "3.4.1-solc-0.7-2"
"@uniswap/v3-core" "^1.0.0-beta.10"

"@walletconnect/client@^1.1.1-alpha.0":
version "1.3.6"
resolved "https://registry.yarnpkg.com/@walletconnect/client/-/client-1.3.6.tgz#537b7af6bf87a906fcf171fd5bc4e56a2a3d1908"
Expand Down

0 comments on commit 32e679c

Please sign in to comment.