diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index a63e141..c113fd0 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -15,8 +15,14 @@ on: jobs: check: - name: Next.js checks + name: Next.js checks (${{ matrix.deployment }}) runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + deployment: + - riseTestnet + - somniaShannon permissions: contents: read defaults: @@ -43,5 +49,7 @@ jobs: - name: Build frontend env: + NEXT_PUBLIC_DEPLOYMENT: ${{ matrix.deployment }} NEXT_PUBLIC_RISE_TESTNET_DUNGEON_ADDRESS: "0x0000000000000000000000000000000000000001" + NEXT_PUBLIC_SOMNIA_SHANNON_DUNGEON_ADDRESS: "0x07c5D071132ae95C3708031790b3feC740F4c292" run: npm run build diff --git a/README.md b/README.md index b09db49..e1b3ca1 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Practice Mode is not onchain, does not persist authoritative state and does not Onchain Mode connects a wallet to a configured deployment. Player state and game actions are handled by the deployed `Delveworn` contract, and randomness-backed actions resolve through the configured provider and callback adapter. -Onchain Mode depends on the selected network, RPC availability, wallet confirmations and the deployed contract address. The current public deployment targets RISE Testnet. +Onchain Mode depends on the selected network, RPC availability, wallet confirmations and the deployed contract address. The current public deployment remains on RISE Testnet; Somnia Shannon is an independently selectable deployment and does not replace the grant-linked RISE experience. ## Project overview @@ -93,7 +93,7 @@ The frontend uses `frontendSnapshotV3()`, `claimRelic(bool)` and `equipOwnedReli | Environment | Status | Scope | | --- | --- | --- | | RISE Testnet | Public beta | Current wallet-connected deployment and frontend integration. | -| Somnia Shannon Testnet | Adapter and deployment path test-covered | Native verifiable VRF requests use Somnia's coordinator-funded Reactivity/drand flow. No public Delveworn deployment is advertised until its address and live fulfillment are verified. | +| Somnia Shannon Testnet | Verified opt-in deployment | Delveworn [`0x07c5…c292`](https://shannon-explorer.somnia.network/address/0x07c5D071132ae95C3708031790b3feC740F4c292) uses a native VRF adapter and Somnia's coordinator-funded Reactivity/drand flow. A live monster request completed with `callbackSuccess=true`; the public frontend remains on RISE unless explicitly configured otherwise. Somnia supports ERC-4337-style smart accounts and session keys, but this Delveworn configuration currently exposes only its tested MetaMask transaction path. | | Local Anvil | Development only | Deterministic contract, relic, balance and request/callback testing through `DevRandomnessAdapter`. | | Chainlink VRF v2.5 adapter | Implemented and test-covered | Adapter support exists, but no public deployment is presented as production-ready. | | Other EVM networks | Architecture target | The core is designed for adapter-based deployments; these networks are not yet advertised as supported public deployments. | @@ -241,6 +241,15 @@ At minimum, the selected public deployment needs its contract address. RISE Test NEXT_PUBLIC_RISE_TESTNET_DUNGEON_ADDRESS ``` +Somnia Shannon is opt-in and uses: + +```text +NEXT_PUBLIC_DEPLOYMENT=somniaShannon +NEXT_PUBLIC_SOMNIA_SHANNON_DUNGEON_ADDRESS=0x07c5D071132ae95C3708031790b3feC740F4c292 +``` + +Do not change the production deployment selector merely by merging Somnia support; the RISE URL is referenced by existing grant applications and remains the default. + Changes must pass the path-filtered contract and frontend workflows before they are merged to `main`. ## Roadmap diff --git a/frontend/.env.example b/frontend/.env.example index 77eacd1..4f0bdf2 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -8,11 +8,9 @@ NEXT_PUBLIC_RISE_TESTNET_RPC_URL=https://testnet.riselabs.xyz NEXT_PUBLIC_RISE_TESTNET_WS_URL=wss://testnet.riselabs.xyz/ws NEXT_PUBLIC_RISE_TESTNET_EXPLORER_URL=https://explorer.testnet.riselabs.xyz -# Somnia Shannon benchmark candidate. -# This deployment is registered but intentionally not selectable yet. -# Set the address after deploying the benchmark/game contracts; enabling it -# still requires changing selectable=true in chain-config.ts after validation. -# NEXT_PUBLIC_SOMNIA_SHANNON_DUNGEON_ADDRESS=0x0000000000000000000000000000000000000000 +# Somnia Shannon deployment (opt in with NEXT_PUBLIC_DEPLOYMENT=somniaShannon). +# The public RISE deployment remains the default. +NEXT_PUBLIC_SOMNIA_SHANNON_DUNGEON_ADDRESS=0x07c5D071132ae95C3708031790b3feC740F4c292 NEXT_PUBLIC_SOMNIA_SHANNON_RPC_URL=https://dream-rpc.somnia.network/ NEXT_PUBLIC_SOMNIA_SHANNON_EXPLORER_URL=https://shannon-explorer.somnia.network/ diff --git a/frontend/README.md b/frontend/README.md index 2d1726d..c1ed216 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,6 +1,6 @@ # Delveworn -Delveworn is a fully onchain dungeon crawler. The current public frontend deployment targets RISE Testnet and supports RISE Wallet session keys for fast, popup-free gameplay, plus MetaMask standard transactions. +Delveworn is a fully onchain dungeon crawler. The public frontend remains on RISE Testnet and supports RISE Wallet session keys for fast, popup-free gameplay, plus MetaMask standard transactions. A separately selectable Somnia Shannon configuration uses MetaMask and Somnia Native VRF without changing the public RISE experience. ## Status @@ -31,6 +31,13 @@ Create `.env.local` and point the frontend at the deployed Delveworn contract: NEXT_PUBLIC_RISE_TESTNET_DUNGEON_ADDRESS=0x... ``` +To run the separately verified Somnia Shannon deployment instead: + +```bash +NEXT_PUBLIC_DEPLOYMENT=somniaShannon +NEXT_PUBLIC_SOMNIA_SHANNON_DUNGEON_ADDRESS=0x07c5D071132ae95C3708031790b3feC740F4c292 +``` + `NEXT_PUBLIC_DUNGEON_ADDRESS` remains supported as a legacy fallback. Start the development server: @@ -72,4 +79,4 @@ The repository includes `scripts/vrf-latency-monitor.mjs` for measuring request/ ## Network -The current frontend targets RISE Testnet. Product naming is chain-independent; contract addresses and network configuration should be selected per deployment before any mainnet release. +The public frontend targets RISE Testnet. Somnia Shannon is available as an opt-in build configuration using chain ID `50312`, the official Dream RPC and Somnia Native VRF. Somnia supports ERC-4337-style smart accounts and session keys at the network/tooling layer, but Delveworn's Somnia configuration currently uses MetaMask standard transactions until a specific account-abstraction provider and smart-account flow are integrated and tested. Product naming remains chain-independent; contract addresses and network configuration must be selected per deployment before any mainnet release. diff --git a/frontend/app/chain-config.ts b/frontend/app/chain-config.ts index db6a29d..c5d693a 100644 --- a/frontend/app/chain-config.ts +++ b/frontend/app/chain-config.ts @@ -12,6 +12,7 @@ export type InstantPlayProvider = export type RandomnessProvider = | "rise-vrf" + | "somnia-native-vrf" | "chainlink-vrf" | "supra-dvrf" | "other"; @@ -80,12 +81,6 @@ function validateDeploymentConfig(config: DeploymentConfig) { throw new Error(`Deployment ${config.key} must provide an ecosystem name.`); } - if (config.selectable && !config.dungeonAddress) { - throw new Error( - `Deployment ${config.key} is selectable but has no dungeon contract address.` - ); - } - if (config.realtime.websocket && !config.wsUrl) { throw new Error( `Deployment ${config.key} enables WebSocket realtime but has no wsUrl.` @@ -161,8 +156,7 @@ export const deployments = { ecosystemName: "RISE", selectable: true, chain: riseTestnet, - dungeonAddress: requiredAddress( - "NEXT_PUBLIC_RISE_TESTNET_DUNGEON_ADDRESS or NEXT_PUBLIC_DUNGEON_ADDRESS", + dungeonAddress: optionalAddress( process.env.NEXT_PUBLIC_RISE_TESTNET_DUNGEON_ADDRESS ?? process.env.NEXT_PUBLIC_DUNGEON_ADDRESS ), @@ -207,10 +201,12 @@ export const deployments = { key: "somnia-shannon", label: "Somnia Shannon Testnet", ecosystemName: "Somnia", - selectable: false, + selectable: true, chain: somniaShannon, - dungeonAddress: optionalAddress( - process.env.NEXT_PUBLIC_SOMNIA_SHANNON_DUNGEON_ADDRESS + dungeonAddress: requiredAddress( + "NEXT_PUBLIC_SOMNIA_SHANNON_DUNGEON_ADDRESS", + process.env.NEXT_PUBLIC_SOMNIA_SHANNON_DUNGEON_ADDRESS ?? + "0x07c5D071132ae95C3708031790b3feC740F4c292" ), rpcUrl: process.env.NEXT_PUBLIC_SOMNIA_SHANNON_RPC_URL ?? @@ -230,8 +226,8 @@ export const deployments = { shreds: false, }, randomness: { - provider: "chainlink-vrf", - providerLabel: "Chainlink VRF v2.5 (direct-funding adapter)", + provider: "somnia-native-vrf", + providerLabel: "Somnia Native VRF", retrySupported: true, }, timing: { @@ -256,10 +252,16 @@ if (!(configuredDeployment in deployments)) { const selectedDeployment = deployments[configuredDeployment]; -if (!selectedDeployment.selectable || !selectedDeployment.dungeonAddress) { +if (!selectedDeployment.selectable) { throw new Error( `Deployment ${selectedDeployment.key} is registered for benchmarking but is not selectable yet.` ); } +if (!selectedDeployment.dungeonAddress) { + throw new Error( + `Deployment ${selectedDeployment.key} is selected but has no dungeon contract address.` + ); +} + export const activeDeployment = selectedDeployment as ActiveDeploymentConfig; diff --git a/frontend/app/game-ui.tsx b/frontend/app/game-ui.tsx index 2e07441..67273f9 100644 --- a/frontend/app/game-ui.tsx +++ b/frontend/app/game-ui.tsx @@ -454,7 +454,7 @@ export function DungeonEntry({ ] : [ "Wallet or temporary session authorization.", - "RISE Fast VRF provides verifiable randomness.", + "The configured VRF provider supplies verifiable randomness.", "Game state and rewards are stored by the Delveworn contract.", ]; diff --git a/frontend/app/page-runtime-bindings.ts b/frontend/app/page-runtime-bindings.ts index 763ff66..10378d0 100644 --- a/frontend/app/page-runtime-bindings.ts +++ b/frontend/app/page-runtime-bindings.ts @@ -31,6 +31,9 @@ import { export const DUNGEON_ADDRESS = activeDeployment.dungeonAddress; +export const DUNGEON_EXPLORER_URL = + `${activeDeployment.explorerUrl.replace(/\/$/, "")}/address/${DUNGEON_ADDRESS}`; + export const RPC_URL = activeDeployment.rpcUrl; diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index a7fd0d0..553c6f9 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -2,33 +2,25 @@ import { useEffect, useRef, useState } from "react"; import { - createPublicClient, createWalletClient, custom, decodeEventLog, encodeFunctionData, getAddress, - http, keccak256, toHex, - webSocket, type Address, } from "viem"; -import { riseTestnet } from "viem/chains"; -import { shredActions } from "shreds/viem"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { WagmiProvider, - createConfig, useChainId, useConnect, useConnection, useDisconnect, useConnectors, } from "wagmi"; -import { metaMask } from "wagmi/connectors/metaMask"; -import { Chains, RiseWallet } from "rise-wallet"; -import { Hooks, riseWallet } from "rise-wallet/wagmi"; +import { Hooks } from "rise-wallet/wagmi"; import { P256, PublicKey, Signature } from "ox"; import { describeRelicEquipImpact, @@ -51,6 +43,38 @@ import { RoomProgressLine, SmallStat, } from "./game-ui"; +import { createRiseShredsClient } from "./rise-shreds-client"; +import { + ACTION_READY_POLL_MS, + ACTION_READY_TIMEOUT_MS, + ACTIVE_CHAIN, + ACTIVE_CHAIN_ID, + ACTIVE_ECOSYSTEM_NAME, + ACTIVE_NETWORK_LABEL, + DUNGEON_ADDRESS, + DUNGEON_EXPLORER_URL, + METAMASK_CONNECTOR_ID, + METAMASK_CONNECTOR_NAME, + MIN_VRF_DISPLAY_MS, + RISE_WALLET_CONNECTOR_ID, + SESSION_DURATION_SECONDS, + TESTNET_POLLING_MS, + VRF_CANONICAL_FALLBACK_MS, + VRF_DELAYED_NOTICE_MS, + activeRandomnessProviderLabel, + connectedNetworkLabel, + delayedRandomnessText, + delayedRandomnessTitle, + ensureActiveChain, + isMetaMaskConnector, + isRiseWalletConnector, + publicClient, + runtimeFooterLabel, + sessionStorageKey, + supportsInstantPlay, + supportsRandomnessRetry, + wagmiConfig, +} from "./page-runtime-bindings"; /* ============================================================ @@ -59,90 +83,11 @@ import { ============================================================ */ -const CONFIGURED_DUNGEON_ADDRESS = - process.env.NEXT_PUBLIC_RISE_TESTNET_DUNGEON_ADDRESS ?? - process.env.NEXT_PUBLIC_DUNGEON_ADDRESS; - -if (!CONFIGURED_DUNGEON_ADDRESS) { - throw new Error( - "NEXT_PUBLIC_RISE_TESTNET_DUNGEON_ADDRESS or NEXT_PUBLIC_DUNGEON_ADDRESS is not set. Add the deployed Delveworn address to frontend/.env.local and restart Next.js." - ); -} - -const DUNGEON_ADDRESS = - getAddress( - CONFIGURED_DUNGEON_ADDRESS - ); - -const DUNGEON_EXPLORER_URL = - `https://explorer.testnet.riselabs.xyz/address/${DUNGEON_ADDRESS}`; - -const RPC_URL = - "https://testnet.riselabs.xyz"; - -const WS_URL = - "wss://testnet.riselabs.xyz/ws"; - -const TESTNET_POLLING_MS = 50; -const MIN_VRF_DISPLAY_MS = 300; -const VRF_DELAYED_NOTICE_MS = 5_000; -const VRF_CANONICAL_FALLBACK_MS = 20_000; -const ACTION_READY_TIMEOUT_MS = 45_000; -const ACTION_READY_POLL_MS = 250; const FRONTEND_SNAPSHOT_V3_RETRY_MS = 5_000; -const SESSION_DURATION_SECONDS = 8 * 60 * 60; const SESSION_STATUS_TIMEOUT_MS = 12_000; const SESSION_STATUS_POLL_MS = 40; -const RISE_WALLET_CONNECTOR_ID = - "com.risechain.wallet"; - -const METAMASK_CONNECTOR_ID = - "metaMaskSDK"; - -const METAMASK_CONNECTOR_NAME = - "MetaMask"; - -const riseWalletConnector = - riseWallet( - RiseWallet.defaultConfig - ); - -const metaMaskConnector = - metaMask({ - dapp: { - name: - "RISE Dungeon", - url: - typeof window === - "undefined" - ? "https://rise-dungeon-frontend.vercel.app" - : window.location.origin, - }, - }); - -const wagmiConfig = - createConfig({ - ssr: true, - - chains: [ - Chains.riseTestnet, - ], - - connectors: [ - riseWalletConnector, - metaMaskConnector, - ], - - transports: { - [Chains.riseTestnet.id]: - http( - RPC_URL - ), - }, - }); - /* ============================================================ BALANCE CONSTANTS @@ -205,90 +150,6 @@ function asInjectedProvider( InjectedProvider; } -function getErrorCode( - error: unknown -) { - if ( - typeof error === - "object" && - error !== null && - "code" in error - ) { - return Number( - ( - error as { - code: unknown; - } - ).code - ); - } - - return undefined; -} - -async function ensureRiseTestnet( - provider: - InjectedProvider -) { - const chainId = - `0x${riseTestnet.id.toString(16)}`; - - try { - await provider.request({ - method: - "wallet_switchEthereumChain", - - params: [ - { - chainId, - }, - ], - }); - } catch ( - error - ) { - if ( - getErrorCode(error) !== - 4902 - ) { - throw error; - } - - await provider.request({ - method: - "wallet_addEthereumChain", - - params: [ - { - chainId, - - chainName: - "RISE Testnet", - - nativeCurrency: { - name: - "Ether", - - symbol: - "ETH", - - decimals: - 18, - }, - - rpcUrls: [ - RPC_URL, - ], - - blockExplorerUrls: [ - "https://explorer.testnet.riselabs.xyz", - ], - }, - ], - }); - } -} - async function createConnectedWalletClient( account: Address, @@ -296,7 +157,7 @@ async function createConnectedWalletClient( provider: InjectedProvider ) { - await ensureRiseTestnet( + await ensureActiveChain( provider ); @@ -304,7 +165,7 @@ async function createConnectedWalletClient( account, chain: - riseTestnet, + ACTIVE_CHAIN, transport: custom( @@ -313,49 +174,8 @@ async function createConnectedWalletClient( }); } -const publicClient = - createPublicClient({ - chain: - riseTestnet, - - pollingInterval: - TESTNET_POLLING_MS, - - cacheTime: 0, - - transport: http( - RPC_URL - ), - }); - const realtimeClient = - createPublicClient({ - chain: - riseTestnet, - - cacheTime: 0, - - transport: - webSocket( - WS_URL, - { - keepAlive: { - interval: 5_000, - }, - - reconnect: { - attempts: 100, - delay: 500, - }, - - retryCount: 5, - retryDelay: 100, - timeout: 15_000, - } - ), - }).extend( - shredActions - ); + createRiseShredsClient(); /* ============================================================ @@ -962,9 +782,6 @@ type SessionAction = | PendingAction | RecoveryAction; -const SESSION_PERMISSION_VERSION = - "4"; - const SESSION_FUNCTION_SIGNATURES = [ "startGame()", "attack()", @@ -996,14 +813,6 @@ function selectorFor( ) as `0x${string}`; } -function sessionStorageKey( - address: Address -) { - return ( - `rise_dungeon_${DUNGEON_ADDRESS.toLowerCase()}_${address.toLowerCase()}_session_v${SESSION_PERMISSION_VERSION}_key` - ); -} - /* ============================================================ MONSTER PERSONALITIES @@ -2099,7 +1908,7 @@ async function fetchPlayerState( const reader = source === "realtime" - ? realtimeClient + ? realtimeClient ?? publicClient : publicClient; let snapshot: unknown; @@ -2976,7 +2785,7 @@ function getLootMessage( ============================================================ */ -function RiseProviders({ +function ChainProviders({ children, }: { children: @@ -3010,9 +2819,9 @@ function RiseProviders({ export default function Home() { return ( - + - + ); } @@ -3044,7 +2853,12 @@ function DelvewornGame() { Hooks.useRevokePermissions(); const permissionsQuery = - Hooks.usePermissions(); + Hooks.usePermissions({ + query: { + enabled: + supportsInstantPlay(), + }, + }); const [ player, @@ -3220,14 +3034,14 @@ function DelvewornGame() { if (!timing) { console.info( - `[RISE TIMING] ${stage}` + `[${ACTIVE_ECOSYSTEM_NAME.toUpperCase()} TIMING] ${stage}` ); return; } console.info( - `[RISE TIMING] ${timing.name} ${stage}: +${runtimeNowMs() - timing.startedAt}ms` + `[${ACTIVE_ECOSYSTEM_NAME.toUpperCase()} TIMING] ${timing.name} ${stage}: +${runtimeNowMs() - timing.startedAt}ms` ); } @@ -3295,14 +3109,14 @@ function DelvewornGame() { ); const isRiseWallet = - connector?.id === - RISE_WALLET_CONNECTOR_ID; + isRiseWalletConnector( + connector + ); const isMetaMask = - connector?.id === - METAMASK_CONNECTOR_ID || - connector?.name === - METAMASK_CONNECTOR_NAME; + isMetaMaskConnector( + connector + ); const canPlay = Boolean( @@ -3594,7 +3408,8 @@ function DelvewornGame() { }; const unwatchShreds = - realtimeClient.watchShreds({ + realtimeClient + ? realtimeClient.watchShreds({ includeStateChanges: false, @@ -3686,7 +3501,8 @@ function DelvewornGame() { error ); }, - }); + }) + : () => {}; const unwatchHttpEvents = publicClient.watchContractEvent({ @@ -3753,7 +3569,7 @@ function DelvewornGame() { error ) => { console.warn( - "RISE HTTP event fallback issue:", + `${ACTIVE_NETWORK_LABEL} event polling issue:`, error ); }, @@ -4143,6 +3959,7 @@ function DelvewornGame() { if ( elapsed >= VRF_DELAYED_NOTICE_MS && + supportsRandomnessRetry() && runtimeNowMs() - lastRetryAvailabilityCheck >= 1_000 @@ -4287,7 +4104,7 @@ function DelvewornGame() { Important: a frontend timeout must NEVER unlock the action while the contract still has pendingRequestId != 0. This preserves the original action context so the battle log can be generated even - when RISE Testnet fulfills VRF several minutes late. + when the active network fulfills VRF several minutes late. */ if ( elapsed > @@ -4586,7 +4403,7 @@ function DelvewornGame() { recovered ) { addMessages([ - "🎲 Pending RISE Fast VRF request resolved.", + `🎲 Pending ${activeRandomnessProviderLabel()} request resolved.`, ]); } } catch ( @@ -4631,7 +4448,7 @@ function DelvewornGame() { ); setWalletMessage( - "Could not read Delveworn from RISE Testnet." + `Could not read Delveworn from ${ACTIVE_NETWORK_LABEL}.` ); setLoading( @@ -4688,7 +4505,7 @@ function DelvewornGame() { connector: connectorToUse, chainId: - riseTestnet.id, + ACTIVE_CHAIN_ID, }); } catch ( error @@ -5569,7 +5386,7 @@ function DelvewornGame() { account: connectedAddress, chain: - riseTestnet, + ACTIVE_CHAIN, to: DUNGEON_ADDRESS, data, @@ -5639,12 +5456,15 @@ function DelvewornGame() { } throw new Error( - "Connect RISE Wallet or MetaMask before continuing." + supportsInstantPlay() + ? "Connect RISE Wallet or MetaMask before continuing." + : "Connect MetaMask before continuing." ); } async function retryVrf() { if ( + !supportsRandomnessRetry() || !connectedAddress || !canPlay || canonicalSyncing || @@ -5726,7 +5546,7 @@ function DelvewornGame() { } console.info( - `[RISE VRF] retrying request ${beforeRetry.pendingRequestId.toString()}` + `[${ACTIVE_ECOSYSTEM_NAME.toUpperCase()} VRF] retrying request ${beforeRetry.pendingRequestId.toString()}` ); await sendDungeonActionCall( @@ -5791,7 +5611,7 @@ function DelvewornGame() { ); console.info( - `[RISE VRF] request ${beforeRetry.pendingRequestId.toString()} replaced by ${afterRetry.pendingRequestId.toString()}` + `[${ACTIVE_ECOSYSTEM_NAME.toUpperCase()} VRF] request ${beforeRetry.pendingRequestId.toString()} replaced by ${afterRetry.pendingRequestId.toString()}` ); } catch ( error @@ -5876,7 +5696,7 @@ function DelvewornGame() { ); console.info( - `[RISE VRF] retry landed despite wallet status error: ${originalRequestId.toString()} -> ${recovered.pendingRequestId.toString()}` + `[${ACTIVE_ECOSYSTEM_NAME.toUpperCase()} VRF] retry landed despite wallet status error: ${originalRequestId.toString()} -> ${recovered.pendingRequestId.toString()}` ); return; @@ -6457,7 +6277,7 @@ function DelvewornGame() { BigInt(0) ) { setWalletMessage( - "Previous action is still finalizing on RISE. Please wait until the action buttons unlock." + `Previous action is still finalizing on ${ACTIVE_ECOSYSTEM_NAME}. Please wait until the action buttons unlock.` ); return; @@ -6484,7 +6304,9 @@ function DelvewornGame() { !canPlay ) { setWalletMessage( - "Connect RISE Wallet or MetaMask before continuing." + supportsInstantPlay() + ? "Connect RISE Wallet or MetaMask before continuing." + : "Connect MetaMask before continuing." ); return; @@ -7120,7 +6942,7 @@ function DelvewornGame() { ); alert( - "Transaction failed. Check your wallet, RISE Testnet balance and browser console." + `Transaction failed. Check your wallet, ${ACTIVE_NETWORK_LABEL} balance and browser console.` ); } } finally { @@ -7163,12 +6985,12 @@ function DelvewornGame() { const supportedConnector = connector && ( - connector.id === - RISE_WALLET_CONNECTOR_ID || - connector.id === - METAMASK_CONNECTOR_ID || - connector.name === - METAMASK_CONNECTOR_NAME + isRiseWalletConnector( + connector + ) || + isMetaMaskConnector( + connector + ) ); if ( @@ -7187,7 +7009,9 @@ function DelvewornGame() { ); setWalletMessage( - "Unsupported wallet connection. Connect RISE Wallet or MetaMask." + supportsInstantPlay() + ? "Unsupported wallet connection. Connect RISE Wallet or MetaMask." + : "Unsupported wallet connection. Connect MetaMask." ); return; @@ -7281,7 +7105,7 @@ function DelvewornGame() { ) { return (
- Connecting to RISE Testnet... + Connecting to {ACTIVE_NETWORK_LABEL}...
); } @@ -7295,16 +7119,18 @@ function DelvewornGame() {
@@ -7314,17 +7140,19 @@ function DelvewornGame() { > {walletChoiceOpen ? (
- + {supportsInstantPlay() && ( + + )} @@ -7335,7 +7163,11 @@ function DelvewornGame() { > back to entrance -

MetaMask confirms each action. RISE Wallet enables popup-free play after one session approval.

+

+ {supportsInstantPlay() + ? "MetaMask confirms each action. RISE Wallet enables popup-free play after one session approval." + : "MetaMask confirms each onchain action."} +

) : ( <> @@ -7373,7 +7205,7 @@ function DelvewornGame() {

- LIVE ON RISE TESTNET + LIVE ON {ACTIVE_NETWORK_LABEL.toUpperCase()}

@@ -7456,7 +7288,7 @@ function DelvewornGame() { )}

- RISE Testnet · {connectedAddress.slice(0, 6)}…{connectedAddress.slice(-4)} + {connectedNetworkLabel(connectedAddress)}

@@ -7839,7 +7671,7 @@ function DelvewornGame() { "FINALIZING ACTION"; rollingText = - "Randomness is resolved. Waiting until RISE is ready for your next transaction..."; + `Randomness is resolved. Waiting until ${ACTIVE_ECOSYSTEM_NAME} is ready for your next transaction...`; } if ( @@ -7850,15 +7682,15 @@ function DelvewornGame() { "⏳"; rollingLabel = - "RISE TESTNET"; + ACTIVE_NETWORK_LABEL.toUpperCase(); rollingTitle = - "WAITING FOR RISE VRF"; + delayedRandomnessTitle(); rollingText = - vrfRetryAvailable - ? "RISE has not fulfilled this request within the onchain timeout. You can safely replace it with a fresh VRF request." - : "Your action is submitted. RISE has not fulfilled the randomness request yet. The result will appear automatically."; + delayedRandomnessText( + vrfRetryAvailable + ); } /* @@ -7876,7 +7708,7 @@ function DelvewornGame() { ONCHAIN SESSION · {connectedAddress.slice(0, 6)}…{connectedAddress.slice(-4)}} > @@ -8445,7 +8277,8 @@ function DelvewornGame() {
- {vrfRetryAvailable && + {supportsRandomnessRetry() && + vrfRetryAvailable && !canonicalSyncing && ( <>