From a40f9b008d0e2822a5e8db6f9d0131d797d55134 Mon Sep 17 00:00:00 2001 From: David Melendez Date: Wed, 8 Oct 2025 00:17:15 -0600 Subject: [PATCH 1/3] Update target network to devnet and enhance RandomnessComponent with new contract address and validation checks --- .../contract/RandomnessComponent.tsx | 130 +---- .../nextjs/contracts/deployedContracts.ts | 477 ++++++++++++++++++ packages/nextjs/scaffold.config.ts | 2 +- .../snfoundry/contracts/src/Randomness.cairo | 4 +- 4 files changed, 495 insertions(+), 118 deletions(-) diff --git a/packages/nextjs/app/debug/_components/contract/RandomnessComponent.tsx b/packages/nextjs/app/debug/_components/contract/RandomnessComponent.tsx index 1612e58..eda2a5e 100644 --- a/packages/nextjs/app/debug/_components/contract/RandomnessComponent.tsx +++ b/packages/nextjs/app/debug/_components/contract/RandomnessComponent.tsx @@ -16,6 +16,11 @@ import { Call, CallData, num } from "starknet"; const VRF_PROVIDER_ADDRESS = "0x051fea4450da9d6aee758bdeba88b2f665bcbf549d2c61421aa724e9ac0ced8f"; +// Dirección esperada del contrato de Randomness desplegado en testnet +// Esta dirección se actualiza con cada nuevo deployment para pruebas +const EXPECTED_RANDOMNESS_CONTRACT_ADDRESS = + "0x036BcAC633A4B319190Ad7691E2B92DBfFf8EEF098feba82E6a20488824204F7"; + interface RandomnessComponentProps { contractName: ContractName; contractAddress: AddressType; @@ -72,12 +77,10 @@ export const RandomnessComponent = ({ // Verificación adicional de que la dirección es válida antes de proceder if ( account?.address && - (!account.address.startsWith("0x") || account.address.length !== 66) + (!account.address.startsWith("0x") || + account.address.length < 3 || + account.address.length > 66) ) { - console.error( - "❌ Dirección de cuenta con formato inválido:", - account.address, - ); notification.error( "La dirección de la cuenta tiene un formato inválido. Intenta reconectar tu wallet.", ); @@ -85,11 +88,6 @@ export const RandomnessComponent = ({ } if (!account?.address) { - console.error("❌ No se pudo obtener la dirección de la cuenta:", { - account, - isConnected, - walletStatus, - }); notification.error( "No se pudo obtener la dirección de la cuenta conectada. Intenta reconectar tu wallet.", ); @@ -101,7 +99,6 @@ export const RandomnessComponent = ({ account?.address === "0x0297fd6c19289a017d50b1b65a07ea4db27596a8fade85c6b9622a3f9a24d2a9" ) { - console.warn("🚨 CUENTA PROBLEMÁTICA DETECTADA:", account.address); notification.error( "Se ha detectado una cuenta que puede causar problemas. Intenta reconectar tu wallet o usar una cuenta diferente.", ); @@ -113,39 +110,6 @@ export const RandomnessComponent = ({ return; } - // 🔍 DIAGNÓSTICO: Verificar información del contrato antes de proceder - console.log("🔍 DIAGNÓSTICO - Información del contrato:", { - contractName, - contractAddress, - expectedAddress: - "0x31cdafdd0fc1a80d57f3290afff3ba0a62e9d2c628e35c81eb55e05879f0f4f", - addressMatch: - contractAddress === - "0x31cdafdd0fc1a80d57f3290afff3ba0a62e9d2c628e35c81eb55e05879f0f4f", - chain: chain?.name, - targetNetwork: targetNetwork.name, - isDevnet: - chain?.network === "devnet" || targetNetwork.network === "devnet", - }); - - // 🔍 DIAGNÓSTICO ADICIONAL: Verificar información de la cuenta y posibles problemas - console.log("🔍 DIAGNÓSTICO - Información de la cuenta y transacción:", { - accountAddress: account?.address, - accountClass: account?.constructor?.name, - accountProvider: account ? "AccountInterface" : "undefined", - walletStatus, - isConnected, - chainId: chain?.id, - targetNetworkId: targetNetwork.id, - writeDisabledReason: writeDisabled - ? "Wallet en red incorrecta o desconectada" - : "Listo para transacción", - contractAddress, - functionToCall: isDevnet ? "devnet_generate" : "request_randomness_prod", - calldataParams: isDevnet - ? ["seed"] - : ["seed", "callbackFeeLimit", "publishDelay"], - }); setIsLoading(true); setTxHash(""); @@ -161,20 +125,8 @@ export const RandomnessComponent = ({ chain?.network === "devnet" || targetNetwork.network === "devnet"; - console.log( - "🎯 Modo detectado:", - isDevnet ? "DESARROLLO" : "PRODUCCIÓN", - forceDevMode ? "(FORZADO)" : "", - ); - if (isDevnet) { // Para desarrollo: usar devnet_generate directamente - console.log("🔧 Ejecutando en modo DESARROLLO (devnet_generate)", { - contractAddress, - seed: seedValue.toString(), - account: account?.address, - function: "devnet_generate", - }); const seedHex = num.toHex(seedValue); @@ -188,9 +140,6 @@ export const RandomnessComponent = ({ if (txHash) { setTxHash(txHash); - console.log("✅ Generación de desarrollo ejecutada exitosamente", { - transactionHash: txHash, - }); notification.success( `¡5 números aleatorios generados exitosamente! Hash: ${txHash}`, ); @@ -202,15 +151,6 @@ export const RandomnessComponent = ({ // Para producción: usar protocolo VRF correcto con multicall if (useAlternativeMode) { // MODO ALTERNATIVO: Usar parámetros más seguros - console.log( - "🔧 Ejecutando en modo ALTERNATIVO con MULTICALL (parámetros seguros)", - { - contractAddress, - seed: seedValue.toString(), - account: account?.address, - mode: "alternative_multicall", - }, - ); // Usar parámetros más conservadores const safeCallbackFeeLimit = "50000"; // Más bajo que el original 100000 @@ -244,9 +184,6 @@ export const RandomnessComponent = ({ if (multicallTx) { setTxHash(multicallTx); - console.log("✅ Multicall alternativo ejecutado exitosamente", { - transactionHash: multicallTx, - }); notification.success( `¡Solicitud VRF enviada (Modo Seguro)! Hash: ${multicallTx}. Esperando respuesta del oráculo...`, ); @@ -256,17 +193,6 @@ export const RandomnessComponent = ({ } } else { // MODO NORMAL: Multicall estándar - console.log( - "🏭 Ejecutando en modo PRODUCCIÓN con MULTICALL (estándar)", - { - contractAddress, - seed: seedValue.toString(), - callbackFeeLimit, - publishDelay, - account: account?.address, - mode: "standard_multicall", - }, - ); const seedHex = num.toHex(seedValue); const callbackFeeLimitHex = num.toHex(BigInt(callbackFeeLimit)); @@ -296,9 +222,6 @@ export const RandomnessComponent = ({ if (multicallTx) { setTxHash(multicallTx); - console.log("✅ Multicall estándar ejecutado exitosamente", { - transactionHash: multicallTx, - }); notification.success( `¡Solicitud VRF enviada! Hash: ${multicallTx}. Esperando respuesta del oráculo...`, ); @@ -309,30 +232,6 @@ export const RandomnessComponent = ({ } } } catch (error: any) { - console.error("❌ Error ejecutando solicitud de aleatoriedad:", error); - - // 🔍 DIAGNÓSTICO: Información detallada del error - console.error("🔍 DIAGNÓSTICO - Error detallado:", { - error: error, - message: error.message, - code: error.code, - data: error.data, - stack: error.stack, - contractAddress: contractAddress, - contractName: contractName, - account: account?.address, - chain: chain?.name, - targetNetwork: targetNetwork.name, - writeTransactionResult: error.writeTransactionResult, - transactionHash: error.transactionHash, - receipt: error.receipt, - // Información adicional específica de Argent - isArgentError: error.message?.includes("argent"), - multicallFailed: error.message?.includes("multicall-failed"), - entrypointNotFound: error.message?.includes("ENTRYPOINT_NOT_FOUND"), - entrypointFailed: error.message?.includes("ENTRYPOINT_FAILED"), - }); - // Proporcionar mensajes de error más específicos let errorMessage = "Error desconocido al solicitar aleatoriedad"; @@ -415,7 +314,7 @@ export const RandomnessComponent = ({

