aelf 백서

bitpro가 원문에서 글자만 모은 내용이에요. 표·그림·수식은 빠지거나 깨질 수 있어요. 전체 41쪽 중 21쪽

not initialized." } ; } ResetBoard ( ) ; State . CurrentPlayer . Value = "X" ; State . GameStatus . Value = "ongoing" ; State . Winner . Value = "" ; return new StringValue { Value = "Game started. Player X's turn." } ; } public override StringValue MakeMove ( MoveInput input ) { if ( State . GameStatus . Value != "ongoing" ) { return new StringValue { Value = "Game is not ongoing." } ; } var board = GetBoardArray ( ) ; if ( board [ input . X , input . Y ] != "" ) { return new StringValue { Value = "Invalid move. Cell is already occupied." } ; } board [ input . X , input . Y ] = State . CurrentPlayer . Value ; SaveBoard ( board ) ; if ( CheckWinner ( ) ) { State . GameStatus . Value = "finished" ; State . Winner . Value = State . CurrentPlayer . Value ; return new StringValue { Value = $"Player { State . CurrentPlayer . Value } wins!" } ; } if ( IsBoardFull ( board ) ) { State . GameStatus . Value = "draw" ; return new StringValue { Value = "It's a draw!" } ; } State . CurrentPlayer . Value = State . CurrentPlayer . Value == "X" ? "O" : "X" ; return new StringValue { Value = $"Player { State . CurrentPlayer . Value } 's turn." } ; } public override Board GetBoard ( Empty input ) { var board = GetBoardArray ( ) ; var boardMessage = new Board ( ) ; for ( var i = 0 ; i < 3 ; i ++ ) // Adjusted to 3 for a 3x3 Tic-Tac-Toe board { var row = new List < string > ( ) ; for ( var j = 0 ; j < 3 ; j ++ ) { row . Add ( board [ i , j ] ) ; } boardMessage . Rows . Add ( string . Join ( "," , row ) ) ; } return boardMessage ; } public override GameStatus GetGameStatus ( Empty input ) { return new GameStatus { Status = State . GameStatus . Value , Winner = State . Winner . Value } ; } public override BoolValue GetInitialStatus ( Empty input ) { return new BoolValue { Value = State . Initialized . Value } ; } private void ResetBoard ( ) { var emptyBoard = new string [ BoardSize , BoardSize ] ; for ( var i = 0 ; i < BoardSize ; i ++ ) { for ( var j = 0 ; j < BoardSize ; j ++ ) { emptyBoard [ i , j ] = "" ; } } SaveBoard ( emptyBoard ) ; } private string [ , ] GetBoardArray ( ) { var boardString = State . Board . Value ; var rows = boardString . Split ( ';' ) ; var board = new string [ BoardSize , BoardSize ] ; for ( var i = 0 ; i < BoardSize ; i ++ ) { var cells = rows [ i ] . Split ( ',' ) ; for ( var j = 0 ; j < BoardSize ; j ++ ) { board [ i , j ] = cells [ j ] ; } } return board ; } private void SaveBoard ( string [ , ] board ) { var rows = new string [ BoardSize ] ; for ( var i = 0 ; i < BoardSize ; i ++ ) { rows [ i ] = string . Join ( "," , board [ i , 0 ] , board [ i , 1 ] , board [ i , 2 ] ) ; } State . Board . Value = string . Join ( ";" , rows ) ; } private bool CheckWinner ( ) { var board = GetBoardArray ( ) ; var player = State . CurrentPlayer . Value ; for ( var i = 0 ; i < BoardSize ; i ++ ) { if ( board [ i , 0 ] == player && board [ i , 1 ] == player && board [ i , 2 ] == player ) return true ; if ( board [ 0 , i ] == player && board [ 1 , i ] == player && board [ 2 , i ] == player ) return true ; } if ( board [ 0 , 0 ] == player && board [ 1 , 1 ] == player && board [ 2 , 2 ] == player ) return true ; if ( board [ 0 , 2 ] == player && board [ 1 , 1 ] == player && board [ 2 , 0 ] == player ) return true ; return false ; } private bool IsBoardFull ( string [ , ] board ) { for ( var i = 0 ; i < BoardSize ; i ++ ) { for ( var j = 0 ; j < BoardSize ; j ++ ) { if ( board [ i , j ] == "" ) return false ; } } return true ; } } } Building Smart Contract ​ Build the smart contract code with the following command inside src folder: Terminal dotnet build You should see TicTacToe.dll.patched in the directory 1-smart-contract/src/bin/Debug/net.6.0 Step 3 - Deploy Smart Contract ​ Create A Wallet ​ To send transactions on the aelf blockchain, you must have a wallet. Run this command to create aelf wallet. Terminal aelf-command create You will be prompted to save your account, please do save your account as shown below: Terminal ? Save account info into a file? ( Y/n ) Y Make sure to choose Y to save your account information. tip ℹ️ Note: If you do not save your account information (by selecting n or N), do not export the wallet password. Only proceed to the next step if you have saved your account information. Next, enter and confirm your password. Then export your wallet password as shown below: Linux and macOs Windows Terminal export WALLET_PASSWORD = "YOUR_WALLET_PASSWORD" Command Prompt $env :WALLET_PASSWORD = "YOUR_WALLET_PASSWORD" Acquire Testnet Tokens (Faucet) for Development ​ To deploy smart contracts or execute on-chain transactions on aelf, you'll require testnet ELF tokens. Get ELF Tokens Go to https://faucet-ui.aelf.dev Enter your address and click Get Tokens . Deploy Smart Contract: The smart contract needs to be deployed on the chain before users can interact with it. Run the following command to deploy a contract. Remember to export the path of TicTacToe.dll.patched to CONTRACT_PATH. Linux and macOs Windows Terminal export CONTRACT_PATH = $( find ~+ . -path "*patched*" | head -n 1 ) Terminal aelf-deploy -a $WALLET_ADDRESS -p $WALLET_PASSWORD -c $CONTRACT_PATH -e https://tdvw-test-node.aelf.io/ Command Prompt $CONTRACT_PATH = Get-ChildItem -Recurse -Filter "*patched*" | Select-Object -First 1 -ExpandProperty FullName $env :CONTRACT_PATH = $CONTRACT_PATH Command Prompt aelf-deploy -a $env :WALLET_ADDRESS -p $env :WALLET_PASSWORD -c $env :CONTRACT_PATH -e https://tdvw-test-node.aelf.io/ Please wait for approximately 1 to 2 minutes. If the deployment is successful, it will provide you with the contract address. Copy the smart contract address from the address field Export your smart contract address: Linux and macOs Windows Terminal export CONTRACT_ADDRESS = "YOUR_SMART_CONTRACT_ADDRESS e.g. 2LUmicHyH4RXrMjG4beDwuDsiWJESyLkgkwPdGTR8kahRzq5XS" Command Prompt $env :CONTRACT_ADDRESS = "YOUR_SMART_CONTRACT_ADDRESS e.g. 2LUmicHyH4RXrMjG4beDwuDsiWJESyLkgkwPdGTR8kahRzq5XS" tip ℹ️ Note: You are to copy the smart contract address as we will be referencing it in the next steps! info 🎉 You have successfully deployed your Tic-Tac-Toe dApp smart contract on the aelf testnet! In the next steps, we will be building the frontend components that allow us to interact with our deployed smart contract! Step 4 - Interact with Your Deployed Smart Contract through dApp ​ Project Setup ​ Let's start by cloning the frontend project repository from github. Terminal git clone https://github.com/AElfProject/aelf-samples.git Next, navigate to the frontend project directory with this command: Terminal cd aelf-samples/tic-tac-toe/2-dapp Once you're inside the 2-dapp directory, open the project with your preferred IDE (e.g., VSCode). You should see the project structure as shown below. Install necessary libraries ​ Run this command in the terminal to install all necessary packages and libraries: Terminal npm install We are now ready to build the frontend components of our Tic-Tac-Toe dApp. Configure Portkey Provider & Write Connect Wallet Function ​ Now, we'll set up our Portkey wallet provider to allow users to connect their Portkey wallets to the dApp and interact with the smart contract. We'll be interacting with the already deployed Tic-Tac-Toe smart contract for this tutorial. Step 1. Locate the File: Go to the src/hooks/useSmartContract.ts file. Step 2. Fetch the Smart Contract: Find the comment //Step A - Function to fetch a smart contract based on deployed wallet address Replace the existing fetchContract function with this updated code: useSmartContract.ts //Step A - Function to fetch a smart contract based on deployed wallet address const fetchContract = async ( ) => { if ( ! provider ) return null ; try { // 1. get the dAppChain tDVW using provider.getChain const chain = await provider ?. getChain ( "tDVW" ) ; if ( ! chain ) throw new Error ( "No chain" ) ; //Address of TicTacToe Smart Contract //Replace with Address of Deployed Smart Contract const address = "your_deployed_tic_tac_toe_contract_address" ; // 2. get the TicTacToe contract const contract = chain ?. getContract ( address ) ; setSmartContract ( contract ) ; } catch ( error ) { console . log ( error , "====error" ) ; } } tip ℹ️ Note: You are to replace the address placeholder with your deployed Tic Tac Toe smart contract address from "Deploy Smart Contract" step! example: Replace with Address of Deployed Smart Contract const address = "your_deployed_tic_tac_toe_contract_address"; Explanation: fetchContract Function : This function fetches a smart contract based on the given chain symbol (e.g., "AELF" or "tDVW") and the contract address. Check Provider : If no provider is available, the function returns null. Fetch Chain : The function fetches chain information using the provider. Get Contract : It retrieves the smart contract instance from the chain. AELF represents the mainnet chain and tDVW represents the testnet chain respectively on the aelf blockchain. Step 3. Initialize and Fetch the Smart Contracts: Find the comment // Step B - Effect hook to initialize and fetch the smart contract when the provider changes. Replace the existing useEffect hook with this updated code: useSmartContract.ts // Step B - Effect hook to initialize and fetch the smart contract when the provider changes useEffect ( ( ) => { fetchContract ( ) ; } , [ provider ] ) ; // Dependency array ensures this runs when the provider changes Explanation: useEffect Hook : This hook initializes and fetches the smart contracts when the provider changes. Check Provider : If no provider is available, the function returns null. Fetch Contracts : It fetches and sets the smart contracts. By following these steps, we'll configure the Portkey provider to connect users' wallets to our app and interact with the Tic-Tac-Toe smart contract including Tic-Tac-Toe Game Play related functionalities. This setup will enable our frontend components to perform actions like initializeContract , startGame , makeMove , getGameStatus and getLatestBoard etc. Configure Connect Wallet Function ​ Step 1: Locate the File Go to the src/components/layout/header/index.tsx file. Step 2: Write the Connect Wallet Function The header/index.tsx file is the header of our Tic-Tac-Toe dApp. It allows users to connect their Portkey wallet with the Tic-Tac-Toe dApp. Before users can interact with the smart contract, we need to write the Connect Wallet function. Find the comment // Step C - Connect Portkey Wallet . Replace the existing connect function with this code snippet: header/index.tsx const connect = async ( walletProvider ? : IPortkeyProvider ) => { // Step C - Connect Portkey Wallet const accounts = await ( walletProvider ? walletProvider : provider ) ?. request ( { method : MethodsBase . REQUEST_ACCOUNTS , } ) ; const account = accounts ?. AELF && accounts ?. AELF [ 0 ] ; if ( account ) { setCurrentWalletAddress ( account . replace ( / ^ ELF_ / , "" ) . replace ( / _AELF $ / , "" ) ) ; setIsConnected ( true ) ; } ! walletProvider && toast . success ( "Successfully connected" ) ; } ; Explanation: connect Function : This function connects the user's Portkey wallet with the dApp. Fetch Accounts : It fetches the wallet accounts using the provider. Log Accounts : Logs the accounts to the console for debugging. Set Wallet Address : Sets the current wallet address state variable with the fetched account. In this code, we fetch the Portkey wallet account using the provider and update the wallet address state variable. An alert notifies the user that their wallet is successfully connected. With the connect wallet function defined, we're ready to write the remaining functions in the next steps. Check Contract Initialization ​ Step 1: Locate the File Go to the src/pages/home/index.tsx file. This file contains all the functionalities like show initializeContract , startGame , makeMove , getGameStatus and getLatestBoard etc. Step 2: Prepare a Function to Check Whether the Contract is Initialized or not Scroll down to find the comment // step 1 - Check If Contract is Initialized or not . Replace the existing checkIsContractInitialized function with this code snippet: home/index.tsx // step 1 - Check If Contract is Initialized or not const checkIsContractInitialized = async ( ) => { const result = await smartContract ?. callViewMethod ( "GetInitialStatus" , "" ) ; // Call the GetInitialStatus method which is present on Smart Contract setIsContractInitialized ( result ?. data ?. value ) ; // Expect value True if it's Initialized otherwise NULL if it's not } ; Initialize Contract ​ Scroll down to find the comment // step 2 - Initialize the smart contract . Replace the existing checkIsContractInitialized function with this code snippet: home/index.tsx // step 2 - Initialize the smart contract const initializeContract = async ( ) => { let initializeLoadingId ; try { // Start Loading initializeLoadingId = toast . loading ( "Initializing a Contract.." ) ; await smartContract ?. callSendMethod ( "Initialize" , // Function Name currentWalletAddress as string , // User Wallet Address { } // No Arguments ) ; // Update Loading Message with Success toast . update ( initializeLoadingId , { render : "Contract Successfully Initialized" , type : "success" , isLoading : false , } ) ; return ; } catch ( error : any ) { // Update Loading Message with Error toast . update ( initializeLoadingId as Id , { render : error . message , type : "error" , isLoading : false , } ) ; return ; } finally { // Remove Loading Message removeNotification ( initializeLoadingId as Id ) ; } } ; Fetch Game Status ​ Write the function to fetch the game status. Find the comment // step 3 - Fetch Game Status function on same file. Replace the existing getGameStatus function with this code snippet: home/index.tsx // step 3 - Fetch Game Status function const getGameStatus = async ( isFirstCheck ? : boolean ) => { try { const result = await smartContract ?. callViewMethod ( "GetGameStatus" , "" ) ; console . log ( "result" , result ) ; if ( result ?. data . status === "finished" ) { if ( ! isFirstCheck ) { toast . success ( ` ${ result . data . winner } is Winner 🥳 🏆 ` ) ; setWinner ( result . data . winner ) ; } } else { setIsStarted ( true ) ; getLatestBoard ( ) ; } } catch ( error : any ) { toast . error ( error . message ) ; } finally { setLoading ( false ) ; return ; } } ; What This Function Does: ​ Calls Smart Contract Method : It interacts with the blockchain smart contract to fetch the game status using getGameStatus Function. Next, we'll write the Fetch Board Data function. Fetch Board Data ​ Write the function to fetch the board data. Scroll down to find the comment // step 4 - Fetch Latest Board Data from the Contract . Replace the existing getLatestBoard function with this code snippet: home/index.tsx // step 4 - Fetch Latest Board Data from the Contract const getLatestBoard = async ( ) => { try { const result = await smartContract ?. callViewMethod ( "GetBoard" , "" ) ; const arrayData = result ?. data . rows . map ( ( rowData : any ) => rowData . split ( "," ) . map ( ( item : string ) => ( item === "" ? null : item ) ) ) . flat ( ) ; getNextTurn ( arrayData ) ; setBoard ( arrayData ) ; } catch ( error : any ) { toast . error ( error . message ) ; } finally { return ; } } ; What This Function Does: ​ Calls Smart Contract Method : It interacts with the blockchain smart contract to fetch the latest board data using getLatestBoard Function. Convert Respnose Data into Array : It converts object of the response data to an array to adjust every move into the UI board. Next, we'll write the Start Game function. Start Game ​ Write the Function to start the Tic-Tac-Toe game. Scroll down to find the comment // step 5 - Start Game function . Replace the existing startGame function with the following code snippet: home/index.tsx // step 5 - Start Game function const startGame = async ( ) => { try { if ( ! currentWalletAddress ) { toast . info ( "Please Login First" ) ; return ; } if ( ! isContractInitialized ) { await initializeContract ( ) ; } await smartContract ?. callSendMethod ( "StartGame" , currentWalletAddress ) ; setTurnType ( "X" ) ; setIsStarted ( true ) ; getLatestBoard ( ) ; toast . success ( "Game Has been Started ✅" ) ; } catch ( error : any ) { toast . error ( error . message ) ; } } ; What This Function Does: ​ Calls Smart Contract Method : It interacts with the blockchain smart contract to start the game by using the startGame Function. Next, we'll write the Make the Move function. Perform the Move ​ Write a function to make the move. Scroll down to find the comment // step 6 - Make the Move Function . Replace the existing makeMove function with this code snippet: home/index.tsx // step 6 - Make the Move Function const makeMove = async ( x : number , y : number ) => { try { if ( ! currentWalletAddress ) { toast . info ( "Please Login First" ) ; return ; } const moveIndex = getIndexFromPosition ( x , y ) ; setMoveLoadingIndex ( moveIndex as number ) ; const params = { x : x , y : y , } ; await smartContract ?. callSendMethod ( "MakeMove" , currentWalletAddress , params ) ; // toast.success("Your Move Submitted"); changeTurn ( ) ; await getLatestBoard ( ) ; await getGameStatus ( ) ; } catch ( error : any ) { toast . error ( error . message ) ; } finally { } } ; What This Function Does: ​ Calls Smart Contract Method : It interacts with the blockchain smart contract to make the move by an input from a player using makeMove function by passing X and Y value of the Board. Now that we've written all the necessary frontend functions and components for play the Tic-Tac-Toe page, we're ready to run the Tic-Tac-Toe dApp application in the next step. Run Application ​ In this step, we will run the Tic-Tac-Toe dApp application. To begin, run the following command on your terminal. Terminal npm run dev info Note : Ensure that you are running this command under the tic-tac-toe/2-dapp folder. You should observe the following as shown below. Upon clicking on the localhost URL , you should be directed to the Tic-Tac-Toe dApp landing page as shown below. tip If you are developing and testing this with github codespace, you can use port forward to test the web server that is running in codespace, here is the link on how to use port forward for codespace https://docs.github.com/en/codespaces/developing-in-a-codespace/forwarding-ports-in-your-codespace Usually codespaces automatically forward ports, you should see a pop-up message at the bottom right of your codespace browser window as shown in the diagram below: Click the link to open the Tic-Tac-Toe dApp in the browser. Create Portkey Wallet ​ info Portkey is the first AA wallet from aelf's ecosystem, migrating users, developers and projects from Web2 to Web3 with DID solution. Users can swiftly log into Portkey via their Web2 social info with no private keys o
프로젝트로 돌아가기