Skip to content

Commit

Permalink
feat: chain select on v4 project page -> reserved token card
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnyd-eth committed Jan 20, 2025
1 parent 77a1af2 commit 5afe8d8
Show file tree
Hide file tree
Showing 35 changed files with 418 additions and 173 deletions.
3 changes: 3 additions & 0 deletions src/locales/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -2786,6 +2786,9 @@ msgstr ""
msgid "Transfer unclaimed {0}"
msgstr ""

msgid "Ok"
msgstr ""

msgid "Cannot set payouts because your <0>Total payouts</0> is Zero."
msgstr ""

Expand Down
5 changes: 3 additions & 2 deletions src/packages/v4/components/PayoutsTable/TotalRows.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Trans, t } from '@lingui/macro'

import { Tooltip } from 'antd'
import EthereumAddress from 'components/EthereumAddress'
import { PayoutsTableCell } from 'components/PayoutsTable/PayoutsTableCell'
import { PayoutsTableRow } from 'components/PayoutsTable/PayoutsTableRow'
import TooltipLabel from 'components/TooltipLabel'
import round from 'lodash/round'
import useProjectOwnerOf from 'packages/v4/hooks/useV4ProjectOwnerOf'
import useV4ProjectOwnerOf from 'packages/v4/hooks/useV4ProjectOwnerOf'
import { usePayoutsTable } from './hooks/usePayoutsTable'