Dirección esperada:{" "} - 0x31cdafdd0fc1a80d57f3290afff3ba0a62e9d2c628e35c81eb55e05879f0f4f + {EXPECTED_RANDOMNESS_CONTRACT_ADDRESS}

Dirección actual: {contractAddress} @@ -536,8 +435,11 @@ export const RandomnessComponent = ({ {/* Diagnóstico de problemas potenciales */} {contractAddress && - contractAddress !== - "0x31cdafdd0fc1a80d57f3290afff3ba0a62e9d2c628e35c81eb55e05879f0f4f" && ( + contractAddress.toLowerCase().replace(/^0x0+/, "0x") !== + EXPECTED_RANDOMNESS_CONTRACT_ADDRESS.toLowerCase().replace( + /^0x0+/, + "0x", + ) && (

🚨 Problema Detectado @@ -547,8 +449,7 @@ export const RandomnessComponent = ({ Dirección del contrato incorrecta:

- • Dirección esperada: - 0x31cdafdd0fc1a80d57f3290afff3ba0a62e9d2c628e35c81eb55e05879f0f4f + • Dirección esperada: {EXPECTED_RANDOMNESS_CONTRACT_ADDRESS}

• Dirección actual: {contractAddress}

@@ -877,7 +778,6 @@ const VRFCoordinatorConfig = ({ setIsExpanded(false); } } catch (error: any) { - console.error("Error actualizando VRF coordinator:", error); notification.error( "Error actualizando VRF coordinator: " + (error.message || "Error desconocido"), diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 283d8ef..716018a 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -4,6 +4,483 @@ */ const deployedContracts = { + devnet: { + Randomness: { + address: + "0x36bcac633a4b319190ad7691e2b92dbfff8eef098feba82e6a20488824204f7", + abi: [ + { + type: "impl", + name: "RandomnessImpl", + interface_name: + "starklotto_adapter_vrf::Randomness::IRandomnessLottery", + }, + { + type: "interface", + name: "starklotto_adapter_vrf::Randomness::IRandomnessLottery", + items: [ + { + type: "function", + name: "request_randomness_prod", + inputs: [ + { + name: "seed", + type: "core::integer::u64", + }, + { + name: "callback_fee_limit", + type: "core::integer::u128", + }, + { + name: "publish_delay", + type: "core::integer::u64", + }, + ], + outputs: [ + { + type: "core::integer::u64", + }, + ], + state_mutability: "external", + }, + { + type: "function", + name: "devnet_generate", + inputs: [ + { + name: "seed", + type: "core::integer::u64", + }, + ], + outputs: [ + { + type: "core::integer::u64", + }, + ], + state_mutability: "external", + }, + { + type: "function", + name: "get_generation_numbers", + inputs: [ + { + name: "id", + type: "core::integer::u64", + }, + ], + outputs: [ + { + type: "core::array::Array::", + }, + ], + state_mutability: "view", + }, + { + type: "function", + name: "get_generation_status", + inputs: [ + { + name: "id", + type: "core::integer::u64", + }, + ], + outputs: [ + { + type: "core::integer::u8", + }, + ], + state_mutability: "view", + }, + { + type: "function", + name: "get_generation_timestamps", + inputs: [ + { + name: "id", + type: "core::integer::u64", + }, + ], + outputs: [ + { + type: "(core::integer::u64, core::integer::u64)", + }, + ], + state_mutability: "view", + }, + { + type: "function", + name: "get_latest_id", + inputs: [], + outputs: [ + { + type: "core::integer::u64", + }, + ], + state_mutability: "view", + }, + ], + }, + { + type: "impl", + name: "OwnableImpl", + interface_name: "openzeppelin_access::ownable::interface::IOwnable", + }, + { + type: "interface", + name: "openzeppelin_access::ownable::interface::IOwnable", + items: [ + { + type: "function", + name: "owner", + inputs: [], + outputs: [ + { + type: "core::starknet::contract_address::ContractAddress", + }, + ], + state_mutability: "view", + }, + { + type: "function", + name: "transfer_ownership", + inputs: [ + { + name: "new_owner", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [], + state_mutability: "external", + }, + { + type: "function", + name: "renounce_ownership", + inputs: [], + outputs: [], + state_mutability: "external", + }, + ], + }, + { + type: "enum", + name: "core::bool", + variants: [ + { + name: "False", + type: "()", + }, + { + name: "True", + type: "()", + }, + ], + }, + { + type: "constructor", + name: "constructor", + inputs: [ + { + name: "owner", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "vrf_coordinator", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "dev_mode", + type: "core::bool", + }, + ], + }, + { + type: "struct", + name: "core::array::Span::", + members: [ + { + name: "snapshot", + type: "@core::array::Array::", + }, + ], + }, + { + type: "function", + name: "receive_random_words", + inputs: [ + { + name: "requester_address", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "request_id", + type: "core::integer::u64", + }, + { + name: "random_words", + type: "core::array::Span::", + }, + { + name: "_calldata", + type: "core::array::Array::", + }, + ], + outputs: [], + state_mutability: "external", + }, + { + type: "function", + name: "mark_generation_failed", + inputs: [ + { + name: "id", + type: "core::integer::u64", + }, + { + name: "code", + type: "core::felt252", + }, + ], + outputs: [], + state_mutability: "external", + }, + { + type: "function", + name: "set_vrf_coordinator", + inputs: [ + { + name: "addr", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [], + state_mutability: "external", + }, + { + type: "event", + name: "openzeppelin_access::ownable::ownable::OwnableComponent::OwnershipTransferred", + kind: "struct", + members: [ + { + name: "previous_owner", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "new_owner", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + ], + }, + { + type: "event", + name: "openzeppelin_access::ownable::ownable::OwnableComponent::OwnershipTransferStarted", + kind: "struct", + members: [ + { + name: "previous_owner", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + { + name: "new_owner", + type: "core::starknet::contract_address::ContractAddress", + kind: "key", + }, + ], + }, + { + type: "event", + name: "openzeppelin_access::ownable::ownable::OwnableComponent::Event", + kind: "enum", + variants: [ + { + name: "OwnershipTransferred", + type: "openzeppelin_access::ownable::ownable::OwnableComponent::OwnershipTransferred", + kind: "nested", + }, + { + name: "OwnershipTransferStarted", + type: "openzeppelin_access::ownable::ownable::OwnableComponent::OwnershipTransferStarted", + kind: "nested", + }, + ], + }, + { + type: "event", + name: "starklotto_adapter_vrf::Randomness::Randomness::GenerationRequested", + kind: "struct", + members: [ + { + name: "id", + type: "core::integer::u64", + kind: "key", + }, + { + name: "requester", + type: "core::starknet::contract_address::ContractAddress", + kind: "data", + }, + { + name: "timestamp", + type: "core::integer::u64", + kind: "data", + }, + { + name: "is_test", + type: "core::bool", + kind: "data", + }, + ], + }, + { + type: "event", + name: "starklotto_adapter_vrf::Randomness::Randomness::GenerationCompleted", + kind: "struct", + members: [ + { + name: "id", + type: "core::integer::u64", + kind: "key", + }, + { + name: "n1", + type: "core::integer::u8", + kind: "data", + }, + { + name: "n2", + type: "core::integer::u8", + kind: "data", + }, + { + name: "n3", + type: "core::integer::u8", + kind: "data", + }, + { + name: "n4", + type: "core::integer::u8", + kind: "data", + }, + { + name: "n5", + type: "core::integer::u8", + kind: "data", + }, + { + name: "timestamp", + type: "core::integer::u64", + kind: "data", + }, + { + name: "is_test", + type: "core::bool", + kind: "data", + }, + ], + }, + { + type: "event", + name: "starklotto_adapter_vrf::Randomness::Randomness::GenerationFailed", + kind: "struct", + members: [ + { + name: "id", + type: "core::integer::u64", + kind: "key", + }, + { + name: "code", + type: "core::felt252", + kind: "data", + }, + { + name: "timestamp", + type: "core::integer::u64", + kind: "data", + }, + ], + }, + { + type: "event", + name: "starklotto_adapter_vrf::Randomness::Randomness::TestGeneration", + kind: "struct", + members: [ + { + name: "id", + type: "core::integer::u64", + kind: "key", + }, + { + name: "n1", + type: "core::integer::u8", + kind: "data", + }, + { + name: "n2", + type: "core::integer::u8", + kind: "data", + }, + { + name: "n3", + type: "core::integer::u8", + kind: "data", + }, + { + name: "n4", + type: "core::integer::u8", + kind: "data", + }, + { + name: "n5", + type: "core::integer::u8", + kind: "data", + }, + { + name: "timestamp", + type: "core::integer::u64", + kind: "data", + }, + ], + }, + { + type: "event", + name: "starklotto_adapter_vrf::Randomness::Randomness::Event", + kind: "enum", + variants: [ + { + name: "OwnableEvent", + type: "openzeppelin_access::ownable::ownable::OwnableComponent::Event", + kind: "flat", + }, + { + name: "GenerationRequested", + type: "starklotto_adapter_vrf::Randomness::Randomness::GenerationRequested", + kind: "nested", + }, + { + name: "GenerationCompleted", + type: "starklotto_adapter_vrf::Randomness::Randomness::GenerationCompleted", + kind: "nested", + }, + { + name: "GenerationFailed", + type: "starklotto_adapter_vrf::Randomness::Randomness::GenerationFailed", + kind: "nested", + }, + { + name: "TestGeneration", + type: "starklotto_adapter_vrf::Randomness::Randomness::TestGeneration", + kind: "nested", + }, + ], + }, + ], + classHash: + "0x17d717a5813f50ee62b9f786ab6d14977ba6c25464c6d55cb3f1429686c123", + }, + }, sepolia: { Randomness: { address: diff --git a/packages/nextjs/scaffold.config.ts b/packages/nextjs/scaffold.config.ts index 230cf80..993d640 100644 --- a/packages/nextjs/scaffold.config.ts +++ b/packages/nextjs/scaffold.config.ts @@ -13,7 +13,7 @@ export type ScaffoldConfig = { }; const scaffoldConfig = { - targetNetworks: [chains.sepolia], + targetNetworks: [chains.devnet], // Only show the Burner Wallet when running on devnet onlyLocalBurnerWallet: false, rpcProviderUrl: { diff --git a/packages/snfoundry/contracts/src/Randomness.cairo b/packages/snfoundry/contracts/src/Randomness.cairo index aa1b016..61a203c 100644 --- a/packages/snfoundry/contracts/src/Randomness.cairo +++ b/packages/snfoundry/contracts/src/Randomness.cairo @@ -408,8 +408,8 @@ pub mod Randomness { while out.len() < 5_usize { state_u128 = (state_u128 * a + c) % modulus; let state: u64 = state_u128.try_into().unwrap(); - // candidate in [1,49] - let candidate: u8 = (((state % 49_u64) + 1_u64) % 256_u64).try_into().unwrap(); + // candidate in [1,40] for lottery numbers (1-40 range) + let candidate: u8 = (((state % 40_u64) + 1_u64) % 256_u64).try_into().unwrap(); if !contains_u8(@out, candidate) { out.append(candidate); } From 7f0911e6c73d5d0b924181b71254d3d85b9799be Mon Sep 17 00:00:00 2001 From: David Melendez Date: Thu, 9 Oct 2025 00:48:03 -0600 Subject: [PATCH 2/3] Update RandomnessComponent with new contract address, improve error messages, and enhance user notifications for better clarity --- .../contract/RandomnessComponent.tsx | 377 +++++++++--------- .../snfoundry/contracts/src/Randomness.cairo | 12 +- 2 files changed, 194 insertions(+), 195 deletions(-) diff --git a/packages/nextjs/app/debug/_components/contract/RandomnessComponent.tsx b/packages/nextjs/app/debug/_components/contract/RandomnessComponent.tsx index eda2a5e..b865178 100644 --- a/packages/nextjs/app/debug/_components/contract/RandomnessComponent.tsx +++ b/packages/nextjs/app/debug/_components/contract/RandomnessComponent.tsx @@ -19,7 +19,7 @@ const VRF_PROVIDER_ADDRESS = // Dirección esperada del contrato de Randomness desplegado en testnet // Esta dirección se actualiza con cada nuevo deployment para pruebas const EXPECTED_RANDOMNESS_CONTRACT_ADDRESS = - "0x036BcAC633A4B319190Ad7691E2B92DBfFf8EEF098feba82E6a20488824204F7"; + "0x5b3558ec6cbe58d1d1279b428aaace0fd9230b5993e19f482af82306076c54f"; interface RandomnessComponentProps { contractName: ContractName; @@ -69,12 +69,12 @@ export const RandomnessComponent = ({ const handleRequestRandomness = async () => { if (!isConnected || writeDisabled) { notification.error( - "Por favor conecta tu wallet y asegúrate de estar en la red correcta", + "Please connect your wallet and make sure you are on the correct network", ); return; } - // Verificación adicional de que la dirección es válida antes de proceder + // Additional verification that the address is valid before proceeding if ( account?.address && (!account.address.startsWith("0x") || @@ -82,31 +82,31 @@ export const RandomnessComponent = ({ account.address.length > 66) ) { notification.error( - "La dirección de la cuenta tiene un formato inválido. Intenta reconectar tu wallet.", + "The account address has an invalid format. Try reconnecting your wallet.", ); return; } if (!account?.address) { notification.error( - "No se pudo obtener la dirección de la cuenta conectada. Intenta reconectar tu wallet.", + "Could not get the connected account address. Try reconnecting your wallet.", ); return; } - // 🚨 VERIFICACIÓN ESPECÍFICA: Detectar cuenta problemática + // 🚨 SPECIFIC VERIFICATION: Detect problematic account if ( account?.address === "0x0297fd6c19289a017d50b1b65a07ea4db27596a8fade85c6b9622a3f9a24d2a9" ) { notification.error( - "Se ha detectado una cuenta que puede causar problemas. Intenta reconectar tu wallet o usar una cuenta diferente.", + "A problematic account has been detected. Try reconnecting your wallet or use a different account.", ); return; } if (!seed || isNaN(Number(seed))) { - notification.error("Por favor ingresa un seed válido (número entero)"); + notification.error("Please enter a valid seed (integer number)"); return; } @@ -126,7 +126,7 @@ export const RandomnessComponent = ({ targetNetwork.network === "devnet"; if (isDevnet) { - // Para desarrollo: usar devnet_generate directamente + // For development: use devnet_generate directly const seedHex = num.toHex(seedValue); @@ -141,40 +141,40 @@ export const RandomnessComponent = ({ if (txHash) { setTxHash(txHash); notification.success( - `¡5 números aleatorios generados exitosamente! Hash: ${txHash}`, + `5 random numbers generated successfully! Hash: ${txHash}`, ); if (onSuccess) { onSuccess(txHash, generationId); } } } else { - // Para producción: usar protocolo VRF correcto con multicall + // For production: use correct VRF protocol with multicall if (useAlternativeMode) { - // MODO ALTERNATIVO: Usar parámetros más seguros + // ALTERNATIVE MODE: Use safer parameters - // Usar parámetros más conservadores - const safeCallbackFeeLimit = "50000"; // Más bajo que el original 100000 + // Use more conservative parameters + const safeCallbackFeeLimit = "50000"; // Lower than the original 100000 const safePublishDelay = "0"; const seedHex = num.toHex(seedValue); const callbackFeeLimitHex = num.toHex(BigInt(safeCallbackFeeLimit)); const publishDelayHex = num.toHex(BigInt(safePublishDelay)); - // Crear el source para el VRF usando el seed + // Create the source for VRF using the seed const sourceValue = seedValue; - // MULTICALL: Dos transacciones según protocolo VRF correcto + // MULTICALL: Two transactions according to correct VRF protocol const multicallTx = await writeTransaction([ - // Paso 1: Solicitar aleatoriedad al VRF provider + // Step 1: Request randomness from VRF provider { contractAddress: VRF_PROVIDER_ADDRESS, entrypoint: "request_random", calldata: [ - contractAddress as string, // caller (nuestro contrato) - num.toHex(sourceValue), // source (el seed) + contractAddress as string, // caller (our contract) + num.toHex(sourceValue), // source (the seed) ], }, - // Paso 2: Consumir aleatoriedad en nuestro contrato + // Step 2: Consume randomness in our contract { contractAddress: contractAddress as string, entrypoint: "request_randomness_prod", @@ -185,34 +185,34 @@ export const RandomnessComponent = ({ if (multicallTx) { setTxHash(multicallTx); notification.success( - `¡Solicitud VRF enviada (Modo Seguro)! Hash: ${multicallTx}. Esperando respuesta del oráculo...`, + `VRF request sent (Safe Mode)! Hash: ${multicallTx}. Waiting for oracle response...`, ); if (onSuccess) { onSuccess(multicallTx, generationId); } } } else { - // MODO NORMAL: Multicall estándar + // NORMAL MODE: Standard Multicall const seedHex = num.toHex(seedValue); const callbackFeeLimitHex = num.toHex(BigInt(callbackFeeLimit)); const publishDelayHex = num.toHex(BigInt(publishDelay)); - // Crear el source para el VRF usando el seed + // Create the source for VRF using the seed const sourceValue = seedValue; - // MULTICALL: Dos transacciones según protocolo VRF correcto + // MULTICALL: Two transactions according to correct VRF protocol const multicallTx = await writeTransaction([ - // Paso 1: Solicitar aleatoriedad al VRF provider + // Step 1: Request randomness from VRF provider { contractAddress: VRF_PROVIDER_ADDRESS, entrypoint: "request_random", calldata: [ - contractAddress as string, // caller (nuestro contrato) - num.toHex(sourceValue), // source (el seed) + contractAddress as string, // caller (our contract) + num.toHex(sourceValue), // source (the seed) ], }, - // Paso 2: Consumir aleatoriedad en nuestro contrato + // Step 2: Consume randomness in our contract { contractAddress: contractAddress as string, entrypoint: "request_randomness_prod", @@ -223,7 +223,7 @@ export const RandomnessComponent = ({ if (multicallTx) { setTxHash(multicallTx); notification.success( - `¡Solicitud VRF enviada! Hash: ${multicallTx}. Esperando respuesta del oráculo...`, + `VRF request sent! Hash: ${multicallTx}. Waiting for oracle response...`, ); if (onSuccess) { onSuccess(multicallTx, generationId); @@ -232,40 +232,40 @@ export const RandomnessComponent = ({ } } } catch (error: any) { - // Proporcionar mensajes de error más específicos - let errorMessage = "Error desconocido al solicitar aleatoriedad"; + // Provide more specific error messages + let errorMessage = "Unknown error requesting randomness"; if ( error.name === "UserRejectedRequestError" || error.message?.includes("User rejected request") ) { errorMessage = - "Transacción cancelada por el usuario. Por favor, inténtalo de nuevo."; + "Transaction canceled by user. Please try again."; } else if (error.message?.includes("insufficient")) { errorMessage = - "Fondos insuficientes para cubrir los fees de la transacción"; + "Insufficient funds to cover transaction fees"; } else if (error.message?.includes("nonce")) { - errorMessage = "Error de nonce. Intenta nuevamente"; + errorMessage = "Nonce error. Please try again"; } else if (error.message?.includes("network")) { - errorMessage = "Error de red. Verifica tu conexión"; + errorMessage = "Network error. Check your connection"; } else if (error.message?.includes("ENTRYPOINT_NOT_FOUND")) { - errorMessage = `❌ ENTRYPOINT_NOT_FOUND: La función no existe en el contrato desplegado. - Dirección del contrato: ${contractAddress} - Función intentada: ${chain?.network === "devnet" || targetNetwork.network === "devnet" ? "devnet_generate" : "request_randomness_prod"} - Posible solución: El contrato necesita ser recompilado y redeployado.`; + errorMessage = `❌ ENTRYPOINT_NOT_FOUND: Function does not exist in deployed contract. + Contract address: ${contractAddress} + Attempted function: ${chain?.network === "devnet" || targetNetwork.network === "devnet" ? "devnet_generate" : "request_randomness_prod"} + Possible solution: Contract needs to be recompiled and redeployed.`; } else if (error.message?.includes("ENTRYPOINT_FAILED")) { - errorMessage = `❌ ENTRYPOINT_FAILED: Error ejecutando la función del contrato. - Dirección del contrato: ${contractAddress} - Función: ${chain?.network === "devnet" || targetNetwork.network === "devnet" ? "devnet_generate" : "request_randomness_prod"} - Posible solución: Verifica que el contrato esté correctamente inicializado.`; + errorMessage = `❌ ENTRYPOINT_FAILED: Error executing contract function. + Contract address: ${contractAddress} + Function: ${chain?.network === "devnet" || targetNetwork.network === "devnet" ? "devnet_generate" : "request_randomness_prod"} + Possible solution: Verify that the contract is correctly initialized.`; } else if (error.message?.includes("argent/multicall-failed")) { - errorMessage = `❌ ARGENT_MULTICALL_FAILED: Error en multicall VRF. - Transacciones ejecutadas: + errorMessage = `❌ ARGENT_MULTICALL_FAILED: Error in VRF multicall. + Executed transactions: 1. request_random → VRF Provider (${VRF_PROVIDER_ADDRESS}) - 2. request_randomness_prod → Contrato (${contractAddress}) - Posible solución: Verifica que el VRF coordinator esté configurado correctamente.`; + 2. request_randomness_prod → Contract (${contractAddress}) + Possible solution: Verify that the VRF coordinator is correctly configured.`; } else if (error.message) { - errorMessage = `❌ Error específico: ${error.message}`; + errorMessage = `❌ Specific error: ${error.message}`; } notification.error(errorMessage); @@ -274,12 +274,12 @@ export const RandomnessComponent = ({ } }; - // Verificar que tenemos toda la información necesaria + // Verify that we have all necessary information if (!contractAddress || !account?.address) { return (

-

Cargando información del contrato...

+

Loading contract information...

); @@ -289,91 +289,91 @@ export const RandomnessComponent = ({

- 🏆 Multicall VRF - Solicitar Aleatoriedad con Cartridge + 🏆 Multicall VRF - Request Randomness with Cartridge

{isDevnet ? ( <> - Esta función genera 5 números aleatorios únicos en el rango [1,49] - usando generación local para desarrollo. + This function generates 5 unique random numbers in the range [1,40] + using local generation for development. ) : ( <> - Esta función ejecuta un multicall que primero solicita - aleatoriedad al VRF provider de Cartridge, luego consume esa - aleatoriedad para generar 5 números únicos en el rango [1,49]. + This function executes a multicall that first requests + randomness from the Cartridge VRF provider, then consumes that + randomness to generate 5 unique numbers in the range [1,40]. )}

- {/* Información del contrato */} + {/* Contract information */}
-

Contrato Consumidor:

+

Consumer Contract:

- Dirección esperada:{" "} + Expected address:{" "} {EXPECTED_RANDOMNESS_CONTRACT_ADDRESS}

- Dirección actual: {contractAddress} + Current address: {contractAddress}

- Red: {chain?.name || "Desconocida"} →{" "} + Network: {chain?.name || "Unknown"} →{" "} {targetNetwork.name}

- Modo:{" "} + Mode:{" "} {isDevnet - ? "Desarrollo (devnet)" - : "Producción (testnet/sepolia)"} + ? "Development (devnet)" + : "Production (testnet/sepolia)"}

- {/* Información técnica */} + {/* Technical information */}

- 📋 Modo:{" "} + 📋 Mode:{" "} {isDevnet ? forceDevMode - ? "Desarrollo Forzado (devnet_generate)" - : "Desarrollo (Local)" + ? "Forced Development (devnet_generate)" + : "Development (Local)" : useAlternativeMode - ? "Producción (Multicall Seguro)" - : "Producción (Multicall Estándar)"} + ? "Production (Safe Multicall)" + : "Production (Standard Multicall)"}

{isDevnet ? ( <>

- Método: devnet_generate (generación local) + Method: devnet_generate (local generation)

- Contrato: {contractAddress} + Contract: {contractAddress}

- Estado:{" "} - {forceDevMode ? "Forzado para testing" : "Automático"} + Status:{" "} + {forceDevMode ? "Forced for testing" : "Automatic"}

) : ( <>

- Método: Multicall VRF ( - {useAlternativeMode ? "Modo Seguro" : "Estándar"}) + Method: Multicall VRF ( + {useAlternativeMode ? "Safe Mode" : "Standard"})

- Transacción 1: request_random → VRF Provider + Transaction 1: request_random → VRF Provider

- Transacción 2: request_randomness_prod → - Contrato + Transaction 2: request_randomness_prod → + Contract

VRF Provider: {VRF_PROVIDER_ADDRESS} @@ -383,21 +383,21 @@ export const RandomnessComponent = ({ {useAlternativeMode ? "50,000" : callbackFeeLimit} wei

- Publish Delay: {publishDelay} (sin delay) + Publish Delay: {publishDelay} (no delay)

- Source (Seed): Usado como source para VRF + Source (Seed): Used as source for VRF

)}
- {/* Formulario de entrada */} + {/* Input form */}

- El seed determina la secuencia aleatoria. Usa diferentes valores - para obtener resultados diferentes. + The seed determines the random sequence. Use different values + to get different results.

- {/* Estado de conexión */} + {/* Connection status */} {!isConnected && (

- ⚠️ Wallet no conectado. Conecta tu wallet para usar esta - función. + ⚠️ Wallet not connected. Connect your wallet to use this + function.

)} - {/* Estado de red */} + {/* Network status */} {isConnected && writeDisabled && (

- ⚠️ Wallet conectado a red incorrecta. Cambia a{" "} + ⚠️ Wallet connected to wrong network. Switch to{" "} {targetNetwork.name}.

)} - {/* Diagnóstico de problemas potenciales */} + {/* Potential problems diagnosis */} {contractAddress && contractAddress.toLowerCase().replace(/^0x0+/, "0x") !== EXPECTED_RANDOMNESS_CONTRACT_ADDRESS.toLowerCase().replace( @@ -442,61 +442,60 @@ export const RandomnessComponent = ({ ) && (

- 🚨 Problema Detectado + 🚨 Problem Detected

- Dirección del contrato incorrecta: + Incorrect contract address:

- • Dirección esperada: {EXPECTED_RANDOMNESS_CONTRACT_ADDRESS} + • Expected address: {EXPECTED_RANDOMNESS_CONTRACT_ADDRESS}

-

• Dirección actual: {contractAddress}

+

• Current address: {contractAddress}

- • Solución: El contrato necesita ser - recompilado y redeployado con la dirección correcta. + • Solution: The contract needs to be + recompiled and redeployed with the correct address.

)} - {/* Diagnóstico específico de problemas de cuenta/wallet */} + {/* Specific account/wallet problem diagnosis */} {account?.address && account.address.startsWith( "0x0297fd6c19289a017d50b1b65a07ea4db27596a8fade85c6b9622a3f9a24d2a9", ) && (

- 🚨 Cuenta Problemática Detectada + 🚨 Problematic Account Detected

- Se ha detectado una cuenta que causa errores de - transacción. + An account that causes transaction errors has been detected.

- Dirección problemática: + Problematic address:

{account.address}

- 🔧 Opciones para solucionar: + 🔧 Options to fix:

- Más opciones avanzadas + More advanced options
-

• Usa una cuenta diferente en tu wallet

-

• Verifica que tienes ETH suficiente para fees

-

• Asegúrate de que la cuenta esté activa

-

• Contacta soporte si el problema persiste

+

• Use a different account in your wallet

+

• Verify that you have enough ETH for fees

+

• Make sure the account is active

+

• Contact support if the problem persists

@@ -560,102 +559,102 @@ export const RandomnessComponent = ({
)} - {/* Información sobre Modo Seguro cuando está activo */} + {/* Information about Safe Mode when active */} {useAlternativeMode && (

- ✅ Modo Seguro Activo + ✅ Safe Mode Active

-

• Usando parámetros más conservadores (fee limit: 50,000)

+

• Using more conservative parameters (fee limit: 50,000)

- • Probabilidad más alta de éxito con cuentas problemáticas + • Higher probability of success with problematic accounts

-

• Puedes generar números usando el botón principal

+

• You can generate numbers using the main button

)} - {/* Información sobre Modo Desarrollo Forzado cuando está activo */} + {/* Information about Forced Development Mode when active */} {forceDevMode && (

- ⚠️ Modo Desarrollo Forzado + ⚠️ Forced Development Mode

- • Usando función de desarrollo (devnet_generate) incluso en + • Using development function (devnet_generate) even on testnet

-

• Generación local sin depender de oráculos externos

-

• Útil para testing cuando hay problemas con VRF

+

• Local generation without depending on external oracles

+

• Useful for testing when there are VRF problems

)} - {/* Estado de cuenta (debugging avanzado) */} + {/* Account status (advanced debugging) */} {isConnected && !writeDisabled && !account?.address && (

- 🔍 Estado de cuenta (debugging): + 🔍 Account status (debugging):

- Wallet conectado: {isConnected ? "Sí" : "No"} + Wallet connected: {isConnected ? "Yes" : "No"}

- Dirección de cuenta:{" "} - {account?.address || "No disponible"} + Account address:{" "} + {account?.address || "Not available"}

- Estado de wallet: {walletStatus} + Wallet status: {walletStatus}

- Red actual: {chain?.name || "Desconocida"} + Current network: {chain?.name || "Unknown"}

- Red objetivo: {targetNetwork.name} + Target network: {targetNetwork.name}

- 💡 Si ves esto, intenta reconectar tu wallet o refrescar la - página. + 💡 If you see this, try reconnecting your wallet or refreshing the + page.

)} - {/* Resultado de transacción */} + {/* Transaction result */} {txHash && (

- Hash de transacción: {txHash} + Transaction hash: {txHash}

)} - {/* Botón principal */} + {/* Main button */}
- {/* Configuración del VRF Coordinator (solo producción) */} + {/* VRF Coordinator Configuration (production only) */} {!isDevnet && ( )} - {/* Información adicional */} + {/* Additional information */}

- 💡 Cómo funciona: + 💡 How it works:

{isDevnet ? (
  1. - 1. Se llama directamente a devnet_generate(seed) + 1. Directly calls devnet_generate(seed)
  2. - 2. El contrato genera 5 números únicos usando un algoritmo LCG - local + 2. The contract generates 5 unique numbers using a local LCG + algorithm
  3. - 3. Los números se generan inmediatamente sin depender de - oráculos externos + 3. Numbers are generated immediately without depending on + external oracles
  4. - 4. Los números se almacenan y se pueden consultar con{" "} + 4. Numbers are stored and can be queried with{" "} get_generation_numbers(id)
) : (
  1. - 1. Paso 1: Se ejecuta multicall con 2 - transacciones + 1. Step 1: Executes multicall with 2 + transactions
  2. - 2. Transacción 1:{" "} + 2. Transaction 1:{" "} request_random(caller, source) → VRF Provider
  3. - 3. Transacción 2:{" "} + 3. Transaction 2:{" "} request_randomness_prod(seed, fee, delay) → - Contrato + Contract
  4. - 4. El contrato solicita y consume aleatoriedad usando protocolo - VRF de Cartridge + 4. The contract requests and consumes randomness using Cartridge + VRF protocol
  5. - 5. Los números se generan usando aleatoriedad descentralizada - verificable + 5. Numbers are generated using verifiable decentralized + randomness
  6. - 6. Los números se almacenan y se pueden consultar con{" "} + 6. Numbers are stored and can be queried with{" "} get_generation_numbers(id)
@@ -739,7 +738,7 @@ export const RandomnessComponent = ({ ); }; -// Componente para configurar el VRF Coordinator +// Component to configure VRF Coordinator const VRFCoordinatorConfig = ({ contractAddress, }: VRFCoordinatorConfigProps) => { @@ -756,7 +755,7 @@ const VRFCoordinatorConfig = ({ !newCoordinatorAddress.startsWith("0x") || newCoordinatorAddress.length !== 66 ) { - notification.error("Dirección del VRF coordinator inválida"); + notification.error("Invalid VRF coordinator address"); return; } @@ -773,14 +772,14 @@ const VRFCoordinatorConfig = ({ if (txHash) { notification.success( - `VRF coordinator actualizado exitosamente! Hash: ${txHash}`, + `VRF coordinator updated successfully! Hash: ${txHash}`, ); setIsExpanded(false); } } catch (error: any) { notification.error( - "Error actualizando VRF coordinator: " + - (error.message || "Error desconocido"), + "Error updating VRF coordinator: " + + (error.message || "Unknown error"), ); } finally { setIsLoading(false); @@ -790,26 +789,26 @@ const VRFCoordinatorConfig = ({ return (
-

⚙️ Configuración VRF

+

⚙️ VRF Configuration

{isExpanded && (

- El contrato debe estar configurado con la dirección correcta del VRF - coordinator de Cartridge. + The contract must be configured with the correct VRF + coordinator address from Cartridge.

- Dirección actual configurada:{" "} + Current configured address:{" "} {VRF_PROVIDER_ADDRESS}

- Dirección en formulario:{" "} + Address in form:{" "} {newCoordinatorAddress}

- Nota: Solo el owner del contrato puede cambiar esta - configuración. + Note: Only the contract owner can change this + configuration.

@@ -852,26 +851,26 @@ const VRFCoordinatorConfig = ({ {isLoading && ( )} - Actualizar VRF Coordinator + Update VRF Coordinator
- Información técnica + Technical information

- • Esta función llama a set_vrf_coordinator() en el - contrato + • This function calls set_vrf_coordinator() on the + contract

-

• Solo el owner del contrato puede ejecutar esta función

+

• Only the contract owner can execute this function

- • El contrato usará esta dirección para validar callbacks del - VRF + • The contract will use this address to validate VRF + callbacks

- • Asegúrate de usar la dirección correcta del VRF provider de + • Make sure to use the correct VRF provider address from Cartridge

diff --git a/packages/snfoundry/contracts/src/Randomness.cairo b/packages/snfoundry/contracts/src/Randomness.cairo index 61a203c..b85bea7 100644 --- a/packages/snfoundry/contracts/src/Randomness.cairo +++ b/packages/snfoundry/contracts/src/Randomness.cairo @@ -155,18 +155,18 @@ pub mod Randomness { }, ); - // Consumo sincrónico de aleatorio usando Cartridge VRF. - // El caller debe prefijar la multicall con `request_random(caller, source)`. - // Aquí consumimos con el MISMO `Source`. + // Synchronous consumption of randomness using Cartridge VRF. + // The caller must prefix the multicall with `request_random(caller, source)`. + // Here we consume with the SAME `Source`. let vrf_addr = self.vrf_coordinator.read(); let vrf = IVrfProviderDispatcher { contract_address: vrf_addr }; let rand_felt: felt252 = vrf.consume_random(Source::Salt(seed.into())); - // Derivar 5 números en [1,49] a partir del random consumido + // Derive 5 numbers in [1,40] from the consumed random let base_seed: u64 = felt_to_u64(rand_felt); let mut nums = derive_five_unique_numbers(base_seed); - // persistir números + // persist numbers let n1 = *nums.at(0); let n2 = *nums.at(1); let n3 = *nums.at(2); @@ -387,7 +387,7 @@ pub mod Randomness { let maybe_u128: Option = w0.try_into(); match maybe_u128 { Option::Some(v_u128) => { - // 2^64 (usar literal directa; compila en u128) + // 2^64 (use direct literal; compiles as u128) let mod64_divisor: u128 = 18446744073709551616_u128; let mod64: u128 = v_u128 % mod64_divisor; let seed_u64: u64 = mod64.try_into().unwrap(); From 68dd1621292f0dd9d890b1b871546b1aff7631bd Mon Sep 17 00:00:00 2001 From: David Melendez Date: Thu, 9 Oct 2025 00:58:44 -0600 Subject: [PATCH 3/3] run yarn format --- .../contract/RandomnessComponent.tsx | 62 ++++++++----------- .../nextjs/contracts/deployedContracts.ts | 4 +- 2 files changed, 27 insertions(+), 39 deletions(-) diff --git a/packages/nextjs/app/debug/_components/contract/RandomnessComponent.tsx b/packages/nextjs/app/debug/_components/contract/RandomnessComponent.tsx index b865178..4fe3f64 100644 --- a/packages/nextjs/app/debug/_components/contract/RandomnessComponent.tsx +++ b/packages/nextjs/app/debug/_components/contract/RandomnessComponent.tsx @@ -110,7 +110,6 @@ export const RandomnessComponent = ({ return; } - setIsLoading(true); setTxHash(""); setGenerationId(""); @@ -239,11 +238,9 @@ export const RandomnessComponent = ({ error.name === "UserRejectedRequestError" || error.message?.includes("User rejected request") ) { - errorMessage = - "Transaction canceled by user. Please try again."; + errorMessage = "Transaction canceled by user. Please try again."; } else if (error.message?.includes("insufficient")) { - errorMessage = - "Insufficient funds to cover transaction fees"; + errorMessage = "Insufficient funds to cover transaction fees"; } else if (error.message?.includes("nonce")) { errorMessage = "Nonce error. Please try again"; } else if (error.message?.includes("network")) { @@ -295,14 +292,14 @@ export const RandomnessComponent = ({

{isDevnet ? ( <> - This function generates 5 unique random numbers in the range [1,40] - using local generation for development. + This function generates 5 unique random numbers in the range + [1,40] using local generation for development. ) : ( <> - This function executes a multicall that first requests - randomness from the Cartridge VRF provider, then consumes that - randomness to generate 5 unique numbers in the range [1,40]. + This function executes a multicall that first requests randomness + from the Cartridge VRF provider, then consumes that randomness to + generate 5 unique numbers in the range [1,40]. )}

@@ -408,8 +405,8 @@ export const RandomnessComponent = ({ disabled={isLoading} />

- The seed determines the random sequence. Use different values - to get different results. + The seed determines the random sequence. Use different values to + get different results.

@@ -472,7 +469,8 @@ export const RandomnessComponent = ({

- An account that causes transaction errors has been detected. + An account that causes transaction errors has been + detected.

@@ -483,9 +481,7 @@ export const RandomnessComponent = ({
-

- 🔧 Options to fix: -

+

🔧 Options to fix: