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

feat: hybrid custody #7

Merged
merged 15 commits into from
Aug 21, 2023
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
4 changes: 3 additions & 1 deletion .env.development
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
NEXT_PUBLIC_CHAIN_ENV=mainnet

NEXT_PUBLIC_APP_URL=https://flowview.vercel.app/
NEXT_PUBLIC_APP_URL=http://localhost:3000/
NEXT_PUBLIC_ACCESS_NODE_API=https://floral-special-valley.flow-mainnet.quiknode.pro
NEXT_PUBLIC_WALLET_DISCOVERY=https://fcl-discovery.onflow.org/authn

Expand All @@ -23,3 +23,5 @@ NEXT_PUBLIC_FUNGIBLE_TOKEN_SWITCHBOARD_ADDRESS=0xf233dcee88fe0abe
NEXT_PUBLIC_FLOWBOX_ADDRESS=0x1b3930856571a52b
NEXT_PUBLIC_ACCOUNTBOOKMARK_ADDRESS=0x39b144ab4d348e2b
NEXT_PUBLIC_NFTSTOREFRONTV2_ADDRESS=0x4eb8a10cb9f87357

NEXT_PUBLIC_HYBRIDCUSTODY_ADDRESS=0xd8a7e05a7ac670c0
3 changes: 2 additions & 1 deletion .env.production
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
NEXT_PUBLIC_CHAIN_ENV=mainnet

NEXT_PUBLIC_APP_URL=https://flowview.vercel.app/
NEXT_PUBLIC_APP_URL=https://flowview.app/
NEXT_PUBLIC_ACCESS_NODE_API=https://floral-special-valley.flow-mainnet.quiknode.pro
NEXT_PUBLIC_WALLET_DISCOVERY=https://fcl-discovery.onflow.org/authn

