diff --git a/src/components/claim/ClaimModal.tsx b/src/components/claim/ClaimModal.tsx index 7a2dce1be..7738d38e5 100644 --- a/src/components/claim/ClaimModal.tsx +++ b/src/components/claim/ClaimModal.tsx @@ -51,8 +51,9 @@ export default function ClaimModal() { const isOpen = useModalOpen(ApplicationModal.SELF_CLAIM) const toggleClaimModal = useToggleSelfClaimModal() - const { account, chainId } = useActiveWeb3React() + const { chainId } = useActiveWeb3React() + const account = '0x0Ae21f9700eD15E1a83baa3183a67d54b1DA2086' // used for UI loading states const [attempting, setAttempting] = useState(false) @@ -60,14 +61,15 @@ export default function ClaimModal() { const userClaimData = useUserClaimData(account) // monitor the status of the claim from contracts and txns - const { claimCallback } = useClaimCallback('0x82850293A348107E798E5D366c10D1b566145Cd5') // TODO: remove me, hard coded only for testing + const { claimCallback } = useClaimCallback(account) // TODO: remove me, hard coded only for testing const unclaimedAmount: CurrencyAmount | undefined = useUserUnclaimedAmount(account) const { claimSubmitted, claimTxn } = useUserHasSubmittedClaim(account ?? undefined) const claimConfirmed = Boolean(claimTxn?.receipt) function onClaim() { + console.log(`Trying to claim!!!`, unclaimedAmount?.toString(), claimConfirmed) setAttempting(true) - claimCallback() + claimCallback([{ index: 1080 }]) // reset modal and log error .catch((error) => { setAttempting(false) diff --git a/src/custom/constants/index.ts b/src/custom/constants/index.ts index d2a7508a6..5902bdb19 100644 --- a/src/custom/constants/index.ts +++ b/src/custom/constants/index.ts @@ -57,7 +57,7 @@ export const V_COW_CONTRACT_ADDRESS: Partial> = { // [ChainId.MAINNET]: GPv2Settlement[ChainId.MAINNET].address, // [ChainId.RINKEBY]: GPv2Settlement[ChainId.RINKEBY].address, // [ChainId.XDAI]: GPv2Settlement[ChainId.XDAI].address, - [ChainId.RINKEBY]: '0x8f07778b703f9feb93521fc5230e859dbd032b6b', + [ChainId.RINKEBY]: '0xac17Ae2BcAF9Ed181C4Ab10B179548d6aa30C92E', } // See https://github.com/gnosis/gp-v2-contracts/commit/821b5a8da213297b0f7f1d8b17c893c5627020af#diff-12bbbe13cd5cf42d639e34a39d8795021ba40d3ee1e1a8282df652eb161a11d6R13 diff --git a/src/custom/state/claim/hooks/hooksMod.ts b/src/custom/state/claim/hooks/hooksMod.ts index 4dd8eb3f1..ef5f29a4e 100644 --- a/src/custom/state/claim/hooks/hooksMod.ts +++ b/src/custom/state/claim/hooks/hooksMod.ts @@ -1,15 +1,15 @@ // import JSBI from 'jsbi' -import { CurrencyAmount, Token } from '@uniswap/sdk-core' -import { TransactionResponse } from '@ethersproject/providers' +// import { CurrencyAmount, Token } from '@uniswap/sdk-core' +// import { TransactionResponse } from '@ethersproject/providers' // import { useEffect, useState } from 'react' // import { UNI } from 'constants/tokens' -import { useActiveWeb3React } from 'hooks/web3' -import { useMerkleDistributorContract } from 'hooks/useContract' -import { calculateGasMargin } from 'utils/calculateGasMargin' +// 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, useUserUnclaimedAmount } from '.' +// import { useTransactionAdder } from 'state/enhancedTransactions/hooks' +import { ClaimType, UserClaims } from '.' // import { useSingleCallResult } from '@src/state/multicall/hooks' export { useUserClaimData } from '@src/state/claim/hooks' @@ -101,33 +101,91 @@ export function useUserClaims(account: string | null | undefined): UserClaims | return [ { proof: [ - '0x85bb2d293209f2ef10959e033b3d43c6d67058717f7b0a70568ca7d028b3592d', - '0x045442670919da3b5ce18ccc62308d670555184af497be8907560ff83e96fbc9', - '0x49535c52497395e0f14b85ebe0900de58f0809aca5d54de44b6e1ad4a00868b5', - '0xb3c22776e4694752f3f4d70f4a83fa50457b3df2c383b36fa26043dde76474cc', - '0x23b39cfa6ca6ae97ba67daa849e6497e0e89fbf997eabbd31fe8af7e54544967', - '0x1e88526debfd1b5c3955fc6c3facdbda5a99ba2cb1144d6cb7f21075c4becdf4', - '0x82c926e522b6eeca8139d31cfb200b1af4e4c02e0992d25125fe7ec8c8e15feb', - '0xac5661c776a0808e457967488a00e26d4ccf3e50426fc83a143d9150ae4f058a', + '0x03cc3df79d865ad3bfbdd54ec8ee6001f294655fe0018e660c0879c046d82133', + '0xd044fdd7448e035e36a13a1b3edb2d7158624c6578a31517e8deefc2034c216b', + '0x4531947895cb7cfc7d878e32288a73c04eaf63af8345d47283ba2cb8bac7e8c5', + '0xf1376d3d11b33948440cf71bcfa63e69a9ca436ab3cef016b9da36f2a226d3e2', + '0xa5ff51dde0385f442354e8d2582e81fd7d81f0a9b558ceea8e84136e6b88501c', + '0xdc13f692869b72e45579e0ef7f5afe670ffeb5c2931f5b72cc50a19121c57f68', + '0xbf454c5b68f2a3637a1221ce1e5834ce5725f9fcef7f932f81af24127e312d58', + '0x0c85968537348d6281fb14be6b4528e77fce7adb1ac9a6fae52c83182f64d848', + '0xdc838baad0c5b2844072e96cd5376ca337f80b42746b46a46121afcc0e39e0ee', + '0x52aaac536243500f3d5aae091887032322773b40f7fa906d0043a5d74013a8c4', + '0x57158a64c297f7a0ae2530774437f91667aab006e084f3214986dce3ca898474', + '0xc1d3779a02affbc6b4885b248a636f9a3fd124d356e639347bb04129436133bd', + '0xe0b4fbf77c444bada1498ecbee1431eb297d4fa9a6d04f1dcb19571c334b5dcb', + '0x768e2f52bd7f4c8f1251620800bed30d14d13453dd2f0ced98eff0212d5e5288', + '0x3fb9f3c87451effbb58340761f30e2d2057a0a2fb27eee5ec6af3362be0389f9', ], - index: 138, - type: 'Airdrop', - amount: '3925000000000000000000', + index: 1080, + type: ClaimType.Airdrop, + amount: '9289000000000000000000', }, { proof: [ - '0x9ee4da15b49ddee8590aba5a89c4f137c3574920df8a44a52e6b88e420d068c7', - '0xbc4e08f8cbd18bdc713aa11f6cb5f5b3ea4d5ddccdaed57118d45899c83aa8ff', - '0x47591e84986f34a393c100f30219f4ba72c941053a598a1091644f9ee2920065', - '0x3cbbad2cfe9bdb3dd08d7f31edf23a0e7b33386d28ef5adeb3601289315e4a69', - '0xa168e9a8fd611fc5a6b83d06677a0a9fee5cc1b554a5dc3f5ed2485463901447', - '0xb27279799e2cfd94f9296ab300661ab7b938882420878f87b1fb0dc0d0d4ac35', - '0x82c926e522b6eeca8139d31cfb200b1af4e4c02e0992d25125fe7ec8c8e15feb', - '0xac5661c776a0808e457967488a00e26d4ccf3e50426fc83a143d9150ae4f058a', + '0xe4a4711613f6a6abecec56531200077f399303168c12c794e03a16c7141277c7', + '0x6979fe9243a97222a78662106ec36e652a3b7a96e0306091b441316bb42ee49b', + '0xd60dc85ed37acc5c5623b8ca637210b0c72c578016cbcfc14e0f611683a0ddc4', + '0xf324c5e050526464fff42caa978e415c89dd354721af7312713ce762aa4e3cf9', + '0x111b233c7994b3a246749f97af91788099685536865f43bba299db917624c30f', + '0x5b3bc344c7c6891fb381fb7092f8ef800d58d83d476bcc10cb73ebee97057a6e', + '0x4da4607803446d6145992c69291a9b838eb7fba7a3e47f0783fcf0c5b7ac9e27', + '0x668da11ee65c87085886bdef9d629bcb8f0882e7b375bfe760da962a4d3483ef', + '0xa6bbe6222c6e6c8214d5393eddec4f1e52c968923d5e76f8cea6a45cc30a9033', + '0xa2eb0b6a9bd133c79177ae56ae0f4eb556750562091f659b63462e32464fc4ad', + '0x631279a8a000a2182f0ac5fb7628af58abb740f43541390d3a1b9fc43c240c32', + '0x8db32f710938011f7a52f525fcda77096b5fb6df9a79615fffd2ffacb4eacd25', + '0x3addacdc093b79ee814c396b4df81e4f67d2507638b201bf309531a1e1b46580', + '0x1f84fcb9c266c85347319843efda7c3ddd98d5862064e084fa1dcf3b1c5a014a', + '0x1c5834c15212ba6f0cd97e697b521b41acca40fc7a56d3496e80159ff84887ff', ], - index: 139, - type: 'GnoOption', - amount: '3925000000000000000000', + index: 1081, + type: ClaimType.GnoOption, + amount: '9289000000000000000000', + }, + { + proof: [ + '0x903dad7e81712ab3858558a3ee083d2197c5ab345fc721143a78ac59b2fbe8a7', + '0x4db9088b89dd41f82e2dc34ef47f64389970b50143251a39aa6fe19cdbd656cf', + '0x03be42b4e6980a26ffaed8bebb9e4fe98f9d189baab81045fc3568b847af8080', + '0xa0d55fee34a2b2869e64b66cfe63b6d3eb059020ebce7168558fb96938ad7ff2', + '0x705b26f2b216f99a72e931b1f49161310b22fe21b4dcca40ccd6e63eacd70dc3', + '0x631afde099857df0ccfd45bdba8445e4e0eaaa65a74d3be7db0a586787501f10', + '0x30e698f66f132fd2115c5014f470e7525743f9110469e12dfddd6ea339dd8ccc', + '0xb010642525d139c72ddb4fb874fc19e1b47a866a1976e6898e9d275d2e1b02a8', + '0xdc8c8f45c7346752fe8fa3e3de0442541acb25ff22f2b1813596c75aeb9f3773', + '0x2c92171ab88f4e4ed180c31dae32ea9776a06feb9212b745cd88b99f29e651d4', + '0x83e113c2e7dda5ec1e4de305d8979969a2e53117767f95a520f91d2ab67ad58a', + '0x9ff9f0773b0b1ee89f87d63f4db6f1025e4f1effe2b5333b47ea42130ab283cc', + '0x6b8a0ed76f8d99a71b2aeb28ebc8a029f84affc531956f579e13fdf0dc5e29a6', + '0x7b019fce542fcfd0d9b2d1a79ca54014d4c77d3db26adfb0f3b60816a0e8c2f8', + '0x3fb9f3c87451effbb58340761f30e2d2057a0a2fb27eee5ec6af3362be0389f9', + ], + index: 1082, + type: ClaimType.UserOption, + amount: '9289000000000000000000', + }, + { + proof: [ + '0xac1003d4e9454ec2788204f57830cd442e07aa3c002e96989b4fa1b7ee8fb781', + '0x5d45dbb618e7b8a6e44126d2b31340ec67fef86816adb520b936d496bc2f04da', + '0x069cd55cc7423bf340c19a709779bfaefb73db23c9ca261f36a0695c5809c31f', + '0x9c6d662636dbe17db437904e83710430b7c2f64e668296c01934a32cf7f6d2ad', + '0x9f29f9989c5f2676b9a2ce9e709885db936244244f55a44fb6230c285735fb97', + '0x35d790c7d61eed82fcbeec6228cbf588c53b0127459626d8d43d511f22c8f344', + '0x3142c466c8041cea94c8a93c0856860e55101f932c0e302a63b48df4583fb365', + '0x4eb852823a9f41e409dfc8b4629b7e3de310231fae62355eb76470cdb47ba50b', + '0x35ebda602b28c0a3b6a1d8fe8eba1dbf1d2249430c1b4396d302418f8e8d93f2', + '0x842e5e67e088a322daa9e8f25aa0c9492db9f3359ed5527a1d45fbe64c5547ac', + '0x516f3d9a760004d3d55addc0408764c34cc380551f1cb75efc6801c70ea98c3d', + '0x7bd1e90485acf6b605c462165bc99f821461475bf27aee3783c5bef12a2072ab', + '0xa61b9a8b2e60faeeca7b2972e4278a2e56520cb0621499e8cf2d91d97c181cf1', + '0x1f84fcb9c266c85347319843efda7c3ddd98d5862064e084fa1dcf3b1c5a014a', + '0x1c5834c15212ba6f0cd97e697b521b41acca40fc7a56d3496e80159ff84887ff', + ], + index: 1083, + type: ClaimType.Advisor, + amount: '9289000000000000000000', }, ] @@ -181,40 +239,35 @@ export function useUserClaims(account: string | null | undefined): UserClaims | // return CurrencyAmount.fromRawAmount(uni, JSBI.BigInt(userClaimData.amount)) // } -export function useClaimCallback(account: string | null | undefined): { - claimCallback: () => Promise -} { - // get claim data for this account - const { library, chainId } = useActiveWeb3React() - const claimData = useUserClaims(account) - - // used for popup summary - const unclaimedAmount: CurrencyAmount | undefined = useUserUnclaimedAmount(account) - const addTransaction = useTransactionAdder() - const distributorContract = useMerkleDistributorContract() - - const claimCallback = async function () { - if (!claimData || !account || !library || !chainId || !distributorContract) return - - // const args = [claimData.index, account, claimData.amount, claimData.proof] - - // TODO: Reduce Claimings into a bunch of arrays with all the claimings - // const args = claimData.reduce(...) - const args: string[] = [] - - return distributorContract.estimateGas['claim'](...args, {}).then((estimatedGasLimit) => { - return distributorContract - .claim(...args, { value: null, gasLimit: calculateGasMargin(chainId, estimatedGasLimit) }) - .then((response: TransactionResponse) => { - addTransaction({ - hash: response.hash, - summary: `Claimed ${unclaimedAmount?.toSignificant(4)} CoW`, - claim: { recipient: account }, - }) - return response.hash - }) - }) - } - - return { claimCallback } -} +// export function useClaimCallback(account: string | null | undefined): { +// claimCallback: () => Promise +// } { +// // get claim data for this account +// const { library, chainId } = useActiveWeb3React() +// const claimData = useUserClaimData(account) +// +// // used for popup summary +// const unclaimedAmount: CurrencyAmount | undefined = useUserUnclaimedAmount(account) +// const addTransaction = useTransactionAdder() +// const distributorContract = useMerkleDistributorContract() +// +// const claimCallback = async function () { +// if (!claimData || !account || !library || !chainId || !distributorContract) return +// +// const args = [claimData.index, account, claimData.amount, claimData.proof] +// +// return distributorContract.estimateGas['claim'](...args, {}).then((estimatedGasLimit) => { +// return distributorContract +// .claim(...args, { value: null, gasLimit: calculateGasMargin(chainId, estimatedGasLimit) }) +// .then((response: TransactionResponse) => { +// addTransaction(response, { +// summary: `Claimed ${unclaimedAmount?.toSignificant(4)} UNI`, +// claim: { recipient: account }, +// }) +// return response.hash +// }) +// }) +// } +// +// return { claimCallback } +// } diff --git a/src/custom/state/claim/hooks/index.ts b/src/custom/state/claim/hooks/index.ts index b8d58d9b8..947626264 100644 --- a/src/custom/state/claim/hooks/index.ts +++ b/src/custom/state/claim/hooks/index.ts @@ -1,25 +1,35 @@ -import { useMemo } from 'react' +import { useCallback, useMemo } from 'react' import JSBI from 'jsbi' import { CurrencyAmount, Token } from '@uniswap/sdk-core' +import { TransactionResponse } from '@ethersproject/providers' + +import { VCow as VCowType } from 'abis/types' -import { useUserClaims } from 'state/claim/hooks/hooksMod' import { useVCowContract } from 'hooks/useContract' -import { useSingleContractMultipleData } from 'state/multicall/hooks' import { useActiveWeb3React } from 'hooks/web3' +import { useSingleContractMultipleData } from 'state/multicall/hooks' +import { useTransactionAdder } from 'state/enhancedTransactions/hooks' + import { V_COW } from 'constants/tokens' +import { formatSmart } from 'utils/format' +import { calculateGasMargin } from 'utils/calculateGasMargin' + +import { useUserClaims } from 'state/claim/hooks/hooksMod' + export * from './hooksMod' -export type ClaimType = - | 'Airdrop' // free, no vesting, can be available on both mainnet and gchain - | 'Team' // free, with vesting, only on mainnet - | 'Advisor' // free, with vesting, only on mainnet - | 'GnoOption' // paid, with vesting, must use GNO, can be available on both mainnet and gchain - | '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 enum ClaimType { + Airdrop, // free, no vesting, can be available on both mainnet and gchain + GnoOption, // paid, with vesting, must use GNO, can be available on both mainnet and gchain + 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 + Team, // free, with vesting, only on mainnet + Advisor, // free, with vesting, only on mainnet +} -export const FREE_CLAIM_TYPES: ClaimType[] = ['Airdrop', 'Team', 'Advisor'] -export const PAID_CLAIM_TYPES: ClaimType[] = ['GnoOption', 'UserOption', 'Investor'] +export const FREE_CLAIM_TYPES: ClaimType[] = [ClaimType.Airdrop, ClaimType.Team, ClaimType.Advisor] +export const PAID_CLAIM_TYPES: ClaimType[] = [ClaimType.GnoOption, ClaimType.UserOption, ClaimType.Investor] export interface UserClaimData { index: number @@ -28,6 +38,18 @@ export interface UserClaimData { type: ClaimType } +export interface ClaimInput { + /** + * The index of the claim + */ + index: number + /** + * The amount of the claim. Optional + * If not present, will claim the full amount + */ + amount?: string +} + type Account = string | null | undefined export type UserClaims = UserClaimData[] @@ -94,3 +116,202 @@ export function useUserUnclaimedAmount(account: string | null | undefined): Curr return CurrencyAmount.fromRawAmount(vCow, JSBI.BigInt(totalAmount)) } + +/** + * Hook that returns the claimCallback + * + * Different from the original version, the returned callback takes as input a list of ClaimInputs, + * which is an object of the claim index and the amount being claimed. + * + * @param account + */ +export function useClaimCallback(account: string | null | undefined): { + claimCallback: (claimInputs: ClaimInput[]) => Promise +} { + // get claim data for given account + const { chainId, account: connectedAccount } = useActiveWeb3React() + const claims = useUserAvailableClaims(account) + const vCowContract = useVCowContract() + + // used for popup summary + const addTransaction = useTransactionAdder() + const vCowToken = chainId ? V_COW[chainId] : undefined + + const claimCallback = useCallback( + async function (claimInput: ClaimInput[]) { + if ( + claims.length === 0 || + claimInput.length === 0 || + !account || + !connectedAccount || + !chainId || + !vCowContract || + !vCowToken + ) { + throw new Error("Not initialized, can't claim") + } + + const { args, totalClaimedAmount } = _getClaimManyArgs({ claimInput, claims, account, connectedAccount }) + + if (!args) { + throw new Error('There were no valid claims selected') + } + + const vCowAmount = CurrencyAmount.fromRawAmount(vCowToken, totalClaimedAmount) + + return vCowContract.estimateGas['claimMany'](...args).then((estimatedGas) => { + // Last item in the array contains the call overrides + args[args.length - 1] = { + ...args[args.length - 1], // add back whatever is already there + from: connectedAccount, // add the `from` as the connected account + gasLimit: calculateGasMargin(chainId, estimatedGas), // add the estimated gas limit + } + + return vCowContract.claimMany(...args).then((response: TransactionResponse) => { + addTransaction({ + hash: response.hash, + summary: `Claimed ${formatSmart(vCowAmount)} vCOW`, + claim: { recipient: account }, + }) + return response.hash + }) + }) + }, + [account, addTransaction, chainId, claims, connectedAccount, vCowContract, vCowToken] + ) + + return { claimCallback } +} + +type GetClaimManyArgsParams = { + claimInput: ClaimInput[] + claims: UserClaims + account: string + connectedAccount: string +} + +type ClaimManyFnArgs = Parameters + +type GetClaimManyArgsResult = { + args: ClaimManyFnArgs | undefined + totalClaimedAmount: JSBI +} + +/** + * Prepares the list of args to be passed to vCow.claimMany function + */ +function _getClaimManyArgs({ + claimInput, + claims, + account, + connectedAccount, +}: GetClaimManyArgsParams): GetClaimManyArgsResult { + // Arrays are named according to contract parameters + // For more info, check https://github.com/gnosis/gp-v2-token/blob/main/src/contracts/mixins/MerkleDistributor.sol#L123 + const indices: ClaimManyFnArgs[0] = [] + const claimTypes: ClaimManyFnArgs[1] = [] + const claimants: ClaimManyFnArgs[2] = [] + const claimableAmounts: ClaimManyFnArgs[3] = [] + const claimedAmounts: ClaimManyFnArgs[4] = [] + const merkleProofs: ClaimManyFnArgs[5] = [] + const sendEth: ClaimManyFnArgs[6] = [] + + let totalClaimedAmount = JSBI.BigInt('0') + let totalValue = JSBI.BigInt('0') + + // Creating a map for faster access when checking what's being claimed + const claimsMap = claims.reduce>((acc, claim) => { + acc[claim.index] = claim + return acc + }, {}) + + claimInput.forEach((input) => { + const claim = claimsMap[input.index] + + // It can be that the index being passed is already claimed or belongs to another account + // Thus, it's possible that the returned `args` is "empty" + if (claim) { + indices.push(claim.index) + // always the same + claimants.push(account) + // always the max available + claimableAmounts.push(claim.amount) + + claimTypes.push(claim.type) + // depends on claim type and whether claimed account == connected account + const claimedAmount = _getClaimedAmount({ claim, input, account, connectedAccount }) + claimedAmounts.push(claimedAmount) + + merkleProofs.push(claim.proof) + // only used on UserOption, equal to claimedAmount + const value = claim.type === ClaimType.UserOption ? claimedAmount : '0' + sendEth.push(value) // TODO: verify ETH balance < input.amount ? + + // sum of claimedAmounts for the toast notification + totalClaimedAmount = JSBI.add(totalClaimedAmount, JSBI.BigInt(claimedAmount)) + // sum of Native currency to be used on call options + totalValue = JSBI.add(totalValue, JSBI.BigInt(value)) + } + }) + + const value = totalValue.toString() === '0' ? undefined : totalValue.toString() + const args: GetClaimManyArgsResult['args'] = + indices.length > 0 + ? [indices, claimTypes, claimants, claimableAmounts, claimedAmounts, merkleProofs, sendEth, { value }] + : undefined + + return { + args, + totalClaimedAmount, + } +} + +type GetClaimedAmountParams = Pick & { + claim: UserClaimData + input: ClaimInput +} + +/** + * Gets the allowed claimed amount based on claim type and whether claiming account === connectedAccount + * Rules are same as the contract to prevent reverts + */ +function _getClaimedAmount({ claim, input, account, connectedAccount }: GetClaimedAmountParams): string { + if ( + _isClaimForOther(account, connectedAccount, claim) || + _isFreeClaim(claim) || + _hasNoInputOrInputIsGreaterThanClaimAmount(input, claim) || + // had to duplicate this check because I can't get TS to understand input.amount is not undefined in the else clause + !input.amount + ) { + // use full amount + return claim.amount + } else { + // use partial amount + return input.amount + } +} + +/** + * Claim 100% when claiming investment for someone else + */ +function _isClaimForOther(account: string, connectedAccount: string, claim: UserClaimData) { + return account !== connectedAccount && claim.type in PAID_CLAIM_TYPES +} + +/** + * Claim 100% when it's a free claim + */ +function _isFreeClaim(claim: UserClaimData) { + return claim.type in FREE_CLAIM_TYPES +} + +/** + * Claim 100% when input is not set + * Claim 100% when input > amount + */ +function _hasNoInputOrInputIsGreaterThanClaimAmount( + input: ClaimInput, + claim: UserClaimData +): input is Required { + return !input.amount || JSBI.greaterThan(JSBI.BigInt(input.amount), JSBI.BigInt(claim.amount)) +}