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

Commit

Permalink
Claim hooks part 0 (#2032)
Browse files Browse the repository at this point in the history
* Added V_COW Token objects (only rinkeby for now)

* Added GNO Token objects (will be used later)

* Modded initial set of claim hooks

* Restored and commented out original claim hooks on mod file

* Added utils for checking what type of user claims are

Not yet in use, will be useful later

* Temporary hardcoded address for loading the claims in the UI

* Removed unecessary `@src` import

* Using the chain id enum rather than magic numbers

Co-authored-by: Leandro Boscariol <[email protected]>
  • Loading branch information
alfetopito and Leandro Boscariol authored Dec 23, 2021
1 parent b1628bb commit 52b416f
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 34 deletions.
4 changes: 2 additions & 2 deletions src/components/claim/ClaimModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import tokenLogo from '../../assets/images/token-logo.png'
import { useActiveWeb3React } from '../../hooks/web3'
import { ApplicationModal } from '../../state/application/actions'
import { useModalOpen, useToggleSelfClaimModal } from '../../state/application/hooks'
import { useClaimCallback, useUserClaimData, useUserUnclaimedAmount } from '../../state/claim/hooks'
import { useClaimCallback, useUserClaimData, useUserUnclaimedAmount } from 'state/claim/hooks'
import { useUserHasSubmittedClaim } from '../../state/transactions/hooks'
import { CloseIcon, CustomLightSpinner, ExternalLink, TYPE, UniTokenAnimated } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
Expand Down Expand Up @@ -60,7 +60,7 @@ export default function ClaimModal() {
const userClaimData = useUserClaimData(account)

// monitor the status of the claim from contracts and txns
const { claimCallback } = useClaimCallback(account)
const { claimCallback } = useClaimCallback('0x82850293A348107E798E5D366c10D1b566145Cd5') // TODO: remove me, hard coded only for testing
const unclaimedAmount: CurrencyAmount<Token> | undefined = useUserUnclaimedAmount(account)
const { claimSubmitted, claimTxn } = useUserHasSubmittedClaim(account ?? undefined)
const claimConfirmed = Boolean(claimTxn?.receipt)
Expand Down
53 changes: 52 additions & 1 deletion src/custom/constants/tokens/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { ChainId } from '@uniswap/sdk'
import { WETH9 } from '@uniswap/sdk-core'
import { WETH9, Token } from '@uniswap/sdk-core'
import { DAI_RINKEBY, USDC_RINKEBY, USDT_RINKEBY, WBTC_RINKEBY } from 'utils/rinkeby/constants'
import { DAI, USDC, USDT, WBTC } from 'constants/tokens'
import { USDC_XDAI, /*USDT_XDAI,*/ WBTC_XDAI, WETH_XDAI, WXDAI } from 'utils/xdai/constants'
import { SupportedChainId } from 'constants/chains'
import { V_COW_CONTRACT_ADDRESS } from 'constants/index'

export * from './tokensMod'

Expand All @@ -28,3 +30,52 @@ export const ADDRESS_IMAGE_OVERRIDE = {
'https://raw.githubusercontent.com/1Hive/default-token-list/master/src/assets/xdai/0xe91d153e0b41518a2ce8dd3d7944fa863463a97d/logo.png',
[WETH_XDAI.address]: getTrustImage(WETH_ADDRESS_MAINNET),
}

export const V_COW: Record<number, Token> = {
// TODO: enable once contract addresses are added
// [SupportedChainId.MAINNET]: new Token(
// SupportedChainId.MAINNET,
// V_COW_CONTRACT_ADDRESS[SupportedChainId.MAINNET] || '',
// 18,
// 'vCOW',
// 'Virtual CowSwap Token'
// ),
// [SupportedChainId.XDAI]: new Token(
// SupportedChainId.XDAI,
// V_COW_CONTRACT_ADDRESS[SupportedChainId.XDAI] || '',
// 18,
// 'vCOW',
// 'Virtual CowSwap Token'
// ),
[SupportedChainId.RINKEBY]: new Token(
SupportedChainId.RINKEBY,
V_COW_CONTRACT_ADDRESS[SupportedChainId.RINKEBY] || '',
18,
'vCOW',
'Virtual CowSwap Token'
),
}

export const GNO: Record<number, Token> = {
[SupportedChainId.MAINNET]: new Token(
SupportedChainId.MAINNET,
'0x6810e776880c02933d47db1b9fc05908e5386b96',
18,
'GNO',
'Gnosis'
),
[SupportedChainId.XDAI]: new Token(
SupportedChainId.XDAI,
'0x9c58bacc331c9aa871afd802db6379a98e80cedb',
18,
'GNO',
'Gnosis'
),
[SupportedChainId.RINKEBY]: new Token(
SupportedChainId.RINKEBY,
'0xd0dab4e640d95e9e8a47545598c33e31bdb53c7c',
18,
'GNO',
'Gnosis'
),
}
54 changes: 24 additions & 30 deletions src/custom/state/claim/hooks/hooksMod.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import JSBI from 'jsbi'
// import JSBI from 'jsbi'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
import { TransactionResponse } from '@ethersproject/providers'
// import { useEffect, useState } from 'react'
import { UNI } from 'constants/tokens'
// import { UNI } from 'constants/tokens'
import { useActiveWeb3React } from 'hooks/web3'
import { useMerkleDistributorContract } from 'hooks/useContract'
import { calculateGasMargin } from 'utils/calculateGasMargin'
// import { useSingleCallResult } from 'state/multicall/hooks'
import { isAddress } from 'utils/index'
import { useTransactionAdder } from 'state/enhancedTransactions/hooks'
import { UserClaims } from '.'
import { UserClaims, useUserUnclaimedAmount } from '.'
// import { useSingleCallResult } from '@src/state/multicall/hooks'
export { useUserClaimData } from '@src/state/claim/hooks'

// interface UserClaimData {
// index: number
Expand Down Expand Up @@ -158,34 +160,26 @@ export function useUserClaims(account: string | null | undefined): UserClaims |
}

// check if user is in blob and has not yet claimed UNI
export function useUserHasAvailableClaim(account: string | null | undefined): boolean {
const userClaims = useUserClaims(account)
// const distributorContract = useMerkleDistributorContract()

// TODO: Go claiming by claiming, and check if claimed or not
// TODO: Should we do a multicall instead, or the contract allows to check multiple claimings at once?
const isClaimedResult = { loading: false, result: [false] } //useSingleCallResult(distributorContract, 'isClaimed', [userClaimData?.index])

// user is in blob and contract marks as unclaimed
return Boolean(userClaims && !isClaimedResult.loading && isClaimedResult.result?.[0] === false)
}

export function useUserUnclaimedAmount(account: string | null | undefined): CurrencyAmount<Token> | undefined {
const { chainId } = useActiveWeb3React()
const claims = useUserClaims(account)
const canClaim = useUserHasAvailableClaim(account)

const uni = chainId ? UNI[chainId] : undefined
if (!uni) return undefined
if (!canClaim || !claims) {
return CurrencyAmount.fromRawAmount(uni, JSBI.BigInt(0))
}
const totalAmount = claims.reduce((acc, claim) => {
return JSBI.add(acc, JSBI.BigInt(claim.amount))
}, JSBI.BigInt('0'))
// export function useUserHasAvailableClaim(account: string | null | undefined): boolean {
// const userClaimData = useUserClaimData(account)
// const distributorContract = useMerkleDistributorContract()
// const isClaimedResult = useSingleCallResult(distributorContract, 'isClaimed', [userClaimData?.index])
// // user is in blob and contract marks as unclaimed
// return Boolean(userClaimData && !isClaimedResult.loading && isClaimedResult.result?.[0] === false)
// }

return CurrencyAmount.fromRawAmount(uni, JSBI.BigInt(totalAmount))
}
// export function useUserUnclaimedAmount(account: string | null | undefined): CurrencyAmount<Token> | undefined {
// const { chainId } = useActiveWeb3React()
// const userClaimData = useUserClaimData(account)
// const canClaim = useUserHasAvailableClaim(account)
//
// const uni = chainId ? UNI[chainId] : undefined
// if (!uni) return undefined
// if (!canClaim || !userClaimData) {
// return CurrencyAmount.fromRawAmount(uni, JSBI.BigInt(0))
// }
// return CurrencyAmount.fromRawAmount(uni, JSBI.BigInt(userClaimData.amount))
// }

export function useClaimCallback(account: string | null | undefined): {
claimCallback: () => Promise<string>
Expand Down
79 changes: 78 additions & 1 deletion src/custom/state/claim/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
import { useMemo } from 'react'
import JSBI from 'jsbi'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'

import { useUserClaims } from 'state/claim/hooks/hooksMod'
import { useVCowContract } from 'hooks/useContract'
import { useSingleContractMultipleData } from 'state/multicall/hooks'
import { useActiveWeb3React } from 'hooks/web3'
import { V_COW } from 'constants/tokens'

export * from './hooksMod'

export type ClaimType =
Expand All @@ -8,12 +18,79 @@ export type ClaimType =
| 'UserOption' // paid, with vesting, must use Native currency, can be available on both mainnet and gchain
| 'Investor' // paid, with vesting, must use USDC, only on mainnet

export const FREE_CLAIM_TYPES: ClaimType[] = ['Airdrop', 'Team', 'Advisor']
export const PAID_CLAIM_TYPES: ClaimType[] = ['GnoOption', 'UserOption', 'Investor']

export interface UserClaimData {
index: number
amount: string
proof: string[]
type: ClaimType
// TODO: Either add the missing fields, or add https://github.com/gnosis/gp-v2-token type
}

type Account = string | null | undefined

export type UserClaims = UserClaimData[]

/**
* Gets an array of available claim
*
* @param account
*/
export function useUserAvailableClaims(account: Account): UserClaims {
const userClaims = useUserClaims(account)
const contract = useVCowContract()

// build list of parameters, with the claim index
const claimIndexes = userClaims?.map(({ index }) => [index]) || []

const results = useSingleContractMultipleData(contract, 'isClaimed', claimIndexes)

console.log(`useUserAvailableClaims::re-render`, userClaims, claimIndexes, results)

return useMemo(() => {
if (!userClaims || userClaims.length === 0) {
// user has no claims
return []
}

return results.reduce<UserClaims>((acc, result, index) => {
if (
result.valid && // result is valid
!result.loading && // result is not loading
result.result?.[0] === false // result is false, meaning not claimed
) {
acc.push(userClaims[index]) // get the claim not yet claimed
}
return acc
}, [])
}, [results, userClaims])
}

/**
* Returns whether the user has any available claim
* Syntactic sugar on top of `useUserAvailableClaims`
*
* @param account
*/
export function useUserHasAvailableClaim(account: Account): boolean {
const availableClaims = useUserAvailableClaims(account)

return availableClaims.length > 0
}

export function useUserUnclaimedAmount(account: string | null | undefined): CurrencyAmount<Token> | undefined {
const { chainId } = useActiveWeb3React()
const claims = useUserAvailableClaims(account)

const vCow = chainId ? V_COW[chainId] : undefined
if (!vCow) return undefined
if (!claims || claims.length === 0) {
return CurrencyAmount.fromRawAmount(vCow, JSBI.BigInt(0))
}
const totalAmount = claims.reduce((acc, claim) => {
return JSBI.add(acc, JSBI.BigInt(claim.amount))
}, JSBI.BigInt('0'))

return CurrencyAmount.fromRawAmount(vCow, JSBI.BigInt(totalAmount))
}
19 changes: 19 additions & 0 deletions src/custom/state/claim/hooks/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { FREE_CLAIM_TYPES, PAID_CLAIM_TYPES, UserClaims } from 'state/claim/hooks/index'

/**
* Helper function to check whether any claim is an investment option
*
* @param claims
*/
export function hasPaidClaim(claims: UserClaims | null): boolean {
return claims?.some((claim) => claim.type in PAID_CLAIM_TYPES) || false
}

/**
* Helper function to check whether any claim is an airdrop option
*
* @param claims
*/
export function hasFreeClaim(claims: UserClaims | null): boolean {
return claims?.some((claim) => claim.type in FREE_CLAIM_TYPES) || false
}

0 comments on commit 52b416f

Please sign in to comment.