Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allowlist feature #439

Merged
merged 120 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
120 commits
Select commit Hold shift + click to select a range
4ee7a68
allow list feature initial commit + forge fmt (for changes in CV test)
kafann Aug 31, 2024
5b16532
Merge remote-tracking branch 'origin/dev' into allowlist-feature
Corantin Sep 2, 2024
1716b00
Change to Registry access control center + remove temp allo grant
Corantin Sep 2, 2024
4b9dacd
Mostly false positive so slither disable
kafann Sep 5, 2024
b861806
:zap: natspec wip, init audit
kamikazebr Sep 5, 2024
38b29b4
feat: AllowListInput
Lucianosc Sep 7, 2024
922eab2
add AllowList in PoolForm
Lucianosc Sep 7, 2024
af9afb9
Merge branch 'persist-arbitrable-config' into allowlist-feature
Corantin Sep 7, 2024
42c88fb
Contract event + Subgraph
Corantin Sep 7, 2024
cbf4d1e
Merge branch 'persist-arbitrable-config' into allowlist-feature
Corantin Sep 7, 2024
316a7dd
Update subgraph version in chains + add the initialAllowList to creat…
Corantin Sep 7, 2024
e819f80
Fix startegy need to be grant as allowlist admin
Corantin Sep 7, 2024
2a6428e
feat AllowList finished
Lucianosc Sep 8, 2024
2f28cf9
Merge commit 'e819f80af6b882b5abb5492dbf73bc755f8bce4f' into ui-allow…
Lucianosc Sep 8, 2024
df3b650
Update chains.tsx
Corantin Sep 8, 2024
d788a47
fix PoolForm
Lucianosc Sep 9, 2024
9aca812
fix Button tooltip
Lucianosc Sep 9, 2024
308d167
add subgraph query
Lucianosc Sep 9, 2024
b0fd0c9
feat useCheckllowList
Lucianosc Sep 9, 2024
3843afc
add check allow list implementation
Lucianosc Sep 9, 2024
4fe4fcc
fix sybil resistance order section
Lucianosc Sep 9, 2024
92d7de8
Merge branch 'allowlist-feature' of https://github.com/1Hive/gardens-…
kafann Sep 10, 2024
75c9a29
allowlist-feature done, need to write tests
kafann Sep 10, 2024
59814fa
Merge remote-tracking branch 'origin/dev' into allowlist-feature
Corantin Sep 12, 2024
709819a
V0_1
Corantin Sep 12, 2024
9f33b41
Change sub version
Corantin Sep 12, 2024
aaf9065
Deploy v0_1 + update subgraph for it
Corantin Sep 12, 2024
5ea06c2
Merge remote-tracking branch 'origin/allowlist-feature' into ui-allow…
Lucianosc Sep 12, 2024
696bf95
PR fixes
Lucianosc Sep 12, 2024
a48dd93
fixes & clean up
Lucianosc Sep 12, 2024
dc3669f
add sybil resistance restriction for pooltypes
Lucianosc Sep 13, 2024
a1565d6
Change abi to v0_1
Corantin Sep 13, 2024
286cc76
New dpeloy with external setPoolParams
Corantin Sep 15, 2024
5b8ed37
Merge branch 'allowlist-feature' into ui-allowlist
Corantin Sep 15, 2024
1945de7
Run latest
Corantin Sep 16, 2024
c128f8a
Merge remote-tracking branch 'origin/allowlist-feature' into ui-allow…
Corantin Sep 16, 2024
df9fe76
Initial refactor after upgrade for allowlist-feature, fixed deployScr…
kafann Sep 13, 2024
5341a6a
Cleanup for upgrade
kafann Sep 17, 2024
3cf4fa7
Merge remote-tracking branch 'origin/dev' into ui-allowlist
Lucianosc Sep 17, 2024
176f38c
Move createRegistry to v0.1
Corantin Sep 17, 2024
9cbf023
getRegistry
Corantin Sep 17, 2024
eb4a3ca
wip add sybil resistance inputs in PoolEditForm
Lucianosc Sep 19, 2024
07ae011
minor fixes
Lucianosc Sep 19, 2024
7021296
add fetch passport score in PoolEditForm
Lucianosc Sep 19, 2024
4a0fa06
:zap: initial commit
kamikazebr Sep 19, 2024
51f0a25
Refactor structs
Corantin Sep 19, 2024
ff272b4
Fix comment
Corantin Sep 19, 2024
bdf7ec1
Added proposalInvalidForAlloction error and check in allocate (CV V0_1)
kafann Sep 20, 2024
181595d
Merge remote-tracking branch 'origin/allowlist-feature' into 2diamond…
kamikazebr Sep 20, 2024
1355f20
:bug: fix structs and tests
kamikazebr Sep 20, 2024
8cd7763
:bug: fix shadow var
kamikazebr Sep 20, 2024
b3a061b
:zap: diamond
kamikazebr Sep 20, 2024
5e73d8a
:zap: diamond base
kamikazebr Sep 20, 2024
7f505c6
:zap: basediamond + factory
kamikazebr Sep 20, 2024
b283da0
:bug: rollback internal var
kamikazebr Sep 20, 2024
22a40fb
:bug: fix initialAllowlist UI
kamikazebr Sep 20, 2024
dd2d900
Merge branch '2diamond-pattern' into allowlist-feature
kamikazebr Sep 20, 2024
7030770
Merge remote-tracking branch 'origin/dev' into ui-allowlist
Lucianosc Sep 23, 2024
e3acea6
final fix
Lucianosc Sep 24, 2024
a0c199d
add modifyThreshold
Lucianosc Sep 25, 2024
2b2ba3e
build fix
Lucianosc Sep 25, 2024
b99a4d2
Merge branch 'allowlist-feature' into ui-allowlist
Lucianosc Sep 25, 2024
e9bb09a
Wrote tests for allowlist feature
kafann Sep 25, 2024
a19298e
Deploy with setPoolParams with threshold
Corantin Sep 25, 2024
8dad1c6
Merge branch 'allowlist-feature' into ui-allowlist
Corantin Sep 25, 2024
5dc46a1
Upgrade
Corantin Sep 25, 2024
5efd3b6
Merge branch 'allowlist-feature' into ui-allowlist
Corantin Sep 25, 2024
89b6666
Fix remove passportThreshold in init
Corantin Sep 26, 2024
61bcd14
Merge branch 'allowlist-feature' into ui-allowlist
Corantin Sep 26, 2024
81409d7
fix PoolEditForm
Lucianosc Sep 26, 2024
a8d32e3
Fix
Corantin Sep 29, 2024
77afbe6
Merge remote-tracking branch 'origin/ui-allowlist' into ui-allowlist
Lucianosc Oct 1, 2024
ba9811a
minor fix PoolForm
Lucianosc Oct 1, 2024
02a9a01
minor fixes
Lucianosc Oct 1, 2024
cb001b1
Added onlyStrategyAddress modifier to activatePoints
kafann Oct 2, 2024
3af644b
Fix abi function selection + fix pasport threshold not being added to…
Corantin Oct 3, 2024
ce13b64
Merge remote-tracking branch 'origin/dev' into allowlist-feature
Corantin Oct 3, 2024
d276849
Upgrade with D precision increase to 14
Corantin Oct 3, 2024
c703e3e
Merge remote-tracking branch 'origin/allowlist-feature' into ui-allow…
Corantin Oct 3, 2024
fa2684e
Test change precision to 14
Corantin Oct 3, 2024
3901e96
Revert "Added onlyStrategyAddress modifier to activatePoints"
Corantin Oct 4, 2024
5233092
Merge branch 'allowlist-feature' into ui-allowlist
Corantin Oct 4, 2024
40d7c3a
Revert "Test change precision to 14"
Corantin Oct 4, 2024
c1d2ad1
Fix typing from subgraph
Corantin Oct 4, 2024
27ee5a4
Update prod subgraph
Corantin Oct 4, 2024
5b8ad9b
Fix allowing all not set in form value
Corantin Oct 4, 2024
1f33361
Merge remote-tracking branch 'origin/dev' into allowlist-feature
Corantin Oct 4, 2024
20641dd
Build
Corantin Oct 4, 2024
d155f57
Checked for loop gas vulnerability, added limit of 10000 after gas re…
kafann Oct 7, 2024
0da7d85
Removed comments
kafann Oct 8, 2024
aaf1f22
Merge pull request #459 from 1Hive/for-loop-vuln
Corantin Oct 9, 2024
c69070c
Merge branch 'dev' into ui-allowlist
Corantin Oct 9, 2024
7b6a1e5
Build contracts
Corantin Oct 9, 2024
602278f
refactor: update type definitions and streamline imports.
Corantin Oct 9, 2024
763de7d
Merge v0 and v1 to make the diamond transition easier
Corantin Oct 9, 2024
3cb0e74
Merge branch 'allowlist-feature' into ui-allowlist
Corantin Oct 9, 2024
870572d
feat: Enhance subgraph schema for collateral management.
Corantin Oct 9, 2024
4d5bc3d
:recycle: Simplified import and removed unused code
Corantin Oct 10, 2024
fb8ede5
Lock file update
Corantin Oct 10, 2024
62ba2c4
Merge from dev
Corantin Oct 10, 2024
272d611
:bug: Fixed null poolTokenAddress issue
Corantin Oct 10, 2024
fc2d52e
Merge remote-tracking branch 'origin/dev' into allowlist-feature
Corantin Oct 10, 2024
de0aa83
Merge branch 'allowlist-feature' into ui-allowlist
Corantin Oct 10, 2024
6a966c9
Merge remote-tracking branch 'origin/dev' into ui-allowlist
Corantin Oct 10, 2024
9c2e535
Auto stash before merge of "ui-allowlist" and "origin/dev"
Corantin Oct 10, 2024
0868c93
:recycle: Refactored form input components
Corantin Oct 10, 2024
a77169a
Merge from dev
Corantin Oct 11, 2024
6b98db6
:recycle: Refactored code for multi-chain support and improved UI
Corantin Oct 14, 2024
906f077
Build contracts
Corantin Oct 14, 2024
baea356
:recycle: Refactored code to improve passport scoring system
Corantin Oct 14, 2024
d6971e5
:rotating_light: Fix compile
Corantin Oct 14, 2024
b3e58da
:recycle: Updated PoolGovernance component
Corantin Oct 14, 2024
c707f61
:rotating_light: Fix compile
Corantin Oct 14, 2024
420f7cc
:recycle: Refactored error messages and improved code readability
Corantin Oct 15, 2024
eaea92f
:recycle: Refactored code for better readability and efficiency
Corantin Oct 15, 2024
eaf327d
Merge pull request #410 from 1Hive/ui-allowlist
Corantin Oct 15, 2024
33271ef
Merge from dev
Corantin Oct 15, 2024
73a8754
Merge remote-tracking branch 'origin/dev' into allowlist-feature
Corantin Oct 15, 2024
e88de83
Merge branch 'allowlist-feature' into HEAD
Corantin Oct 15, 2024
5024ee7
:zap: Update contract addresses and upgrade logic
Corantin Oct 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { useMetadataIpfsFetch } from "@/hooks/useIpfsFetch";
import { useSubgraphQuery } from "@/hooks/useSubgraphQuery";
import { alloABI } from "@/src/generated";
import { PoolTypes, ProposalStatus } from "@/types";
import { abiWithErrors } from "@/utils/abiWithErrors";
import { abiWithErrors } from "@/utils/abi";
import { useErrorDetails } from "@/utils/getErrorName";
import { prettyTimestamp } from "@/utils/text";

Expand Down Expand Up @@ -124,7 +124,7 @@ export default function Page({
abi: abiWithErrors(alloABI),
functionName: "distribute",
contractName: "Allo",
fallbackErrorMessage: "Error executing proposal. Please try again.",
fallbackErrorMessage: "Error executing proposal, please report a bug.",
onConfirmations: () => {
publish({
topic: "proposal",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { useCollectQueryParams } from "@/contexts/collectQueryParams.context";
import { useMetadataIpfsFetch } from "@/hooks/useIpfsFetch";
import { useSubgraphQuery } from "@/hooks/useSubgraphQuery";
import { PoolTypes } from "@/types";
import { CV_SCALE_PRECISION } from "@/utils/numbers";

export const dynamic = "force-dynamic";

Expand All @@ -28,7 +27,7 @@ export default function Page({
params: { chain: string; poolId: number; garden: string };
}) {
const searchParams = useCollectQueryParams();

const { data, refetch, error } = useSubgraphQuery<getPoolDataQuery>({
query: getPoolDataDocument,
variables: { poolId: poolId, garden: garden },
Expand Down Expand Up @@ -109,12 +108,9 @@ export default function Page({
return <div className="mt-52 text-center">Pool {poolId} not found</div>;
}

const pointSystem = data.cvstrategies?.[0].config.pointSystem;
const communityAddress = strategyObj.registryCommunity.id as Address;
const alloInfo = data.allos[0];
const poolAmount = strategyObj.poolAmount as number;
const spendingLimitPct =
(Number(strategyObj.config.maxRatio || 0) / CV_SCALE_PRECISION) * 100;

const isEnabled = data.cvstrategies?.[0]?.isEnabled as boolean;

Expand All @@ -128,10 +124,7 @@ export default function Page({
poolId={poolId}
ipfsResult={ipfsResult}
isEnabled={isEnabled}
pointSystem={pointSystem}
chainId={chain}
proposalType={proposalType}
spendingLimitPct={spendingLimitPct}
/>
{isEnabled && (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default function Page({

if (!token) {
return (
<div className="mt-96">
<div className="my-40">
<LoadingSpinner />
</div>
);
Expand Down
27 changes: 10 additions & 17 deletions apps/web/app/api/passport-oracle/daily-job/[chain]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { privateKeyToAccount } from "viem/accounts";
import { getConfigByChain } from "@/configs/chains";
import { initUrqlClient } from "@/providers/urql";
import { passportScorerABI } from "@/src/generated";
import { CV_PERCENTAGE_SCALE } from "@/utils/numbers";
import { CV_PASSPORT_THRESHOLD_SCALE } from "@/utils/numbers";
import { getViemChain } from "@/utils/web3";

const LIST_MANAGER_PRIVATE_KEY = process.env.LIST_MANAGER_PRIVATE_KEY ?? "";
Expand Down Expand Up @@ -107,19 +107,7 @@ const updateScoresOnChain = async (
const CONTRACT_ADDRESS = getConfigByChain(chain)?.passportScorer as Address;

for (const update of updates) {
const integerScore = Number(update.score) * CV_PERCENTAGE_SCALE;
const data = {
abi: passportScorerABI,
address: CONTRACT_ADDRESS,
functionName: "addUserScore" as const,
args: [
update.userAddress,
{
score: BigInt(integerScore),
lastUpdated: BigInt(Date.now()),
},
] as const,
};
const integerScore = Number(update.score) * CV_PASSPORT_THRESHOLD_SCALE;

const client = createPublicClient({
chain: getViemChain(chain),
Expand All @@ -132,20 +120,25 @@ const updateScoresOnChain = async (
transport: custom(client.transport),
});

const hash = await walletClient.writeContract(data);
const hash = await walletClient.writeContract({
abi: passportScorerABI,
address: CONTRACT_ADDRESS,
functionName: "addUserScore" as const,
args: [update.userAddress, BigInt(integerScore)] as const,
});
await client.waitForTransactionReceipt({ hash });
}
};

const updateScores = async (chain: string) => {
const SUBGRAPH = getConfigByChain(chain)?.subgraphUrl as string;
const subgraphUrl = getConfigByChain(chain)?.subgraphUrl as string;
const { urqlClient } = initUrqlClient({ chainId: chain });
const subgraphResponse = await urqlClient
.query<{ passportUsers: PassportUser[] }>(
query,
{},
{
url: SUBGRAPH,
url: subgraphUrl,
requestPolicy: "network-only",
},
)
Expand Down
105 changes: 78 additions & 27 deletions apps/web/app/api/passport-oracle/write-score/[chain]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ import {
Address,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
import {
getMemberPassportAndCommunitiesDocument,
getMemberPassportAndCommunitiesQuery,
} from "#/subgraph/.graphclient";
import { getConfigByChain } from "@/configs/chains";
import { initUrqlClient } from "@/providers/urql";
import { passportScorerABI } from "@/src/generated";
import { CV_PERCENTAGE_SCALE } from "@/utils/numbers";
import { CV_PASSPORT_THRESHOLD_SCALE } from "@/utils/numbers";
import { getViemChain } from "@/utils/web3";

const LIST_MANAGER_PRIVATE_KEY = process.env.LIST_MANAGER_PRIVATE_KEY;
const LOCAL_RPC = "http://127.0.0.1:8545";

Expand All @@ -37,20 +41,10 @@ const fetchScoreFromGitcoin = async (user: string) => {
};

export async function POST(req: Request, { params }: Params) {
const apiKey = req.headers.get("Authorization");
const { chain } = params;

if (apiKey !== process.env.CRON_SECRET) {
console.error("Unauthorized", {
req: req.url,
chain,
});
return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
}

const { user } = await req.json();

if (!user) {
if (typeof user !== "string") {
return NextResponse.json(
{
error: "User address is required",
Expand All @@ -59,14 +53,67 @@ export async function POST(req: Request, { params }: Params) {
);
}

const chainConfig = getConfigByChain(chain);

try {
const RPC_URL = getConfigByChain(chain)?.rpcUrl ?? LOCAL_RPC;
const subgraphUrl = chainConfig?.subgraphUrl as string;
const { urqlClient } = initUrqlClient({ chainId: chain });
const subgraphResponse = await urqlClient
.query<getMemberPassportAndCommunitiesQuery>(
getMemberPassportAndCommunitiesDocument,
{
memberId: user.toLowerCase(),
},
{
url: subgraphUrl,
requestPolicy: "network-only",
},
)
.toPromise();

if (subgraphResponse.data == null) {
return NextResponse.json({ error: "User not found" }, { status: 404 });
}

const { member, passportUser } = subgraphResponse.data;

if (!member?.memberCommunity || member.memberCommunity.length === 0) {
return NextResponse.json(
{ error: "User has no communities" },
{ status: 400 },
);
}

const CONTRACT_ADDRESS = getConfigByChain(chain)?.passportScorer as Address;
// Throttle the score update to once per day
const twoHoursMs = 2 * 60 * 60 * 1000;
if (
passportUser &&
+passportUser.score > 0 &&
+passportUser.lastUpdated * 1000 > Date.now() - twoHoursMs
) {
return NextResponse.json(
{
error:
"User score cannot be updated before " +
new Date(
passportUser.lastUpdated * 1000 + twoHoursMs,
).toUTCString(),
},
{ status: 400 },
);
}
} catch (error) {
console.error("Error fetching user data:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 },
);
}

try {
const client = createPublicClient({
chain: getViemChain(chain),
transport: http(RPC_URL),
transport: http(chainConfig?.rpcUrl ?? LOCAL_RPC),
});

const walletClient = createWalletClient({
Expand All @@ -78,18 +125,22 @@ export async function POST(req: Request, { params }: Params) {
});

const score = await fetchScoreFromGitcoin(user);
const integerScore = Number(score) * CV_PERCENTAGE_SCALE;
const data = {
const integerScore = Number(score) * CV_PASSPORT_THRESHOLD_SCALE;

if (!chainConfig?.passportScorer) {
console.error("Passport scorer contract address is missing");
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 },
);
}

const hash = await walletClient.writeContract({
abi: passportScorerABI,
address: CONTRACT_ADDRESS,
functionName: "addUserScore" as const,
args: [
user,
{ score: BigInt(integerScore), lastUpdated: BigInt(Date.now()) },
] as const,
};

const hash = await walletClient.writeContract(data);
address: chainConfig.passportScorer,
functionName: "addUserScore",
args: [user as Address, BigInt(integerScore)],
});

return NextResponse.json({
message: "User score added successfully",
Expand Down
Binary file added apps/web/assets/vector_curve_quadratic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 18 additions & 8 deletions apps/web/components/ActivatePoints.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,28 @@
import React from "react";
import { useConnectModal } from "@rainbow-me/rainbowkit";
import { Address, useAccount } from "wagmi";
import { CVStrategy, CVStrategyConfig } from "#/subgraph/.graphclient";
import { Button } from "./Button";
import { usePubSubContext } from "@/contexts/pubsub.context";
import { useChainIdFromPath } from "@/hooks/useChainIdFromPath";
import useCheckAllowList from "@/hooks/useCheckAllowList";
import { useContractWriteWithConfirmations } from "@/hooks/useContractWriteWithConfirmations";
import { ConditionObject, useDisableButtons } from "@/hooks/useDisableButtons";
import { cvStrategyABI } from "@/src/generated";
import { abiWithErrors } from "@/utils/abiWithErrors";
import { abiWithErrors } from "@/utils/abi";
import { useErrorDetails } from "@/utils/getErrorName";

type ActiveMemberProps = {
strategyAddress: Address;
strategy: Pick<CVStrategy, "id"> & {
config: Pick<CVStrategyConfig, "allowlist">;
};
communityAddress: Address;
isMemberActivated: boolean | undefined;
isMember: boolean | undefined;
};

export function ActivatePoints({
strategyAddress,
strategy,
communityAddress,
isMember,
isMemberActivated,
Expand All @@ -29,15 +33,17 @@ export function ActivatePoints({
const { openConnectModal } = useConnectModal();
const chainId = useChainIdFromPath();
const { publish } = usePubSubContext();
const allowList = (strategy?.config?.allowlist as Address[]) ?? [];
const isAllowed = useCheckAllowList(allowList, connectedAccount);

const { write: writeActivatePoints, error: errorActivatePoints } =
useContractWriteWithConfirmations({
chainId,
address: strategyAddress,
address: strategy.id as Address,
contractName: "CV Strategy",
abi: abiWithErrors(cvStrategyABI),
functionName: "activatePoints",
fallbackErrorMessage: "Error activating points. Please try again.",
fallbackErrorMessage: "Error activating points, please report a bug.",
onConfirmations: () => {
publish({
topic: "member",
Expand All @@ -52,11 +58,11 @@ export function ActivatePoints({

const { write: writeDeactivatePoints, error: errorDeactivatePoints } =
useContractWriteWithConfirmations({
address: strategyAddress,
address: strategy.id as Address,
abi: abiWithErrors(cvStrategyABI),
contractName: "CV Strategy",
functionName: "deactivatePoints",
fallbackErrorMessage: "Error deactivating points. Please try again.",
fallbackErrorMessage: "Error deactivating points, please report a bug.",
onConfirmations: () => {
publish({
topic: "member",
Expand Down Expand Up @@ -92,6 +98,10 @@ export function ActivatePoints({
condition: !isMember,
message: "Join community to activate points",
},
{
condition: !isAllowed,
message: "Address not in allowlist",
},
];

const disableActiveBtn = disableActiveBtnCondition.some(
Expand All @@ -107,7 +117,7 @@ export function ActivatePoints({
onClick={handleChange}
btnStyle={isMemberActivated ? "outline" : "filled"}
color={isMemberActivated ? "danger" : "primary"}
disabled={missmatchUrl || disableActiveBtn}
disabled={missmatchUrl || disableActiveBtn || !isAllowed}
tooltip={String(tooltipMessage)}
>
{isMemberActivated ? "Deactivate governance" : "Activate governance"}
Expand Down
5 changes: 2 additions & 3 deletions apps/web/components/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ import Link from "next/link";
import { usePathname } from "next/navigation";
import { Button } from "./Button";
import { getTitlesFromUrlSegments } from "@/services/getTitlesFromUrlSegments";
import { truncateString } from "@/utils/text";

interface Breadcrumb {
href: string;
label: string;
}

const truncateString = (str: string) => {
return `${str.slice(0, 6)}...${str.slice(-4)}`;
};


export function Breadcrumbs() {
const path = usePathname();
Expand Down
Loading
Loading