const Row = PayoutsTableRow
Expand All @@ -31,7 +32,7 @@ export function TotalRows() {
? round(distributionLimit, roundingPrecision)
: t`Unlimited`

const { data: projectOwnerAddress } = useProjectOwnerOf()
const { data: projectOwnerAddress } = useV4ProjectOwnerOf()

const subTotalExceedsMax = distributionLimitIsInfinite && subTotal > 100

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const ProjectChainSelect: React.FC<

return (
<JuiceListbox
className="text-sm font-normal"
value={{
label: NETWORKS[value ?? DEFAULT_PROJECT_CHAIN_ID]?.label,
value,
Expand Down
37 changes: 37 additions & 0 deletions src/packages/v4/hooks/useJBAllRulesetsCrossChain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { CashOutTaxRate, ReservedPercent, RulesetWeight, WeightCutPercent } from "juice-sdk-core"

import { useReadJbControllerAllRulesetsOf } from "juice-sdk-react"

export function useJBAllRulesetsCrossChain({
projectId,
rulesetNumber
}: {
projectId: bigint
rulesetNumber: bigint
}) {
const { data, isLoading } = useReadJbControllerAllRulesetsOf({
args: [
projectId,
rulesetNumber,
10n, // size (The maximum number of rulesets to return). Arbritrarily set
]
})

if (!data) return { data: undefined, isLoading }

return {
data: data.map((obj) => ({
ruleset: {
...obj.ruleset,
weight: new RulesetWeight(obj.ruleset.weight),
weightCutPercent: new WeightCutPercent(obj.ruleset.weightCutPercent),
},
metadata: {
...obj.metadata,
cashOutTaxRate: new CashOutTaxRate(obj.metadata.cashOutTaxRate),
reservedPercent: new ReservedPercent(obj.metadata.reservedPercent)
}
})),
isLoading
}
}
46 changes: 46 additions & 0 deletions src/packages/v4/hooks/useJBRulesetByChain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { CashOutTaxRate, JBChainId, JBRulesetData, JBRulesetMetadata, ReservedPercent, RulesetWeight, WeightCutPercent } from "juice-sdk-core";
import { useJBContractContext, useReadJbControllerCurrentRulesetOf } from "juice-sdk-react";

import { useProjectIdOfChain } from "./useProjectIdOfChain";

export function useJBRulesetByChain(chainId: JBChainId | undefined) {
const { contracts } = useJBContractContext();
const projectId = useProjectIdOfChain({ chainId })
const { data, isLoading } = useReadJbControllerCurrentRulesetOf({
chainId,
address: contracts?.controller?.data ?? undefined,
args: [BigInt(projectId ?? 0)],
query: {
select([ruleset, rulesetMetadata]) {
return [
{
...ruleset,
weight: new RulesetWeight(ruleset.weight),
weightCutPercent: new WeightCutPercent(ruleset.weightCutPercent),
},
{
...rulesetMetadata,
cashOutTaxRate: new CashOutTaxRate(rulesetMetadata.cashOutTaxRate),
reservedPercent: new ReservedPercent(
rulesetMetadata.reservedPercent
),
},
];
},
},
});

if (!chainId) {
return {
ruleset: undefined,
rulesetMetadata: undefined,
isLoading: false,
}
}

return {
ruleset: data?.[0] as JBRulesetData,
rulesetMetadata: data?.[1] as JBRulesetMetadata,
isLoading,
}
}
8 changes: 3 additions & 5 deletions src/packages/v4/hooks/useJBUpcomingRuleset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,15 @@ export function useJBUpcomingRuleset(chainId?: JBChainId): {
rulesetMetadata: JBRulesetMetadata | undefined
isLoading: boolean
} {
const { contracts } = useJBContractContext()
const { contracts, projectId: defaultProjectId } = useJBContractContext()

const projectIdOfChain = useProjectIdOfChain({ chainId })
const projectId = useProjectIdOfChain({ chainId })

const { data, isLoading } = useReadJbControllerUpcomingRulesetOf({
address: contracts.controller?.data ?? undefined,
args: [BigInt(projectIdOfChain ?? 0)],
args: [BigInt(projectId ?? defaultProjectId)],
chainId
})

if (!projectIdOfChain) return { ruleset: undefined, rulesetMetadata: undefined, isLoading: false }

const _latestUpcomingRuleset = data?.[0]
const _latestUpcomingRulesetMetadata = data?.[1]
Expand Down
12 changes: 3 additions & 9 deletions src/packages/v4/hooks/useProjectIdOfChain.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import { JBChainId } from "juice-sdk-core";
import { useSuckers } from "juice-sdk-react";
import { useCurrentRouteChainId } from "./useCurrentRouteChainId";

// Gets the projectId of a project on a particular chain
// Gets the projectId of a project on a given chain
// -> (Project IDs can vary across chains)
//
// If project does not exist on given chain, returns undefined
export function useProjectIdOfChain({
chainId
}: {
chainId: JBChainId | undefined
}) {
const currentRouteChainId = useCurrentRouteChainId()
const _chainId = chainId ?? currentRouteChainId

}) {
const { data: suckers } = useSuckers()

return suckers?.find((suckerPair) => suckerPair.peerChainId === _chainId )?.peerChainId
return suckers?.find((suckerPair) => suckerPair.peerChainId === chainId )?.projectId
}
40 changes: 40 additions & 0 deletions src/packages/v4/hooks/useProjectRulesetsDiffAcrossChains.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { JBChainId, JBRulesetData, JBRulesetMetadata } from "juice-sdk-core";
import { useJBContractContext, useSuckers } from "juice-sdk-react";


export function useProjectRulesetsDiffAcrossChains(type: 'upcoming' | 'current') {
const { data: suckers } = useSuckers()
const { projectId, contracts } = useJBContractContext()

const currentRulesetsAndMetadataByChain = {
// 1234: {
// ruleset: JBRulesetData
// metadata: JBRulesetMetadata
// },
// etc.
} as Record<JBChainId, JBRulesetData & JBRulesetMetadata>
const upcomingRulesetsAndMetadataByChain = {
// 1234: {
// ruleset: JBRulesetData
// metadata: JBRulesetMetadata
// },
// etc.
}
// suckers?.forEach((suckerPair) => {
// const { data: currentRuleset, isLoading: currentLoading } = useJBRuleset(suckerPair.chainId)
// const { data: upcomingRuleset, isLoading: upcomingLoading } = useJBUpcomingRuleset(suckerPair.peerChainId as JBChainId)
// // how to fill currentRulesetsAndMetadataByChain and upcomingRulesetsAndMetadataByChain?
// })

// if (type === 'upcoming') {
// return {
// data: getDiffedAttrBetweenRulesets(upcomingRulesetsAndMetadataByChain),
// isLoading
// }
// }

// return {
// data: getDiffedAttrBetweenRulesets(currentRulesetsAndMetadataByChain),
// isLoading
// }
}
6 changes: 2 additions & 4 deletions src/packages/v4/hooks/useV4CurrentPayoutSplits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ import {
import { useProjectIdOfChain } from './useProjectIdOfChain'

export const useV4CurrentPayoutSplits = (chainId?: JBChainId) => {
const projectIdOfChainId = useProjectIdOfChain({ chainId })
const projectId = useProjectIdOfChain({ chainId })

const { data: tokenAddress } = useReadJbTokensTokenOf()
const { data: ruleset, isLoading: rulesetIsLoading } = useJBRuleset()
const rulesetId = BigInt(ruleset?.id ?? 0)
const groupId = BigInt(tokenAddress ?? NATIVE_TOKEN) // contracts say this is: `uint256(uint160(tokenAddress))`

const { data, isLoading } = useReadJbSplitsSplitsOf({
args: [BigInt(projectIdOfChainId ?? 0), rulesetId, groupId],
args: [BigInt(projectId ?? 0), rulesetId, groupId],
query: {
select(data) {
return data.map(
Expand All @@ -37,7 +37,5 @@ export const useV4CurrentPayoutSplits = (chainId?: JBChainId) => {

if (rulesetIsLoading) return { data: undefined, isLoading: true}

if (!projectIdOfChainId) return { data: undefined, isLoading: false}

return { data, isLoading }
}
12 changes: 7 additions & 5 deletions src/packages/v4/hooks/useV4ProjectOwnerOf.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useJBContractContext, useReadJbProjectsOwnerOf } from "juice-sdk-react";
import { JBChainId } from "juice-sdk-core";
import { useReadJbProjectsOwnerOf } from "juice-sdk-react";
import { useProjectIdOfChain } from "./useProjectIdOfChain";

const useProjectOwnerOf = () => {
const { projectId } = useJBContractContext();
const useV4ProjectOwnerOf = (chainId?: JBChainId) => {
const projectId = useProjectIdOfChain({ chainId })

const { data: projectOwnerAddress, isLoading } = useReadJbProjectsOwnerOf({
args: [projectId],
args: [BigInt(projectId ?? 0)],
});

return {
Expand All @@ -13,4 +15,4 @@ const useProjectOwnerOf = () => {
};
};

export default useProjectOwnerOf;
export default useV4ProjectOwnerOf;
15 changes: 8 additions & 7 deletions src/packages/v4/hooks/useV4ReservedSplits.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { JBSplit, SplitPortion } from 'juice-sdk-core'
import { JBChainId, JBSplit, SplitPortion } from 'juice-sdk-core'
import {
useJBContractContext,
useJBRuleset,
useReadJbSplitsSplitsOf,
useReadJbSplitsSplitsOf
} from 'juice-sdk-react'

import { useProjectIdOfChain } from './useProjectIdOfChain'

const RESERVED_SPLITS_GROUP_ID = 1n

export const useV4ReservedSplits = () => {
const { projectId } = useJBContractContext()
export const useV4ReservedSplits = (chainId?: JBChainId) => {
const projectId = useProjectIdOfChain({ chainId })
const { data: ruleset } = useJBRuleset()

const { data: _splits, isLoading: currentSplitsLoading } =
useReadJbSplitsSplitsOf({
args: [projectId, BigInt(ruleset?.id ?? 0), RESERVED_SPLITS_GROUP_ID],
args: [BigInt(projectId ?? 0), BigInt(ruleset?.id ?? 0), RESERVED_SPLITS_GROUP_ID],
query: {
select(data) {
return data.map(d => ({
Expand All @@ -23,7 +24,7 @@ export const useV4ReservedSplits = () => {
},
},
})

const splits: JBSplit[] = _splits ? [..._splits] : []

return { splits, isLoading: currentSplitsLoading }
Expand Down
6 changes: 3 additions & 3 deletions src/packages/v4/hooks/useV4UpcomingPayoutSplits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useJBUpcomingRuleset } from './useJBUpcomingRuleset'
import { useProjectIdOfChain } from './useProjectIdOfChain'

export const useV4UpcomingPayoutSplits = (chainId?: JBChainId) => {
const projectIdOfChainId = useProjectIdOfChain({ chainId })
const projectId = useProjectIdOfChain({ chainId })

const { ruleset: upcomingRuleset, isLoading: upcomingRulesetLoading } =
useJBUpcomingRuleset(chainId)
Expand All @@ -22,7 +22,7 @@ export const useV4UpcomingPayoutSplits = (chainId?: JBChainId) => {

const { data, isLoading } = useReadJbSplitsSplitsOf({
args: [
BigInt(projectIdOfChainId ?? 0),
BigInt(projectId ?? 0),
BigInt(upcomingRuleset?.id ?? 0),
groupId,
],
Expand All @@ -41,7 +41,7 @@ export const useV4UpcomingPayoutSplits = (chainId?: JBChainId) => {
return { data: undefined, isLoading: true }
}

if (!projectIdOfChainId) return { data: undefined, isLoading: false}
if (!projectId) return { data: undefined, isLoading: false}


return { data, isLoading }
Expand Down
7 changes: 4 additions & 3 deletions src/packages/v4/hooks/useV4WalletHasPermission.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { useWallet } from 'hooks/Wallet'
import {
useJBContractContext,
useReadJbPermissionsHasPermissions,
} from 'juice-sdk-react'

import { useWallet } from 'hooks/Wallet'
import { isEqualAddress } from 'utils/address'
import { zeroAddress } from 'viem'
import { V4OperatorPermission } from '../models/v4Permissions'
import useProjectOwnerOf from './useV4ProjectOwnerOf'
import useV4ProjectOwnerOf from './useV4ProjectOwnerOf'

export function useV4WalletHasPermission(
permission: V4OperatorPermission | V4OperatorPermission[],
): boolean {
const { userAddress } = useWallet()

const { projectId } = useJBContractContext()
const { data: projectOwnerAddress } = useProjectOwnerOf()
const { data: projectOwnerAddress } = useV4ProjectOwnerOf()

const _operator = userAddress ?? zeroAddress
const _account = projectOwnerAddress ?? zeroAddress
Expand Down
40 changes: 40 additions & 0 deletions src/packages/v4/utils/rulesetDiff.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { JBChainId, JBRulesetData, JBRulesetMetadata } from "juice-sdk-core";

export function getDiffedAttrBetweenRulesets(rulesetsByChain: Record<JBChainId, {
ruleset: JBRulesetData,
metadata: JBRulesetMetadata
}>) {
// Get a list of all attributes we're keeping (diffed attributes)
const diffedRulesetAttrs = Object.keys(Object.values(rulesetsByChain)[0].ruleset).filter((rulesetAttr) => (
// @ts-ignore
rulesets.slice(1).some(({ ruleset }) => Boolean(ruleset[rulesetAttr] !== rulesets[0][rulesetAttr]))
))

const diffedMetadataAttrs = Object.keys(Object.values(rulesetsByChain)[0].metadata).filter((metadataAttr) => (
// @ts-ignore
rulesets.slice(1).some(({ ruleset }) => Boolean(ruleset[metadataAttr] !== rulesets[0][metadataAttr]))
))

if (!diffedRulesetAttrs.length && !diffedMetadataAttrs) return []

const rulesetsWithDiffedAttrsOnly = {} as Record<JBChainId, Partial<JBRulesetData & JBRulesetMetadata>>

Object.keys(rulesetsByChain).map((chainIdStr) => {
const chainId = parseInt(chainIdStr) as JBChainId
const ruleset = rulesetsByChain[chainId].ruleset
const metadata = rulesetsByChain[chainId].metadata
rulesetsWithDiffedAttrsOnly[chainId] = {}

diffedRulesetAttrs.forEach((rulesetAttr) => {
// @ts-ignore
rulesetsWithDiffedAttrsOnly[chainId][rulesetAttr] = ruleset[rulesetAttr]
})

diffedMetadataAttrs.forEach((metadataAttr) => {
// @ts-ignore
rulesetsWithDiffedAttrsOnly[chainId][metadataAttr] = metadata[rulesetAttr]
})
})

return rulesetsWithDiffedAttrsOnly
}
Loading

0 comments on commit 5afe8d8

Please sign in to comment.