Expand All @@ -23,3 +23,4 @@ NEXT_PUBLIC_FUNGIBLE_TOKEN_SWITCHBOARD_ADDRESS=0xf233dcee88fe0abe
NEXT_PUBLIC_FLOWBOX_ADDRESS=0x1b3930856571a52b
NEXT_PUBLIC_ACCOUNTBOOKMARK_ADDRESS=0x39b144ab4d348e2b
NEXT_PUBLIC_NFTSTOREFRONTV2_ADDRESS=0x4eb8a10cb9f87357
NEXT_PUBLIC_HYBRIDCUSTODY_ADDRESS=0xd8a7e05a7ac670c0
30 changes: 21 additions & 9 deletions components/common/Siderbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@ export default function Sidebar(props) {
{ id: "5", label: `Storefront`, link: { pathname: "/account/[account]/storefront", query: { account: account } } },
{ id: "6", label: `Contract`, link: { pathname: "/account/[account]/contract", query: { account: account } } },
{
id: "7", label: "Storage", subItems: [
{ id: "7-0", isSubItem: true, label: "Public Items", smLabel: "Public", link: { pathname: "/account/[account]/public", query: { account: account } } },
{ id: "7-1", isSubItem: true, label: "Stored Items", smLabel: "Stored", link: { pathname: "/account/[account]/storage", query: { account: account } } },
{ id: "7-2", isSubItem: true, label: "Private Items", smLabel: "Private", link: { pathname: "/account/[account]/private", query: { account: account } } },
id: "7", label: `Acct Linking`, subItems: [
{ id: "7-0", isSubItem: true, label: "Owned Acct", smLabel: "Owned Acct", link: { pathname: "/account/[account]/hc/owned_account", query: { account: account } } },
{ id: "7-1", isSubItem: true, label: "HC Manager", smLabel: "HC Manager", link: { pathname: "/account/[account]/hc/manager", query: { account: account } } },
]
},
{
id: "8", label: "Storage", subItems: [
{ id: "8-0", isSubItem: true, label: "Public Items", smLabel: "Public", link: { pathname: "/account/[account]/public", query: { account: account } } },
{ id: "8-1", isSubItem: true, label: "Stored Items", smLabel: "Stored", link: { pathname: "/account/[account]/storage", query: { account: account } } },
{ id: "8-2", isSubItem: true, label: "Private Items", smLabel: "Private", link: { pathname: "/account/[account]/private", query: { account: account } } },
]
}
// { id: "5", label: `Analyzer`, link: { pathname: "/account/[account]/analyzer", query: { account: account } } },
Expand All @@ -33,10 +39,16 @@ export default function Sidebar(props) {
{ id: "4", label: `Collection`, link: { pathname: "/account/[account]/collection", query: { account: account } } },
{ id: "5", label: `Contract`, link: { pathname: "/account/[account]/contract", query: { account: account } } },
{
id: "6", label: "Storage", subItems: [
{ id: "6-0", isSubItem: true, label: "Public Items", smLabel: "Public", link: { pathname: "/account/[account]/public", query: { account: account } } },
{ id: "6-1", isSubItem: true, label: "Stored Items", smLabel: "Stored", link: { pathname: "/account/[account]/storage", query: { account: account } } },
{ id: "6-2", isSubItem: true, label: "Private Items", smLabel: "Private", link: { pathname: "/account/[account]/private", query: { account: account } } },
id: "6", label: `Acct Linking`, subItems: [
{ id: "6-0", isSubItem: true, label: "Owned Acct", smLabel: "Owned Acct", link: { pathname: "/account/[account]/hc/owned_account", query: { account: account } } },
{ id: "6-1", isSubItem: true, label: "HC Manager", smLabel: "HC Manager", link: { pathname: "/account/[account]/hc/manager", query: { account: account } } },
]
},
{
id: "7", label: "Storage", subItems: [
{ id: "7-0", isSubItem: true, label: "Public Items", smLabel: "Public", link: { pathname: "/account/[account]/public", query: { account: account } } },
{ id: "7-1", isSubItem: true, label: "Stored Items", smLabel: "Stored", link: { pathname: "/account/[account]/storage", query: { account: account } } },
{ id: "7-2", isSubItem: true, label: "Private Items", smLabel: "Private", link: { pathname: "/account/[account]/private", query: { account: account } } },
]
}
// { id: "5", label: `Analyzer`, link: { pathname: "/account/[account]/analyzer", query: { account: account } } },
Expand Down Expand Up @@ -78,7 +90,7 @@ export default function Sidebar(props) {
<div
className="flex flex-col p-3 rounded-xl"
>
<div className="flex flex-col gap-y-4 items-start">
<div className="flex flex-col gap-y-3 items-start">
{menuItems.map(({ label: label, ...menu }, index) => {
const classes = getNavItemClasses(menu)
return (
Expand Down
71 changes: 71 additions & 0 deletions components/hybrid_custody/ChildView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { useRouter } from "next/router";
import publicConfig from "../../publicConfig";
import { useRecoilState } from "recoil";
import { showSetupDisplayState, transactionInProgressState, transactionStatusState } from "../../lib/atoms";
import { removeChildAccount, removeChildFromChild, setupChildAccountDisplay } from "../../flow/hc_transactions";
import { useSWRConfig } from "swr";
import OwnedDisplayView from "./OwnedDisplayView";

export default function ChildView(props) {
const [transactionInProgress, setTransactionInProgress] = useRecoilState(transactionInProgressState)
const [, setTransactionStatus] = useRecoilState(transactionStatusState)
const [showSetupDisplay, setShowSetupDisplay] = useRecoilState(showSetupDisplayState)
const { mutate } = useSWRConfig()

const router = useRouter()
const { child, account, user } = props

return (
<div className="min-w-[1076px] flex flex-col gap-y-3 p-4 shadow-md rounded-2xl bg-white">
<div className="flex flex-col gap-y-2">
<div className="flex gap-x-2 justify-between items-center">
<div className="cursor-pointer px-2 text-xl font-bold text-black decoration-drizzle decoration-2 underline">
<a href={`${publicConfig.appURL}//account/${child.address}`}
target="_blank"
rel="noopener noreferrer">
{child.address}
</a>
</div>
<div className="flex gap-x-2 justify-between">
{/* <button
type="button"
disabled={transactionInProgress}
className={`text-black disabled:bg-drizzle-light disabled:text-gray-500 bg-drizzle hover:bg-drizzle-dark px-3 py-2 text-sm rounded-2xl font-semibold shrink-0`}
onClick={async () => {
// TODO: REMOVE CHILD
mutate(["hcManagerInfoFetcher", account])
}}
>
{"Set Manager Cap Filter"}
</button> */}
<button
type="button"
disabled={transactionInProgress || !(user && user.loggedIn && user.addr == account)}
className={`text-black disabled:bg-drizzle-light disabled:text-gray-500 bg-drizzle hover:bg-drizzle-dark px-3 py-2 text-sm rounded-2xl font-semibold shrink-0`}
onClick={async () => {
setShowSetupDisplay({ show: true, mode: "ChildAccount", childAddress: child.address })
}}
>
{"Set Display"}
</button>
<button
type="button"
disabled={transactionInProgress || !(user && user.loggedIn && user.addr == account)}
className={`text-white disabled:bg-red-400 disabled:text-white bg-red-600 hover:bg-red-800 px-3 py-2 text-sm rounded-2xl font-semibold shrink-0`}
onClick={async () => {
await removeChildAccount(child.address, setTransactionInProgress, setTransactionStatus)
mutate(["hcManagerInfoFetcher", account])
}}
>
{"Remove"}
</button>
</div>
</div>
{
child.display ?
<OwnedDisplayView display={child.display} style={"Small"} type="Child" /> : null
}
</div>
</div>
)
}
45 changes: 45 additions & 0 deletions components/hybrid_custody/OwnedDisplayView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Image from "next/image"
import publicConfig from "../../publicConfig"
import { getImageSrcFromMetadataViewsFile } from "../../lib/utils"

export default function OwnedDisplayView(props) {
const { display, style } = props

if (style == "Small") {
return (
<div className="flex gap-x-3 justify-between">
<div className="flex items-center gap-x-3">
<div className="w-10 rounded-full overflow-hidden aspect-square relative shrink-0">
<Image src={getImageSrcFromMetadataViewsFile(display.thumbnail)} alt="" fill sizes="5vw" />
</div>
<div className="flex flex-col">
<label className="text-medium font-semibold">
{`${display.name}`}
</label>
<label className="text-sm font-medium text-gray-600">
{`${display.description}`}
</label>
</div>
</div>
</div>
)
}

return (
<div className="flex gap-x-3 justify-between">
<div className="flex items-center gap-x-3">
<div className="w-20 rounded-full overflow-hidden aspect-square relative">
<Image src={getImageSrcFromMetadataViewsFile(display.thumbnail)} alt="" fill sizes="5vw" />
</div>
<div className="flex flex-col w-full">
<label className="text-lg font-bold">
{`${display.name}`}
</label>
<label className="text-sm font-medium text-gray-600">
{`${display.description}`}
</label>
</div>
</div>
</div>
)
}
59 changes: 59 additions & 0 deletions components/hybrid_custody/OwnedView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useRouter } from "next/router";
import publicConfig from "../../publicConfig";
import { useRecoilState } from "recoil";
import { showSetupDisplayState, showTransferOwnershipState, transactionInProgressState, transactionStatusState } from "../../lib/atoms";
import { removeChildAccount, removeChildFromChild, setupChildAccountDisplay } from "../../flow/hc_transactions";
import { useSWRConfig } from "swr";
import OwnedDisplayView from "./OwnedDisplayView";

export default function OwnedView(props) {
const [transactionInProgress, setTransactionInProgress] = useRecoilState(transactionInProgressState)
const [, setTransactionStatus] = useRecoilState(transactionStatusState)
const [showSetupDisplay, setShowSetupDisplay] = useRecoilState(showSetupDisplayState)
const [showTransferOwnership, setShowTransferOwnership] = useRecoilState(showTransferOwnershipState)
const { mutate } = useSWRConfig()

const router = useRouter()
const { child, account, user } = props

return (
<div className="min-w-[1076px] flex flex-col gap-y-3 p-4 shadow-md rounded-2xl bg-white">
<div className="flex flex-col gap-y-2">
<div className="flex gap-x-2 justify-between items-center">
<div className="cursor-pointer px-2 text-xl font-bold text-black decoration-drizzle decoration-2 underline">
<a href={`${publicConfig.appURL}//account/${child.address}`}
target="_blank"
rel="noopener noreferrer">
{child.address}
</a>
</div>
<div className="flex gap-x-2 justify-between">
<button
className={`text-white disabled:bg-red-400 bg-red-600 hover:bg-red-800 px-3 py-2 text-sm rounded-2xl font-semibold shrink-0`}
disabled={transactionInProgress || !(user && user.loggedIn && user.addr == account)}
onClick={async () => {
setShowTransferOwnership({ show: true, mode: "FromManager", ownedAddress: child.address })
}}
>
Transfer Ownership
</button>

{/* <button
type="button"
disabled={transactionInProgress || !(user && user.loggedIn && user.addr == account)}
className={`text-white disabled:bg-red-400 disabled:text-white bg-red-600 hover:bg-red-800 px-3 py-2 text-sm rounded-2xl font-semibold shrink-0`}
onClick={async () => {
}}
>
{"Remove"}
</button> */}
</div>
</div>
{
child.display ?
<OwnedDisplayView display={child.display} style={"Small"} type="Owned" /> : null
}
</div>
</div>
)
}
78 changes: 78 additions & 0 deletions components/hybrid_custody/ParentView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { useRouter } from "next/router";
import publicConfig from "../../publicConfig";
import { useRecoilState } from "recoil";
import { transactionInProgressState, transactionStatusState } from "../../lib/atoms";
import { removeParentFromChild } from "../../flow/hc_transactions";
import { useSWRConfig } from "swr";

export default function ParentView(props) {
const [transactionInProgress, setTransactionInProgress] = useRecoilState(transactionInProgressState)
const [, setTransactionStatus] = useRecoilState(transactionStatusState)
const { mutate } = useSWRConfig()

const router = useRouter()
const { parent, account, user } = props

return (
<div className="min-w-[1076px] flex flex-col gap-y-3 p-4 shadow-md rounded-2xl bg-white">
<div className="flex flex-col gap-y-2">
{
!parent.isClaimed ?
<div>
<label className={`font-bold text-xs px-2 py-1 leading-5 rounded-full bg-yellow-100 text-yellow-800`}>{"UNCLAIMED"}</label>
</div>
: <div>
<label className={`font-bold text-xs px-2 py-1 leading-5 rounded-full bg-green-100 text-green-800`}>{"CLAIMED"}</label>
</div>
}
<div className="flex gap-x-2 justify-between items-center">
<div className="cursor-pointer px-2 text-xl font-bold text-black decoration-drizzle decoration-2 underline">
<a href={`${publicConfig.appURL}//account/${parent.address}`}
target="_blank"
rel="noopener noreferrer">
{parent.address}
</a>
</div>
<div>
<button
type="button"
disabled={transactionInProgress || !(user && user.loggedIn && user.addr == account) || !parent.isClaimed}
className={`text-white disabled:bg-red-400 disabled:text-white bg-red-600 hover:bg-red-800 px-3 py-2 text-sm rounded-2xl font-semibold shrink-0`}
onClick={async () => {
await removeParentFromChild(parent.address, setTransactionInProgress, setTransactionStatus)
mutate(["ownedAccountInfoFetcher", account])
}}
>
{"Remove"}
</button>
</div>
</div>
<div className="flex gap-x-2 px-2 text-base text-black">
<div className="text-sm font-semibold text-black">Factory&nbsp;
<a
href={`${publicConfig.appURL}/account/${parent.childAccount.factory.address}`}
target="_blank"
rel="noopener noreferrer"
className="text-gray-600 text-sm font-medium cursor-pointer decoration-drizzle decoration-2 underline">
{`${parent.childAccount.factory.address}`}
</a>
</div>
</div>
<div className="flex gap-x-2 px-2 text-base font-semibold text-black">
<div className="text-sm font-semibold text-black">Filter&nbsp;
<a
href={`${publicConfig.appURL}/account/${parent.childAccount.filter.address}`}
target="_blank"
rel="noopener noreferrer"
className="text-gray-600 text-sm font-medium cursor-pointer decoration-drizzle decoration-2 underline">
{`${parent.childAccount.filter.address}`}
</a>
</div>
</div>
</div>


</div>

)
}
Loading