diff --git a/config.json b/config.json
index 0356444..810d1ce 100644
--- a/config.json
+++ b/config.json
@@ -1,6 +1,6 @@
{
- "API_URL": "https://rpc.hasrv.averel10.app/",
- "CONTRACT_ADDRESS": "0xC3D2A1471A5e19ce586D4D3cB398Ce560efAF6Ca",
+ "API_URL": "http://185.48.228.49:8545",
+ "CONTRACT_ADDRESS": "0x375dDb60596f9587756012d95597dba54A247000",
"ABI": [
{
"inputs": [
@@ -58,5 +58,325 @@
"stateMutability": "nonpayable",
"type": "function"
}
+ ],
+ "GAME_CONTRACT_ADDRESS": "0x3209690ae3785924525453997d553624123871e6",
+ "GAME_ABI": [
+ {
+ "inputs": [],
+ "name": "BET_MIN",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "REVEAL_TIMEOUT",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "bothPlayed",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "bothRevealed",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getActiveGameIds",
+ "outputs": [
+ {
+ "internalType": "uint256[]",
+ "name": "",
+ "type": "uint256[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getContractBalance",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "gameId",
+ "type": "uint256"
+ }
+ ],
+ "name": "getGameDetails",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "playerAAddr",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "playerBAddr",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "initialBet",
+ "type": "uint256"
+ },
+ {
+ "internalType": "enum Game.Outcomes",
+ "name": "outcome",
+ "type": "uint8"
+ },
+ {
+ "internalType": "bool",
+ "name": "isActive",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getLastWinner",
+ "outputs": [
+ {
+ "internalType": "enum Game.Outcomes",
+ "name": "",
+ "type": "uint8"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getMyActiveGameId",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getOutcome",
+ "outputs": [
+ {
+ "internalType": "enum Game.Outcomes",
+ "name": "",
+ "type": "uint8"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "index",
+ "type": "uint256"
+ }
+ ],
+ "name": "getPastGame",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "playerAAddr",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "playerBAddr",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "initialBet",
+ "type": "uint256"
+ },
+ {
+ "internalType": "enum Game.Outcomes",
+ "name": "outcome",
+ "type": "uint8"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getPastGamesCount",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "encrMove",
+ "type": "bytes32"
+ }
+ ],
+ "name": "play",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "playerARevealed",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "playerBRevealed",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "gameId",
+ "type": "uint256"
+ }
+ ],
+ "name": "register",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "playerId",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "returnGameId",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "clearMove",
+ "type": "string"
+ }
+ ],
+ "name": "reveal",
+ "outputs": [
+ {
+ "internalType": "enum Game.Moves",
+ "name": "",
+ "type": "uint8"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "revealTimeLeft",
+ "outputs": [
+ {
+ "internalType": "int256",
+ "name": "",
+ "type": "int256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "whoAmI",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ }
]
}
\ No newline at end of file
diff --git a/crypto_clash_contract/scripts/deploy.ts b/crypto_clash_contract/scripts/deploy.ts
index 7c5c03c..e335b27 100644
--- a/crypto_clash_contract/scripts/deploy.ts
+++ b/crypto_clash_contract/scripts/deploy.ts
@@ -10,11 +10,21 @@ dotenv.config();
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
-async function main() {
- const artifactPath = path.join(
- __dirname,
- "../../artifacts/contracts/testcontract.sol/HelloWorld.json"
- );
+interface ContractDeploymentConfig {
+ name: string;
+ artifactPath: string;
+ deployArgs?: unknown[];
+ configKeys: {
+ address: string;
+ abi: string;
+ };
+}
+
+async function deployContract(
+ signer: ethers.Signer,
+ config: ContractDeploymentConfig
+): Promise<{ address: string; abi: unknown }> {
+ const artifactPath = path.join(__dirname, "../../artifacts/contracts", config.artifactPath);
if (!fs.existsSync(artifactPath)) {
throw new Error(`Artifact not found at ${artifactPath}. Please compile the contracts first.`);
@@ -24,37 +34,69 @@ async function main() {
const contractABI = artifact.abi;
const contractBytecode = artifact.bytecode;
+ const factory = new ethers.ContractFactory(contractABI, contractBytecode, signer);
+
+ console.log(`Deploying ${config.name} contract...`);
+ const deployedContract = await factory.deploy(...(config.deployArgs || []));
+ await deployedContract.waitForDeployment();
+
+ console.log(`✓ ${config.name} deployed to:`, deployedContract.target);
+
+ return {
+ address: deployedContract.target as string,
+ abi: contractABI
+ };
+}
+
+async function main() {
// Create provider and signer
const provider = new ethers.JsonRpcProvider(process.env.API_URL);
const signer = new ethers.Wallet(process.env.WALLET_PRIVATE_KEY!, provider);
- // Create contract factory
- const HelloWorldFactory = new ethers.ContractFactory(
- contractABI,
- contractBytecode,
- signer
- );
+ const config: any = {};
+ const deployedContracts: any = {};
- // Deploy the contract
- console.log("Deploying HelloWorld contract...");
- const hello_world = await HelloWorldFactory.deploy("Hello World!");
-
- // Wait for deployment to complete
- await hello_world.waitForDeployment();
-
- console.log("Contract deployed to address:", hello_world.target);
+ // Load existing config if it exists
+ const configPath = path.join(__dirname, "../../../config.json");
+ if (fs.existsSync(configPath)) {
+ Object.assign(config, JSON.parse(fs.readFileSync(configPath, "utf8")));
+ }
- // Save contract address to config.json
- const configPath = path.join(__dirname, "../../../config.json");
- let config = {};
- if (fs.existsSync(configPath)) {
- config = JSON.parse(fs.readFileSync(configPath, "utf8"));
- }
- (config as any).CONTRACT_ADDRESS = hello_world.target;
- (config as any).API_URL = process.env.API_URL;
- (config as any).ABI = contractABI;
- fs.writeFileSync(configPath, JSON.stringify(config, null, 4));
- console.log("✓ Contract address saved to config.json");
+ // Define contracts to deploy
+ const contractsToDeploy: ContractDeploymentConfig[] = [
+ {
+ name: "HelloWorld",
+ artifactPath: "testcontract.sol/HelloWorld.json",
+ deployArgs: ["Hello World!"],
+ configKeys: {
+ address: "CONTRACT_ADDRESS",
+ abi: "ABI"
+ }
+ },
+ {
+ name: "Game",
+ artifactPath: "Game.sol/Game.json",
+ deployArgs: [],
+ configKeys: {
+ address: "GAME_CONTRACT_ADDRESS",
+ abi: "GAME_ABI"
+ }
+ }
+ ];
+
+ // Deploy all contracts
+ for (const contractConfig of contractsToDeploy) {
+ const deployed = await deployContract(signer, contractConfig);
+ config[contractConfig.configKeys.address] = deployed.address;
+ config[contractConfig.configKeys.abi] = deployed.abi;
+ }
+
+ // Save configuration
+ config.API_URL = process.env.API_URL;
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 4));
+
+ console.log("\n✓ All contracts deployed successfully!");
+ console.log("✓ Configuration saved to config.json");
}
main()
diff --git a/crypto_clash_frontend/app/clash/page.tsx b/crypto_clash_frontend/app/clash/page.tsx
new file mode 100644
index 0000000..131f58e
--- /dev/null
+++ b/crypto_clash_frontend/app/clash/page.tsx
@@ -0,0 +1,11 @@
+"use client";
+
+
+export default function Clash() {
+ return (
+
+
Clash Page
+
This is the Clash page content.
+
+ );
+}
diff --git a/crypto_clash_frontend/app/hello_world/page.tsx b/crypto_clash_frontend/app/hello_world/page.tsx
new file mode 100644
index 0000000..836bb68
--- /dev/null
+++ b/crypto_clash_frontend/app/hello_world/page.tsx
@@ -0,0 +1,245 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import Web3 from "web3";
+
+
+
+export default function Home() {
+ const [config, setConfig] = useState(null);
+ const [web3, setWeb3] = useState(null);
+ const [contract, setContract] = useState(null);
+ const [message, setMessage] = useState("");
+ const [newMessage, setNewMessage] = useState("");
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState("");
+ const [account, setAccount] = useState("");
+
+ // Initialize Web3 and contract
+ useEffect(() => {
+ const loadConfig = async () => {
+ try {
+ const response = await fetch("/crypto_clash/config.json");
+ const data = await response.json();
+ setConfig(data);
+
+ // Initialize Web3
+ const web3Instance = new Web3(data.API_URL);
+ setWeb3(web3Instance);
+
+ // Create contract instance
+ const contractInstance = new web3Instance.eth.Contract(
+ data.ABI,
+ data.CONTRACT_ADDRESS
+ );
+ setContract(contractInstance);
+
+ // Try to get connected account (if MetaMask or similar is available)
+ if (typeof window !== "undefined" && (window as any).ethereum) {
+ try {
+ const accounts = await (window as any).ethereum.request({
+ method: "eth_requestAccounts",
+ });
+ setAccount(accounts[0]);
+
+ // Get the network ID from the RPC endpoint
+ const networkId = await web3Instance.eth.net.getId();
+ const currentChainId = await (window as any).ethereum.request({
+ method: "eth_chainId",
+ });
+
+ // If on different network, notify user (they may need to switch networks manually)
+ console.log(
+ `RPC Network ID: ${networkId}, MetaMask Chain ID: ${currentChainId}`
+ );
+ } catch (err) {
+ console.log("MetaMask not available or user denied access");
+ }
+ }
+
+ // Load initial message
+ await readMessage(contractInstance);
+ } catch (err) {
+ setError(`Failed to load config: ${err}`);
+ console.error(err);
+ }
+ };
+
+ loadConfig();
+ }, []);
+
+ // Read message from contract
+ const readMessage = async (contractInstance: any) => {
+ try {
+ setLoading(true);
+ setError("");
+ const result = await contractInstance.methods.message().call();
+ setMessage(result);
+ } catch (err) {
+ setError(`Failed to read message: ${err}`);
+ console.error(err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ // Update message on contract
+ const updateMessage = async () => {
+ if (!newMessage.trim()) {
+ setError("Please enter a message");
+ return;
+ }
+
+ try {
+ setLoading(true);
+ setError("");
+
+ if (!web3 || !contract) {
+ throw new Error("Web3 or contract not initialized");
+ }
+
+ // Check if MetaMask is available
+ if (!account && typeof window !== "undefined" && !(window as any).ethereum) {
+ throw new Error(
+ "MetaMask not available. Please install MetaMask to update the message."
+ );
+ }
+
+ // Create transaction
+ const tx = contract.methods.update(newMessage);
+ const gas = await tx.estimateGas({ from: account });
+
+ console.log(await web3.eth.net.getId());
+
+ // Send transaction via MetaMask
+ const result = await (window as any).ethereum.request({
+ method: "eth_sendTransaction",
+ params: [
+ {
+ from: account,
+ to: config?.CONTRACT_ADDRESS,
+ data: tx.encodeABI(),
+ gas: web3.utils.toHex(gas),
+ chainId: web3.utils.toHex(await web3.eth.net.getId()),
+ },
+ ],
+ });
+
+
+
+ setError(`Transaction sent: ${result}`);
+ setNewMessage("");
+
+ // Wait a bit and refresh message from the RPC endpoint
+ setTimeout(() => {
+ if (contract) {
+ readMessage(contract);
+ }
+ }, 2000);
+ } catch (err) {
+ setError(`Failed to update message: ${err}`);
+ console.error(err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+
+ Smart Contract Interaction
+
+
+ Read and update messages on the blockchain
+
+
+ {/* Status Section */}
+
+
+ Connected Account:{" "}
+ {account ? `${account.slice(0, 6)}...${account.slice(-4)}` : "Not connected"}
+
+
+ Contract Address:{" "}
+ {config?.CONTRACT_ADDRESS}
+
+
+
+ {/* Current Message Display */}
+
+
+ Current Message:
+
+ {loading && !message ? (
+
Loading...
+ ) : message ? (
+
+ {message}
+
+ ) : (
+
+ No message yet
+
+ )}
+
+
+ {/* Refresh Button */}
+
+
+ {/* Update Message Form */}
+
+
+ Update Message:
+
+ setNewMessage(e.target.value)}
+ placeholder="Enter new message..."
+ className="w-full px-4 py-3 border border-slate-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-700 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500"
+ />
+
+
+
+ {/* Error/Status Messages */}
+ {error && (
+
+ )}
+
+ {/* Info Section */}
+
+
ℹ️ Note:
+
+ - To update messages, you need MetaMask or a compatible Web3 wallet
+ - Make sure your MetaMask is connected to the correct test network
+ - Reading messages is free and doesn't require a wallet
+ - Updates are written to the blockchain and may take time to confirm
+
+
+
+
+
+ );
+}
diff --git a/crypto_clash_frontend/app/layout.tsx b/crypto_clash_frontend/app/layout.tsx
index f7fa87e..cb2b4e2 100644
--- a/crypto_clash_frontend/app/layout.tsx
+++ b/crypto_clash_frontend/app/layout.tsx
@@ -13,8 +13,8 @@ const geistMono = Geist_Mono({
});
export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
+ title: "Crypto Clash",
+ description: "Challenge yourself with competitive battles",
};
export default function RootLayout({
diff --git a/crypto_clash_frontend/app/page.tsx b/crypto_clash_frontend/app/page.tsx
index c740e19..66c4ab9 100644
--- a/crypto_clash_frontend/app/page.tsx
+++ b/crypto_clash_frontend/app/page.tsx
@@ -1,248 +1,26 @@
"use client";
-import { useEffect, useState } from "react";
-import Web3 from "web3";
-
-interface Config {
- API_URL: string;
- CONTRACT_ADDRESS: string;
- ABI: any[];
-}
+import Link from "next/link";
export default function Home() {
- const [config, setConfig] = useState(null);
- const [web3, setWeb3] = useState(null);
- const [contract, setContract] = useState(null);
- const [message, setMessage] = useState("");
- const [newMessage, setNewMessage] = useState("");
- const [loading, setLoading] = useState(false);
- const [error, setError] = useState("");
- const [account, setAccount] = useState("");
-
- // Initialize Web3 and contract
- useEffect(() => {
- const loadConfig = async () => {
- try {
- const response = await fetch("/crypto_clash/config.json");
- const data = await response.json();
- setConfig(data);
-
- // Initialize Web3
- const web3Instance = new Web3(data.API_URL);
- setWeb3(web3Instance);
-
- // Create contract instance
- const contractInstance = new web3Instance.eth.Contract(
- data.ABI,
- data.CONTRACT_ADDRESS
- );
- setContract(contractInstance);
-
- // Try to get connected account (if MetaMask or similar is available)
- if (typeof window !== "undefined" && (window as any).ethereum) {
- try {
- const accounts = await (window as any).ethereum.request({
- method: "eth_requestAccounts",
- });
- setAccount(accounts[0]);
-
- // Get the network ID from the RPC endpoint
- const networkId = await web3Instance.eth.net.getId();
- const currentChainId = await (window as any).ethereum.request({
- method: "eth_chainId",
- });
-
- // If on different network, notify user (they may need to switch networks manually)
- console.log(
- `RPC Network ID: ${networkId}, MetaMask Chain ID: ${currentChainId}`
- );
- } catch (err) {
- console.log("MetaMask not available or user denied access");
- }
- }
-
- // Load initial message
- await readMessage(contractInstance);
- } catch (err) {
- setError(`Failed to load config: ${err}`);
- console.error(err);
- }
- };
-
- loadConfig();
- }, []);
-
- // Read message from contract
- const readMessage = async (contractInstance: any) => {
- try {
- setLoading(true);
- setError("");
- const result = await contractInstance.methods.message().call();
- setMessage(result);
- } catch (err) {
- setError(`Failed to read message: ${err}`);
- console.error(err);
- } finally {
- setLoading(false);
- }
- };
-
- // Update message on contract
- const updateMessage = async () => {
- if (!newMessage.trim()) {
- setError("Please enter a message");
- return;
- }
-
- try {
- setLoading(true);
- setError("");
-
- if (!web3 || !contract) {
- throw new Error("Web3 or contract not initialized");
- }
-
- // Check if MetaMask is available
- if (!account && typeof window !== "undefined" && !(window as any).ethereum) {
- throw new Error(
- "MetaMask not available. Please install MetaMask to update the message."
- );
- }
-
- // Create transaction
- const tx = contract.methods.update(newMessage);
- const gas = await tx.estimateGas({ from: account });
-
- console.log(await web3.eth.net.getId());
-
- // Send transaction via MetaMask
- const result = await (window as any).ethereum.request({
- method: "eth_sendTransaction",
- params: [
- {
- from: account,
- to: config?.CONTRACT_ADDRESS,
- data: tx.encodeABI(),
- gas: web3.utils.toHex(gas),
- chainId: web3.utils.toHex(await web3.eth.net.getId()),
- },
- ],
- });
-
-
-
- setError(`Transaction sent: ${result}`);
- setNewMessage("");
-
- // Wait a bit and refresh message from the RPC endpoint
- setTimeout(() => {
- if (contract) {
- readMessage(contract);
- }
- }, 2000);
- } catch (err) {
- setError(`Failed to update message: ${err}`);
- console.error(err);
- } finally {
- setLoading(false);
- }
- };
-
return (
-
-
-
-
- Smart Contract Interaction
-
-
- Read and update messages on the blockchain
-
+
+
+ Crypto Clash
+ Welcome! Choose a page below:
- {/* Status Section */}
-
-
- Connected Account:{" "}
- {account ? `${account.slice(0, 6)}...${account.slice(-4)}` : "Not connected"}
-
-
- Contract Address:{" "}
- {config?.CONTRACT_ADDRESS}
-
-
-
- {/* Current Message Display */}
-
-
- Current Message:
-
- {loading && !message ? (
-
Loading...
- ) : message ? (
-
- {message}
-
- ) : (
-
- No message yet
-
- )}
-
-
- {/* Refresh Button */}
-
-
- {/* Update Message Form */}
-
-
- Update Message:
-
- setNewMessage(e.target.value)}
- placeholder="Enter new message..."
- className="w-full px-4 py-3 border border-slate-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-700 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500"
- />
-
-
-
- {/* Error/Status Messages */}
- {error && (
-
- )}
-
- {/* Info Section */}
-
-
ℹ️ Note:
-
- - To update messages, you need MetaMask or a compatible Web3 wallet
- - Make sure your MetaMask is connected to the correct test network
- - Reading messages is free and doesn't require a wallet
- - Updates are written to the blockchain and may take time to confirm
-
-
-
+
+ -
+
+ Crypto Clash - Battle with others
+
+
+ -
+
+ Hello World - A simple introduction
+
+
+
);
diff --git a/crypto_clash_frontend/public/config.json b/crypto_clash_frontend/public/config.json
index c598b44..0356444 100644
--- a/crypto_clash_frontend/public/config.json
+++ b/crypto_clash_frontend/public/config.json
@@ -1,6 +1,6 @@
{
- "API_URL": "https://rpc.hasrv.averel10.app",
- "CONTRACT_ADDRESS": "0x62A3a88E7D5021AD960426206BD05Ef09eee02a0",
+ "API_URL": "https://rpc.hasrv.averel10.app/",
+ "CONTRACT_ADDRESS": "0xC3D2A1471A5e19ce586D4D3cB398Ce560efAF6Ca",
"ABI": [
{
"inputs": [
diff --git a/crypto_clash_frontend/types.ts b/crypto_clash_frontend/types.ts
new file mode 100644
index 0000000..82d6898
--- /dev/null
+++ b/crypto_clash_frontend/types.ts
@@ -0,0 +1,7 @@
+interface Config {
+ API_URL: string;
+ CONTRACT_ADDRESS: string;
+ ABI: any[];
+ GAME_CONTRACT_ADDRESS: string;
+ GAME_ABI: any[];
+}
\ No newline at end of file