From 8702a518567819f3a7e1ed0c8b3faf8915c8f888 Mon Sep 17 00:00:00 2001 From: ECWireless Date: Tue, 25 Jun 2024 12:06:39 -0400 Subject: [PATCH 1/3] Render character token address in creation flow --- .../src/components/ConnectWalletModal.tsx | 5 ++- .../client/src/pages/CharacterCreation.tsx | 36 +++++++++++++++++-- packages/client/src/utils/helpers.ts | 3 ++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/packages/client/src/components/ConnectWalletModal.tsx b/packages/client/src/components/ConnectWalletModal.tsx index 6cc2c4e5b..a9dbaf6ab 100644 --- a/packages/client/src/components/ConnectWalletModal.tsx +++ b/packages/client/src/components/ConnectWalletModal.tsx @@ -11,6 +11,7 @@ import { import { useMemo } from 'react'; import { useAccount, useWalletClient } from 'wagmi'; +import { shortenAddress } from '../utils/helpers'; import { ConnectWalletButton } from './ConnectWalletButton'; import { DelegationButton } from './DelegationButton'; @@ -32,9 +33,7 @@ export const ConnectWalletModal = ({ Connected account: - - {address.slice(0, 6)}...{address.slice(-4)} - + {shortenAddress(address)} In order to play, you must delegate in-game power to a session account. diff --git a/packages/client/src/pages/CharacterCreation.tsx b/packages/client/src/pages/CharacterCreation.tsx index ea2c4a3b4..a4e629899 100644 --- a/packages/client/src/pages/CharacterCreation.tsx +++ b/packages/client/src/pages/CharacterCreation.tsx @@ -17,6 +17,8 @@ import { useBreakpointValue, VStack, } from '@chakra-ui/react'; +import { useComponentValue } from '@latticexyz/react'; +import { singletonEntity } from '@latticexyz/store-sync/recs'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { FaLock } from 'react-icons/fa'; import { useNavigate } from 'react-router-dom'; @@ -26,6 +28,7 @@ import { useMUD } from '../contexts/MUDContext'; import { useToast } from '../hooks/useToast'; import { useUploadFile } from '../hooks/useUploadFile'; import { API_URL } from '../utils/constants'; +import { shortenAddress } from '../utils/helpers'; import { CharacterClasses } from '../utils/types'; export const CharacterCreation = (): JSX.Element => { @@ -34,6 +37,7 @@ export const CharacterCreation = (): JSX.Element => { const isSmallScreen = useBreakpointValue({ base: true, lg: false }); const { burnerBalance, + components: { UltimateDominionConfig }, delegatorAddress, isDelegationLoaded, systemCalls: { enterGame, mintCharacter, rollStats }, @@ -58,6 +62,11 @@ export const CharacterCreation = (): JSX.Element => { const [isRollingStats, setIsRollingStats] = useState(false); const [isEnteringGame, setIsEnteringGame] = useState(false); + const { characterToken } = useComponentValue( + UltimateDominionConfig, + singletonEntity, + ) ?? { characterToken: null }; + // Reset showError state when any of the form fields change useEffect(() => { setShowError(false); @@ -264,14 +273,35 @@ export const CharacterCreation = (): JSX.Element => { my={4} w="100%" > - {character ? ( + {character && characterToken ? (
- {character.name} - {character.description} + + + Address:{' '} + + {shortenAddress(characterToken)} + + + | + + ID:{' '} + + {character.characterId} + + + + + {character.name} + {character.description} + + + Class:{' '} + {rolledOnce ? CharacterClasses[character.characterClass] : 'None'} +
) : ( diff --git a/packages/client/src/utils/helpers.ts b/packages/client/src/utils/helpers.ts index 643ee83b5..03d2df142 100644 --- a/packages/client/src/utils/helpers.ts +++ b/packages/client/src/utils/helpers.ts @@ -51,3 +51,6 @@ export const fetchMetadataFromUri = async (uri: string): Promise => { metadata.image = uriToHttp(metadata.image)[0] || ''; return metadata; }; + +export const shortenAddress = (address: string, length = 4): string => + `${address.slice(0, length + 2)}...${address.slice(-length)}`; From c3239cd9fdf3ba4a774e0471d43fcf6dcd1aca63 Mon Sep 17 00:00:00 2001 From: ECWireless Date: Tue, 25 Jun 2024 16:02:00 -0400 Subject: [PATCH 2/3] Minor fixes for Vercel build --- packages/api/api/uploadFile.ts | 6 +++++- packages/api/api/uploadMetadata.ts | 6 +++++- packages/contracts/package.json | 3 +-- packages/contracts/worlds.json | 6 +++--- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/api/api/uploadFile.ts b/packages/api/api/uploadFile.ts index 73f585667..0f51761c6 100644 --- a/packages/api/api/uploadFile.ts +++ b/packages/api/api/uploadFile.ts @@ -16,12 +16,16 @@ export default async function uploadFile( res: VercelResponse ) { res.setHeader("Access-Control-Allow-Origin", "*"); - res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS"); + res.setHeader("Access-Control-Allow-Methods", "POST,OPTIONS"); if (!(req.method === "POST" || req.method == "OPTIONS")) { return res.status(405).json({ error: "Method not allowed" }); } + if (req.method === "OPTIONS") { + return res.status(200).end(); + } + const fileName = req.query.name as string; const form = formidable({}); diff --git a/packages/api/api/uploadMetadata.ts b/packages/api/api/uploadMetadata.ts index c61a6e2cd..489a4f5a8 100644 --- a/packages/api/api/uploadMetadata.ts +++ b/packages/api/api/uploadMetadata.ts @@ -5,13 +5,17 @@ import { uploadToPinata } from "../lib/fileStorage"; const uploadMetadata = async (req: VercelRequest, res: VercelResponse) => { try { res.setHeader("Access-Control-Allow-Origin", "*"); - res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS"); + res.setHeader("Access-Control-Allow-Methods", "POST,OPTIONS"); res.setHeader("Access-Control-Allow-Headers", "Content-Type"); if (!(req.method === "POST" || req.method == "OPTIONS")) { return res.status(405).json({ error: "Method not allowed" }); } + if (req.method === "OPTIONS") { + return res.status(200).end(); + } + const fileName = req.query.name as string; const metadata = req.body; diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 8fdb3a6e8..99be911d3 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -7,8 +7,7 @@ "build": "mud build", "clean": "forge clean && rimraf src/codegen", "deploy:local": "pnpm run build && DEBUG=mud:* mud deploy --forgeScriptOptions=\"--slow --priority-gas-price=1000000\" --profile=mudFoundry && CHAIN_ID=31337", - "deploy:testnet": "pnpm run build && mud deploy --profile=lattice-testnet", - "deploy:testnet-base": "DEBUG=mud:* mud deploy --profile=base-sepolia", + "deploy:testnet-base": "DEBUG=mud:* mud deploy --forgeScriptOptions=\"--slow --priority-gas-price=1000000\" --profile=base-sepolia", "dev": "pnpm run build && DEBUG=mud:* mud deploy --forgeScriptOptions=\"--slow --priority-gas-price=1000000\" --profile=mudFoundry && CHAIN_ID=31337", "lint": "pnpm run prettier && pnpm run solhint", "lint:fix": "pnpm run prettier && pnpm lint:sol-tests --fix && yarn lint:sol-logic --fix", diff --git a/packages/contracts/worlds.json b/packages/contracts/worlds.json index a328f0e05..24a5bcc30 100644 --- a/packages/contracts/worlds.json +++ b/packages/contracts/worlds.json @@ -1,9 +1,9 @@ { "31337": { - "address": "0x855a205bc47d9f292d8e3bff2105a32da300dee8" + "address": "0xab8df557966eed76ebdb840899866e5441cad200" }, "84532": { - "address": "0xea59f64d860d4be9918dc2c93bf8a5e84c875324", - "blockNumber": 10874436 + "address": "0xeafba96222596ac92cd335b0adfc1c2f50357571", + "blockNumber": 11787696 } } \ No newline at end of file From 2e905babc1bafe190f75c1377b674c1afa54bb2c Mon Sep 17 00:00:00 2001 From: ECWireless Date: Tue, 25 Jun 2024 16:25:05 -0400 Subject: [PATCH 3/3] Get synced status --- packages/client/src/contexts/MUDContext.tsx | 25 +++++++++++++------ .../client/src/pages/CharacterCreation.tsx | 6 ++--- packages/client/src/pages/GameBoard.tsx | 6 ++--- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/packages/client/src/contexts/MUDContext.tsx b/packages/client/src/contexts/MUDContext.tsx index 9438dcc8e..0d8e6da20 100644 --- a/packages/client/src/contexts/MUDContext.tsx +++ b/packages/client/src/contexts/MUDContext.tsx @@ -1,5 +1,6 @@ +import { useComponentValue } from '@latticexyz/react'; import { getComponentValue } from '@latticexyz/recs'; -import { encodeEntity } from '@latticexyz/store-sync/recs'; +import { encodeEntity, singletonEntity } from '@latticexyz/store-sync/recs'; import { createContext, ReactNode, @@ -27,7 +28,7 @@ type MUDContextType = { delegatorAddress: Address | null; delegatorEntity: string | null; getBurner: () => void; - isDelegationLoaded: boolean; + isSynced: boolean; network: NetworkResult; systemCalls: SystemCallsResult; }; @@ -48,7 +49,12 @@ export const MUDProvider = ({ children, setupResult }: Props): JSX.Element => { const [burner, setBurner] = useState(null); const [burnerBalance, setBurnerBalance] = useState('0'); - const [isDelegationLoaded, setIsDelegationLoaded] = useState(false); + const [isSynced, setIsSynced] = useState(false); + + const syncProgress = useComponentValue( + setupResult.components.SyncProgress, + singletonEntity, + ); const getBurner = useCallback(async () => { if (!(externalWalletClient && setupResult.network)) return; @@ -70,12 +76,15 @@ export const MUDProvider = ({ children, setupResult }: Props): JSX.Element => { createBurner(setupResult.network, externalWalletClient.account.address), ); } - setIsDelegationLoaded(true); + setIsSynced(true); }, [burner, externalWalletClient, setupResult]); useEffect(() => { + if (syncProgress?.step !== 'live') return; + if (isSynced) return; + getBurner(); - }, [getBurner]); + }, [getBurner, isSynced, syncProgress]); const getBurnerBalance = useCallback(async () => { if (!(burner && setupResult.network)) return; @@ -103,7 +112,7 @@ export const MUDProvider = ({ children, setupResult }: Props): JSX.Element => { delegatorAddress: null, delegatorEntity: null, getBurner, - isDelegationLoaded, + isSynced, network: setupResult.network, systemCalls: setupResult.systemCalls, }; @@ -119,11 +128,11 @@ export const MUDProvider = ({ children, setupResult }: Props): JSX.Element => { { address: burner.delegatorAddress }, ), getBurner, - isDelegationLoaded, + isSynced, network: burner.network, systemCalls: burner.systemCalls, }; - }, [burner, burnerBalance, getBurner, isDelegationLoaded, setupResult]); + }, [burner, burnerBalance, getBurner, isSynced, setupResult]); // const currentValue = useContext(MUDContext); // if (currentValue) throw new Error('MUDProvider can only be used once'); diff --git a/packages/client/src/pages/CharacterCreation.tsx b/packages/client/src/pages/CharacterCreation.tsx index a4e629899..35a4b07ca 100644 --- a/packages/client/src/pages/CharacterCreation.tsx +++ b/packages/client/src/pages/CharacterCreation.tsx @@ -39,7 +39,7 @@ export const CharacterCreation = (): JSX.Element => { burnerBalance, components: { UltimateDominionConfig }, delegatorAddress, - isDelegationLoaded, + isSynced, systemCalls: { enterGame, mintCharacter, rollStats }, } = useMUD(); const { character, isRefreshing, refreshCharacter } = useCharacter(); @@ -259,10 +259,10 @@ export const CharacterCreation = (): JSX.Element => { navigate('/game-board'); } - if (!delegatorAddress && isDelegationLoaded) { + if (!delegatorAddress && isSynced) { navigate('/'); } - }, [character, delegatorAddress, isDelegationLoaded, navigate, rolledOnce]); + }, [character, delegatorAddress, isSynced, navigate, rolledOnce]); return ( { const navigate = useNavigate(); - const { delegatorAddress, isDelegationLoaded } = useMUD(); + const { delegatorAddress, isSynced } = useMUD(); const { character } = useCharacter(); useEffect(() => { - if (isDelegationLoaded && !delegatorAddress) { + if (isSynced && !delegatorAddress) { navigate('/'); } if (character?.locked) { navigate('/game-board'); } - }, [character, delegatorAddress, isDelegationLoaded, navigate]); + }, [character, delegatorAddress, isSynced, navigate]); return (