mirror of
https://github.com/penxio/penx.git
synced 2026-05-12 03:03:12 -04:00
feat: can create subscription record
This commit is contained in:
@@ -1,38 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { UserAvatar } from '@/components/UserAvatar'
|
||||
import { useHolders } from '@/hooks/useHolders'
|
||||
import { PostWithSpace } from '@/hooks/usePost'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface Props {
|
||||
post: PostWithSpace
|
||||
}
|
||||
|
||||
export function AvatarList({ post }: Props) {
|
||||
const { holders, isLoading } = useHolders(post.id)
|
||||
|
||||
if (isLoading) return null
|
||||
|
||||
return (
|
||||
<div className="flex items-center cursor-pointer relative">
|
||||
<div className="flex z-1">
|
||||
{holders.slice(0, 4).map((item) => (
|
||||
<UserAvatar
|
||||
key={item.id}
|
||||
user={item.user as any}
|
||||
className={cn('w-8 h-8 -ml-2 border-2 border-white')}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<Badge
|
||||
className="-ml-2 z-10 text-neutral-500"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
>
|
||||
{holders.length} holders
|
||||
</Badge>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import { Skeleton } from '@/components/ui/skeleton'
|
||||
import { UserAvatar } from '@/components/UserAvatar'
|
||||
import { useHolders } from '@/hooks/useHolders'
|
||||
import { PostWithSpace } from '@/hooks/usePost'
|
||||
import { precision } from '@/lib/math'
|
||||
import { getEnsAvatar, shortenAddress } from '@/lib/utils'
|
||||
import { Space } from '@prisma/client'
|
||||
|
||||
interface Props {
|
||||
space: Space
|
||||
post: PostWithSpace
|
||||
}
|
||||
|
||||
export function HolderList({ space, post }: Props) {
|
||||
const { holders, isLoading } = useHolders(post.id)
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="grid gap-2">
|
||||
{Array(10)
|
||||
.fill('')
|
||||
.map((_, index) => (
|
||||
<Skeleton key={index} className="h-8" />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (holders.length === 0) {
|
||||
return (
|
||||
<div className="flex flex-col items-center text-gray-600 text-sm">
|
||||
No holders yet
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-3 mt-4">
|
||||
{holders.map((item) => (
|
||||
<div key={item.id} className="flex justify-between">
|
||||
<div className="flex gap-2 items-center">
|
||||
<UserAvatar className="w-7 h-7" user={item.user as any} />
|
||||
<div>{item.user.ensName || shortenAddress(item.user.address)}</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="font-bold">{item.amount}</span> Keys
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@/components/ui/dialog'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { PostWithSpace } from '@/hooks/usePost'
|
||||
import { Space } from '@prisma/client'
|
||||
import { AvatarList } from './AvatarList'
|
||||
import { HolderList } from './HolderList'
|
||||
import { PostTradeList } from './PostTradeList'
|
||||
|
||||
interface Props {
|
||||
space: Space
|
||||
post: PostWithSpace
|
||||
}
|
||||
export function PostTradeModal({ space, post }: Props) {
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger>
|
||||
<AvatarList post={post} />
|
||||
</DialogTrigger>
|
||||
<DialogContent className="w-[700px] sm:w-[740px] min-h-[60vh]">
|
||||
<DialogHeader>
|
||||
{/* <DialogTitle>#</DialogTitle> */}
|
||||
<Tabs defaultValue="keys" className="">
|
||||
<TabsList className="flex w-full">
|
||||
<TabsTrigger value="keys">Key Holders</TabsTrigger>
|
||||
<TabsTrigger value="trades">Trade History</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="pt-5">
|
||||
<TabsContent value="keys">
|
||||
<HolderList space={space} post={post} />
|
||||
</TabsContent>
|
||||
<TabsContent value="trades">
|
||||
<PostTradeList post={post} />
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</DialogHeader>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { UserAvatar } from '@/components/UserAvatar'
|
||||
import { PostWithSpace } from '@/hooks/usePost'
|
||||
import { usePostTrades } from '@/hooks/usePostTrades'
|
||||
import { precision } from '@/lib/math'
|
||||
import { cn, shortenAddress } from '@/lib/utils'
|
||||
|
||||
interface Props {
|
||||
post: PostWithSpace
|
||||
}
|
||||
|
||||
export function PostTradeList({ post }: Props) {
|
||||
return <div className="space-y-3 mt-4"></div>
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { atom, useAtom } from 'jotai'
|
||||
|
||||
const tradeDialogAtom = atom<boolean>(false)
|
||||
|
||||
export function useTradeDialog() {
|
||||
const [isOpen, setIsOpen] = useAtom(tradeDialogAtom)
|
||||
return { isOpen, setIsOpen }
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import { handlers } from './handlers'
|
||||
import { ImageCreation } from './ImageCreation'
|
||||
import { PostActionBar } from './PostActionBar'
|
||||
import { PostCreation } from './PostCreation'
|
||||
import { PostTradeModal } from './PostTradeDialog/PostTradeDialog'
|
||||
import { PromotionCard } from './PromotionCard'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
@@ -4,10 +4,10 @@ import { ReactNode } from 'react'
|
||||
import { NavbarWrapper } from '@/components/Navbar/NavbarWrapper'
|
||||
import { useChainSpace, useQueryChainSpace } from '@/hooks/useChainSpace'
|
||||
import { SpaceInfo } from '../Space/SpaceInfo'
|
||||
import { TradeList } from '../Space/TradeList'
|
||||
import { Transaction } from '../Transaction'
|
||||
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
const { isLoading, data } = useQueryChainSpace()
|
||||
const { space } = useChainSpace()
|
||||
|
||||
if (!space) return null
|
||||
@@ -21,7 +21,11 @@ export default function Layout({ children }: { children: ReactNode }) {
|
||||
{children}
|
||||
</div>
|
||||
|
||||
<Transaction />
|
||||
<div className="w-[360px]">
|
||||
<Transaction />
|
||||
<div className="text-base font-bold mt-8">Trades</div>
|
||||
<TradeList />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use client'
|
||||
|
||||
import { useSpace } from '@/hooks/useSpace'
|
||||
import { SpaceTradeList } from '../../Space/SpaceTradeList'
|
||||
import { SubscriptionRecordList } from '../../Space/SubscriptionRecordList'
|
||||
|
||||
export default function Page() {
|
||||
const { space } = useSpace()
|
||||
if (!space) return
|
||||
return <SpaceTradeList space={space} />
|
||||
return <SubscriptionRecordList space={space} />
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { MemberDialog } from '@/components/MemberDialog/MemberDialog'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Skeleton } from '@/components/ui/skeleton'
|
||||
import { UpdatePriceDialog } from '@/components/UpdatePriceDialog/UpdatePriceDialog'
|
||||
import { useSpace } from '@/hooks/useSpace'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useSession } from 'next-auth/react'
|
||||
@@ -11,7 +12,6 @@ import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { ClaimShareRewards } from './ClaimShareRewards'
|
||||
import { MemberButton } from './MemberButton'
|
||||
import { UpdatePriceDialog } from '@/components/UpdatePriceDialog/UpdatePriceDialog'
|
||||
|
||||
interface Props {}
|
||||
|
||||
@@ -97,7 +97,7 @@ export function SpaceInfo({}: Props) {
|
||||
<div className="">
|
||||
<div className="flex gap-2">
|
||||
<MemberDialog space={space} />
|
||||
<UpdatePriceDialog/>
|
||||
<UpdatePriceDialog />
|
||||
<MemberButton />
|
||||
</div>
|
||||
</div>
|
||||
@@ -118,7 +118,7 @@ export function SpaceInfo({}: Props) {
|
||||
</Link> */}
|
||||
|
||||
<Link href={Paths.trades} className={linkClassName(Paths.trades)}>
|
||||
Trades
|
||||
Activities
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { UserAvatar } from '@/components/UserAvatar'
|
||||
import { SECONDS_PER_DAY } from '@/domains/Space'
|
||||
import { useSpaceTrades } from '@/hooks/useSpaceTrades'
|
||||
import { useSubscriptionRecords } from '@/hooks/useSpaceTrades'
|
||||
import { SubscriptionType } from '@/lib/constants'
|
||||
import { precision } from '@/lib/math'
|
||||
import { cn, getEnsAvatar, shortenAddress } from '@/lib/utils'
|
||||
import { Space } from '@prisma/client'
|
||||
@@ -12,12 +13,12 @@ interface Props {
|
||||
space: Space
|
||||
}
|
||||
|
||||
export function SpaceTradeList({ space }: Props) {
|
||||
const { trades } = useSpaceTrades(space.id)
|
||||
export function SubscriptionRecordList({ space }: Props) {
|
||||
const { records } = useSubscriptionRecords(space.id)
|
||||
|
||||
return (
|
||||
<div className="space-y-3 mt-4">
|
||||
{trades.map((item) => (
|
||||
{records.map((item) => (
|
||||
<div key={item.id} className="flex items-center gap-2">
|
||||
<div className="flex gap-2 items-center">
|
||||
<UserAvatar user={item.user as any} />
|
||||
@@ -30,11 +31,13 @@ export function SpaceTradeList({ space }: Props) {
|
||||
<div>
|
||||
<Badge
|
||||
className={cn(
|
||||
item.type === 'BUY' && 'bg-green-500',
|
||||
item.type === 'SELL' && 'bg-red-500',
|
||||
item.type === SubscriptionType.SUBSCRIBE && 'bg-green-500',
|
||||
item.type === SubscriptionType.UNSUBSCRIBE && 'bg-red-500',
|
||||
)}
|
||||
>
|
||||
{item.type === 'BUY' ? 'Subscribe' : 'Unsubscribe'}
|
||||
{item.type === SubscriptionType.SUBSCRIBE
|
||||
? 'Subscribe'
|
||||
: 'Unsubscribe'}
|
||||
</Badge>
|
||||
</div>
|
||||
<div>
|
||||
52
app/~/space/[id]/Space/TradeList.tsx
Normal file
52
app/~/space/[id]/Space/TradeList.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
'use client'
|
||||
|
||||
import { UserAvatar } from '@/components/UserAvatar'
|
||||
import { useSpace } from '@/hooks/useSpace'
|
||||
import { useTrades } from '@/hooks/useTrades'
|
||||
import { TradeType } from '@/lib/constants'
|
||||
import { precision } from '@/lib/math'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface Props {}
|
||||
|
||||
export function TradeList({}: Props) {
|
||||
const { space } = useSpace()
|
||||
const { records: trades } = useTrades()
|
||||
|
||||
return (
|
||||
<div className="space-y-3 mt-4">
|
||||
{trades.map((item) => (
|
||||
<div key={item.id} className="flex items-center gap-2 text-sm">
|
||||
<div className="flex gap-2 items-center">
|
||||
<UserAvatar className="w-6 h-6" user={item.user as any} />
|
||||
<div className="text-sm">
|
||||
{item.user.ensName
|
||||
? item.user.ensName
|
||||
: item.user.address.slice(0, 5)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
className={cn(
|
||||
item.type === TradeType.BUY && 'text-green-500',
|
||||
item.type === TradeType.SELL && 'text-red-500',
|
||||
)}
|
||||
>
|
||||
{item.type === TradeType.BUY ? 'Bought' : 'sold'}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="font-bold">
|
||||
{precision
|
||||
.toDecimal(
|
||||
item.type === TradeType.BUY ? item.amountOut : item.amountIn,
|
||||
)
|
||||
.toFixed(2)}{' '}
|
||||
</span>
|
||||
<span>{space.symbolName}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,88 +1,65 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useAddress } from '@/hooks/useAddress';
|
||||
import { useTokenKxy } from '@/hooks/useTokenKxy';
|
||||
import { precision } from '@/lib/math';
|
||||
import { Address } from 'viem';
|
||||
import { useAccount, useBalance } from 'wagmi';
|
||||
import { useSpace } from "@/hooks/useSpace"
|
||||
import { useSpaceTokenBalance } from '@/components/spaceToken/hooks/useSpaceTokenBalance';
|
||||
import { Buy } from '@/components/spaceToken/Buy';
|
||||
import { Sell } from '@/components/spaceToken/Sell';
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { BuyPanel } from '@/components/spaceToken/BuyPanel'
|
||||
import { SellPanel } from '@/components/spaceToken/SellPanel'
|
||||
import { useAddress } from '@/hooks/useAddress'
|
||||
import { useSpace } from '@/hooks/useSpace'
|
||||
import { precision } from '@/lib/math'
|
||||
import { Address } from 'viem'
|
||||
import { useAccount, useBalance } from 'wagmi'
|
||||
|
||||
enum Direction {
|
||||
buy = 1,
|
||||
sell = 2
|
||||
sell = 2,
|
||||
}
|
||||
|
||||
export function Transaction() {
|
||||
const { space } = useSpace()
|
||||
const address = useAddress()
|
||||
const { isConnected } = useAccount()
|
||||
const { data: balanceData } = useBalance({ address })
|
||||
const { isLoading, data: tokenBalance } = useSpaceTokenBalance()
|
||||
const [direction, setDirection] = useState<Direction>(Direction.buy)
|
||||
const { updateTokenKxy } = useTokenKxy()
|
||||
|
||||
const ethBalance = useMemo<string>(() => {
|
||||
if (balanceData?.value) {
|
||||
// Numerical precision issues: precision.toDecimal(tokenBalance).toString()
|
||||
return precision.toExactDecimalString(balanceData?.value)
|
||||
}
|
||||
|
||||
return '0.00'
|
||||
}, [balanceData])
|
||||
|
||||
const onSwitch = (direction: Direction) => {
|
||||
setDirection(direction)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (space) {
|
||||
updateTokenKxy(space.spaceAddress as Address)
|
||||
}
|
||||
}, [space])
|
||||
|
||||
return (
|
||||
<div className="w-[350px]">
|
||||
<div className="p-4 rounded-lg border border-neutral-100">
|
||||
<div className="rounded-lg">
|
||||
<div className='flex mb-[12px]'>
|
||||
<div className="flex mb-[12px]">
|
||||
<button
|
||||
onClick={() => onSwitch(Direction.buy)}
|
||||
className={`mr-[10px] text-[#222222] py-[6px] px-[16px] rounded-[16px] ${direction === Direction.buy ? 'bg-[#22222212]' : ''
|
||||
}`}
|
||||
className={`mr-[10px] text-[#222222] py-[6px] px-[16px] rounded-[16px] ${
|
||||
direction === Direction.buy ? 'bg-[#22222212]' : ''
|
||||
}`}
|
||||
>
|
||||
Buy
|
||||
</button>
|
||||
<button
|
||||
onClick={() => onSwitch(Direction.sell)}
|
||||
className={`py-[6px] px-[16px] rounded-[16px] ${direction === Direction.sell ? 'bg-[#22222212]' : '' }`}
|
||||
className={`py-[6px] px-[16px] rounded-[16px] ${
|
||||
direction === Direction.sell ? 'bg-[#22222212]' : ''
|
||||
}`}
|
||||
>
|
||||
Sell
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
display: direction === Direction.buy ? 'block' : 'none'
|
||||
}}>
|
||||
<Buy
|
||||
tokenBalance={tokenBalance}
|
||||
ethBalance={ethBalance}
|
||||
isConnected={isConnected}
|
||||
space={space}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
display: direction === Direction.buy ? 'block' : 'none',
|
||||
}}
|
||||
>
|
||||
<BuyPanel isConnected={isConnected} space={space} />
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
display: direction === Direction.sell ? 'block' : 'none'
|
||||
}}>
|
||||
<Sell
|
||||
tokenBalance={tokenBalance}
|
||||
ethBalance={ethBalance}
|
||||
isConnected={isConnected}
|
||||
space={space}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
display: direction === Direction.sell ? 'block' : 'none',
|
||||
}}
|
||||
>
|
||||
<SellPanel isConnected={isConnected} space={space} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { PropsWithChildren } from 'react'
|
||||
import { useAddress } from '@/hooks/useAddress'
|
||||
import { useQueryChainSpace } from '@/hooks/useChainSpace'
|
||||
import { useQueryEthBalance } from '@/hooks/useEthBalance'
|
||||
import { useQueryEthPrice } from '@/hooks/useEthPrice'
|
||||
import { CreateSpaceDialog } from '../CreateSpaceDialog/CreateSpaceDialog'
|
||||
@@ -11,6 +12,7 @@ import { Sidebar } from './Sidebar/Sidebar'
|
||||
export function DashboardLayout({ children }: PropsWithChildren) {
|
||||
useQueryEthPrice()
|
||||
useQueryEthBalance()
|
||||
useQueryChainSpace()
|
||||
|
||||
return (
|
||||
<div className="mx-auto h-screen">
|
||||
|
||||
@@ -24,47 +24,66 @@ export function SpaceMenu() {
|
||||
pathname === '/~/create-space'
|
||||
|
||||
if (!space || isNotSpace) return null
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<div className="flex items-center justify-between px-2 hover:bg-sidebar/50 cursor-pointer font-semibold h-10 w-[240px] rounded-lg mt-0.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<Image
|
||||
src={
|
||||
space.logo! ||
|
||||
'https://public.blob.vercel-storage.com/eEZHAoPTOBSYGBE3/JRajRyC-PhBHEinQkupt02jqfKacBVHLWJq7Iy.png'
|
||||
}
|
||||
alt=""
|
||||
width={24}
|
||||
height={24}
|
||||
className="w-6 h-6 rounded-full"
|
||||
/>
|
||||
<div className="flex items-center justify-between px-2 hover:bg-sidebar/50 cursor-pointer font-semibold h-10 w-[240px] rounded-lg mt-0.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<Image
|
||||
src={
|
||||
space.logo! ||
|
||||
'https://public.blob.vercel-storage.com/eEZHAoPTOBSYGBE3/JRajRyC-PhBHEinQkupt02jqfKacBVHLWJq7Iy.png'
|
||||
}
|
||||
alt=""
|
||||
width={24}
|
||||
height={24}
|
||||
className="w-6 h-6 rounded-full"
|
||||
/>
|
||||
|
||||
<div>{space.name}</div>
|
||||
<ChevronDown size={16} className="text-neutral-600" />
|
||||
</div>
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="start"
|
||||
alignOffset={10}
|
||||
className="w-[200px]"
|
||||
>
|
||||
<DropdownMenuItem
|
||||
key={space.id}
|
||||
className="cursor-pointer flex gap-2 items-center"
|
||||
disabled={space.userId !== session?.userId}
|
||||
onClick={() => {
|
||||
push(`/~/space/${space.id}/settings`)
|
||||
}}
|
||||
>
|
||||
<Settings size={18} className="inline-flex" />
|
||||
<div className="">Space settings</div>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<div>{space.name}</div>
|
||||
{/* <ChevronDown size={16} className="text-neutral-600" /> */}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
// return (
|
||||
// <div className="relative">
|
||||
// <DropdownMenu>
|
||||
// <DropdownMenuTrigger asChild>
|
||||
// <div className="flex items-center justify-between px-2 hover:bg-sidebar/50 cursor-pointer font-semibold h-10 w-[240px] rounded-lg mt-0.5">
|
||||
// <div className="flex items-center gap-2">
|
||||
// <Image
|
||||
// src={
|
||||
// space.logo! ||
|
||||
// 'https://public.blob.vercel-storage.com/eEZHAoPTOBSYGBE3/JRajRyC-PhBHEinQkupt02jqfKacBVHLWJq7Iy.png'
|
||||
// }
|
||||
// alt=""
|
||||
// width={24}
|
||||
// height={24}
|
||||
// className="w-6 h-6 rounded-full"
|
||||
// />
|
||||
|
||||
// <div>{space.name}</div>
|
||||
// <ChevronDown size={16} className="text-neutral-600" />
|
||||
// </div>
|
||||
// </div>
|
||||
// </DropdownMenuTrigger>
|
||||
// <DropdownMenuContent
|
||||
// align="start"
|
||||
// alignOffset={10}
|
||||
// className="w-[200px]"
|
||||
// >
|
||||
// <DropdownMenuItem
|
||||
// key={space.id}
|
||||
// className="cursor-pointer flex gap-2 items-center"
|
||||
// disabled={space.userId !== session?.userId}
|
||||
// onClick={() => {
|
||||
// push(`/~/space/${space.id}/settings`)
|
||||
// }}
|
||||
// >
|
||||
// <Settings size={18} className="inline-flex" />
|
||||
// <div className="">Space settings</div>
|
||||
// </DropdownMenuItem>
|
||||
// </DropdownMenuContent>
|
||||
// </DropdownMenu>
|
||||
// </div>
|
||||
// )
|
||||
}
|
||||
|
||||
@@ -3,17 +3,14 @@
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import { useQueryEthBalance } from '@/hooks/useEthBalance'
|
||||
import { RouterOutputs } from '@/server/_app'
|
||||
import { useMutation } from '@tanstack/react-query'
|
||||
import { ProfileAvatar } from '../Profile/ProfileAvatar'
|
||||
import { AmountInput } from './AmountInput'
|
||||
import { MemberForm } from './MemberForm'
|
||||
import { useMemberDialog } from './useMemberDialog'
|
||||
import { useSubscribe } from './useSubscribe'
|
||||
|
||||
interface Props {
|
||||
space: RouterOutputs['space']['byId']
|
||||
@@ -26,6 +23,7 @@ export function MemberDialog({ space }: Props) {
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={(v) => setIsOpen(v)}>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogDescription></DialogDescription>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Subscription</DialogTitle>
|
||||
<div className="text-sm text-neutral-600">
|
||||
|
||||
@@ -19,7 +19,7 @@ import { useChainSpace } from '@/hooks/useChainSpace'
|
||||
import { useQueryEthBalance } from '@/hooks/useEthBalance'
|
||||
import { useSubscription } from '@/hooks/useSubscription'
|
||||
import { useTokenBalance } from '@/hooks/useTokenBalance'
|
||||
import { TradeType } from '@/lib/constants'
|
||||
import { SubscriptionType, TradeType } from '@/lib/constants'
|
||||
import { precision } from '@/lib/math'
|
||||
import { RouterOutputs } from '@/server/_app'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
@@ -45,7 +45,7 @@ const FormSchema = z.object({
|
||||
})
|
||||
|
||||
export function MemberForm({ space }: Props) {
|
||||
const { isOpen, setIsOpen } = useMemberDialog()
|
||||
const { setIsOpen } = useMemberDialog()
|
||||
const [loading, setLoading] = useState(false)
|
||||
useQueryEthBalance()
|
||||
const trade = useSubscribe(space)
|
||||
@@ -56,13 +56,13 @@ export function MemberForm({ space }: Props) {
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
type: TradeType.BUY,
|
||||
type: SubscriptionType.SUBSCRIBE,
|
||||
token: 'ETH',
|
||||
times: '180',
|
||||
times: '180', // 180 days by default
|
||||
},
|
||||
})
|
||||
|
||||
const isSubscribe = form.watch('type') === 'BUY'
|
||||
const isSubscribe = form.watch('type') === SubscriptionType.SUBSCRIBE
|
||||
const token = form.watch('token')
|
||||
const times = form.watch('times')
|
||||
|
||||
@@ -86,7 +86,7 @@ export function MemberForm({ space }: Props) {
|
||||
}, [isSubscribe, token, space.symbolName])
|
||||
|
||||
async function onSubmit(data: z.infer<typeof FormSchema>) {
|
||||
const isSubscribe = data.type === 'BUY'
|
||||
const isSubscribe = data.type === SubscriptionType.SUBSCRIBE
|
||||
|
||||
setLoading(true)
|
||||
const amount = getAmount(data.token, data.times, isSubscribe)
|
||||
@@ -128,13 +128,13 @@ export function MemberForm({ space }: Props) {
|
||||
>
|
||||
<ToggleGroupItem
|
||||
className="data-[state=on]:bg-white ring-black bg-accent text-sm font-semibold flex-1 h-full"
|
||||
value={TradeType.BUY}
|
||||
value={SubscriptionType.SUBSCRIBE}
|
||||
>
|
||||
Subscribe
|
||||
</ToggleGroupItem>
|
||||
|
||||
<ToggleGroupItem
|
||||
value={TradeType.SELL}
|
||||
value={SubscriptionType.UNSUBSCRIBE}
|
||||
className="data-[state=on]:bg-white ring-black bg-accent text-sm font-semibold flex-1 h-full"
|
||||
>
|
||||
Unsubscribe
|
||||
|
||||
@@ -3,21 +3,18 @@ import { useMembers } from '@/hooks/useMembers'
|
||||
import { refetchSpaces } from '@/hooks/useSpaces'
|
||||
import { useSubscription } from '@/hooks/useSubscription'
|
||||
import { spaceAbi } from '@/lib/abi'
|
||||
import { TradeType } from '@/lib/constants'
|
||||
import { SubscriptionType } from '@/lib/constants'
|
||||
import { extractErrorMessage } from '@/lib/extractErrorMessage'
|
||||
import { precision } from '@/lib/math'
|
||||
import { api } from '@/lib/trpc'
|
||||
import { wagmiConfig } from '@/lib/wagmi'
|
||||
import { RouterOutputs } from '@/server/_app'
|
||||
import { Post } from '@prisma/client'
|
||||
import {
|
||||
readContract,
|
||||
waitForTransactionReceipt,
|
||||
writeContract,
|
||||
} from '@wagmi/core'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { toast } from 'sonner'
|
||||
import { Address, isAddress, zeroAddress } from 'viem'
|
||||
import { Address } from 'viem'
|
||||
import { useWriteContract } from 'wagmi'
|
||||
|
||||
export function useSubscribe(space: RouterOutputs['space']['byId']) {
|
||||
@@ -32,9 +29,18 @@ export function useSubscribe(space: RouterOutputs['space']['byId']) {
|
||||
isSubscribe: boolean,
|
||||
duration: number,
|
||||
) => {
|
||||
const tradeType = isSubscribe ? TradeType.BUY : TradeType.SELL
|
||||
const subscriptionType = isSubscribe
|
||||
? SubscriptionType.SUBSCRIBE
|
||||
: SubscriptionType.UNSUBSCRIBE
|
||||
try {
|
||||
if (isSubscribe) {
|
||||
console.log(
|
||||
'=====amount:',
|
||||
amount,
|
||||
'space.spaceAddress:',
|
||||
space.spaceAddress,
|
||||
)
|
||||
|
||||
const hash = await writeContractAsync({
|
||||
address: space.spaceAddress as Address,
|
||||
abi: spaceAbi,
|
||||
@@ -62,9 +68,8 @@ export function useSubscribe(space: RouterOutputs['space']['byId']) {
|
||||
functionName: 'getSubscription',
|
||||
args: [address],
|
||||
})
|
||||
console.log('========subscription.info:', info)
|
||||
|
||||
await api.trade.tradeSpaceKey.mutate({
|
||||
await api.subscriptionRecord.upsertSubscription.mutate({
|
||||
spaceId: space.id,
|
||||
tradeDuration: duration,
|
||||
start: Number(info.start),
|
||||
@@ -73,7 +78,7 @@ export function useSubscribe(space: RouterOutputs['space']['byId']) {
|
||||
amount: String(info.amount),
|
||||
consumed: String(info.consumed),
|
||||
|
||||
type: tradeType,
|
||||
type: subscriptionType,
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
@@ -82,9 +87,9 @@ export function useSubscribe(space: RouterOutputs['space']['byId']) {
|
||||
refetchSpaces(),
|
||||
])
|
||||
|
||||
toast.success('Buy Key successful!')
|
||||
toast.success('Subscribe successful!')
|
||||
} catch (error) {
|
||||
console.log('=======>>>>error:', error)
|
||||
console.log('=======>>>>error:', JSON.stringify(error))
|
||||
const msg = extractErrorMessage(error)
|
||||
toast.error(msg)
|
||||
} finally {
|
||||
|
||||
47
components/spaceToken/AmountInput.tsx
Normal file
47
components/spaceToken/AmountInput.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import { ReactNode } from 'react'
|
||||
import { matchNumber } from '@/lib/utils'
|
||||
|
||||
interface Props {
|
||||
symbolName: string
|
||||
icon: ReactNode
|
||||
disabled?: boolean
|
||||
value: string
|
||||
onChange: (value: string) => void
|
||||
}
|
||||
|
||||
export const AmountInput = ({
|
||||
symbolName,
|
||||
icon,
|
||||
value,
|
||||
onChange,
|
||||
disabled = false,
|
||||
}: Props) => {
|
||||
return (
|
||||
<div className="flex items-center gap-1 h-9">
|
||||
<input
|
||||
type="text"
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
onChange={(e) => {
|
||||
let value = e.target.value
|
||||
if ((e.nativeEvent as any)?.data === '。') {
|
||||
value = value.replace('。', '.')
|
||||
}
|
||||
|
||||
if (!matchNumber(value, 8) && value.length) {
|
||||
if (/^\.\d+$/.test(value)) {
|
||||
onChange?.('0' + value)
|
||||
e.preventDefault()
|
||||
}
|
||||
return
|
||||
}
|
||||
onChange(e.target.value)
|
||||
}}
|
||||
placeholder="0.0"
|
||||
className="font-bold text-2xl text-black pl-0 w-full border-none focus:border-none outline-none bg-transparent h-full"
|
||||
/>
|
||||
{icon}
|
||||
<span className="text-lg font-semibold">{symbolName}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
import { ChangeEvent, useMemo, useState } from 'react'
|
||||
import { useTokenKxy } from '@/hooks/useTokenKxy'
|
||||
import { precision } from '@/lib/math'
|
||||
import { Space } from '@prisma/client'
|
||||
import { Address } from 'viem'
|
||||
import { Button } from '../ui/button'
|
||||
import { BuyBtn } from './BuyBtn'
|
||||
import { formatAmount } from './hooks/useSpaceTokenBalance'
|
||||
|
||||
interface Props {
|
||||
ethBalance: string
|
||||
tokenBalance: bigint | undefined
|
||||
isConnected: boolean
|
||||
space: Space
|
||||
}
|
||||
|
||||
export const Buy = ({
|
||||
space,
|
||||
ethBalance,
|
||||
tokenBalance,
|
||||
isConnected,
|
||||
}: Props) => {
|
||||
const [ethAmount, setEthAmount] = useState<string>('0')
|
||||
const [purchasedAmount, setPurchasedAmount] = useState<string>('0')
|
||||
const { updateTokenKxy, getBuyTokenAmount } = useTokenKxy()
|
||||
|
||||
const isAmountValid =
|
||||
parseFloat(ethAmount) > 0 && parseFloat(purchasedAmount) > 0
|
||||
|
||||
const isInsufficientBalance = parseFloat(ethBalance) < parseFloat(ethAmount)
|
||||
|
||||
const validateAndSetEthAmount = (value: string) => {
|
||||
// Validate and format input
|
||||
if (/^\d*\.?\d*$/.test(value) && !value.startsWith('.')) {
|
||||
const formattedValue = formatAmount(value)
|
||||
setEthAmount(formattedValue)
|
||||
const decimalAmount = getBuyTokenAmount(
|
||||
precision.toExactDecimalBigint(value),
|
||||
)
|
||||
if (!Number(value) || !decimalAmount) {
|
||||
setPurchasedAmount('')
|
||||
} else {
|
||||
setPurchasedAmount(precision.toExactDecimalString(decimalAmount))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const validateAndsetPurchasedAmount = (value: string) => {
|
||||
// Validate and format input
|
||||
// if (/^\d*\.?\d*$/.test(value) && !value.startsWith('.')) { }
|
||||
}
|
||||
|
||||
const handleMax = () => {
|
||||
setEthAmount(ethBalance)
|
||||
const decimalAmount = getBuyTokenAmount(
|
||||
precision.toExactDecimalBigint(ethBalance),
|
||||
)
|
||||
if (!ethAmount || !decimalAmount) {
|
||||
setPurchasedAmount('')
|
||||
} else {
|
||||
setPurchasedAmount(precision.toExactDecimalString(decimalAmount))
|
||||
}
|
||||
}
|
||||
|
||||
const displayBalance = useMemo(() => {
|
||||
if (tokenBalance) {
|
||||
return Number(precision.toExactDecimalString(tokenBalance)).toFixed(4)
|
||||
}
|
||||
|
||||
return '0.0000'
|
||||
}, [tokenBalance])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-2 bg-gray-100 rounded-[16px] p-[16px] border border-transparent hover:border-[#18181b] transition-colors duration-300">
|
||||
<div className="text-[12px]">Sell</div>
|
||||
<div className="flex font-[600] items-center gap-1">
|
||||
<input
|
||||
type="text"
|
||||
value={ethAmount}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
validateAndSetEthAmount(e.target.value)
|
||||
}
|
||||
placeholder="Amount in ETH"
|
||||
className="p-2 font-[600] text-[24px] text-[#222222] pl-0 bg-gray-100 rounded w-full border-none focus:border-none outline-none"
|
||||
/>
|
||||
<img src="/eth.png" alt="ETH" className="w-[20px] h-auto" />
|
||||
<span className="text-[18px]">ETH</span>
|
||||
</div>
|
||||
<div className="text-right text-[#222222]">
|
||||
Balance: {ethBalance}
|
||||
<Button
|
||||
onClick={handleMax}
|
||||
disabled={!ethBalance}
|
||||
className="h-[20px] cursor-pointer text-white px-[4px] rounded ml-2"
|
||||
>
|
||||
Max
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-4 bg-gray-100 rounded-[16px] p-[16px] border border-transparent hover:border-[#18181b] transition-colors duration-300">
|
||||
<div className="text-[12px]">Buy</div>
|
||||
<div className="flex font-[600] items-center gap-1">
|
||||
<input
|
||||
type="text"
|
||||
value={purchasedAmount}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
validateAndsetPurchasedAmount(e.target.value)
|
||||
}
|
||||
placeholder="Amount in PenX"
|
||||
className="p-2 font-[500] text-[24px] text-[#222222] pl-0 bg-gray-100 rounded w-full border-none focus:border-none outline-none"
|
||||
/>
|
||||
<img
|
||||
src="https://cryptologos.cc/logos/bitcoin-btc-logo.png"
|
||||
alt="PenX"
|
||||
className="w-[20px] h-auto"
|
||||
/>
|
||||
<span className="text-[18px]">{space?.name}</span>
|
||||
</div>
|
||||
<div className="text-right text-[#222222]">
|
||||
Balance: {displayBalance}
|
||||
</div>
|
||||
</div>
|
||||
<BuyBtn
|
||||
ethAmount={ethAmount}
|
||||
isConnected={isConnected}
|
||||
handleSwap={() => {
|
||||
setEthAmount('')
|
||||
setPurchasedAmount('')
|
||||
updateTokenKxy(space.spaceAddress as Address)
|
||||
}}
|
||||
isInsufficientBalance={isInsufficientBalance}
|
||||
isAmountValid={isAmountValid}
|
||||
space={space}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
import { useQueryEthBalance } from '@/hooks/useEthBalance'
|
||||
import { useTrades } from '@/hooks/useTrades'
|
||||
import { spaceAbi } from '@/lib/abi'
|
||||
import { TradeType } from '@/lib/constants'
|
||||
import { extractErrorMessage } from '@/lib/extractErrorMessage'
|
||||
import { precision } from '@/lib/math'
|
||||
import { api } from '@/lib/trpc'
|
||||
import { wagmiConfig } from '@/lib/wagmi'
|
||||
import { Space } from '@prisma/client'
|
||||
import { waitForTransactionReceipt } from '@wagmi/core'
|
||||
@@ -14,6 +18,7 @@ import { useSpaceTokenBalance } from './hooks/useSpaceTokenBalance'
|
||||
|
||||
interface Props {
|
||||
ethAmount: string
|
||||
purchasedAmount: string
|
||||
handleSwap: () => void
|
||||
isInsufficientBalance: boolean
|
||||
isAmountValid: boolean
|
||||
@@ -23,6 +28,7 @@ interface Props {
|
||||
|
||||
export const BuyBtn = ({
|
||||
ethAmount,
|
||||
purchasedAmount,
|
||||
isInsufficientBalance,
|
||||
isAmountValid,
|
||||
handleSwap,
|
||||
@@ -31,10 +37,12 @@ export const BuyBtn = ({
|
||||
}: Props) => {
|
||||
const { writeContractAsync, isPending } = useWriteContract()
|
||||
const balance = useSpaceTokenBalance()
|
||||
const { refetch: refetchEth } = useQueryEthBalance()
|
||||
const trade = useTrades()
|
||||
|
||||
const onBuy = async () => {
|
||||
try {
|
||||
const value = precision.token(parseFloat(ethAmount), 18)
|
||||
const value = precision.token(ethAmount, 18)
|
||||
const hash = await writeContractAsync({
|
||||
address: space.spaceAddress as Address,
|
||||
abi: spaceAbi,
|
||||
@@ -43,7 +51,18 @@ export const BuyBtn = ({
|
||||
})
|
||||
|
||||
await waitForTransactionReceipt(wagmiConfig, { hash })
|
||||
await balance.refetch()
|
||||
await Promise.all([
|
||||
api.trade.create.mutate({
|
||||
spaceId: space.id,
|
||||
type: TradeType.BUY,
|
||||
amountIn: String(value),
|
||||
amountOut: precision.token(purchasedAmount).toString(),
|
||||
}),
|
||||
balance.refetch(),
|
||||
refetchEth(),
|
||||
])
|
||||
|
||||
trade.refetch()
|
||||
handleSwap()
|
||||
toast.success(`${space?.name} bought successfully!`)
|
||||
} catch (error) {
|
||||
@@ -56,7 +75,7 @@ export const BuyBtn = ({
|
||||
<>
|
||||
{isConnected ? (
|
||||
<Button
|
||||
className="w-full h-[58px]"
|
||||
className="w-full h-[50px]"
|
||||
disabled={!isAmountValid || isInsufficientBalance || isPending}
|
||||
onClick={() => onBuy()}
|
||||
>
|
||||
|
||||
113
components/spaceToken/BuyPanel.tsx
Normal file
113
components/spaceToken/BuyPanel.tsx
Normal file
@@ -0,0 +1,113 @@
|
||||
import { useState } from 'react'
|
||||
import { useChainSpace, useQueryChainSpace } from '@/hooks/useChainSpace'
|
||||
import { useEthBalance } from '@/hooks/useEthBalance'
|
||||
import { precision } from '@/lib/math'
|
||||
import { toFloorFixed } from '@/lib/utils'
|
||||
import { Space } from '@prisma/client'
|
||||
import { Button } from '../ui/button'
|
||||
import { AmountInput } from './AmountInput'
|
||||
import { BuyBtn } from './BuyBtn'
|
||||
import { EthBalance } from './EthBalance'
|
||||
import { SpaceTokenBalance } from './SpaceTokenBalance'
|
||||
|
||||
interface Props {
|
||||
isConnected: boolean
|
||||
space: Space
|
||||
}
|
||||
|
||||
export const BuyPanel = ({ space, isConnected }: Props) => {
|
||||
const [ethAmount, setEthAmount] = useState<string>('')
|
||||
const [purchasedAmount, setPurchasedAmount] = useState<string>('')
|
||||
const { refetch } = useQueryChainSpace()
|
||||
const { ethBalance } = useEthBalance()
|
||||
const { space: chainSpace } = useChainSpace()
|
||||
|
||||
const isAmountValid =
|
||||
parseFloat(ethAmount) > 0 && parseFloat(purchasedAmount) > 0
|
||||
|
||||
const isInsufficientBalance = ethBalance.valueDecimal < parseFloat(ethAmount)
|
||||
|
||||
const handleEthChange = (value: string) => {
|
||||
setEthAmount(value)
|
||||
if (!value) {
|
||||
return setPurchasedAmount('')
|
||||
}
|
||||
|
||||
const tokenAmountDecimal = precision.toDecimal(
|
||||
chainSpace.getTokenAmount(precision.token(value)),
|
||||
)
|
||||
setPurchasedAmount(toFloorFixed(tokenAmountDecimal, 4).toString())
|
||||
}
|
||||
|
||||
const validateAndSetPurchasedAmount = (value: string) => {
|
||||
// Validate and format input
|
||||
// if (/^\d*\.?\d*$/.test(value) && !value.startsWith('.')) { }
|
||||
}
|
||||
|
||||
const handleMax = () => {
|
||||
setEthAmount(toFloorFixed(ethBalance.valueDecimal, 6).toString())
|
||||
|
||||
const tokenAmountDecimal = precision.toDecimal(
|
||||
chainSpace.getTokenAmount(ethBalance.value),
|
||||
)
|
||||
setPurchasedAmount(toFloorFixed(tokenAmountDecimal, 4).toString())
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-2 bg-gray-100 rounded-xl p-4">
|
||||
<div className="text-sm">Sell</div>
|
||||
<AmountInput
|
||||
symbolName="ETH"
|
||||
icon={<img src="/eth.png" alt="ETH" className="w-5 h-auto" />}
|
||||
value={ethAmount}
|
||||
onChange={(value) => handleEthChange(value)}
|
||||
/>
|
||||
<div className="flex items-center justify-end gap-2 h-6">
|
||||
<EthBalance></EthBalance>
|
||||
<Button
|
||||
onClick={handleMax}
|
||||
disabled={!ethBalance}
|
||||
className="h-6 cursor-pointer text-xs text-white rounded-md px-2"
|
||||
>
|
||||
Max
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-4 bg-gray-100 rounded-xl p-4">
|
||||
<div className="text-sm">Buy</div>
|
||||
<AmountInput
|
||||
symbolName={space.symbolName}
|
||||
disabled
|
||||
icon={
|
||||
<img
|
||||
src={space.logo || ''}
|
||||
alt={space.symbolName}
|
||||
className="w-5 h-auto"
|
||||
/>
|
||||
}
|
||||
value={purchasedAmount}
|
||||
onChange={(value) => validateAndSetPurchasedAmount(value)}
|
||||
/>
|
||||
|
||||
<div className="flex items-center justify-end gap-2 h-6">
|
||||
<SpaceTokenBalance />
|
||||
</div>
|
||||
</div>
|
||||
<BuyBtn
|
||||
ethAmount={ethAmount}
|
||||
purchasedAmount={purchasedAmount}
|
||||
isConnected={isConnected}
|
||||
handleSwap={() => {
|
||||
setEthAmount('')
|
||||
setPurchasedAmount('')
|
||||
refetch()
|
||||
}}
|
||||
isInsufficientBalance={isInsufficientBalance}
|
||||
isAmountValid={isAmountValid}
|
||||
space={space}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
17
components/spaceToken/EthBalance.tsx
Normal file
17
components/spaceToken/EthBalance.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
'use client'
|
||||
|
||||
import { useEthBalance } from '@/hooks/useEthBalance'
|
||||
import { Skeleton } from '../ui/skeleton'
|
||||
|
||||
export const EthBalance = () => {
|
||||
const { ethBalance } = useEthBalance()
|
||||
if (!ethBalance.valueDecimal) return <Skeleton></Skeleton>
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
<span className="i-[iconoir--wallet-solid] w-5 h-5 bg-neutral-400"></span>
|
||||
<div className="text-sm text-neutral-500">
|
||||
{ethBalance.valueFormatted}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
import { ChangeEvent, useMemo, useState } from 'react'
|
||||
import { Button } from '../ui/button'
|
||||
import { SellBtn } from './SellBtn'
|
||||
import { precision } from '@/lib/math'
|
||||
import { useTokenKxy } from '@/hooks/useTokenKxy'
|
||||
import { Address } from 'viem'
|
||||
import { Space } from '@prisma/client'
|
||||
import { formatAmount } from './hooks/useSpaceTokenBalance'
|
||||
|
||||
interface Props {
|
||||
ethBalance: string
|
||||
tokenBalance: bigint | undefined
|
||||
isConnected: boolean
|
||||
space: Space
|
||||
}
|
||||
|
||||
export const Sell = ({ space, ethBalance, tokenBalance, isConnected }: Props) => {
|
||||
const [ethAmount, setEthAmount] = useState<string>('0')
|
||||
const [purchasedAmount, setPurchasedAmount] = useState<string>('0')
|
||||
|
||||
// const isAmountValid = parseFloat(ethAmount) > 0 && parseFloat(purchasedAmount) > 0
|
||||
// TODO: please add eth judgment logic
|
||||
const isAmountValid = parseFloat(purchasedAmount) > 0
|
||||
|
||||
const { updateTokenKxy, getSellEthAmount } = useTokenKxy()
|
||||
|
||||
const validateAndSetEthAmount = (value: string) => {
|
||||
// Validate and format input
|
||||
// if (/^\d*\.?\d*$/.test(value) && !value.startsWith('.')) { }
|
||||
}
|
||||
|
||||
const validateAndsetPurchasedAmount = (value: string) => {
|
||||
// Validate and format input
|
||||
if (/^\d*\.?\d*$/.test(value) && !value.startsWith('.')) {
|
||||
const formattedValue = formatAmount(value)
|
||||
setPurchasedAmount(formattedValue)
|
||||
const decimalAmount = getSellEthAmount(precision.toExactDecimalBigint(value))
|
||||
if (!Number(value) || !decimalAmount) {
|
||||
setEthAmount('')
|
||||
} else {
|
||||
setEthAmount(precision.toExactDecimalString(decimalAmount))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleMax = () => {
|
||||
if (tokenBalance) {
|
||||
setPurchasedAmount(precision.toExactDecimalString(tokenBalance))
|
||||
const decimalAmount = getSellEthAmount(tokenBalance)
|
||||
if (!ethAmount || !decimalAmount) {
|
||||
setEthAmount('')
|
||||
} else {
|
||||
setEthAmount(precision.toExactDecimalString(decimalAmount))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const { decimalBalance, displayBalance } = useMemo(() => {
|
||||
if (tokenBalance) {
|
||||
const decimal = precision.toExactDecimalString(tokenBalance);
|
||||
return {
|
||||
decimalBalance: Number(decimal),
|
||||
displayBalance: Number(decimal).toFixed(4),
|
||||
};
|
||||
}
|
||||
return {
|
||||
decimalBalance: 0,
|
||||
displayBalance: '0.0000',
|
||||
};
|
||||
}, [tokenBalance]);
|
||||
|
||||
const isInsufficientBalance = decimalBalance < parseFloat(purchasedAmount)
|
||||
|
||||
return <>
|
||||
<div className="mb-2 bg-gray-100 rounded-[16px] p-[16px] border border-transparent hover:border-[#18181b] transition-colors duration-300">
|
||||
<div className="text-[12px]">Sell</div>
|
||||
<div className="flex font-[600] items-center gap-1">
|
||||
<input
|
||||
type="text"
|
||||
value={purchasedAmount}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
validateAndsetPurchasedAmount(e.target.value)
|
||||
}
|
||||
placeholder="Amount in PenX"
|
||||
className="p-2 font-[500] text-[24px] text-[#222222] pl-0 bg-gray-100 rounded w-full border-none focus:border-none outline-none"
|
||||
/>
|
||||
<img
|
||||
src="https://cryptologos.cc/logos/bitcoin-btc-logo.png"
|
||||
alt="PenX"
|
||||
className="w-[20px] h-auto"
|
||||
/>
|
||||
<span className="text-[18px]">{space?.name}</span>
|
||||
</div>
|
||||
<div className="text-right text-[#222222]">
|
||||
Balance: {displayBalance}
|
||||
<Button
|
||||
onClick={handleMax}
|
||||
disabled={decimalBalance <= 0}
|
||||
className="h-[20px] cursor-pointer text-white px-[4px] rounded ml-2"
|
||||
>
|
||||
Max
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-4 bg-gray-100 rounded-[16px] p-[16px] border border-transparent hover:border-[#18181b] transition-colors duration-300">
|
||||
<div className="text-[12px]">Buy</div>
|
||||
<div className="flex font-[600] items-center gap-1">
|
||||
<input
|
||||
type="text"
|
||||
value={ethAmount}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
validateAndSetEthAmount(e.target.value)
|
||||
}
|
||||
placeholder="Amount in ETH"
|
||||
className="p-2 font-[600] text-[24px] text-[#222222] pl-0 bg-gray-100 rounded w-full border-none focus:border-none outline-none"
|
||||
/>
|
||||
<img src="/eth.png" alt="ETH" className="w-[20px] h-auto" />
|
||||
<span className="text-[18px]">ETH</span>
|
||||
</div>
|
||||
<div className="text-right text-[#222222]">
|
||||
Balance: {ethBalance}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SellBtn
|
||||
ethAmount={ethAmount}
|
||||
purchasedAmount={purchasedAmount}
|
||||
isConnected={isConnected}
|
||||
handleSwap={() => {
|
||||
setEthAmount('')
|
||||
setPurchasedAmount('')
|
||||
updateTokenKxy(space.spaceAddress as Address)
|
||||
}}
|
||||
isInsufficientBalance={isInsufficientBalance}
|
||||
isAmountValid={isAmountValid}
|
||||
space={space}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
import { useEthBalance, useQueryEthBalance } from '@/hooks/useEthBalance'
|
||||
import { useTrades } from '@/hooks/useTrades'
|
||||
import { erc20Abi, spaceAbi } from '@/lib/abi'
|
||||
import { TradeType } from '@/lib/constants'
|
||||
import { extractErrorMessage } from '@/lib/extractErrorMessage'
|
||||
import { precision } from '@/lib/math'
|
||||
import { api } from '@/lib/trpc'
|
||||
import { wagmiConfig } from '@/lib/wagmi'
|
||||
import { Space } from '@prisma/client'
|
||||
import { waitForTransactionReceipt } from '@wagmi/core'
|
||||
@@ -23,6 +27,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export const SellBtn = ({
|
||||
ethAmount,
|
||||
purchasedAmount,
|
||||
isInsufficientBalance,
|
||||
isAmountValid,
|
||||
@@ -32,6 +37,8 @@ export const SellBtn = ({
|
||||
}: Props) => {
|
||||
const { writeContractAsync, isPending } = useWriteContract()
|
||||
const balance = useSpaceTokenBalance()
|
||||
const { refetch: refetchEth } = useQueryEthBalance()
|
||||
const trade = useTrades()
|
||||
|
||||
const onSell = async () => {
|
||||
try {
|
||||
@@ -54,7 +61,18 @@ export const SellBtn = ({
|
||||
})
|
||||
|
||||
await waitForTransactionReceipt(wagmiConfig, { hash })
|
||||
await balance.refetch()
|
||||
|
||||
await Promise.all([
|
||||
api.trade.create.mutate({
|
||||
spaceId: space.id,
|
||||
type: TradeType.SELL,
|
||||
amountIn: String(value),
|
||||
amountOut: precision.token(ethAmount).toString(),
|
||||
}),
|
||||
balance.refetch(),
|
||||
refetchEth(),
|
||||
])
|
||||
trade.refetch()
|
||||
handleSwap()
|
||||
toast.success(`${space?.name} sell successfully!`)
|
||||
} catch (error) {
|
||||
@@ -68,14 +86,14 @@ export const SellBtn = ({
|
||||
<>
|
||||
{isConnected ? (
|
||||
<Button
|
||||
className="w-full h-[58px]"
|
||||
className="w-full h-[50px]"
|
||||
disabled={!isAmountValid || isInsufficientBalance || isPending}
|
||||
onClick={() => onSell()}
|
||||
>
|
||||
{isPending || balance.isPending ? (
|
||||
<LoadingDots color="white" />
|
||||
) : isInsufficientBalance ? (
|
||||
`Insufficient ${space.name} balance`
|
||||
`Insufficient ${space.symbolName} balance`
|
||||
) : isAmountValid ? (
|
||||
'Sell'
|
||||
) : (
|
||||
|
||||
133
components/spaceToken/SellPanel.tsx
Normal file
133
components/spaceToken/SellPanel.tsx
Normal file
@@ -0,0 +1,133 @@
|
||||
import { ChangeEvent, useMemo, useState } from 'react'
|
||||
import { useChainSpace, useQueryChainSpace } from '@/hooks/useChainSpace'
|
||||
import { useEthBalance, useQueryEthBalance } from '@/hooks/useEthBalance'
|
||||
import { precision } from '@/lib/math'
|
||||
import { toFloorFixed } from '@/lib/utils'
|
||||
import { Space } from '@prisma/client'
|
||||
import { Address } from 'viem'
|
||||
import { Button } from '../ui/button'
|
||||
import { AmountInput } from './AmountInput'
|
||||
import { EthBalance } from './EthBalance'
|
||||
import {
|
||||
formatAmount,
|
||||
useSpaceTokenBalance,
|
||||
} from './hooks/useSpaceTokenBalance'
|
||||
import { SellBtn } from './SellBtn'
|
||||
import { SpaceTokenBalance } from './SpaceTokenBalance'
|
||||
|
||||
interface Props {
|
||||
isConnected: boolean
|
||||
space: Space
|
||||
}
|
||||
|
||||
export const SellPanel = ({ space, isConnected }: Props) => {
|
||||
const [ethAmount, setEthAmount] = useState<string>('')
|
||||
const [purchasedAmount, setPurchasedAmount] = useState<string>('')
|
||||
const { space: chainSpace } = useChainSpace()
|
||||
const { refetch: refetchChainSpace } = useQueryChainSpace()
|
||||
|
||||
// const isAmountValid = parseFloat(ethAmount) > 0 && parseFloat(purchasedAmount) > 0
|
||||
// TODO: please add eth judgment logic
|
||||
const isAmountValid = parseFloat(purchasedAmount) > 0
|
||||
|
||||
const { data: tokenBalance } = useSpaceTokenBalance()
|
||||
const { ethBalance } = useEthBalance()
|
||||
|
||||
const validateAndSetEthAmount = (value: string) => {
|
||||
// Validate and format input
|
||||
// if (/^\d*\.?\d*$/.test(value) && !value.startsWith('.')) { }
|
||||
}
|
||||
|
||||
const handleTokenChange = (value: string) => {
|
||||
setPurchasedAmount(value)
|
||||
if (!value) {
|
||||
return setEthAmount('')
|
||||
}
|
||||
|
||||
const ethAmountDecimal = precision.toDecimal(
|
||||
chainSpace.getEthAmount(precision.token(value)),
|
||||
)
|
||||
setEthAmount(toFloorFixed(ethAmountDecimal, 4).toString())
|
||||
}
|
||||
|
||||
const handleMax = () => {
|
||||
if (!tokenBalance) return
|
||||
|
||||
setPurchasedAmount(
|
||||
toFloorFixed(precision.toDecimal(tokenBalance), 4).toString(),
|
||||
)
|
||||
|
||||
const ethAmountDecimal = precision.toDecimal(
|
||||
chainSpace.getEthAmount(tokenBalance),
|
||||
)
|
||||
|
||||
setEthAmount(toFloorFixed(ethAmountDecimal, 4).toString())
|
||||
}
|
||||
|
||||
const isInsufficientBalance =
|
||||
precision.toDecimal(tokenBalance! || '0') < parseFloat(purchasedAmount)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-2 bg-gray-100 rounded-xl p-4">
|
||||
<div className="text-sm">Sell</div>
|
||||
|
||||
<AmountInput
|
||||
symbolName={space.symbolName}
|
||||
icon={
|
||||
<img
|
||||
src={space.logo || ''}
|
||||
alt={space.symbolName}
|
||||
className="w-5 h-auto"
|
||||
/>
|
||||
}
|
||||
value={purchasedAmount}
|
||||
onChange={(value) => handleTokenChange(value)}
|
||||
/>
|
||||
|
||||
<div className="flex items-center justify-end gap-2 h-6">
|
||||
<SpaceTokenBalance />
|
||||
<Button
|
||||
onClick={handleMax}
|
||||
disabled={
|
||||
typeof tokenBalance === undefined ||
|
||||
precision.toDecimal(tokenBalance!) <= 0
|
||||
}
|
||||
className="h-6 cursor-pointer text-xs text-white rounded-md px-2"
|
||||
>
|
||||
Max
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-4 bg-gray-100 rounded-xl p-4">
|
||||
<div className="text-sm">Buy</div>
|
||||
|
||||
<AmountInput
|
||||
symbolName="ETH"
|
||||
disabled
|
||||
icon={<img src="/eth.png" alt="ETH" className="w-5 h-auto" />}
|
||||
value={ethAmount}
|
||||
onChange={(value) => validateAndSetEthAmount(value)}
|
||||
/>
|
||||
<div className="flex items-center justify-end gap-2 h-6">
|
||||
<EthBalance />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SellBtn
|
||||
ethAmount={ethAmount}
|
||||
purchasedAmount={purchasedAmount}
|
||||
isConnected={isConnected}
|
||||
handleSwap={() => {
|
||||
setEthAmount('')
|
||||
setPurchasedAmount('')
|
||||
refetchChainSpace()
|
||||
}}
|
||||
isInsufficientBalance={isInsufficientBalance}
|
||||
isAmountValid={isAmountValid}
|
||||
space={space}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
18
components/spaceToken/SpaceTokenBalance.tsx
Normal file
18
components/spaceToken/SpaceTokenBalance.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
'use client'
|
||||
|
||||
import { precision } from '@/lib/math'
|
||||
import { Skeleton } from '../ui/skeleton'
|
||||
import { useSpaceTokenBalance } from './hooks/useSpaceTokenBalance'
|
||||
|
||||
export const SpaceTokenBalance = () => {
|
||||
const { isLoading, data } = useSpaceTokenBalance()
|
||||
if (isLoading) return <Skeleton></Skeleton>
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
<span className="i-[iconoir--wallet-solid] w-5 h-5 bg-neutral-400"></span>
|
||||
<div className="text-sm text-neutral-500">
|
||||
{precision.toDecimal(data!).toFixed(4)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -83,7 +83,7 @@ export class Space {
|
||||
|
||||
getTokenPricePerSecond() {
|
||||
const ethPricePerSecond = this.getEthPricePerSecond()
|
||||
const { tokenAmount } = this.getTokenAmount(ethPricePerSecond)
|
||||
const tokenAmount = this.getTokenAmount(ethPricePerSecond)
|
||||
return tokenAmount
|
||||
}
|
||||
|
||||
@@ -93,10 +93,7 @@ export class Space {
|
||||
const newX = this.x + ethAmountAfterFee
|
||||
const newY = this.k / newX
|
||||
const tokenAmount = this.y - newY
|
||||
return {
|
||||
tokenAmount,
|
||||
tokenAmountFormatted: toFloorFixed(Number(tokenAmount), 2),
|
||||
}
|
||||
return tokenAmount
|
||||
}
|
||||
|
||||
getEthAmount(tokenAmount: bigint) {
|
||||
@@ -105,9 +102,6 @@ export class Space {
|
||||
const newY = this.y + tokenAmountAfterFee
|
||||
const newX = this.k / newY
|
||||
const ethAmount = this.x - newX
|
||||
return {
|
||||
ethAmount,
|
||||
ethAmountFormatted: toFloorFixed(Number(ethAmount), 2),
|
||||
}
|
||||
return ethAmount
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { trpc } from '@/lib/trpc'
|
||||
|
||||
export function useSpaceTrades(spaceId: string) {
|
||||
const { data: trades = [], ...rest } =
|
||||
trpc.trade.listBySpaceId.useQuery(spaceId)
|
||||
return { trades, ...rest }
|
||||
export function useSubscriptionRecords(spaceId: string) {
|
||||
const { data: records = [], ...rest } =
|
||||
trpc.subscriptionRecord.listBySpaceId.useQuery(spaceId)
|
||||
return { records, ...rest }
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
import { spaceAbi } from '@/lib/abi'
|
||||
import { wagmiConfig } from '@/lib/wagmi'
|
||||
import { readContract, readContracts } from '@wagmi/core'
|
||||
import { atom, useAtom } from 'jotai'
|
||||
import { Address } from 'viem'
|
||||
|
||||
interface IKxy {
|
||||
k: bigint
|
||||
x: bigint
|
||||
y: bigint
|
||||
}
|
||||
|
||||
const tokenKxyAtom = atom<IKxy>({
|
||||
k: BigInt(0),
|
||||
x: BigInt(0),
|
||||
y: BigInt(0),
|
||||
})
|
||||
|
||||
const FEE_RATE = BigInt(1)
|
||||
|
||||
export function useTokenKxy() {
|
||||
const [tokenKxy, setTokenKxy] = useAtom(tokenKxyAtom)
|
||||
|
||||
const updateTokenKxy = async (spaceAddress: Address) => {
|
||||
try {
|
||||
const { x, y, k } = await readContract(wagmiConfig, {
|
||||
address: spaceAddress,
|
||||
abi: spaceAbi,
|
||||
functionName: 'getSpaceInfo',
|
||||
})
|
||||
|
||||
setTokenKxy({ k, x, y })
|
||||
} catch (error) {
|
||||
console.error('Failed to update kxy values:', error)
|
||||
}
|
||||
}
|
||||
|
||||
function getBuyTokenAmount(ethAmount: bigint): bigint {
|
||||
const fee = (ethAmount * FEE_RATE) / BigInt(100)
|
||||
const ethAmountAfterFee = ethAmount - fee
|
||||
const newX = tokenKxy.x + ethAmountAfterFee
|
||||
const newY = tokenKxy.k / newX
|
||||
const tokenAmount = tokenKxy.y - newY
|
||||
|
||||
return tokenAmount
|
||||
}
|
||||
|
||||
function getSellEthAmount(tokenAmount: bigint): bigint {
|
||||
const fee = (tokenAmount * FEE_RATE) / BigInt(100)
|
||||
const tokenAmountAfterFee = tokenAmount - fee
|
||||
const newY = tokenKxy.y + tokenAmountAfterFee
|
||||
const newX = tokenKxy.k / newY
|
||||
const ethAmount = tokenKxy.x - newX
|
||||
|
||||
return ethAmount
|
||||
}
|
||||
|
||||
const getTokenKxy = (): IKxy => {
|
||||
return tokenKxy
|
||||
}
|
||||
|
||||
return { getBuyTokenAmount, getTokenKxy, updateTokenKxy, getSellEthAmount }
|
||||
}
|
||||
13
hooks/useTrades.ts
Normal file
13
hooks/useTrades.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { trpc } from '@/lib/trpc'
|
||||
import { useSpace } from './useSpace'
|
||||
|
||||
export function useTrades() {
|
||||
const { space } = useSpace()
|
||||
const { data: trades = [], ...rest } = trpc.trade.listBySpaceId.useQuery(
|
||||
space.id,
|
||||
{
|
||||
enabled: !!space?.id,
|
||||
},
|
||||
)
|
||||
return { records: trades, ...rest }
|
||||
}
|
||||
@@ -3,6 +3,11 @@ export enum TradeType {
|
||||
SELL = 'SELL',
|
||||
}
|
||||
|
||||
export enum SubscriptionType {
|
||||
SUBSCRIBE = 'SUBSCRIBE',
|
||||
UNSUBSCRIBE = 'UNSUBSCRIBE',
|
||||
}
|
||||
|
||||
export enum TradeSource {
|
||||
MEMBER = 'MEMBER',
|
||||
SPONSOR = 'SPONSOR',
|
||||
|
||||
@@ -34,7 +34,10 @@ export const precision = {
|
||||
return BigInt(parseInt(times(Math.pow(10, decimal), value) as any, 10))
|
||||
},
|
||||
|
||||
toDecimal(value: bigint | number, decimals: number = Decimals.TOKEN) {
|
||||
toDecimal(
|
||||
value: bigint | number | string = '',
|
||||
decimals: number = Decimals.TOKEN,
|
||||
) {
|
||||
if (!value) return 0
|
||||
return div(value.toString(), Math.pow(10, decimals))
|
||||
},
|
||||
@@ -43,8 +46,11 @@ export const precision = {
|
||||
},
|
||||
|
||||
// Maintaining Numeric Precision
|
||||
toExactDecimalString(value: bigint, decimals: number = Decimals.TOKEN): string {
|
||||
if (!value) return "0"
|
||||
toExactDecimalString(
|
||||
value: bigint,
|
||||
decimals: number = Decimals.TOKEN,
|
||||
): string {
|
||||
if (!value) return '0'
|
||||
const factor = BigInt(Math.pow(10, decimals))
|
||||
const integerPart = value / factor
|
||||
const fractionalPart = value % factor
|
||||
@@ -52,10 +58,13 @@ export const precision = {
|
||||
},
|
||||
|
||||
// Maintaining Numeric Precision
|
||||
toExactDecimalBigint(decimalValue: string, decimals: number = Decimals.TOKEN): bigint {
|
||||
const [integerPart, fractionalPart = ""] = decimalValue.split(".")
|
||||
toExactDecimalBigint(
|
||||
decimalValue: string,
|
||||
decimals: number = Decimals.TOKEN,
|
||||
): bigint {
|
||||
const [integerPart, fractionalPart = ''] = decimalValue.split('.')
|
||||
const integerBigInt = BigInt(integerPart) * BigInt(Math.pow(10, decimals))
|
||||
const fractionalBigInt = BigInt(fractionalPart.padEnd(decimals, "0"))
|
||||
const fractionalBigInt = BigInt(fractionalPart.padEnd(decimals, '0'))
|
||||
return integerBigInt + fractionalBigInt
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -49,10 +49,10 @@ export const siweConfig = createSIWEConfig({
|
||||
}
|
||||
},
|
||||
|
||||
// onSignIn: (session?: SIWESession) => {
|
||||
// location.href = '/'
|
||||
// location.reload()
|
||||
// },
|
||||
onSignIn: (session?: SIWESession) => {
|
||||
// location.href = '/'
|
||||
location.reload()
|
||||
},
|
||||
signOut: async () => {
|
||||
try {
|
||||
await signOut({
|
||||
|
||||
@@ -24,7 +24,16 @@ const metadata = {
|
||||
|
||||
// Create wagmiConfig
|
||||
const chains = [
|
||||
arbitrumSepolia,
|
||||
{
|
||||
...arbitrumSepolia,
|
||||
rpcUrls: {
|
||||
default: {
|
||||
http: [
|
||||
'https://arb-sepolia.g.alchemy.com/v2/HI5irVjoVHajk9VrB7FAkpt2Inz1iymo',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
// baseSepolia,
|
||||
// mainnet,
|
||||
// optimism,
|
||||
|
||||
@@ -6,7 +6,7 @@ const { env } = require('./server/env')
|
||||
module.exports = {
|
||||
experimental: {
|
||||
serverActions: {
|
||||
allowedOrigins: ['app.localhost:3000'],
|
||||
// allowedOrigins: ['app.localhost:3000'],
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -42,10 +42,10 @@
|
||||
"@vercel/analytics": "^1.3.1",
|
||||
"@vercel/blob": "^0.15.0",
|
||||
"@vercel/kv": "^1.0.1",
|
||||
"@vercel/postgres": "^0.5.1",
|
||||
"@vercel/postgres": "^0.9.0",
|
||||
"@wagmi/core": "^2.13.4",
|
||||
"@web3modal/siwe": "^5.1.0",
|
||||
"@web3modal/wagmi": "^5.1.0",
|
||||
"@web3modal/siwe": "^5.1.1",
|
||||
"@web3modal/wagmi": "^5.1.1",
|
||||
"ai": "^2.2.22",
|
||||
"big.js": "^6.2.1",
|
||||
"c": "^1.1.1",
|
||||
|
||||
317
pnpm-lock.yaml
generated
317
pnpm-lock.yaml
generated
@@ -96,17 +96,17 @@ dependencies:
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1
|
||||
'@vercel/postgres':
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1
|
||||
specifier: ^0.9.0
|
||||
version: 0.9.0
|
||||
'@wagmi/core':
|
||||
specifier: ^2.13.4
|
||||
version: 2.13.4(@types/react@18.2.37)(react@18.2.0)(typescript@5.2.2)(viem@2.18.2)
|
||||
'@web3modal/siwe':
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
specifier: ^5.1.1
|
||||
version: 5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@web3modal/wagmi':
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(@wagmi/connectors@5.1.1)(@wagmi/core@2.13.4)(ioredis@5.4.1)(react-dom@18.2.0)(react@18.2.0)(viem@2.18.2)(vue@3.3.8)(wagmi@2.12.1)
|
||||
specifier: ^5.1.1
|
||||
version: 5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(@wagmi/connectors@5.1.1)(@wagmi/core@2.13.4)(ioredis@5.4.1)(react-dom@18.2.0)(react@18.2.0)(viem@2.18.2)(vue@3.3.8)(wagmi@2.12.1)
|
||||
ai:
|
||||
specifier: ^2.2.22
|
||||
version: 2.2.22(react@18.2.0)(solid-js@1.8.5)(svelte@4.2.3)(vue@3.3.8)
|
||||
@@ -2685,10 +2685,10 @@ packages:
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/@neondatabase/serverless@0.6.0:
|
||||
resolution: {integrity: sha512-qXxBRYN0m2v8kVQBfMxbzNGn2xFAhTXFibzQlE++NfJ56Shz3m7+MyBBtXDlEH+3Wfa6lToDXf1MElocY4sJ3w==}
|
||||
/@neondatabase/serverless@0.9.4:
|
||||
resolution: {integrity: sha512-D0AXgJh6xkf+XTlsO7iwE2Q1w8981E1cLCPAALMU2YKtkF/1SF6BiAzYARZFYo175ON+b1RNIy9TdSFHm5nteg==}
|
||||
dependencies:
|
||||
'@types/pg': 8.6.6
|
||||
'@types/pg': 8.11.6
|
||||
dev: false
|
||||
|
||||
/@next/env@14.0.2:
|
||||
@@ -5399,12 +5399,12 @@ packages:
|
||||
resolution: {integrity: sha512-5PjwB0uP2XDp3nt5u5NJAG2DORHIRClPzWT/TTZhJ2Ekwe8M5bA9tvPdi9NO/n2uvu2/ictat8kgqvLfcIE1SA==}
|
||||
dev: false
|
||||
|
||||
/@types/pg@8.6.6:
|
||||
resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==}
|
||||
/@types/pg@8.11.6:
|
||||
resolution: {integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==}
|
||||
dependencies:
|
||||
'@types/node': 20.9.0
|
||||
pg-protocol: 1.6.0
|
||||
pg-types: 2.2.0
|
||||
pg-types: 4.0.2
|
||||
dev: false
|
||||
|
||||
/@types/prop-types@15.7.10:
|
||||
@@ -5593,14 +5593,14 @@ packages:
|
||||
'@upstash/redis': 1.25.1
|
||||
dev: false
|
||||
|
||||
/@vercel/postgres@0.5.1:
|
||||
resolution: {integrity: sha512-JKl8QOBIDnifhkxAhIKtY0A5Tb8oWBf2nzZhm0OH7Ffjsl0hGVnDL2w1/FCfpX8xna3JAWM034NGuhZfTFdmiw==}
|
||||
/@vercel/postgres@0.9.0:
|
||||
resolution: {integrity: sha512-WiI2g3+ce2g1u1gP41MoDj2DsMuQQ+us7vHobysRixKECGaLHpfTI7DuVZmHU087ozRAGr3GocSyqmWLLo+fig==}
|
||||
engines: {node: '>=14.6'}
|
||||
dependencies:
|
||||
'@neondatabase/serverless': 0.6.0
|
||||
'@neondatabase/serverless': 0.9.4
|
||||
bufferutil: 4.0.8
|
||||
utf-8-validate: 6.0.3
|
||||
ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3)
|
||||
utf-8-validate: 6.0.4
|
||||
ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||
dev: false
|
||||
|
||||
/@vue/compiler-core@3.3.8:
|
||||
@@ -5866,8 +5866,8 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@walletconnect/core@2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1):
|
||||
resolution: {integrity: sha512-QekYQlpxyn2bcQXMkMxo0+v7nUOQKyu3j5ZKzTg/HGU1eSgTRLIvYIEkC8VVflIgOw7meOAb5pFChX51wShksQ==}
|
||||
/@walletconnect/core@2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1):
|
||||
resolution: {integrity: sha512-9MWVt33MFrLiAeK9nqY/B30/y0M4uiq8v9EXenIBQdlgkmXM++RTcOnn7u7EAbthGgzx3WLPRm4ViwIb+rI/Cg==}
|
||||
engines: {node: '>=18'}
|
||||
dependencies:
|
||||
'@walletconnect/heartbeat': 1.2.2
|
||||
@@ -5881,8 +5881,8 @@ packages:
|
||||
'@walletconnect/relay-auth': 1.0.4
|
||||
'@walletconnect/safe-json': 1.0.2
|
||||
'@walletconnect/time': 1.0.2
|
||||
'@walletconnect/types': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/utils': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/types': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/utils': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
events: 3.3.0
|
||||
lodash.isequal: 4.5.0
|
||||
uint8arrays: 3.1.0
|
||||
@@ -5946,18 +5946,18 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@walletconnect/ethereum-provider@2.15.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0):
|
||||
resolution: {integrity: sha512-qQyHVwJtPo7RZJIIn7KAp20t2pthhr9P2Nnhv196+49dTMJ5Es962cgouA410XA7DSQkom+4esiXR2AR5SsrAA==}
|
||||
/@walletconnect/ethereum-provider@2.15.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0):
|
||||
resolution: {integrity: sha512-3ssEAKc/rLYshwyE2ZIaoTxzi/p9Ws+kj/FIsd1Ed/CC37Rl5l/KYHaRJtevWeni9s4dGqyqKsYkJ0VwwUcnfQ==}
|
||||
dependencies:
|
||||
'@walletconnect/jsonrpc-http-connection': 1.0.8
|
||||
'@walletconnect/jsonrpc-provider': 1.0.14
|
||||
'@walletconnect/jsonrpc-types': 1.0.4
|
||||
'@walletconnect/jsonrpc-utils': 1.0.8
|
||||
'@walletconnect/modal': 2.6.2(@types/react@18.2.37)(react@18.2.0)
|
||||
'@walletconnect/sign-client': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/types': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/universal-provider': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/utils': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/sign-client': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/types': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/universal-provider': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/utils': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
events: 3.3.0
|
||||
transitivePeerDependencies:
|
||||
- '@azure/app-configuration'
|
||||
@@ -6168,17 +6168,17 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@walletconnect/sign-client@2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1):
|
||||
resolution: {integrity: sha512-efwrPfIwKWKeku44TGBCnQqPZGCILI1wBKK9bTF0F0/qrLR/zRe6RWpM3/L4+jOMr/BktxPZ5lRozBh+c2U7Pg==}
|
||||
/@walletconnect/sign-client@2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1):
|
||||
resolution: {integrity: sha512-YnLNEmCHgZ8yBpE3hwZnHD/bVznVMguSAlwLBNOoWUH2f4d9mR8bqa6KeVXqZ3e8mVHcxKTJTjTJ3oQMLyKIjw==}
|
||||
dependencies:
|
||||
'@walletconnect/core': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/core': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/events': 1.0.1
|
||||
'@walletconnect/heartbeat': 1.2.2
|
||||
'@walletconnect/jsonrpc-utils': 1.0.8
|
||||
'@walletconnect/logger': 2.1.2
|
||||
'@walletconnect/time': 1.0.2
|
||||
'@walletconnect/types': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/utils': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/types': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/utils': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
events: 3.3.0
|
||||
transitivePeerDependencies:
|
||||
- '@azure/app-configuration'
|
||||
@@ -6231,8 +6231,8 @@ packages:
|
||||
- uWebSockets.js
|
||||
dev: false
|
||||
|
||||
/@walletconnect/types@2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1):
|
||||
resolution: {integrity: sha512-hLffDKKe70jIrK+YcLkAnzi6vqNki1SDBWjV+M/72mKcU2KzXxk0G2STFsWsQDx8DoqxMiuGehd0DlD1jwQmBg==}
|
||||
/@walletconnect/types@2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1):
|
||||
resolution: {integrity: sha512-4WkMsHD8ioZI5GmxNT0qMlz6msI7ZajBcTyDxfRncaNZVau0C+Btw1U4jWO+gxwJVDJY+Ue/cb1QKJ5BanZsyw==}
|
||||
dependencies:
|
||||
'@walletconnect/events': 1.0.1
|
||||
'@walletconnect/heartbeat': 1.2.2
|
||||
@@ -6289,17 +6289,17 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@walletconnect/universal-provider@2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1):
|
||||
resolution: {integrity: sha512-+jIuYyLfud1XRYPWt/3wYiD7DYUOSZk26qbtvZFMj1m947NRnZGzp+0gt1ORi7NInEtX3R0fUhMOYKnPwadp6g==}
|
||||
/@walletconnect/universal-provider@2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1):
|
||||
resolution: {integrity: sha512-JvKwHoE/ugWSKOmrEr03go1V79N0bbYV6w24Lqlzz4VAoReZZo8TDKsya7UkJ1L5HUCgKVP+AVktuJv8khzJ6w==}
|
||||
dependencies:
|
||||
'@walletconnect/jsonrpc-http-connection': 1.0.8
|
||||
'@walletconnect/jsonrpc-provider': 1.0.14
|
||||
'@walletconnect/jsonrpc-types': 1.0.4
|
||||
'@walletconnect/jsonrpc-utils': 1.0.8
|
||||
'@walletconnect/logger': 2.1.2
|
||||
'@walletconnect/sign-client': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/types': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/utils': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/sign-client': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/types': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/utils': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
events: 3.3.0
|
||||
transitivePeerDependencies:
|
||||
- '@azure/app-configuration'
|
||||
@@ -6355,8 +6355,8 @@ packages:
|
||||
- uWebSockets.js
|
||||
dev: false
|
||||
|
||||
/@walletconnect/utils@2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1):
|
||||
resolution: {integrity: sha512-xaazgCMyr5fUPm2QuZ76G+W8beDfKMILqJ3INL6wyuaLil2YQNdsCSvWMNhSP+EZeKD3SUqqBmQaM/maP0YHTg==}
|
||||
/@walletconnect/utils@2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1):
|
||||
resolution: {integrity: sha512-i5AR8XpZdcX8ghaCjYV13Er/KAGe56c1mLaG9c2cv9kmnZMZijeMdInjX/flnSM1RFDUiZXvKPMUNwlCL4NsWw==}
|
||||
dependencies:
|
||||
'@stablelib/chacha20poly1305': 1.0.1
|
||||
'@stablelib/hkdf': 1.0.1
|
||||
@@ -6366,11 +6366,10 @@ packages:
|
||||
'@walletconnect/relay-api': 1.0.11
|
||||
'@walletconnect/safe-json': 1.0.2
|
||||
'@walletconnect/time': 1.0.2
|
||||
'@walletconnect/types': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/types': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@walletconnect/window-getters': 1.0.1
|
||||
'@walletconnect/window-metadata': 1.0.1
|
||||
detect-browser: 5.3.0
|
||||
elliptic: 6.5.7
|
||||
query-string: 7.1.3
|
||||
uint8arrays: 3.1.0
|
||||
transitivePeerDependencies:
|
||||
@@ -6403,32 +6402,32 @@ packages:
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
/@web3modal/common@5.1.0:
|
||||
resolution: {integrity: sha512-TIYncrKDnFKE+q0mudzVCvGOZdNWa0kzkp+iL0zpbHm9sL+ceV4eOCip09Xcvrb5HeaBv1ROgAMPGLmpVCO3AA==}
|
||||
/@web3modal/common@5.1.1:
|
||||
resolution: {integrity: sha512-3rXsfFhaGPdr0F1iQ0andnZ4o9Dtq23m4ZC+IkEZ9nYjQ3U8i1KkI7jlSL3Ziq5jSTy1/uBcr154Db4frb6+jQ==}
|
||||
dependencies:
|
||||
bignumber.js: 9.1.2
|
||||
dayjs: 1.11.10
|
||||
dev: false
|
||||
|
||||
/@web3modal/core@5.1.0(@types/react@18.2.37)(react@18.2.0):
|
||||
resolution: {integrity: sha512-dasGgDnhAFKvdm4OwC4iiWsCwx+kPjrZBEqnz1vxY1Z27aQx19eke4xN+2IYjN/TCRG+m+5BoeCqyNomHEjaug==}
|
||||
/@web3modal/core@5.1.1(@types/react@18.2.37)(react@18.2.0):
|
||||
resolution: {integrity: sha512-76ywvsayfj7LcdrxfQBMOj62HRULnH3tIvIO9khQm/8EAjqTo23kKMPxNxd5kctw8EN6C0qonTFAzxY46v6QHA==}
|
||||
dependencies:
|
||||
'@web3modal/common': 5.1.0
|
||||
'@web3modal/wallet': 5.1.0
|
||||
'@web3modal/common': 5.1.1
|
||||
'@web3modal/wallet': 5.1.1
|
||||
valtio: 1.11.2(@types/react@18.2.37)(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
- react
|
||||
dev: false
|
||||
|
||||
/@web3modal/polyfills@5.1.0:
|
||||
resolution: {integrity: sha512-Vj0+htFFi053oU4n10vfkNDCDv0VladWW7WdpbneiYs8nVThIP1+aGil5DG1iL0JsModgwaWgJwKwDKbwlCFtA==}
|
||||
/@web3modal/polyfills@5.1.1:
|
||||
resolution: {integrity: sha512-Y91SBc12r2x1V3Y3OsNZM5zmNLBUEd3mIzJ9fGrBu38q6Fe6XzxVr6VEWCPiK7g/y1eA++1AdbiVZq587zeuRg==}
|
||||
dependencies:
|
||||
buffer: 6.0.3
|
||||
dev: false
|
||||
|
||||
/@web3modal/scaffold-react@5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-XfgRiIVCvhAPBBjXJIKMQIdQXSqfLza8XtylakqiFtgh9B8taFJOCH4vomi+WucAvGAtxGju4IyEub7afSIvog==}
|
||||
/@web3modal/scaffold-react@5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-u88KVr/7qKmCGaIVEJvUQhGf3VaqPKzyqWDaymLgo6IvsTCnnsoVZdejpkxh1FY28vOehsBD2QMh/ruPPzpnRw==}
|
||||
peerDependencies:
|
||||
react: '>=17'
|
||||
react-dom: '>=17'
|
||||
@@ -6438,7 +6437,7 @@ packages:
|
||||
react-dom:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@web3modal/scaffold': 5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@web3modal/scaffold': 5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
@@ -6459,15 +6458,15 @@ packages:
|
||||
- uWebSockets.js
|
||||
dev: false
|
||||
|
||||
/@web3modal/scaffold-ui@5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0):
|
||||
resolution: {integrity: sha512-X2WjL6TtuCFw2qeVClVjmYDWbBQDK7JV0CiO57FUBo8xLMhYcj1pSQ1G+zOvikkWaGWwiOyKxJWzVsfrDeihOQ==}
|
||||
/@web3modal/scaffold-ui@5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0):
|
||||
resolution: {integrity: sha512-Pi1TAPPtw3Xxb3BD8EDsRVhtKh9UPNa6ACTrDrKnAeXBPSWMRI2GBZOTrfrqfJzixsjoFfH+79J/D2JDvvXCEA==}
|
||||
dependencies:
|
||||
'@web3modal/common': 5.1.0
|
||||
'@web3modal/core': 5.1.0(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/scaffold-utils': 5.1.0(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/siwe': 5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@web3modal/ui': 5.1.0
|
||||
'@web3modal/wallet': 5.1.0
|
||||
'@web3modal/common': 5.1.1
|
||||
'@web3modal/core': 5.1.1(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/scaffold-utils': 5.1.1(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/siwe': 5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@web3modal/ui': 5.1.1
|
||||
'@web3modal/wallet': 5.1.1
|
||||
lit: 3.1.0
|
||||
transitivePeerDependencies:
|
||||
- '@azure/app-configuration'
|
||||
@@ -6488,29 +6487,29 @@ packages:
|
||||
- uWebSockets.js
|
||||
dev: false
|
||||
|
||||
/@web3modal/scaffold-utils@5.1.0(@types/react@18.2.37)(react@18.2.0):
|
||||
resolution: {integrity: sha512-q4SwEWgUT03VJEMvOuegm+k89eWU/BYq/2bJYIyO5bf0hpVCTLDk2MG9nNJ1wafJdYv8iCAe5xWhfdv8OKPC3Q==}
|
||||
/@web3modal/scaffold-utils@5.1.1(@types/react@18.2.37)(react@18.2.0):
|
||||
resolution: {integrity: sha512-oHZ9LKidN36sFDFaTcBgkfhKRxSx+wYPpLtL7hdN782w5MI6M/rhnefmUogKblWfXSmZ3GvDVbpG3QLvKEPIZg==}
|
||||
dependencies:
|
||||
'@coinbase/wallet-sdk': 4.0.3
|
||||
'@web3modal/core': 5.1.0(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/polyfills': 5.1.0
|
||||
'@web3modal/wallet': 5.1.0
|
||||
'@web3modal/core': 5.1.1(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/polyfills': 5.1.1
|
||||
'@web3modal/wallet': 5.1.1
|
||||
valtio: 1.11.2(@types/react@18.2.37)(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
- react
|
||||
dev: false
|
||||
|
||||
/@web3modal/scaffold-vue@5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)(vue@3.3.8):
|
||||
resolution: {integrity: sha512-d0Ar9b+lXVVlhzFVAACFrYbzCEen5hdzgmevRibKvhkvYnKZjYweTSldTNt8z0qnn1JNZMOA23/9Q4gGMJHACA==}
|
||||
/@web3modal/scaffold-vue@5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)(vue@3.3.8):
|
||||
resolution: {integrity: sha512-NiwLGZpPEgHHf22KD2Xvd7mK70RKK0kfQOB8sm3W0LSfxh5wfrY1WrhwXR0XDs9mSFN2fD4bxEDbUwvcTXD/XQ==}
|
||||
peerDependencies:
|
||||
vue: '>=3'
|
||||
peerDependenciesMeta:
|
||||
vue:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@web3modal/core': 5.1.0(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/scaffold': 5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@web3modal/core': 5.1.1(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/scaffold': 5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
vue: 3.3.8(typescript@5.2.2)
|
||||
transitivePeerDependencies:
|
||||
- '@azure/app-configuration'
|
||||
@@ -6531,16 +6530,16 @@ packages:
|
||||
- uWebSockets.js
|
||||
dev: false
|
||||
|
||||
/@web3modal/scaffold@5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0):
|
||||
resolution: {integrity: sha512-92SO2gQF1N3TWJBIor1ju2RoBvubCbhm/zdVG1nGYvyIf3k9ulX2crZAmg0P8CE8Cc3rrLPty2wW10hncbdv7g==}
|
||||
/@web3modal/scaffold@5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0):
|
||||
resolution: {integrity: sha512-E51ksfT0EWyttUmIjnkKDzTo5WafrzcrScXVeuMySYGk0ldN4yh70A8Y82qWcCtPRQ8hzb8MrMB4F26P67BGlA==}
|
||||
dependencies:
|
||||
'@web3modal/common': 5.1.0
|
||||
'@web3modal/core': 5.1.0(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/scaffold-ui': 5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@web3modal/scaffold-utils': 5.1.0(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/siwe': 5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@web3modal/ui': 5.1.0
|
||||
'@web3modal/wallet': 5.1.0
|
||||
'@web3modal/common': 5.1.1
|
||||
'@web3modal/core': 5.1.1(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/scaffold-ui': 5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@web3modal/scaffold-utils': 5.1.1(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/siwe': 5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@web3modal/ui': 5.1.1
|
||||
'@web3modal/wallet': 5.1.1
|
||||
lit: 3.1.0
|
||||
transitivePeerDependencies:
|
||||
- '@azure/app-configuration'
|
||||
@@ -6561,15 +6560,15 @@ packages:
|
||||
- uWebSockets.js
|
||||
dev: false
|
||||
|
||||
/@web3modal/siwe@5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0):
|
||||
resolution: {integrity: sha512-HUS/lBswY+AUiYvDbUaJX1RFoDH4HLFouUDv+Q4DhpY8qOT2vT8IdxkVyKezDAtXRcak7L/qSzLdgSv5ijDcDw==}
|
||||
/@web3modal/siwe@5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0):
|
||||
resolution: {integrity: sha512-tuWIKuXP0cRL+7DI3pkK0UqMWPwxptfI+ojinndQfwc972sFNGGZZLxeYWCShWqbUnMw0eVQOjoJCXDF9zXTtA==}
|
||||
dependencies:
|
||||
'@walletconnect/utils': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@web3modal/common': 5.1.0
|
||||
'@web3modal/core': 5.1.0(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/scaffold-utils': 5.1.0(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/ui': 5.1.0
|
||||
'@web3modal/wallet': 5.1.0
|
||||
'@walletconnect/utils': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@web3modal/common': 5.1.1
|
||||
'@web3modal/core': 5.1.1(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/scaffold-utils': 5.1.1(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/ui': 5.1.1
|
||||
'@web3modal/wallet': 5.1.1
|
||||
lit: 3.1.0
|
||||
valtio: 1.11.2(@types/react@18.2.37)(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
@@ -6591,15 +6590,15 @@ packages:
|
||||
- uWebSockets.js
|
||||
dev: false
|
||||
|
||||
/@web3modal/ui@5.1.0:
|
||||
resolution: {integrity: sha512-msjkOm/PLkfAVglQ8ZsuCLNuaf4IbkWkjZneO1uU+F2+7sCaGZHskFVmJQBbhwN347m0DTU8KgDP0BvFppW4Aw==}
|
||||
/@web3modal/ui@5.1.1:
|
||||
resolution: {integrity: sha512-OSAWbltEBc54dVE2WDdqYFMd6Fg1ivh46BHAn1D5bCjGEgGHdm7j8ZHukcKzP9e+raNz8Ih7ShuPKC+NtMc9Dw==}
|
||||
dependencies:
|
||||
lit: 3.1.0
|
||||
qrcode: 1.5.3
|
||||
dev: false
|
||||
|
||||
/@web3modal/wagmi@5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(@wagmi/connectors@5.1.1)(@wagmi/core@2.13.4)(ioredis@5.4.1)(react-dom@18.2.0)(react@18.2.0)(viem@2.18.2)(vue@3.3.8)(wagmi@2.12.1):
|
||||
resolution: {integrity: sha512-3SrBSSriv8sDgnBNpK1eo8ykbvIAw9Zmv2rfQ3KMkltW/rTTFTLX9mSbALnV+Tj6ZjhQLnVArtH8FX3FztffQA==}
|
||||
/@web3modal/wagmi@5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(@wagmi/connectors@5.1.1)(@wagmi/core@2.13.4)(ioredis@5.4.1)(react-dom@18.2.0)(react@18.2.0)(viem@2.18.2)(vue@3.3.8)(wagmi@2.12.1):
|
||||
resolution: {integrity: sha512-BxQHx1En8+FPSrh+h9P++ixd+LvihCsxZwG0SvlgORTrvGCq/CaO4EgoMUsXek9r5apatwXiJHiqWyIhWDnJsQ==}
|
||||
peerDependencies:
|
||||
'@wagmi/connectors': '>=4'
|
||||
'@wagmi/core': '>=2.0.0'
|
||||
@@ -6618,16 +6617,16 @@ packages:
|
||||
dependencies:
|
||||
'@wagmi/connectors': 5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(@wagmi/core@2.13.4)(ioredis@5.4.1)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(typescript@5.2.2)(viem@2.18.2)(zod@3.23.8)
|
||||
'@wagmi/core': 2.13.4(@types/react@18.2.37)(react@18.2.0)(typescript@5.2.2)(viem@2.18.2)
|
||||
'@walletconnect/ethereum-provider': 2.15.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@walletconnect/utils': 2.15.0(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@web3modal/common': 5.1.0
|
||||
'@web3modal/polyfills': 5.1.0
|
||||
'@web3modal/scaffold': 5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@web3modal/scaffold-react': 5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@web3modal/scaffold-utils': 5.1.0(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/scaffold-vue': 5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)(vue@3.3.8)
|
||||
'@web3modal/siwe': 5.1.0(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@web3modal/wallet': 5.1.0
|
||||
'@walletconnect/ethereum-provider': 2.15.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@walletconnect/utils': 2.15.1(@vercel/kv@1.0.1)(ioredis@5.4.1)
|
||||
'@web3modal/common': 5.1.1
|
||||
'@web3modal/polyfills': 5.1.1
|
||||
'@web3modal/scaffold': 5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@web3modal/scaffold-react': 5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@web3modal/scaffold-utils': 5.1.1(@types/react@18.2.37)(react@18.2.0)
|
||||
'@web3modal/scaffold-vue': 5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)(vue@3.3.8)
|
||||
'@web3modal/siwe': 5.1.1(@types/react@18.2.37)(@vercel/kv@1.0.1)(ioredis@5.4.1)(react@18.2.0)
|
||||
'@web3modal/wallet': 5.1.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
viem: 2.18.2(typescript@5.2.2)(zod@3.23.8)
|
||||
@@ -6654,12 +6653,12 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@web3modal/wallet@5.1.0:
|
||||
resolution: {integrity: sha512-5LdsFMp6wozdvEchfnagsAH/u1moqfRFnBb2iA2gDQZWH0Y+M9UIkw6iRUw0QFnae+uB4ALyUJ3Te0L8VLWmhQ==}
|
||||
/@web3modal/wallet@5.1.1:
|
||||
resolution: {integrity: sha512-i0UOh5GuXy0qJbI9bdAf4iPto7ZPX99rjbyiFs3VAR79DM5Ja4f7f2fgBaZy7LVcUr/Gk5LCGyr5Dffmn7d/YQ==}
|
||||
dependencies:
|
||||
'@walletconnect/logger': 2.1.2
|
||||
'@web3modal/common': 5.1.0
|
||||
'@web3modal/polyfills': 5.1.0
|
||||
'@web3modal/common': 5.1.1
|
||||
'@web3modal/polyfills': 5.1.1
|
||||
zod: 3.22.4
|
||||
dev: false
|
||||
|
||||
@@ -8322,18 +8321,6 @@ packages:
|
||||
minimalistic-crypto-utils: 1.0.1
|
||||
dev: false
|
||||
|
||||
/elliptic@6.5.7:
|
||||
resolution: {integrity: sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==}
|
||||
dependencies:
|
||||
bn.js: 4.12.0
|
||||
brorand: 1.1.0
|
||||
hash.js: 1.1.7
|
||||
hmac-drbg: 1.0.1
|
||||
inherits: 2.0.4
|
||||
minimalistic-assert: 1.0.1
|
||||
minimalistic-crypto-utils: 1.0.1
|
||||
dev: false
|
||||
|
||||
/emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
dev: false
|
||||
@@ -8363,7 +8350,7 @@ packages:
|
||||
'@socket.io/component-emitter': 3.1.2
|
||||
debug: 4.3.4
|
||||
engine.io-parser: 5.2.3
|
||||
ws: 8.17.1
|
||||
ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||
xmlhttprequest-ssl: 2.0.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@@ -10153,7 +10140,7 @@ packages:
|
||||
peerDependencies:
|
||||
ws: '*'
|
||||
dependencies:
|
||||
ws: 8.17.1
|
||||
ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||
dev: false
|
||||
|
||||
/iterator.prototype@1.1.2:
|
||||
@@ -10400,7 +10387,7 @@ packages:
|
||||
whatwg-encoding: 2.0.0
|
||||
whatwg-mimetype: 3.0.0
|
||||
whatwg-url: 11.0.0
|
||||
ws: 8.17.1
|
||||
ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||
xml-name-validator: 4.0.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@@ -12169,6 +12156,10 @@ packages:
|
||||
es-abstract: 1.22.3
|
||||
dev: true
|
||||
|
||||
/obuf@1.1.2:
|
||||
resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==}
|
||||
dev: false
|
||||
|
||||
/ofetch@1.3.4:
|
||||
resolution: {integrity: sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw==}
|
||||
dependencies:
|
||||
@@ -12452,19 +12443,26 @@ packages:
|
||||
engines: {node: '>=4.0.0'}
|
||||
dev: false
|
||||
|
||||
/pg-numeric@1.0.2:
|
||||
resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==}
|
||||
engines: {node: '>=4'}
|
||||
dev: false
|
||||
|
||||
/pg-protocol@1.6.0:
|
||||
resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==}
|
||||
dev: false
|
||||
|
||||
/pg-types@2.2.0:
|
||||
resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
|
||||
engines: {node: '>=4'}
|
||||
/pg-types@4.0.2:
|
||||
resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
pg-int8: 1.0.1
|
||||
postgres-array: 2.0.0
|
||||
postgres-bytea: 1.0.0
|
||||
postgres-date: 1.0.7
|
||||
postgres-interval: 1.2.0
|
||||
pg-numeric: 1.0.2
|
||||
postgres-array: 3.0.2
|
||||
postgres-bytea: 3.0.0
|
||||
postgres-date: 2.1.0
|
||||
postgres-interval: 3.0.0
|
||||
postgres-range: 1.1.4
|
||||
dev: false
|
||||
|
||||
/picocolors@1.0.0:
|
||||
@@ -12672,26 +12670,30 @@ packages:
|
||||
picocolors: 1.0.1
|
||||
source-map-js: 1.2.0
|
||||
|
||||
/postgres-array@2.0.0:
|
||||
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
|
||||
engines: {node: '>=4'}
|
||||
/postgres-array@3.0.2:
|
||||
resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/postgres-bytea@1.0.0:
|
||||
resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/postgres-date@1.0.7:
|
||||
resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/postgres-interval@1.2.0:
|
||||
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
/postgres-bytea@3.0.0:
|
||||
resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==}
|
||||
engines: {node: '>= 6'}
|
||||
dependencies:
|
||||
xtend: 4.0.2
|
||||
obuf: 1.1.2
|
||||
dev: false
|
||||
|
||||
/postgres-date@2.1.0:
|
||||
resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/postgres-interval@3.0.0:
|
||||
resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/postgres-range@1.1.4:
|
||||
resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==}
|
||||
dev: false
|
||||
|
||||
/preact-render-to-string@5.2.6(preact@10.19.1):
|
||||
@@ -15436,8 +15438,8 @@ packages:
|
||||
node-gyp-build: 4.6.1
|
||||
dev: false
|
||||
|
||||
/utf-8-validate@6.0.3:
|
||||
resolution: {integrity: sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==}
|
||||
/utf-8-validate@6.0.4:
|
||||
resolution: {integrity: sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==}
|
||||
engines: {node: '>=6.14.2'}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
@@ -15566,7 +15568,7 @@ packages:
|
||||
isows: 1.0.4(ws@8.17.1)
|
||||
typescript: 5.2.2
|
||||
webauthn-p256: 0.0.5
|
||||
ws: 8.17.1
|
||||
ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
@@ -15893,8 +15895,8 @@ packages:
|
||||
optional: true
|
||||
dev: false
|
||||
|
||||
/ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3):
|
||||
resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==}
|
||||
/ws@8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
||||
resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
@@ -15906,20 +15908,7 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
bufferutil: 4.0.8
|
||||
utf-8-validate: 6.0.3
|
||||
dev: false
|
||||
|
||||
/ws@8.17.1:
|
||||
resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: '>=5.0.2'
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
utf-8-validate: 6.0.4
|
||||
dev: false
|
||||
|
||||
/xml-name-validator@4.0.0:
|
||||
|
||||
@@ -11,59 +11,61 @@ generator client {
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
address String @unique
|
||||
name String?
|
||||
ensName String?
|
||||
email String? @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
bio String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
spaces Space[]
|
||||
posts Post[]
|
||||
members Member[]
|
||||
trades Trade[]
|
||||
holders Holder[]
|
||||
sponsors Sponsor[]
|
||||
comments Comment[]
|
||||
lists List[]
|
||||
contributors Contributor[]
|
||||
messages Message[]
|
||||
id String @id @default(uuid())
|
||||
address String @unique
|
||||
name String?
|
||||
ensName String?
|
||||
email String? @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
bio String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
spaces Space[]
|
||||
posts Post[]
|
||||
members Member[]
|
||||
subscriptionRecords SubscriptionRecord[]
|
||||
holders Holder[]
|
||||
sponsors Sponsor[]
|
||||
comments Comment[]
|
||||
lists List[]
|
||||
contributors Contributor[]
|
||||
messages Message[]
|
||||
trades Trade[]
|
||||
|
||||
@@index([id])
|
||||
@@index([address])
|
||||
}
|
||||
|
||||
model Space {
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
description String @default("") @db.Text
|
||||
logo String? @default("https://public.blob.vercel-storage.com/eEZHAoPTOBSYGBE3/JRajRyC-PhBHEinQkupt02jqfKacBVHLWJq7Iy.png") @db.Text
|
||||
font String @default("font-cal")
|
||||
image String? @default("") @db.Text
|
||||
imageBlurhash String? @default("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAhCAYAAACbffiEAAAACXBIWXMAABYlAAAWJQFJUiTwAAABfUlEQVR4nN3XyZLDIAwE0Pz/v3q3r55JDlSBplsIEI49h76k4opexCK/juP4eXjOT149f2Tf9ySPgcjCc7kdpBTgDPKByKK2bTPFEdMO0RDrusJ0wLRBGCIuelmWJAjkgPGDSIQEMBDCfA2CEPM80+Qwl0JkNxBimiaYGOTUlXYI60YoehzHJDEm7kxjV3whOQTD3AaCuhGKHoYhyb+CBMwjIAFz647kTqyapdV4enGINuDJMSScPmijSwjCaHeLcT77C7EC0C1ugaCTi2HYfAZANgj6Z9A8xY5eiYghDMNQBJNCWhASot0jGsSCUiHWZcSGQjaWWCDaGMOWnsCcn2QhVkRuxqqNxMSdUSElCDbp1hbNOsa6Ugxh7xXauF4DyM1m5BLtCylBXgaxvPXVwEoOBjeIFVODtW74oj1yBQah3E8tyz3SkpolKS9Geo9YMD1QJR1Go4oJkgO1pgbNZq0AOUPChyjvh7vlXaQa+X1UXwKxgHokB2XPxbX+AnijwIU4ahazAAAAAElFTkSuQmCC") @db.Text
|
||||
subdomain String? @unique
|
||||
customDomain String? @unique
|
||||
memberCount Int @default(0)
|
||||
sponsorCount Int @default(0)
|
||||
postCount Int @default(0)
|
||||
message404 String? @default("Blimey! You've found a page that doesn't exist.") @db.Text
|
||||
symbolName String @unique
|
||||
spaceAddress String? @unique // space on chain address
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
||||
userId String
|
||||
posts Post[]
|
||||
channels Channel[]
|
||||
members Member[]
|
||||
trades Trade[]
|
||||
holders Holder[]
|
||||
sponsors Sponsor[]
|
||||
contributors Contributor[]
|
||||
messages Message[]
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
description String @default("") @db.Text
|
||||
logo String? @default("https://public.blob.vercel-storage.com/eEZHAoPTOBSYGBE3/JRajRyC-PhBHEinQkupt02jqfKacBVHLWJq7Iy.png") @db.Text
|
||||
font String @default("font-cal")
|
||||
image String? @default("") @db.Text
|
||||
imageBlurhash String? @default("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAhCAYAAACbffiEAAAACXBIWXMAABYlAAAWJQFJUiTwAAABfUlEQVR4nN3XyZLDIAwE0Pz/v3q3r55JDlSBplsIEI49h76k4opexCK/juP4eXjOT149f2Tf9ySPgcjCc7kdpBTgDPKByKK2bTPFEdMO0RDrusJ0wLRBGCIuelmWJAjkgPGDSIQEMBDCfA2CEPM80+Qwl0JkNxBimiaYGOTUlXYI60YoehzHJDEm7kxjV3whOQTD3AaCuhGKHoYhyb+CBMwjIAFz647kTqyapdV4enGINuDJMSScPmijSwjCaHeLcT77C7EC0C1ugaCTi2HYfAZANgj6Z9A8xY5eiYghDMNQBJNCWhASot0jGsSCUiHWZcSGQjaWWCDaGMOWnsCcn2QhVkRuxqqNxMSdUSElCDbp1hbNOsa6Ugxh7xXauF4DyM1m5BLtCylBXgaxvPXVwEoOBjeIFVODtW74oj1yBQah3E8tyz3SkpolKS9Geo9YMD1QJR1Go4oJkgO1pgbNZq0AOUPChyjvh7vlXaQa+X1UXwKxgHokB2XPxbX+AnijwIU4ahazAAAAAElFTkSuQmCC") @db.Text
|
||||
subdomain String? @unique
|
||||
customDomain String? @unique
|
||||
memberCount Int @default(0)
|
||||
sponsorCount Int @default(0)
|
||||
postCount Int @default(0)
|
||||
message404 String? @default("Blimey! You've found a page that doesn't exist.") @db.Text
|
||||
symbolName String @unique
|
||||
spaceAddress String? @unique // space on chain address
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
||||
userId String
|
||||
posts Post[]
|
||||
channels Channel[]
|
||||
members Member[]
|
||||
subscriptionRecords SubscriptionRecord[]
|
||||
holders Holder[]
|
||||
sponsors Sponsor[]
|
||||
contributors Contributor[]
|
||||
messages Message[]
|
||||
trades Trade[]
|
||||
|
||||
@@index([userId])
|
||||
@@index([name])
|
||||
@@ -200,6 +202,26 @@ model Sponsor {
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
enum SubscriptionType {
|
||||
SUBSCRIBE
|
||||
UNSUBSCRIBE
|
||||
}
|
||||
|
||||
model SubscriptionRecord {
|
||||
id String @id @default(uuid())
|
||||
duration Int @default(0)
|
||||
type SubscriptionType
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
Space Space @relation(fields: [spaceId], references: [id])
|
||||
spaceId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
||||
userId String
|
||||
|
||||
@@index([spaceId])
|
||||
@@index([type])
|
||||
}
|
||||
|
||||
enum TradeType {
|
||||
BUY
|
||||
SELL
|
||||
@@ -207,7 +229,8 @@ enum TradeType {
|
||||
|
||||
model Trade {
|
||||
id String @id @default(uuid())
|
||||
duration Int @default(0)
|
||||
amountIn String @default("0")
|
||||
amountOut String @default("0")
|
||||
type TradeType
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
@@ -217,6 +240,7 @@ model Trade {
|
||||
userId String
|
||||
|
||||
@@index([spaceId])
|
||||
@@index([type])
|
||||
}
|
||||
|
||||
enum ChannelType {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { messageRouter } from './routers/message'
|
||||
import { postRouter } from './routers/post'
|
||||
import { spaceRouter } from './routers/space'
|
||||
import { sponsorRouter } from './routers/sponsor'
|
||||
import { subscriptionRecordRouter } from './routers/subscriptionRecord'
|
||||
import { tradeRouter } from './routers/trade'
|
||||
import { userRouter } from './routers/user'
|
||||
import { createCallerFactory, publicProcedure, router } from './trpc'
|
||||
@@ -26,6 +27,7 @@ export const appRouter = router({
|
||||
trade: tradeRouter,
|
||||
sponsor: sponsorRouter,
|
||||
contributor: contributorRouter,
|
||||
subscriptionRecord: subscriptionRecordRouter,
|
||||
})
|
||||
|
||||
export const createCaller = createCallerFactory(appRouter)
|
||||
|
||||
45
server/routers/subscriptionRecord.ts
Normal file
45
server/routers/subscriptionRecord.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { TradeSource } from '@/lib/constants'
|
||||
import { precision } from '@/lib/math'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { SubscriptionRecord } from '@prisma/client'
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import { z } from 'zod'
|
||||
import { protectedProcedure, publicProcedure, router } from '../trpc'
|
||||
|
||||
enum SubscriptionType {
|
||||
SUBSCRIBE = 'SUBSCRIBE',
|
||||
UNSUBSCRIBE = 'UNSUBSCRIBE',
|
||||
}
|
||||
|
||||
export const subscriptionRecordRouter = router({
|
||||
listBySpaceId: publicProcedure.input(z.string()).query(async ({ input }) => {
|
||||
return [] as (SubscriptionRecord & {
|
||||
user: {
|
||||
name: string | null
|
||||
ensName: string | null
|
||||
email: string | null
|
||||
address: string
|
||||
}
|
||||
})[]
|
||||
}),
|
||||
|
||||
upsertSubscription: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
spaceId: z.string(),
|
||||
tradeDuration: z.number(),
|
||||
type: z.enum([
|
||||
SubscriptionType.SUBSCRIBE,
|
||||
SubscriptionType.UNSUBSCRIBE,
|
||||
]),
|
||||
start: z.number(),
|
||||
checkpoint: z.number(),
|
||||
duration: z.number(),
|
||||
amount: z.string(),
|
||||
consumed: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
return true
|
||||
}),
|
||||
})
|
||||
@@ -19,37 +19,13 @@ export const tradeRouter = router({
|
||||
})[]
|
||||
}),
|
||||
|
||||
tradeSpaceKey: protectedProcedure
|
||||
create: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
spaceId: z.string(),
|
||||
tradeDuration: z.number(),
|
||||
type: z.enum([TradeType.BUY, TradeType.SELL]),
|
||||
|
||||
start: z.number(),
|
||||
checkpoint: z.number(),
|
||||
duration: z.number(),
|
||||
amount: z.string(),
|
||||
consumed: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
return true
|
||||
}),
|
||||
|
||||
tradeSponsorKey: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
spaceId: z.string(),
|
||||
holdAmount: z.string(),
|
||||
tradeAmount: z.string(),
|
||||
price: z.string(),
|
||||
type: z.enum([TradeType.BUY, TradeType.SELL]),
|
||||
name: z.string().optional(),
|
||||
logo: z.string().optional(),
|
||||
homeUrl: z.string().optional(),
|
||||
cover: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
amountIn: z.string(),
|
||||
amountOut: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
|
||||
Reference in New Issue
Block a user