diff --git a/.env.goerli b/.env.goerli index 8c347815..218e15e6 100644 --- a/.env.goerli +++ b/.env.goerli @@ -2,7 +2,6 @@ RESERVOIR_API_KEY= NEXT_PUBLIC_ALCHEMY_API= NEXT_PUBLIC_LOCAL_API=http://localhost:3000/api/ NEXT_PUBLIC_IS_TESTNET=true -NEXT_PUBLIC_STARKNET_CONTRACT_ADDRESS=0xde29d060D45901Fb19ED6C6e959EB22d8626708e NEXT_PUBLIC_ETHERSCAN_URL=https://goerli.etherscan.io NEXT_PUBLIC_VOYAGER_URL=https://goerli.voyager.online NEXT_PUBLIC_STARKSCAN_URL=https://testnet.starkscan.co diff --git a/.env.mainnet b/.env.mainnet index 228b32bf..732f551f 100644 --- a/.env.mainnet +++ b/.env.mainnet @@ -2,7 +2,6 @@ RESERVOIR_API_KEY=test NEXT_PUBLIC_LOCAL_API=http://localhost:3000/api/ NEXT_PUBLIC_ALCHEMY_API= NEXT_PUBLIC_IS_TESTNET=false -NEXT_PUBLIC_STARKNET_CONTRACT_ADDRESS=0xde29d060D45901Fb19ED6C6e959EB22d8626708e NEXT_PUBLIC_ETHERSCAN_URL=https://etherscan.io NEXT_PUBLIC_VOYAGER_URL=https://voyager.online NEXT_PUBLIC_STARKSCAN_URL=https://starkscan.co diff --git a/.env.sepolia b/.env.sepolia index 8c347815..218e15e6 100644 --- a/.env.sepolia +++ b/.env.sepolia @@ -2,7 +2,6 @@ RESERVOIR_API_KEY= NEXT_PUBLIC_ALCHEMY_API= NEXT_PUBLIC_LOCAL_API=http://localhost:3000/api/ NEXT_PUBLIC_IS_TESTNET=true -NEXT_PUBLIC_STARKNET_CONTRACT_ADDRESS=0xde29d060D45901Fb19ED6C6e959EB22d8626708e NEXT_PUBLIC_ETHERSCAN_URL=https://goerli.etherscan.io NEXT_PUBLIC_VOYAGER_URL=https://goerli.voyager.online NEXT_PUBLIC_STARKSCAN_URL=https://testnet.starkscan.co diff --git a/.github/workflows/enforcer.yml b/.github/workflows/enforcer.yml new file mode 100644 index 00000000..9464e892 --- /dev/null +++ b/.github/workflows/enforcer.yml @@ -0,0 +1,14 @@ +name: "Check Production PR Branch" + +on: + pull_request: + +jobs: + check_branch: + runs-on: ubuntu-latest + steps: + - name: Check branch + if: github.base_ref == 'production' && github.head_ref != 'main' + run: | + echo "ERROR: You can only merge to production from main." + exit 1 diff --git a/apps/auth-proxy/nitro.config.ts b/apps/auth-proxy/nitro.config.ts deleted file mode 100644 index 9d04b61a..00000000 --- a/apps/auth-proxy/nitro.config.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default defineNitroConfig({ - logLevel: -999, -}); diff --git a/apps/auth-proxy/package.json b/apps/auth-proxy/package.json index 56a805f6..9642f3f3 100644 --- a/apps/auth-proxy/package.json +++ b/apps/auth-proxy/package.json @@ -11,7 +11,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@auth/core": "^0.21.0" + "@auth/core": "^0.24.0" }, "devDependencies": { "@realms-world/eslint-config": "workspace:*", diff --git a/apps/auth-proxy/routes/[...auth].ts b/apps/auth-proxy/routes/[...auth].ts index dac2b06f..fbfab449 100644 --- a/apps/auth-proxy/routes/[...auth].ts +++ b/apps/auth-proxy/routes/[...auth].ts @@ -3,17 +3,17 @@ import Discord from "@auth/core/providers/discord"; import { eventHandler, toWebRequest } from "h3"; export default eventHandler(async (event) => { - if (!event.context.matchedRoute.params.auth.endsWith("inngest")) { - return Auth(toWebRequest(event), { - secret: process.env.AUTH_SECRET, - trustHost: !!process.env.VERCEL, - redirectProxyUrl: process.env.AUTH_REDIRECT_PROXY_URL, - providers: [ - Discord({ - clientId: process.env.AUTH_DISCORD_ID, - clientSecret: process.env.AUTH_DISCORD_SECRET, - }), - ], - }); - } + //if (!event.context.matchedRoute?.params.auth.endsWith("inngest")) { + return Auth(toWebRequest(event), { + secret: process.env.AUTH_SECRET, + trustHost: !!process.env.VERCEL, + redirectProxyUrl: process.env.AUTH_REDIRECT_PROXY_URL, + providers: [ + Discord({ + clientId: process.env.AUTH_DISCORD_ID, + clientSecret: process.env.AUTH_DISCORD_SECRET, + }), + ], + }); + // } }); diff --git a/apps/expo/.expo-shared/assets.json b/apps/expo/.expo-shared/assets.json deleted file mode 100644 index 1e6decfb..00000000 --- a/apps/expo/.expo-shared/assets.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true, - "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true -} diff --git a/apps/expo/.gitignore b/apps/expo/.gitignore deleted file mode 100644 index 5873d9ab..00000000 --- a/apps/expo/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ - -# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb -# The following patterns were generated by expo-cli - -expo-env.d.ts -# @end expo-cli \ No newline at end of file diff --git a/apps/expo/app.config.ts b/apps/expo/app.config.ts deleted file mode 100644 index 0c8616c6..00000000 --- a/apps/expo/app.config.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { ExpoConfig } from "@expo/config"; - -const defineConfig = (): ExpoConfig => ({ - name: "expo", - slug: "expo", - scheme: "expo", - version: "1.0.0", - orientation: "portrait", - icon: "./assets/icon.png", - userInterfaceStyle: "light", - splash: { - image: "./assets/icon.png", - resizeMode: "contain", - backgroundColor: "#1F104A", - }, - updates: { - fallbackToCacheTimeout: 0, - }, - assetBundlePatterns: ["**/*"], - ios: { - bundleIdentifier: "your.bundle.identifier", - supportsTablet: true, - }, - android: { - package: "your.bundle.identifier", - adaptiveIcon: { - foregroundImage: "./assets/icon.png", - backgroundColor: "#1F104A", - }, - }, - // extra: { - // eas: { - // projectId: "your-eas-project-id", - // }, - // }, - experiments: { - tsconfigPaths: true, - typedRoutes: true, - }, - plugins: ["expo-router", "./expo-plugins/with-modify-gradle.js"], -}); - -export default defineConfig; diff --git a/apps/expo/assets/icon.png b/apps/expo/assets/icon.png deleted file mode 100644 index 67917f52..00000000 Binary files a/apps/expo/assets/icon.png and /dev/null differ diff --git a/apps/expo/babel.config.js b/apps/expo/babel.config.js deleted file mode 100644 index 73b60ebd..00000000 --- a/apps/expo/babel.config.js +++ /dev/null @@ -1,32 +0,0 @@ -const path = require("path"); -const loadConfig = require("tailwindcss/loadConfig"); - -/** @type {import("tailwindcss").Config | null} */ -let _tailwindConfig = null; -/** - * Transpiles tailwind.config.ts for babel - * Fix until nativewind babel plugin supports tailwind.config.ts files - */ -function lazyLoadConfig() { - return ( - _tailwindConfig ?? loadConfig(path.join(__dirname, "tailwind.config.ts")) - ); -} - -/** @type {import("@babel/core").ConfigFunction} */ -module.exports = function (api) { - api.cache.forever(); - - return { - presets: ["babel-preset-expo"], - plugins: [ - [ - "nativewind/babel", - { - tailwindConfig: lazyLoadConfig(), - }, - ], - require.resolve("expo-router/babel"), - ], - }; -}; diff --git a/apps/expo/eas.json b/apps/expo/eas.json deleted file mode 100644 index cdaba524..00000000 --- a/apps/expo/eas.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "cli": { - "version": ">= 3.3.0" - }, - "build": { - "base": { - "node": "18.16.1", - "ios": { - "resourceClass": "m-medium" - } - }, - "development": { - "extends": "base", - "developmentClient": true, - "distribution": "internal" - }, - "preview": { - "extends": "base", - "distribution": "internal", - "ios": { - "simulator": true - } - }, - "production": { - "extends": "base" - } - }, - "submit": { - "production": {} - } -} diff --git a/apps/expo/expo-plugins/with-modify-gradle.js b/apps/expo/expo-plugins/with-modify-gradle.js deleted file mode 100644 index 343c579b..00000000 --- a/apps/expo/expo-plugins/with-modify-gradle.js +++ /dev/null @@ -1,44 +0,0 @@ -// This plugin is required for fixing `.apk` build issue -// It appends Expo and RN versions into the `build.gradle` file -// References: -// https://github.com/t3-oss/create-t3-turbo/issues/120 -// https://github.com/expo/expo/issues/18129 - -/** @type {import("@expo/config-plugins").ConfigPlugin} */ -const defineConfig = (config) => { - // eslint-disable-next-line @typescript-eslint/no-var-requires - return require("@expo/config-plugins").withProjectBuildGradle( - config, - (config) => { - if (!config.modResults.contents.includes("ext.getPackageJsonVersion =")) { - config.modResults.contents = config.modResults.contents.replace( - "buildscript {", - `buildscript { - ext.getPackageJsonVersion = { packageName -> - new File(['node', '--print', "JSON.parse(require('fs').readFileSync(require.resolve('\${packageName}/package.json'), 'utf-8')).version"].execute(null, rootDir).text.trim()) - }`, - ); - } - - if (!config.modResults.contents.includes("reactNativeVersion =")) { - config.modResults.contents = config.modResults.contents.replace( - "ext {", - `ext { - reactNativeVersion = "\${ext.getPackageJsonVersion('react-native')}"`, - ); - } - - if (!config.modResults.contents.includes("expoPackageVersion =")) { - config.modResults.contents = config.modResults.contents.replace( - "ext {", - `ext { - expoPackageVersion = "\${ext.getPackageJsonVersion('expo')}"`, - ); - } - - return config; - }, - ); -}; - -module.exports = defineConfig; diff --git a/apps/expo/index.tsx b/apps/expo/index.tsx deleted file mode 100644 index 80d3d998..00000000 --- a/apps/expo/index.tsx +++ /dev/null @@ -1 +0,0 @@ -import "expo-router/entry"; diff --git a/apps/expo/metro.config.js b/apps/expo/metro.config.js deleted file mode 100644 index ad6852f7..00000000 --- a/apps/expo/metro.config.js +++ /dev/null @@ -1,23 +0,0 @@ -// Learn more: https://docs.expo.dev/guides/monorepos/ -const { getDefaultConfig } = require("@expo/metro-config"); -const path = require("path"); - -const projectRoot = __dirname; -const workspaceRoot = path.resolve(projectRoot, "../.."); - -// Create the default Metro config -const config = getDefaultConfig(projectRoot); - -if (config.resolver) { - // 1. Watch all files within the monorepo - config.watchFolders = [workspaceRoot]; - // 2. Let Metro know where to resolve packages and in what order - config.resolver.nodeModulesPaths = [ - path.resolve(projectRoot, "node_modules"), - path.resolve(workspaceRoot, "node_modules"), - ]; - // 3. Force Metro to resolve (sub)dependencies only from the `nodeModulesPaths` - config.resolver.disableHierarchicalLookup = true; -} - -module.exports = config; diff --git a/apps/expo/package.json b/apps/expo/package.json deleted file mode 100644 index 3e238517..00000000 --- a/apps/expo/package.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "name": "@realms-world/expo", - "version": "0.1.0", - "private": true, - "main": "index.tsx", - "scripts": { - "clean": "git clean -xdf .expo .turbo node_modules", - "dev:android": "expo start --android", - "dev:ios": "expo start --ios", - "lint": "eslint .", - "format": "prettier --check \"**/*.{js,cjs,mjs,ts,tsx,md,json}\"", - "typecheck": "tsc --noEmit", - "android": "expo run:android", - "ios": "expo run:ios" - }, - "dependencies": { - "@expo/metro-config": "^0.10.7", - "@shopify/flash-list": "1.6.3", - "@tanstack/react-query": "5.17.15", - "@trpc/client": "^10.45.0", - "@trpc/react-query": "^10.45.0", - "@trpc/server": "^10.45.0", - "expo": "^49.0.21", - "expo-constants": "~14.4.2", - "expo-linking": "~6.0.0", - "expo-router": "2.0.14", - "expo-splash-screen": "~0.22.0", - "expo-status-bar": "~1.7.1", - "nativewind": "^2.0.11", - "react": "18.2.0", - "react-dom": "18.2.0", - "react-native": "0.73.0", - "react-native-gesture-handler": "~2.14.0", - "react-native-safe-area-context": "4.8.0", - "react-native-screens": "~3.29.0", - "superjson": "2.2.1" - }, - "devDependencies": { - "@realms-world/api": "workspace:*", - "@realms-world/eslint-config": "workspace:*", - "@realms-world/prettier-config": "workspace:*", - "@realms-world/tailwind-config": "workspace:*", - "@realms-world/tsconfig": "workspace:*", - "@babel/core": "^7.23.6", - "@babel/preset-env": "^7.23.6", - "@babel/runtime": "^7.23.6", - "@expo/config-plugins": "^7.2.5", - "@types/babel__core": "^7.20.5", - "@types/react": "^18.2.48", - "eslint": "^8.56.0", - "prettier": "^3.2.4", - "tailwindcss": "3.4.1", - "typescript": "^5.3.3" - }, - "eslintConfig": { - "root": true, - "extends": [ - "@realms-world/eslint-config/base", - "@realms-world/eslint-config/react" - ] - }, - "prettier": "@realms-world/prettier-config" -} diff --git a/apps/expo/src/app/_layout.tsx b/apps/expo/src/app/_layout.tsx deleted file mode 100644 index c785f8ef..00000000 --- a/apps/expo/src/app/_layout.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react"; -import { Stack } from "expo-router"; -import { StatusBar } from "expo-status-bar"; - -import { TRPCProvider } from "~/utils/api"; - -// This is the main layout of the app -// It wraps your pages with the providers they need -const RootLayout = () => { - return ( - - {/* - The Stack component displays the current page. - It also allows you to configure your screens - */} - - - - ); -}; - -export default RootLayout; diff --git a/apps/expo/src/app/index.tsx b/apps/expo/src/app/index.tsx deleted file mode 100644 index b3d63341..00000000 --- a/apps/expo/src/app/index.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import React from "react"; -import { Button, Text, TextInput, TouchableOpacity, View } from "react-native"; -import { SafeAreaView } from "react-native-safe-area-context"; -import { /*Link,*/ Stack } from "expo-router"; -import { FlashList } from "@shopify/flash-list"; - -import { api } from "~/utils/api"; -//import type { RouterOutputs } from "~/utils/api"; - -/*function PostCard(props: { - beast: RouterOutputs["beasts"]["all"]["items"][number]; - onDelete: () => void; -}) { - return ( - - - - - - {props.beast.name} - - {props.beast.image} - - - - - Delete - - - ); -} -*/ -function CreatePost() { - // const utils = api.useContext(); - - const [title, setTitle] = React.useState(""); - const [content, setContent] = React.useState(""); - - /*const { mutate, error } = api.post.create.useMutation({ - async onSuccess() { - setTitle(""); - setContent(""); - await utils.post.all.invalidate(); - }, - });*/ - - return ( - - - {/*error?.data?.zodError?.fieldErrors.title && ( - - {error.data.zodError.fieldErrors.title} - - )*/} - - {/*error?.data?.zodError?.fieldErrors.content && ( - - {error.data.zodError.fieldErrors.content} - - )*/} - { - mutate({ - title, - content, - }); - }}*/ - > - Publish post - - - ); -} - -const Index = () => { - const utils = api.useContext(); - - const postQuery = api.beasts.all.useQuery({ limit: 5 }); - - /*const deletePostMutation = api.post.delete.useMutation({ - onSettled: () => utils.post.all.invalidate(), - });*/ - - return ( - - {/* Changes page title visible on the header */} - - - - Create T3 Turbo - - - ))} diff --git a/apps/nextjs/src/app/api/staking/cumulative-payment-tree.ts b/apps/nextjs/src/app/api/staking/cumulative-payment-tree.ts index 41176714..992f894d 100644 --- a/apps/nextjs/src/app/api/staking/cumulative-payment-tree.ts +++ b/apps/nextjs/src/app/api/staking/cumulative-payment-tree.ts @@ -1,3 +1,6 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { bufferToHex, zeros } from "ethereumjs-util"; import _ from "lodash"; import Web3Utils from "web3-utils"; @@ -23,17 +26,18 @@ import MerkleTree from "./merkle-tree"; */ export default class CumulativePaymentTree extends MerkleTree { - constructor(paymentList) { - let filteredPaymentList = paymentList.filter( + paymentNodes: { payee: string; amount: number }[]; + constructor(paymentList: any[]) { + const filteredPaymentList = paymentList.filter( (payment) => payment.payee && payment.amount, ); - let groupedPayees = _.groupBy( + const groupedPayees = _.groupBy( filteredPaymentList, (payment) => payment.payee, ); - let reducedPaymentList = Object.keys(groupedPayees).map((payee) => { - let payments = groupedPayees[payee]; - let amount = _.reduce( + const reducedPaymentList = Object.keys(groupedPayees).map((payee) => { + const payments = groupedPayees[payee]; + const amount = _.reduce( payments, (sum, payment) => sum + payment.amount, 0, @@ -44,8 +48,8 @@ export default class CumulativePaymentTree extends MerkleTree { this.paymentNodes = reducedPaymentList; } - amountForPayee(payee) { - let payment = _.find(this.paymentNodes, { payee }); + amountForPayee(payee: string) { + const payment = _.find(this.paymentNodes, { payee }); if (!payment) { return 0; } @@ -53,8 +57,8 @@ export default class CumulativePaymentTree extends MerkleTree { return Web3Utils.toHex(payment.amount); } - hexProofForPayee(payee, paymentCycle) { - let leaf = _.find(this.paymentNodes, { payee }); + hexProofForPayee(payee: string, paymentCycle: number) { + const leaf = _.find(this.paymentNodes, { payee }); if (!leaf) { return bufferToHex(zeros(32)); } diff --git a/apps/nextjs/src/app/api/staking/merkle-tree.ts b/apps/nextjs/src/app/api/staking/merkle-tree.ts index 5bb4caa0..90d206a7 100644 --- a/apps/nextjs/src/app/api/staking/merkle-tree.ts +++ b/apps/nextjs/src/app/api/staking/merkle-tree.ts @@ -1,3 +1,11 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/unbound-method */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import type { ToBufferInputTypes } from "ethereumjs-util"; import { bufferToHex, keccak256, @@ -7,7 +15,9 @@ import { import Web3Utils from "web3-utils"; export default class MerkleTree { - constructor(elements) { + elements: Buffer[]; + layers: any[]; + constructor(elements: any[]) { // Filter empty strings and hash elements this.elements = elements.filter((el) => el).map((el) => this.sha3(el)); @@ -20,7 +30,7 @@ export default class MerkleTree { this.layers = this.getLayers(this.elements); } - getLayers(elements) { + getLayers(elements: string | any[]) { if (elements.length === 0) { return [[""]]; } @@ -35,18 +45,21 @@ export default class MerkleTree { return layers; } - getNextLayer(elements) { - return elements.reduce((layer, el, idx, arr) => { - if (idx % 2 === 0) { - // Hash the current element with its pair element - layer.push(this.combinedHash(el, arr[idx + 1])); - } - - return layer; - }, []); + getNextLayer(elements?: any) { + return elements?.reduce( + (layer: any[], el: any, idx: number, arr: Record) => { + if (idx % 2 === 0) { + // Hash the current element with its pair element + layer.push(this.combinedHash(el, arr[idx + 1])); + } + + return layer; + }, + [], + ); } - combinedHash(first, second) { + combinedHash(first: any, second: any) { if (!first) { return second; } @@ -64,7 +77,7 @@ export default class MerkleTree { return bufferToHex(this.getRoot()); } - getProof(el, prefix) { + getProof(el: any, prefix: any[]) { let idx = this.bufIndexOf(el, this.elements); if (idx === -1) { @@ -88,20 +101,25 @@ export default class MerkleTree { prefix = [prefix]; } - prefix = prefix.map((item) => setLengthLeft(toBuffer(item), 32)); + prefix = prefix.map((item: ToBufferInputTypes) => + setLengthLeft(toBuffer(item), 32), + ); proof = prefix.concat(proof); } return proof; } - getHexProof(el, prefix) { + getHexProof( + el: { payee: string; amount: number }, + prefix: (string | number)[], + ) { const proof = this.getProof(el, prefix); return this.bufArrToHex(proof); } - getPairElement(idx, layer) { + getPairElement(idx: number, layer: string | any[]) { const pairIdx = idx % 2 === 0 ? idx + 1 : idx - 1; if (pairIdx < layer.length) { @@ -111,7 +129,7 @@ export default class MerkleTree { } } - bufIndexOf(el, arr) { + bufIndexOf(el: any, arr: any) { let hash; // Convert element to 32 byte hash if it is not one already @@ -130,31 +148,36 @@ export default class MerkleTree { return -1; } - bufDedup(elements) { - return elements.filter((el, idx) => { + bufDedup(elements: any[]) { + return elements.filter((el: any, idx: number) => { return this.bufIndexOf(el, elements) === idx; }); } - bufArrToHex(arr) { - if (arr.some((el) => !Buffer.isBuffer(el))) { + bufArrToHex(arr: any[]) { + if (arr.some((el: any) => !Buffer.isBuffer(el))) { throw new Error("Array is not an array of buffers"); } - return "0x" + arr.map((el) => el.toString("hex")).join(""); + return ( + "0x" + + arr + .map((el: { toString: (arg0: string) => any }) => el.toString("hex")) + .join("") + ); } - sortAndConcat(...args) { + sortAndConcat(...args: any[]) { return Buffer.concat([...args].sort(Buffer.compare)); } - sha3(node) { + sha3(node: { payee: any; amount: any }) { return Buffer.from( Web3Utils.hexToBytes( Web3Utils.soliditySha3( - { t: "address", v: node["payee"] }, - { t: "uint256", v: node["amount"] }, - ), + { t: "address", v: node.payee }, + { t: "uint256", v: node.amount }, + )!, ), ); } diff --git a/apps/nextjs/src/app/bridge/Account.tsx b/apps/nextjs/src/app/bridge/Account.tsx index 95764f33..d4abf854 100644 --- a/apps/nextjs/src/app/bridge/Account.tsx +++ b/apps/nextjs/src/app/bridge/Account.tsx @@ -4,24 +4,12 @@ import React from "react"; import { TransferLog } from "@/app/bridge/TransferLog"; import { useTransferLog } from "@/app/providers/TransferLogProvider"; import { useCompleteTransferToL1 } from "@/hooks/useTransferToL1"; -import { api } from "@/trpc/react"; -import { padAddress } from "@/utils/utils"; -import { useAccount as useL2Account } from "@starknet-react/core"; //import { evaluate } from "@starkware-industries/commons-js-utils"; import PropTypes from "prop-types"; -import { useAccount } from "wagmi"; export const Account = ({ isL1 }: { isL1: boolean }) => { - const { address } = useAccount(); - const { address: l2address } = useL2Account(); const { transfers /*, fetchNextPage, isLoading*/ } = useTransferLog(isL1); const completeTransferToL1 = useCompleteTransferToL1(); - /*const [bridge] = api.bridge.all.useSuspenseQuery({ - l1Account: padAddress(address ?? ""), - l2Account: padAddress(l2address ?? ""), - }); - console.log(bridge);*/ - console.log(transfers); const onCompleteTransferClick = (transfer: any) => { completeTransferToL1(transfer); diff --git a/apps/nextjs/src/app/bridge/TransferLog.tsx b/apps/nextjs/src/app/bridge/TransferLog.tsx index 9130cf30..82540483 100644 --- a/apps/nextjs/src/app/bridge/TransferLog.tsx +++ b/apps/nextjs/src/app/bridge/TransferLog.tsx @@ -1,7 +1,6 @@ -"use client"; - -import React, { useEffect, useState } from "react"; import type { DepositEvent, WithdrawalEvent } from "@/.graphclient"; +import type { ChainTypeL2 } from "@starkware-industries/commons-js-enums"; +import React, { useEffect, useState } from "react"; import { NETWORK_NAME, STARKSCAN_ETH_TX_URL, @@ -10,7 +9,6 @@ import { import { ChainType, tokens } from "@/constants/tokens"; import LordsIcon from "@/icons/lords.svg"; import { useNetwork } from "@starknet-react/core"; -import type { ChainTypeL2 } from "@starkware-industries/commons-js-enums"; import { isOnChain, isRejected, @@ -45,7 +43,6 @@ export const TransferLog = ({ onCompleteTransferClick: () => void; }) => { const [sign, setSign] = useState(""); - const { chain } = useNetwork(); const [l2hash, setL2hash] = useState(""); const { depositEvents, withdrawalEvents, createdTimestamp } = transfer; @@ -54,11 +51,9 @@ export const TransferLog = ({ id, //l2Recipient, amount, - createdTxHash, finishedTxHash: l1hash, - finishedAtDate, - }: DepositEvent | WithdrawalEvent = depositEvents?.[0] || - withdrawalEvents?.[0] || + }: DepositEvent | WithdrawalEvent = depositEvents?.[0] ?? + withdrawalEvents?.[0] ?? transfer; const getl2hash = async () => { @@ -98,7 +93,7 @@ export const TransferLog = ({ > {!isOnChain(typedStatus) ? TransactionStatusFriendlyMessage[ - typedStatus || TransactionStatus.NOT_RECEIVED + typedStatus ?? TransactionStatus.NOT_RECEIVED ] : ""} @@ -158,7 +153,7 @@ export const TransferLog = ({ )}
- {transfer.amount ? amount : formatEther(amount || 0)} + {transfer.amount ? amount : formatEther(amount ?? 0)}
diff --git a/apps/nextjs/src/app/collection/CollectionsList.tsx b/apps/nextjs/src/app/collection/CollectionsList.tsx index 66fce722..619791d9 100644 --- a/apps/nextjs/src/app/collection/CollectionsList.tsx +++ b/apps/nextjs/src/app/collection/CollectionsList.tsx @@ -1,6 +1,8 @@ import type { Collection, L2Collection } from "@/types"; import { CollectionCard } from "@/app/_components/CollectionCard"; -import { getTokenContractAddresses } from "@/utils/utils"; +import { SUPPORTED_L1_CHAIN_ID } from "@/constants/env"; + +import { Collections, getCollectionAddresses } from "@realms-world/constants"; import { getCollections } from "../../lib/reservoir/getCollections"; @@ -11,12 +13,15 @@ export const metadata = { }; export default async function CollectionsList() { - const l1Collections = await getCollections([ - { contract: getTokenContractAddresses("realms").L1! }, - ]); + const { collections } = (await getCollections([ + { + contract: getCollectionAddresses(Collections.REALMS)[ + SUPPORTED_L1_CHAIN_ID + ]!, + }, + ])) as { collections: Collection[] }; // TODO refine collection display logic (with l2 collections included) - const collections: Collection[] = l1Collections?.collections; const l2Collections: L2Collection[] = [ { name: "Beasts", @@ -25,8 +30,8 @@ export default async function CollectionsList() { }, { name: "Golden Token", - link: "goldenToken", - image: "/collections/goldenToken.svg", + link: "goldentoken", + image: "/collections/goldentoken.svg", }, ]; diff --git a/apps/nextjs/src/app/collection/[id]/(list)/AttributesDropdown.tsx b/apps/nextjs/src/app/collection/[id]/(list)/AttributesDropdown.tsx index b8233c1d..50627f38 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/AttributesDropdown.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/AttributesDropdown.tsx @@ -24,12 +24,7 @@ export const AttributesDropdown = ({ attributes?: any; attributesPromise?: Promise; }) => { - const { - handleAttributeClick, - isAttributeInQuery, - isKeyInQuery, - getQueriesFromUrl, - } = useQuery(); + const { handleAttributeClick, isAttributeInQuery, isKeyInQuery } = useQuery(); const { data: attributesFetched } = api.erc721Attributes.all.useQuery( { contractAddress: address, diff --git a/apps/nextjs/src/app/collection/[id]/(list)/CardAction.tsx b/apps/nextjs/src/app/collection/[id]/(list)/CardAction.tsx index 3af7d694..77a56b87 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/CardAction.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/CardAction.tsx @@ -1,4 +1,3 @@ -import LordsIcon from "@/icons/lords.svg"; import { useAccount } from "@starknet-react/core"; import type { RouterOutputs } from "@realms-world/api"; @@ -11,10 +10,8 @@ import { ListingEditModal } from "../../marketplace/listEdit/ListingEditModal"; export const CardAction = ({ token, - layout = "grid", }: { token: RouterOutputs["erc721Tokens"]["all"]["items"][number]; - layout?: "grid" | "list"; }) => { const { address } = useAccount(); return ( @@ -29,7 +26,7 @@ export const CardAction = ({ } // tokenId={tokenId} token={token} - collectionId={token.contract_address} + collectionId={token.contract_address!} orderId={0} /> ) : ( @@ -49,7 +46,7 @@ export const CardAction = ({ List Item diff --git a/apps/nextjs/src/app/collection/[id]/(list)/CollectionSummary.tsx b/apps/nextjs/src/app/collection/[id]/(list)/CollectionSummary.tsx index a3e59ddb..11fba143 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/CollectionSummary.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/CollectionSummary.tsx @@ -1,30 +1,34 @@ -import type { erc721Tokens } from "@/constants"; import type { Collection } from "@reservoir0x/reservoir-kit-ui"; import Image from "next/image"; import Link from "next/link"; +import { SUPPORTED_L1_CHAIN_ID, SUPPORTED_L2_CHAIN_ID } from "@/constants/env"; import Discord from "@/icons/discord.svg"; import { getCollections } from "@/lib/reservoir/getCollections"; import { getGamesByContract } from "@/utils/getters"; -import { getTokenContractAddresses } from "@/utils/utils"; -import { ExternalLink, Globe, Twitter } from "lucide-react"; +import { ExternalLink, Globe, X } from "lucide-react"; import { formatEther } from "viem"; -import { games } from "@realms-world/constants"; +import type { Collections } from "@realms-world/constants"; +import { games, getCollectionAddresses } from "@realms-world/constants"; import L2CollectionSummary from "./L2CollectionSummary"; export default async function CollectionSummary({ collectionId, }: { - collectionId: keyof typeof erc721Tokens; + collectionId: string; }) { - const tokenAddresses = getTokenContractAddresses(collectionId); + const tokenAddresses = getCollectionAddresses(collectionId); + if (!tokenAddresses) { + return
Collection Not Found
; + } - if (tokenAddresses.L2) { - return ; - } else if (tokenAddresses.L1) { + if (tokenAddresses[SUPPORTED_L2_CHAIN_ID]) { + return ; + } else if (tokenAddresses[SUPPORTED_L1_CHAIN_ID]) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const { collections }: { collections: Collection[] } = await getCollections( - [{ contract: tokenAddresses.L1 }], + [{ contract: tokenAddresses[SUPPORTED_L1_CHAIN_ID]! }], ); const collection = collections?.[0]; @@ -43,7 +47,7 @@ export default async function CollectionSummary({ value: collection.discordUrl, }, { - icon: , + icon: , value: "https://twitter.com/" + collection.twitterUsername, }, { icon: , value: collection.externalUrl }, diff --git a/apps/nextjs/src/app/collection/[id]/(list)/L1TokenCard.tsx b/apps/nextjs/src/app/collection/[id]/(list)/L1TokenCard.tsx index fb4ed7f0..bcf4a332 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/L1TokenCard.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/L1TokenCard.tsx @@ -1,12 +1,13 @@ import type { TokenMarketData } from "@/types"; import Image from "next/image"; import Link from "next/link"; -import { findTokenName } from "@/utils/utils"; // import { BuyModal } from "@reservoir0x/reservoir-kit-ui"; import { formatEther } from "viem"; import { Button } from "@realms-world/ui"; +import { BuyButton } from "../../reservoir/BuyModal"; + //import { BuyButton } from "./BuyModal"; interface TokenCardProps { @@ -119,10 +120,11 @@ export const L1TokenCard = (props: TokenCardProps) => { > view + {/* TODO add back with reservoir + />*/} )} diff --git a/apps/nextjs/src/app/collection/[id]/(list)/L1TokenTable.tsx b/apps/nextjs/src/app/collection/[id]/(list)/L1TokenTable.tsx index ceb850cf..6755f2e3 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/L1TokenTable.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/L1TokenTable.tsx @@ -2,7 +2,8 @@ import type { TokenMarketData } from "@/types"; import { L1TokenCard } from "@/app/collection/[id]/(list)/L1TokenCard"; -import { findTokenName } from "@/utils/utils"; + +import { getCollectionFromAddress } from "@realms-world/constants"; import { useUIContext } from "../../../providers/UIProvider"; @@ -18,7 +19,7 @@ export const L1TokenTable = ({ const grid = "grid grid-cols-1 gap-4 sm:pl-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5"; const list = "grid grid-cols-1 mx-4 border border-t-0"; - const collectionName = findTokenName(address); + const collectionName = getCollectionFromAddress(address); return (
@@ -27,7 +28,7 @@ export const L1TokenTable = ({ return ( diff --git a/apps/nextjs/src/app/collection/[id]/(list)/L2CollectionSummary.tsx b/apps/nextjs/src/app/collection/[id]/(list)/L2CollectionSummary.tsx index 58393fc5..95231511 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/L2CollectionSummary.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/L2CollectionSummary.tsx @@ -1,20 +1,29 @@ import Image from "next/image"; -import Link from "next/link"; -import { erc721Tokens, games } from "@/constants"; -import Discord from "@/icons/discord.svg"; -import { getCollections } from "@/lib/reservoir/getCollections"; -import { getGamesByContract } from "@/utils/getters"; -import { getTokenContractAddresses } from "@/utils/utils"; +import { SUPPORTED_L2_CHAIN_ID } from "@/constants/env"; +//import Discord from "@/icons/discord.svg"; +import LordsIcon from "@/icons/lords.svg"; +import { api } from "@/trpc/server"; + +/*import { getGamesByContract } from "@/utils/getters"; import { ExternalLink, Globe, Twitter } from "lucide-react"; -import { formatEther } from "viem"; +import { formatEther } from "viem";*/ + +import type { Collections } from "@realms-world/constants"; +import { + CollectionDisplayName, + getCollectionAddresses, +} from "@realms-world/constants"; export default async function L2CollectionSummary({ collectionId, }: { - collectionId: keyof typeof erc721Tokens; + collectionId: string; }) { - const tokenAddresses = getTokenContractAddresses(collectionId); + const tokenAddresses = getCollectionAddresses(collectionId); + const erc721Collection = await api.erc721Collections.byId({ + id: tokenAddresses[SUPPORTED_L2_CHAIN_ID]!, + }); const contract_details = [ { title: "Type", @@ -25,7 +34,29 @@ export default async function L2CollectionSummary({ value: "Starknet", }, ]; - + const statistics = [ + /* { + value: collection.floorSale?.["1day"], + title: "Top Offer", + }, + { + value: + collection.floorAsk?.price?.amount?.raw && + formatEther(BigInt(collection?.floorAsk?.price?.amount?.raw)), + title: "Floor", + },*/ + //{ value: collection.onSaleCount, title: "Listed" }, + { + value: ( + + {erc721Collection?.[0]?.volume}{" "} + + + ), + title: "Total Volume", + }, + //{ value: collection.tokenCount, title: "Count" }, + ]; //const comptatible_games = getGamesByContract(games, collection.id); return ( @@ -62,7 +93,7 @@ export default async function L2CollectionSummary({ ); })}
-

{erc721Tokens[collectionId].name}

+

{CollectionDisplayName[collectionId as Collections]}

{/*
{comptatible_games.map((game: any, index: any) => { return ( @@ -77,19 +108,19 @@ export default async function L2CollectionSummary({ })}
*/}
- {/*statistics.map((statistic, index) => { + {statistics.map((statistic, index) => { return (
-
+
{statistic.title}
{statistic.value}
); - })*/} + })}
{/*

+ {token.lastPrice && ( + + Last sale: {token.lastPrice} + + + )}
diff --git a/apps/nextjs/src/app/collection/[id]/(list)/L2ERC721Table.tsx b/apps/nextjs/src/app/collection/[id]/(list)/L2ERC721Table.tsx index ef8fad25..748409de 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/L2ERC721Table.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/L2ERC721Table.tsx @@ -7,6 +7,8 @@ import { cleanQuery } from "@/lib/reservoir/getToken"; import { api } from "@/trpc/react"; import { useInView } from "framer-motion"; +import type { RouterInputs } from "@realms-world/api"; + import { TokenCardSkeleton } from "../../TokenCardSkeleton"; import { L2ERC721Card } from "./L2ERC721Card"; @@ -37,7 +39,7 @@ const L2ERC721Table = ({ } const attributeFilter = cleanQuery(attributesObject); - const filters = { + const filters: RouterInputs["erc721Tokens"]["all"] = { limit: 24, contractAddress, attributeFilter: attributeFilter, @@ -49,7 +51,7 @@ const L2ERC721Table = ({ filters.owner = ownerAddress; } - const [erc721Tokens, { fetchNextPage, isLoading, hasNextPage, isFetching }] = + const [erc721Tokens, { fetchNextPage, hasNextPage, isFetching }] = api.erc721Tokens.all.useSuspenseInfiniteQuery(filters, { getNextPageParam(lastPage) { return lastPage.nextCursor; diff --git a/apps/nextjs/src/app/collection/[id]/(list)/LIstingCard.tsx b/apps/nextjs/src/app/collection/[id]/(list)/LIstingCard.tsx new file mode 100644 index 00000000..d555d908 --- /dev/null +++ b/apps/nextjs/src/app/collection/[id]/(list)/LIstingCard.tsx @@ -0,0 +1,72 @@ +import type { Activity } from "@/types"; +import Image from "next/image"; +import Link from "next/link"; +import { useTimeDiff } from "@/hooks/useTimeDiff"; +import LordsIcon from "@/icons/lords.svg"; +import { shortenHex } from "@/utils/utils"; + +import type { RouterOutputs } from "@realms-world/api"; +import { Button } from "@realms-world/ui"; + +import { BuyModal } from "../../marketplace/buy/BuyModal"; + +interface ActivityCardProps { + activity: RouterOutputs["erc721MarketEvents"]["all"]["items"][number]; + token?: RouterOutputs["erc721Tokens"]["byId"]; +} + +export const ListingCard = ({ activity, token }: ActivityCardProps) => { + // convert unix to time + + const expiryDiff = useTimeDiff(activity.expiration ?? Date.now()); + const getLocalizedDate = () => { + return expiryDiff.toLocaleString(); + }; + + return ( +
+
+
+ {activity.price || 0} + +
+
+
+ from:
+ {activity.created_by ? ( + + {activity.created_by ? shortenHex(activity.created_by) : ""} + + ) : ( + "-" + )} +
+ +
+
+ + {expiryDiff} + +
+
+
+ {token && ( + + Buy Now + + } + // tokenId={tokenId} + token={token} + //collectionId={activity.collection_id} + orderId={0} + /> + )} +
+
+ ); +}; diff --git a/apps/nextjs/src/app/collection/[id]/(list)/Trade.tsx b/apps/nextjs/src/app/collection/[id]/(list)/Trade.tsx index 08d4ac1f..dffae9a8 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/Trade.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/Trade.tsx @@ -3,6 +3,7 @@ import { AttributesDropdown } from "@/app/collection/[id]/(list)/AttributesDropd import { AttributeTags } from "@/app/collection/[id]/(list)/AttributeTags"; import { TradeFilters } from "@/app/collection/[id]/(list)/TradeFilters"; import { TokenCardSkeleton } from "@/app/collection/TokenCardSkeleton"; +import { Attributes } from "@/types"; import type { RouterOutputs } from "@realms-world/api"; @@ -13,7 +14,7 @@ export const TradeLayout = ({ attributesPromise, }: { tokenAddress: string; - attributes?: any; + attributes?: Attributes[]; children: React.ReactNode; attributesPromise?: Promise; }) => { @@ -26,13 +27,18 @@ export const TradeLayout = ({
{tokenAddress && ( <> - {attributes || attributesPromise ? ( + {attributes && ( + )} + {attributesPromise && ( + - ) : null} + )} {/**/}
diff --git a/apps/nextjs/src/app/collection/[id]/(list)/TradeFilters.tsx b/apps/nextjs/src/app/collection/[id]/(list)/TradeFilters.tsx index 94055e1d..2b260633 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/TradeFilters.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/TradeFilters.tsx @@ -14,7 +14,7 @@ import { } from "@realms-world/ui"; export const TradeFilters = () => { - const { handleAttributeClick, getQueriesFromUrl } = useQuery(); + const { handleAttributeClick } = useQuery(); const { isGrid, toggleFilter, toggleGrid } = useUIContext(); return (
diff --git a/apps/nextjs/src/app/collection/[id]/(list)/activity/CollectionActivity.tsx b/apps/nextjs/src/app/collection/[id]/(list)/activity/CollectionActivity.tsx index 5ebd3cce..22957f70 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/activity/CollectionActivity.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/activity/CollectionActivity.tsx @@ -5,7 +5,11 @@ import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { Switch } from "@realms-world/ui"; -export const CollectionActivity = () => { +export const CollectionActivity = ({ + searchAttributes = ["sale", "transfer", "bid", "ask"], +}: { + searchAttributes?: string[]; +}) => { const pathname = usePathname(); const searchParams = useSearchParams(); const router = useRouter(); @@ -39,8 +43,6 @@ export const CollectionActivity = () => { router.replace(`${pathname}?${params}`); }; - const searchAttributes = ["sale", "transfer", "bid", "ask"]; - useEffect(() => { const params = new URLSearchParams(searchParams); const newState = searchAttributes.reduce((acc, attribute) => { diff --git a/apps/nextjs/src/app/collection/[id]/(list)/activity/L2ActivityCard.tsx b/apps/nextjs/src/app/collection/[id]/(list)/activity/L2ActivityCard.tsx new file mode 100644 index 00000000..a813fa6d --- /dev/null +++ b/apps/nextjs/src/app/collection/[id]/(list)/activity/L2ActivityCard.tsx @@ -0,0 +1,156 @@ +import Image from "next/image"; +import Link from "next/link"; +import LordsIcon from "@/icons/lords.svg"; +import { shortenHex } from "@/utils/utils"; + +import type { RouterOutputs } from "@realms-world/api"; +import { getCollectionFromId } from "@realms-world/constants/src/Marketplace"; + +interface ActivityCardProps { + activity: RouterOutputs["erc721MarketEvents"]["all"]["items"][number]; +} + +export const L2ActivityCard = ({ activity }: ActivityCardProps) => { + // convert unix to time + const date = activity.updated_at ? new Date(activity.updated_at) : null; + + function getElapsedTime() { + // get time difference from now + if (date) { + const timeDiff = Math.abs(Date.now() - date.getTime()); + + // get time difference in various units + const seconds = Math.floor(timeDiff / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + const days = Math.floor(hours / 24); + const weeks = Math.floor(days / 7); + const months = Math.floor(days / 30); + const years = Math.floor(days / 365); + + // return the most appropriate unit + if (seconds < 60) + return `${seconds} second${seconds === 1 ? "" : "s"} ago`; + if (minutes < 60) + return `${minutes} minute${minutes === 1 ? "" : "s"} ago`; + if (hours < 24) return `${hours} hour${hours === 1 ? "" : "s"} ago`; + if (days < 7) return `${days} day${days === 1 ? "" : "s"} ago`; + if (weeks < 4) return `${weeks} week${weeks === 1 ? "" : "s"} ago`; + if (months < 12) return `${months} month${months === 1 ? "" : "s"} ago`; + return `${years} year${years === 1 ? "" : "s"} ago`; + } + } + const getLocalizedDate = () => { + return date?.toLocaleString(); + }; + + let eventType; + + switch (activity.status) { + case "filled": + eventType = "Sale"; + break; + case "open": + eventType = "Listing"; + break; + case "cancelled": + eventType = "Cancelled Listing"; + break; + default: + eventType = "Unknown"; + break; + } + return ( +
+
+ {eventType} +
+ {activity.token && ( +
+ {activity.token.image && ( + An example image + )} + {activity.token.token_id && activity.collection_id && ( + + + + #{activity.token.token_id} + {" "} +
+ {decodeURIComponent(activity.token.name ?? "")} +
+ + )} +
+ )} + {/*activity.toAddress && ( +
+ to:
+ + {activity.toAddress ? shortenHex(activity.toAddress) : ""} + +
+ )*/} +
+ from:
+ {activity.created_by ? ( + + {activity.created_by ? shortenHex(activity.created_by) : ""} + + ) : ( + "-" + )} +
+
+ {activity.purchaser && ( + <> + to:
+ {activity.created_by ? ( + + {activity.purchaser ? shortenHex(activity.purchaser) : ""} + + ) : ( + "-" + )} + + )} +
+ +
+ {/*activity.type != "transfer" && + (activity.price?.currency ? ( +
+ {activity.price?.amount.native} {activity.price?.currency.symbol} +
+ ) : (*/} +
+ {activity.price ?? 0} + +
+
+
+
+ + {getElapsedTime()} + +
+
+
+ ); +}; diff --git a/apps/nextjs/src/app/collection/[id]/(list)/activity/L2ActivityTable.tsx b/apps/nextjs/src/app/collection/[id]/(list)/activity/L2ActivityTable.tsx new file mode 100644 index 00000000..53284e17 --- /dev/null +++ b/apps/nextjs/src/app/collection/[id]/(list)/activity/L2ActivityTable.tsx @@ -0,0 +1,78 @@ +"use client"; + +import { useEffect, useRef } from "react"; +import { api } from "@/trpc/react"; +import { useInView } from "framer-motion"; + +import type { RouterInputs } from "@realms-world/api"; +import type { Collections } from "@realms-world/constants"; +import { MarketplaceCollectionIds } from "@realms-world/constants"; + +import { L2ActivityCard } from "./L2ActivityCard"; + +export const L2ActivityTable = ({ + searchParams, + collectionId, +}: { + searchParams: { types?: string[] | string }; + collectionId: string; +}) => { + const ref = useRef(null); + + const statusArray = + typeof searchParams.types === "string" + ? [searchParams.types] + : searchParams.types; + //@ts-expect-error works + const status: ("filled" | "open")[] = statusArray?.map((status) => { + switch (status) { + case "sale": + return "filled"; + case "listing": + return "open"; + } + }); + const filters: RouterInputs["erc721MarketEvents"]["all"] = { + collectionId: MarketplaceCollectionIds[collectionId as Collections], + orderBy: "timestamp", + limit: 16, + }; + if (statusArray) filters.status = status; + const [erc721MarketEvents, { fetchNextPage, hasNextPage, isFetching }] = + api.erc721MarketEvents.all.useSuspenseInfiniteQuery(filters, { + getNextPageParam(lastPage) { + return lastPage.nextCursor; + }, + refetchInterval: 0, + }); + + const isInView = useInView(ref, { once: false }); + + useEffect(() => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + if (isInView) fetchNextPage(); + }, [fetchNextPage, isInView]); + + return ( +
+
+ {erc721MarketEvents + ? erc721MarketEvents.pages?.map((page) => + page.items.map((activity, index: number) => { + return ; + }), + ) + : "Encountered a temporary error. Please refresh the page and retry."} + {isFetching && + hasNextPage && + Array.from({ length: 3 }).map((_, index) => ( +
+ ))} +
+
+
+ ); +}; diff --git a/apps/nextjs/src/app/collection/[id]/(list)/activity/loading.tsx b/apps/nextjs/src/app/collection/[id]/(list)/activity/loading.tsx index 9785d80a..1665216c 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/activity/loading.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/activity/loading.tsx @@ -8,6 +8,7 @@ export default function Loading() {
+ {/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment*/} {[...Array(6)].map((_, i) => ( ))} diff --git a/apps/nextjs/src/app/collection/[id]/(list)/activity/page.tsx b/apps/nextjs/src/app/collection/[id]/(list)/activity/page.tsx index 443a65a7..f711ce52 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/activity/page.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/activity/page.tsx @@ -1,43 +1,70 @@ -import type { erc721Tokens } from "@/constants"; import type { Activity } from "@/types"; +import { SUPPORTED_L1_CHAIN_ID, SUPPORTED_L2_CHAIN_ID } from "@/constants/env"; import { getActivity } from "@/lib/reservoir/getActivity"; -import { getTokenContractAddresses } from "@/utils/utils"; +import { api } from "@/trpc/server"; + +import type { RouterInputs } from "@realms-world/api"; +import type { Collections } from "@realms-world/constants"; +import { + getCollectionAddresses, + MarketplaceCollectionIds, +} from "@realms-world/constants"; import { ActivityCard } from "./ActivityCard"; import { CollectionActivity } from "./CollectionActivity"; +import { L2ActivityCard } from "./L2ActivityCard"; +import { L2ActivityTable } from "./L2ActivityTable"; export default async function Page({ params, searchParams, }: { params: { id: string }; - searchParams: any; + searchParams: { types?: string[] | string }; }) { + const tokenAddresses = getCollectionAddresses(params.id); + if (!tokenAddresses) { + return
Collection Not Found
; + } + const types = typeof searchParams.types === "string" ? [{ types: searchParams.types }] - : searchParams.types?.map((q: any) => { + : searchParams.types?.map((q: string) => { return { types: q }; }); - const tokenAddresses = getTokenContractAddresses( - params.id as keyof typeof erc721Tokens, - ); - const { activities } = await getActivity({ - collection: tokenAddresses.L1 ?? params.id, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const { activities }: { activities: Activity[] } = await getActivity({ + collection: tokenAddresses[SUPPORTED_L1_CHAIN_ID] ?? params.id, query: { types: types }, }); - return ( -
- -
- {activities - ? activities.map((activity: Activity, index: number) => { - return ; - }) - : "Encountered a temporary error. Please refresh the page and retry."} + if (tokenAddresses[SUPPORTED_L2_CHAIN_ID]) { + return ( +
+ + +
+ ); + } else if (tokenAddresses[SUPPORTED_L1_CHAIN_ID]) { + return ( +
+ +
+ {activities + ? activities.map((activity: Activity, index: number) => { + return ; + }) + : "Encountered a temporary error. Please refresh the page and retry."} +
-
- ); + ); + } } diff --git a/apps/nextjs/src/app/collection/[id]/(list)/analytics/OwnerDistribution.tsx b/apps/nextjs/src/app/collection/[id]/(list)/analytics/OwnerDistribution.tsx index 31a7b793..de961645 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/analytics/OwnerDistribution.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/analytics/OwnerDistribution.tsx @@ -1,5 +1,7 @@ "use client"; +import type { paths } from "@reservoir0x/reservoir-sdk"; + import { Progress } from "@realms-world/ui"; //import PieChart from "@/homepages/realms-eternum/components/PieChart"; @@ -7,7 +9,7 @@ import { Progress } from "@realms-world/ui"; export const OwnerDistribution = ({ ownersDistribution, }: { - ownersDistribution: { tokenCount: number; ownerCount: number }[]; + ownersDistribution: paths["/collections/{collection}/owners-distribution/v1"]["get"]["responses"]["200"]["schema"]["ownersDistribution"]; }) => { const tokenRanges = [ { min: 0, max: 1 }, @@ -18,15 +20,18 @@ export const OwnerDistribution = ({ { min: 51, max: 100000 }, ]; - const totalOwners = ownersDistribution.reduce( - (sum, { ownerCount }) => sum + ownerCount, + const totalOwners = ownersDistribution?.reduce( + (sum, { ownerCount }) => sum + (ownerCount ?? 0), 0, ); const ownerCountsByTokenRange = tokenRanges.map(({ min, max }) => ownersDistribution - .filter(({ tokenCount }) => tokenCount >= min && tokenCount <= max) - .reduce((sum, { ownerCount, tokenCount }) => sum + ownerCount, 0), + ?.filter( + ({ tokenCount }) => + (tokenCount ?? 0) >= min && (tokenCount ?? 0) <= max, + ) + .reduce((sum, { tokenCount }) => sum + (tokenCount ?? 0), 0), ); return ( @@ -38,25 +43,27 @@ export const OwnerDistribution = ({ {ownerCountsByTokenRange.length && ownerCountsByTokenRange.map((amount, index) => { - const ownerPercentage = (amount / totalOwners) * 100; - const range = tokenRanges[index]; - const { min, max } = range!; - - const rangeLabel = - index > 0 && index + 1 !== tokenRanges.length - ? `${min}-${max}` - : `${min}+`; - - const pluralSuffix = index > 0 ? "s" : ""; - - return ( -
-

- {rangeLabel} item{pluralSuffix}: {ownerPercentage.toFixed(1)}% -

- -
- ); + if (amount && totalOwners) { + const ownerPercentage = (amount / totalOwners) * 100; + const range = tokenRanges[index]; + const { min, max } = range!; + + const rangeLabel = + index > 0 && index + 1 !== tokenRanges.length + ? `${min}-${max}` + : `${min}+`; + + const pluralSuffix = index > 0 ? "s" : ""; + + return ( +
+

+ {rangeLabel} item{pluralSuffix}: {ownerPercentage.toFixed(1)}% +

+ +
+ ); + } })}
); diff --git a/apps/nextjs/src/app/collection/[id]/(list)/analytics/page.tsx b/apps/nextjs/src/app/collection/[id]/(list)/analytics/page.tsx index 5c723c89..c9c84235 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/analytics/page.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/analytics/page.tsx @@ -1,21 +1,33 @@ -import type { erc721Tokens } from "@/constants"; +import type { paths } from "@reservoir0x/reservoir-sdk"; +import { SUPPORTED_L1_CHAIN_ID } from "@/constants/env"; import { getOwnersDistribution } from "@/lib/reservoir/getOwnerDistribution"; import { getOwners } from "@/lib/reservoir/getOwners"; -import { getTokenContractAddresses } from "@/utils/utils"; + +import { getCollectionAddresses } from "@realms-world/constants"; import { OwnerDistribution } from "./OwnerDistribution"; import { TopOwners } from "./TopOwners"; export default async function Page({ params }: { params: { id: string } }) { - const tokenAddresses = getTokenContractAddresses( - params.id as keyof typeof erc721Tokens, - ); - const { ownersDistribution } = await getOwnersDistribution({ - collection: tokenAddresses.L1 ?? params.id, - }); - const { owners } = await getOwners({ - collection: tokenAddresses.L1 ?? params.id, - }); + const tokenAddresses = getCollectionAddresses(params.id); + if (!tokenAddresses[SUPPORTED_L1_CHAIN_ID]) { + return

Coming Soon

; + } + const ownersDistributionData = getOwnersDistribution({ + collection: tokenAddresses[SUPPORTED_L1_CHAIN_ID] ?? params.id, + }) as Promise< + paths["/collections/{collection}/owners-distribution/v1"]["get"]["responses"]["200"]["schema"] + >; + const ownersData = getOwners({ + collection: tokenAddresses[SUPPORTED_L1_CHAIN_ID] ?? params.id, + }) as Promise<{ + owners: paths["/owners/v2"]["get"]["responses"]["200"]["schema"]; + }>; + + const [{ ownersDistribution }, owners] = await Promise.all([ + ownersDistributionData, + ownersData, + ]); const cards = [ { @@ -29,7 +41,7 @@ export default async function Page({ params }: { params: { id: string } }) { {cards.map((card, index) => (
{card.component}
diff --git a/apps/nextjs/src/app/collection/[id]/(list)/layout.tsx b/apps/nextjs/src/app/collection/[id]/(list)/layout.tsx index 710e795a..d75594c9 100644 --- a/apps/nextjs/src/app/collection/[id]/(list)/layout.tsx +++ b/apps/nextjs/src/app/collection/[id]/(list)/layout.tsx @@ -1,7 +1,7 @@ import React from "react"; import CollectionSummary from "@/app/collection/[id]/(list)/CollectionSummary"; -import { NETWORK_NAME } from "@/constants/env"; +import { Collections } from "@realms-world/constants"; import { NavLink } from "@realms-world/ui"; export default function RootLayout({ @@ -14,7 +14,9 @@ export default function RootLayout({ const defaultImage = "/backgrounds/dummy_background.webp"; const imageUrl = params.id ? `/backgrounds/${params.id}.png` : defaultImage; - const isMintable = NETWORK_NAME == "SEPOLIA" && params.id == "goldenToken"; + const isMintable = + process.env.NEXT_PUBLIC_IS_TESTNET == "true" && + params.id == (Collections.GOLDEN_TOKEN as string); const tabs = [ { name: "Trade", @@ -27,15 +29,14 @@ export default function RootLayout({ link: "mint", }); } - if (params.id == "realms") { - tabs.push( - { name: "Analytics", link: "analytics" }, - { - name: "Activity", - link: "activity", - }, - ); - } + tabs.push( + { name: "Analytics", link: "analytics" }, + { + name: "Activity", + link: "activity", + }, + ); + return (
{ - const collection = erc721Tokens[params.id as keyof typeof erc721Tokens]; + const collection = CollectionDisplayName[params.id as Collections]; return { - title: `${collection?.name}`, - description: `Collection Details and Marketplace for ${collection?.name} - Created for adventurers by Bibliotheca DAO`, + title: `${collection}`, + description: `Collection Details and Marketplace for ${collection} - Created for adventurers by Bibliotheca DAO`, }; } @@ -33,10 +39,11 @@ export default async function Page({ page?: string; }; }) { - const tokenAddresses = getTokenContractAddresses( - params.id as keyof typeof erc721Tokens, - ); + const tokenAddresses = getCollectionAddresses(params.id); + if (!tokenAddresses) { + return
Collection Not Found
; + } /* isSepoliaGoldenToken = NETWORK_NAME == "SEPOLIA" && (tokenAddresses.L2 ?? params.id == "goldenToken"); @@ -44,18 +51,18 @@ export default async function Page({ if (isSepoliaGoldenToken) { return ; }*/ - if (tokenAddresses.L2) { - return ; + if (tokenAddresses[SUPPORTED_L2_CHAIN_ID]) { + return ( + + ); } - if (tokenAddresses.L1) { + if (tokenAddresses[SUPPORTED_L1_CHAIN_ID]) { return ( ); - } else { - return
Collection Not Found
; } } @@ -88,19 +95,22 @@ const L1TokenData = async ({ const tokensData = getToken({ collection: tokenAddress, query: searchParams ?? {}, - }); + }) as Promise<{ tokens: TokenMarketData[] }>; const attributesData = getAttributes({ collection: tokenAddress, - }); - const [tokens, attributes] = await Promise.all([tokensData, attributesData]); + }) as Promise<{ attributes: Attributes[] }>; + const [{ tokens }, { attributes }] = await Promise.all([ + tokensData, + attributesData, + ]); if (!tokens) { return
Collection Not Found
; } return ( - - + + ); }; diff --git a/apps/nextjs/src/app/collection/[id]/(list)/trade/page.tsx b/apps/nextjs/src/app/collection/[id]/(list)/trade/page.tsx deleted file mode 100644 index 9affbc24..00000000 --- a/apps/nextjs/src/app/collection/[id]/(list)/trade/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import type { erc721Tokens } from "@/constants"; - -//import { Trade } from "../Trade"; - -export default async function Page({ params }: { params: { id: string } }) { - return "test"; - { - /*;*/ - } -} diff --git a/apps/nextjs/src/app/collection/[id]/[tokenId]/ContractImage.tsx b/apps/nextjs/src/app/collection/[id]/[tokenId]/ContractImage.tsx index 1018a583..99504888 100644 --- a/apps/nextjs/src/app/collection/[id]/[tokenId]/ContractImage.tsx +++ b/apps/nextjs/src/app/collection/[id]/[tokenId]/ContractImage.tsx @@ -1,20 +1,17 @@ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-explicit-any */ "use client"; -import type { ERC721Tokens } from "@/constants/erc721Tokens"; -import type { Attributes, Collection, Token } from "@/types"; import { useMemo } from "react"; import Image from "next/image"; -import Link from "next/link"; import L2_C1ERC20 from "@/abi/L2/C1ERC20.json"; -import { erc721Tokens } from "@/constants/erc721Tokens"; -import { getTokenContractAddresses, shortenHex } from "@/utils/utils"; +import { SUPPORTED_L2_CHAIN_ID } from "@/constants/env"; import { useContractRead } from "@starknet-react/core"; -import { ArrowLeft, Loader } from "lucide-react"; +import { Loader } from "lucide-react"; import { shortString } from "starknet"; -import type { RouterOutputs } from "@realms-world/api"; - -import { TokenAttribute } from "./TokenAttribute"; +import { getCollectionAddresses } from "@realms-world/constants"; export const ContractImage = ({ tokenId, @@ -24,11 +21,10 @@ export const ContractImage = ({ collectionId: string; }) => { const isBeasts = collectionId == "beasts"; - const tokenAddress = getTokenContractAddresses( - collectionId as keyof ERC721Tokens, - ).L2; + const tokenAddress = + getCollectionAddresses(collectionId)[SUPPORTED_L2_CHAIN_ID]; - const { data, isError, isLoading, error } = useContractRead({ + const { data } = useContractRead({ functionName: "token_uri", args: [tokenId], abi: L2_C1ERC20, diff --git a/apps/nextjs/src/app/collection/[id]/[tokenId]/L2Token.tsx b/apps/nextjs/src/app/collection/[id]/[tokenId]/L2Token.tsx index c30ee4f4..45a69c35 100644 --- a/apps/nextjs/src/app/collection/[id]/[tokenId]/L2Token.tsx +++ b/apps/nextjs/src/app/collection/[id]/[tokenId]/L2Token.tsx @@ -3,17 +3,24 @@ import { useTimeDiff } from "@/hooks/useTimeDiff"; import Lords from "@/icons/lords.svg"; import { api } from "@/trpc/react"; -import { findTokenName, padAddress } from "@/utils/utils"; +import { padAddress } from "@/utils/utils"; import { useAccount } from "@starknet-react/core"; import { Clock } from "lucide-react"; import type { RouterOutputs } from "@realms-world/api"; -import { Button } from "@realms-world/ui"; +import { getCollectionFromAddress } from "@realms-world/constants"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, + Button, +} from "@realms-world/ui"; import { BuyModal } from "../../marketplace/buy/BuyModal"; import TokenOwnerActions from "../../marketplace/TokenOwnerActions"; -import { LoadingSkeleton } from "./loading"; -import { TokenInformation } from "./TokenInformation"; +import { L2ActivityCard } from "../(list)/activity/L2ActivityCard"; +import { ListingCard } from "../(list)/LIstingCard"; export const L2Token = ({ contractAddress, @@ -24,7 +31,7 @@ export const L2Token = ({ tokenId: string; token: RouterOutputs["erc721Tokens"]["byId"]; }) => { - const { data: erc721Token, isLoading } = api.erc721Tokens.byId.useQuery( + const { data: erc721Token } = api.erc721Tokens.byId.useQuery( { id: contractAddress + ":" + tokenId, }, @@ -36,18 +43,18 @@ export const L2Token = ({ if (!erc721Token) return
Token Information Loading
; const activeListings = erc721Token.listings?.filter( - (listing) => listing.active, + (listing) => listing.active && listing.created_by == erc721Token.owner, ); const lowestPriceActiveListing = activeListings?.reduce( (minPriceListing, currentListing) => - currentListing.price < minPriceListing.price + (currentListing.price ?? 0) < (minPriceListing?.price ?? 0) ? currentListing : minPriceListing, activeListings[0], ); - const collectionId = findTokenName(contractAddress); + const collectionId = getCollectionFromAddress(contractAddress); const expiryDiff = useTimeDiff(lowestPriceActiveListing?.expiration || 0); const price = lowestPriceActiveListing?.price @@ -79,11 +86,7 @@ export const L2Token = ({ "Not listed" )}{" "} {erc721Token.owner == padAddress(address) ? ( - + ) : (
{lowestPriceActiveListing && ( @@ -103,6 +106,42 @@ export const L2Token = ({ )}
+ + +
+ Listings + + {activeListings.length + ? activeListings.map((listing, index) => { + return ( + + ); + }) + : "No Active Listings"} + +
+
+ +
+ + Token Activity + + + {erc721Token.listings.map((listing, index) => { + return ; + })} + +
+
+
); }; diff --git a/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenAttribute.tsx b/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenAttribute.tsx index 2a4cbf8d..eb40ddc9 100644 --- a/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenAttribute.tsx +++ b/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenAttribute.tsx @@ -1,11 +1,10 @@ "use client"; import Link from "next/link"; -import type { Attributes } from "@/types"; interface TokenAttributeProps { title: string; - value: any; + value: string | number; contractId: string; floorAskPrice?: string | number; attributeTokenCount?: number; diff --git a/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenAttributes.tsx b/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenAttributes.tsx index 51837cb1..80ed8760 100644 --- a/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenAttributes.tsx +++ b/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenAttributes.tsx @@ -1,10 +1,16 @@ "use client"; +import type { Attributes, Collection, Token } from "@/types"; import Link from "next/link"; -import type { Attributes } from "@/types"; -export const TokenAttributes = ({ token, collection }: any) => { - return token.attributes.map((attributes: Attributes, index: string) => { +export const TokenAttributes = ({ + token, + collection, +}: { + token: Token; + collection: Collection; +}) => { + return token.attributes.map((attributes, index) => { return ( {
{attributes.value}
{attributes.floorAskPrice}
-
- {attributes.tokenCount} ( - {( - (attributes.tokenCount / parseInt(collection.tokenCount)) * - 100 - ).toFixed(2)} - %) -
+ {attributes.tokenCount && ( +
+ {attributes.tokenCount} ( + {( + (attributes.tokenCount / parseInt(collection.tokenCount)) * + 100 + ).toFixed(2)} + %) +
+ )}
); diff --git a/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenContent.tsx b/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenContent.tsx index fa20550f..c28ac050 100644 --- a/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenContent.tsx +++ b/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenContent.tsx @@ -1,11 +1,12 @@ "use client"; -import type { Collection, Game, Token } from "@/types"; +import type { Collection, Token } from "@/types"; //import { BuyButton } from "@/app/collection/BuyModal"; //import { ListingModal } from "@/app/collection/ListingModal"; import { GameCard } from "@/app/games/GameCard"; import { getGamesByContract } from "@/utils/getters"; -import { useAccount } from "wagmi"; + +//import { useAccount } from "wagmi"; import { games } from "@realms-world/constants"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@realms-world/ui"; @@ -19,13 +20,13 @@ interface Props { } export const TokenContent = ({ token, collection }: Props) => { - const { address, isConnecting, isConnected } = useAccount(); + //const { address} = useAccount(); const comptatible_games = getGamesByContract(games, collection.id); - const owner = address + /*const owner = address ? token.owner.toUpperCase() === address.toUpperCase() - : false; + : false;*/ const tabs = [ { @@ -36,7 +37,7 @@ export const TokenContent = ({ token, collection }: Props) => { name: "Games", content: (
- {comptatible_games?.map((game: Game, index: any) => { + {comptatible_games?.map((game, index) => { return ; })}
diff --git a/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenInformation.tsx b/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenInformation.tsx index 4c291d2a..3ff15f47 100644 --- a/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenInformation.tsx +++ b/apps/nextjs/src/app/collection/[id]/[tokenId]/TokenInformation.tsx @@ -4,6 +4,7 @@ import { erc721Tokens } from "@/constants/erc721Tokens"; import { shortenHex } from "@/utils/utils"; import { ArrowLeft } from "lucide-react"; +import type { RouterOutputs } from "@realms-world/api"; import { Button } from "@realms-world/ui"; import { ContractImage } from "./ContractImage"; @@ -25,11 +26,11 @@ export const TokenInformation = ({ name: string | null; owner: string | null; image: string | null; - attributes?: any; + attributes?: + | RouterOutputs["erc721Tokens"]["byId"]["attributes"] + | Attributes[]; tokenId: number; }) => { - const isBeasts = collectionId == "beasts"; - return ( <>
@@ -44,7 +45,7 @@ export const TokenInformation = ({ ) : ( )} - {attributes?.length && ( + {attributes?.length ? (
{attributes.map((attribute: Attributes, index) => ( ))}
+ ) : ( + "" )}
diff --git a/apps/nextjs/src/app/collection/[id]/[tokenId]/layout.tsx b/apps/nextjs/src/app/collection/[id]/[tokenId]/layout.tsx index 727dbaa9..5be6e312 100644 --- a/apps/nextjs/src/app/collection/[id]/[tokenId]/layout.tsx +++ b/apps/nextjs/src/app/collection/[id]/[tokenId]/layout.tsx @@ -2,10 +2,8 @@ import React from "react"; export default function RootLayout({ children, - params, }: { children: React.ReactNode; - params: { id: string }; }) { return (
diff --git a/apps/nextjs/src/app/collection/[id]/[tokenId]/loading.tsx b/apps/nextjs/src/app/collection/[id]/[tokenId]/loading.tsx index d673e728..5c01c62b 100644 --- a/apps/nextjs/src/app/collection/[id]/[tokenId]/loading.tsx +++ b/apps/nextjs/src/app/collection/[id]/[tokenId]/loading.tsx @@ -1,5 +1,3 @@ -import { ArrowLeft } from "lucide-react"; - export default function Loading() { // You can add any UI inside Loading, including a Skeleton. return ; diff --git a/apps/nextjs/src/app/collection/[id]/[tokenId]/page.tsx b/apps/nextjs/src/app/collection/[id]/[tokenId]/page.tsx index 22e8bbeb..ef9bb7eb 100644 --- a/apps/nextjs/src/app/collection/[id]/[tokenId]/page.tsx +++ b/apps/nextjs/src/app/collection/[id]/[tokenId]/page.tsx @@ -1,12 +1,13 @@ -import type { erc721Tokens } from "@/constants"; -import type { Collection, Market, Token } from "@/types"; +import type { Collection, Market, Token, TokenMarketData } from "@/types"; import { Suspense } from "react"; +import { SUPPORTED_L1_CHAIN_ID, SUPPORTED_L2_CHAIN_ID } from "@/constants/env"; import { getCollections } from "@/lib/reservoir/getCollections"; import { getToken } from "@/lib/reservoir/getToken"; import { api } from "@/trpc/server"; -import { getTokenContractAddresses } from "@/utils/utils"; import { formatEther } from "viem"; +import { getCollectionAddresses } from "@realms-world/constants"; + import { L2Token } from "./L2Token"; import { LoadingSkeleton } from "./loading"; import { TokenContent } from "./TokenContent"; @@ -17,25 +18,25 @@ export default async function Page({ }: { params: { id: string; tokenId: string }; }) { - const tokenAddresses = getTokenContractAddresses( - params.id as keyof typeof erc721Tokens, - ); - - if (tokenAddresses.L2) { + const tokenAddresses = getCollectionAddresses(params.id); + if (!tokenAddresses) { + return
Collection Not Found
; + } + if (tokenAddresses[SUPPORTED_L2_CHAIN_ID]) { return ( }> ); - } else if (tokenAddresses.L1) { + } else if (tokenAddresses[SUPPORTED_L1_CHAIN_ID]) { return ( ); @@ -71,6 +72,7 @@ const L2TokenData = async ({ @@ -96,15 +98,17 @@ const L1TokenData = async ({ includeAttributes: true, includeQuantity: true, }, - }); - const collectionData = getCollections([{ contract: contractAddress }]); + }) as Promise<{ tokens: TokenMarketData[] }>; + const collectionData = getCollections([ + { contract: contractAddress }, + ]) as Promise<{ collections: Collection[] }>; const [{ tokens }, { collections }] = await Promise.all([ tokensData, collectionData, ]); - const token: Token | undefined = tokens?.[0]?.token; - const market: Market | null = tokens?.[0]?.market; - const collection: Collection | undefined = collections?.[0]; + const token = tokens?.[0]?.token; + const market = tokens?.[0]?.market; + const collection = collections?.[0]; if (!tokens) { return
Collection Not Found
; diff --git a/apps/nextjs/src/app/collection/marketplace/ERC721LineItem.tsx b/apps/nextjs/src/app/collection/marketplace/ERC721LineItem.tsx index 6a1b6711..c3b9623d 100644 --- a/apps/nextjs/src/app/collection/marketplace/ERC721LineItem.tsx +++ b/apps/nextjs/src/app/collection/marketplace/ERC721LineItem.tsx @@ -3,17 +3,17 @@ import React from "react"; import { getTokenName } from "@/utils/utils"; import type { RouterOutputs } from "@realms-world/api"; +import { + CollectionDisplayName, + getCollectionFromAddress, +} from "@realms-world/constants"; import ERC721MarketplaceItem from "./ERC721MarketplaceItem"; interface ERC721LineItemProps { - tokenDetails?: RouterOutputs["erc721Tokens"]["byId"] /*NonNullable< - NonNullable>["data"] - >[0];*/; - collection?: any /*Pick< - NonNullable["data"]>[0], - "name" | "royalties" | "image" - >;*/; + tokenDetails?: + | RouterOutputs["erc721Tokens"]["byId"] + | RouterOutputs["erc721Tokens"]["all"]["items"][number]; usdPrice?: number; isUnavailable?: boolean; warning?: string; @@ -27,14 +27,13 @@ interface ERC721LineItemProps { const ERC721LineItem: FC = ({ tokenDetails, - collection, usdPrice, isUnavailable, price, priceSubtitle, warning, expires, - showRoyalties, + //showRoyalties, quantity, }) => { if (!tokenDetails) { @@ -43,19 +42,23 @@ const ERC721LineItem: FC = ({ return ( diff --git a/apps/nextjs/src/app/collection/marketplace/ERC721MarketplaceItem.tsx b/apps/nextjs/src/app/collection/marketplace/ERC721MarketplaceItem.tsx index ab49a344..b371b7ba 100644 --- a/apps/nextjs/src/app/collection/marketplace/ERC721MarketplaceItem.tsx +++ b/apps/nextjs/src/app/collection/marketplace/ERC721MarketplaceItem.tsx @@ -2,11 +2,9 @@ import type { FC } from "react"; import React from "react"; import Image from "next/image"; import Lords from "@/icons/lords.svg"; -import Starknet from "@/icons/starknet.svg"; -import { formatBigInt } from "@/utils/utils"; import { Tooltip, TooltipProvider } from "@realms-world/ui"; -import { formatBN, formatNumber } from "@realms-world/utils"; +import { formatNumber } from "@realms-world/utils"; interface Props { img?: string; diff --git a/apps/nextjs/src/app/collection/marketplace/TokenOwnerActions.tsx b/apps/nextjs/src/app/collection/marketplace/TokenOwnerActions.tsx index 917b0aff..abe96d59 100644 --- a/apps/nextjs/src/app/collection/marketplace/TokenOwnerActions.tsx +++ b/apps/nextjs/src/app/collection/marketplace/TokenOwnerActions.tsx @@ -1,7 +1,6 @@ "use client"; import React from "react"; -import Lords from "@/icons/lords.svg"; import { RefreshCw, Trash2 } from "lucide-react"; import type { RouterOutputs } from "@realms-world/api"; @@ -17,20 +16,16 @@ interface TokenOwnerActionsProps { token: RouterOutputs["erc721Tokens"]["byId"]; tokenId: string; //tokenOwnerAddress: string; - contractAddress: string; } const TokenOwnerActions: React.FC = ({ token, tokenId, //tokenOwnerAddress, - contractAddress, }) => { //const { toast } = useToast(); //const { listItem } = useBurner(); - const [isSubmitting, setIsSubmitting] = React.useState(false); - - const onItemlist = async () => {}; + const [isSubmitting, _] = React.useState(false); const activeListings = token?.listings?.filter((listing) => listing.active); @@ -68,7 +63,7 @@ const TokenOwnerActions: React.FC = ({ listingId={lowestPriceActiveListing?.id} collectionId={"test"} trigger={ - } @@ -97,7 +92,7 @@ const TokenOwnerActions: React.FC = ({ tokenId={tokenId} collectionId={"test"} trigger={ - - ); - }, -); -MotionButton.displayName = "MotionButton"; - -export { MotionButton }; diff --git a/apps/ui/src/components/ui/nav-link.tsx b/apps/ui/src/components/ui/nav-link.tsx index 9431b0f7..9b1834d5 100644 --- a/apps/ui/src/components/ui/nav-link.tsx +++ b/apps/ui/src/components/ui/nav-link.tsx @@ -30,7 +30,6 @@ export const NavLink = ({ variant, size, className, - ...props }: NavLinkProps) => { const pathname = usePathname(); const isActive = exact ? pathname === href : pathname.startsWith(href); diff --git a/apps/ui/src/components/ui/progress.tsx b/apps/ui/src/components/ui/progress.tsx index 22c8ba07..ce1c04ec 100644 --- a/apps/ui/src/components/ui/progress.tsx +++ b/apps/ui/src/components/ui/progress.tsx @@ -12,14 +12,14 @@ const Progress = React.forwardRef< )); diff --git a/apps/ui/src/components/ui/radio-group.tsx b/apps/ui/src/components/ui/radio-group.tsx index 18f27750..37208af6 100644 --- a/apps/ui/src/components/ui/radio-group.tsx +++ b/apps/ui/src/components/ui/radio-group.tsx @@ -23,7 +23,7 @@ RadioGroup.displayName = RadioGroupPrimitive.Root.displayName; const RadioGroupItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => { +>(({ className, ...props }, ref) => { return ( ; export const Base: Story = { - render: (args) => ( + render: () => (