Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 8 additions & 1 deletion components/hypercert/creator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { Cuboid } from "lucide-react";
import { SUPPORTED_CHAINS, SupportedChainIdType } from "@/configs/constants";
import CopyableHypercertId from "@/components/copyable-hypercert-id";
import { HypercertState } from "@/hypercerts/fragments/hypercert-state.fragment";
import TransferRestrictionsLabel from "./transfer-restrictions-label";

export default function Creator({ hypercert }: { hypercert: HypercertState }) {
if (!hypercert) return null;
return (
<div className="flex flex-wrap items-center space-x-1 text-sm text-slate-600 font-medium">
<div className="flex flex-wrap items-center space-x-1 text-sm text-slate-600 font-medium space-y-1">
{hypercert.hypercert_id && (
<CopyableHypercertId id={hypercert.hypercert_id} />
)}
Expand All @@ -17,6 +18,12 @@ export default function Creator({ hypercert }: { hypercert: HypercertState }) {
<EthAddress address={hypercert.creator_address} showEnsName />
</div>
)}
<div className="flex space-x-1 items-center">
<TransferRestrictionsLabel
hypercertId={hypercert.hypercert_id || ""}
showSeparator
/>
</div>
{hypercert.contract?.chain_id && (
<div className="flex space-x-2 items-center">
<span className="text-slate-400">•</span>
Expand Down
77 changes: 77 additions & 0 deletions components/hypercert/transfer-restrictions-label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"use client";

import {
parseClaimOrFractionId,
TransferRestrictions,
} from "@hypercerts-org/sdk";
import { getAddress } from "viem";
import { useReadContract } from "wagmi";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { useState } from "react";
import { useReadTransferRestrictions } from "@/hooks/use-read-transfer-restrictions";

export default function TransferRestrictionsLabel({
hypercertId,
showSeparator = false,
}: {
hypercertId: string;
showSeparator?: boolean;
}) {
const [isOpen, setIsOpen] = useState(false);
const transferRestrictions = useReadTransferRestrictions(hypercertId);

if (transferRestrictions === undefined) return null;
return (
<>
{showSeparator && <span className="text-slate-400">•</span>}
<div className="flex items-center gap-2 content-center px-1 py-0.5 bg-slate-100 rounded-md w-max text-sm">
<Popover open={isOpen} onOpenChange={setIsOpen}>
<PopoverTrigger asChild>
<span
className="cursor-help"
onMouseEnter={() => setIsOpen(true)}
onMouseLeave={() => setIsOpen(false)}
>
{getTransferRestrictionsText(transferRestrictions)}
</span>
</PopoverTrigger>
<PopoverContent className="w-80 p-3" side="top">
<p className="text-sm text-slate-700">
{getTransferRestrictionsLabel(transferRestrictions)}
</p>
</PopoverContent>
</Popover>
</div>
</>
);
}

export const getTransferRestrictionsText = (
transferRestrictions: TransferRestrictions,
) => {
switch (transferRestrictions) {
case TransferRestrictions.AllowAll:
return "Transferable";
case TransferRestrictions.DisallowAll:
return "Not transferable";
case TransferRestrictions.FromCreatorOnly:
return "Transferable-once";
}
};

export const getTransferRestrictionsLabel = (
transferRestrictions: TransferRestrictions,
) => {
switch (transferRestrictions) {
case TransferRestrictions.AllowAll:
return "Fractions can be transferred without limitations.";
case TransferRestrictions.DisallowAll:
return "Fractions can not be transferred";
case TransferRestrictions.FromCreatorOnly:
return "Fractions can be transferred once from the creator to another user.";
}
};
36 changes: 9 additions & 27 deletions components/marketplace/list-for-sale-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { useState } from "react";
import { getAddress } from "viem";

import { isChainIdSupported } from "@/lib/isChainIdSupported";
import { useReadTransferRestrictions } from "@/hooks/use-read-transfer-restrictions";
import { TransferRestrictions } from "@hypercerts-org/sdk";

export function ListForSaleButton({
hypercert,
Expand All @@ -34,29 +36,9 @@ export function ListForSaleButton({
const { chain_id: chainId, contract_address: contractAddress } =
hypercert.contract || {};

const { data: transferRestrictions } = useReadContract({
abi: [
{
inputs: [{ internalType: "uint256", name: "tokenID", type: "uint256" }],
name: "readTransferRestriction",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
],
address: getAddress(contractAddress || ""),
functionName: "readTransferRestriction",
args: [tokenId!],
query: {
enabled: !!contractAddress && !!tokenId,
},
});
const transferRestrictions = useReadTransferRestrictions(
hypercert.hypercert_id || "",
);

const [isOpen, setIsOpen] = useState(false);

Expand Down Expand Up @@ -87,8 +69,8 @@ export function ListForSaleButton({
!client ||
!client.isClaimOrFractionOnConnectedChain(hypercertId) ||
!fractionsOwnedByUser.length ||
transferRestrictions === "DisallowAll" ||
(transferRestrictions === "FromCreatorOnly" &&
transferRestrictions === TransferRestrictions.DisallowAll ||
(transferRestrictions === TransferRestrictions.FromCreatorOnly &&
address?.toLowerCase() !== hypercert.creator_address?.toLowerCase());

const getToolTipMessage = () => {
Expand All @@ -114,11 +96,11 @@ export function ListForSaleButton({
return "You do not own any fractions of this hypercert";
}

if (transferRestrictions === "DisallowAll") {
if (transferRestrictions === TransferRestrictions.DisallowAll) {
return "Secondary sales are not allowed for this hypercert";
}

if (transferRestrictions === "FromCreatorOnly") {
if (transferRestrictions === TransferRestrictions.FromCreatorOnly) {
return "Only the creator can sell this hypercert";
}

Expand Down
44 changes: 44 additions & 0 deletions hooks/use-read-transfer-restrictions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
parseClaimOrFractionId,
TransferRestrictions,
} from "@hypercerts-org/sdk";
import { getAddress } from "viem";
import { useReadContract } from "wagmi";

export const useReadTransferRestrictions = (hypercertId: string) => {
const { contractAddress, id } = parseClaimOrFractionId(hypercertId);
const { data: transferRestrictions } = useReadContract({
abi: [
{
inputs: [{ internalType: "uint256", name: "tokenID", type: "uint256" }],
name: "readTransferRestriction",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
],
address: getAddress(contractAddress || ""),
functionName: "readTransferRestriction",
args: [id],
query: {
enabled: !!contractAddress && !!id,
select: (data) => {
if (data === "AllowAll") {
return TransferRestrictions.AllowAll;
} else if (data === "DisallowAll") {
return TransferRestrictions.DisallowAll;
} else if (data === "FromCreatorOnly") {
return TransferRestrictions.FromCreatorOnly;
}
},
},
});

return transferRestrictions;
};