aelf 백서

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

nerating unique IDs } } The State.cs file in an aelf blockchain smart contract holds the variables that store the contract's data, making sure this data is saved and accessible whenever the contract needs it. Implement ToDo Smart Contract ​ The implementation of the ToDo App smart contract inside file src/ToDoApp.cs is as follows: src/ToDoApp.cs using Google . Protobuf . WellKnownTypes ; using System . Collections . Generic ; namespace AElf . Contracts . ToDo { public class ToDo : ToDoContainer . ToDoBase { public override Empty Initialize ( Empty input ) { if ( State . Initialized . Value ) { return new Empty ( ) ; } State . Initialized . Value = true ; State . Owner . Value = Context . Sender ; State . TaskIds . Value = "" ; State . TaskCounter . Value = 0 ; return new Empty ( ) ; } public override StringValue CreateTask ( TaskInput input ) { if ( ! State . Initialized . Value ) { return new StringValue { Value = "Contract not initialized." } ; } var taskId = ( State . TaskCounter . Value + 1 ) . ToString ( ) ; State . TaskCounter . Value ++ ; var timestamp = Context . CurrentBlockTime . Seconds ; // Create task dictionary entry directly in ToDo class State . Tasks [ taskId ] = new Task { TaskId = taskId , Name = input . Name , Description = input . Description , Category = input . Category , Status = "pending" , CreatedAt = timestamp , UpdatedAt = timestamp , Owner = Context . Sender . ToString ( ) . Trim ( '"' ) , } ; State . TaskExistence [ taskId ] = true ; // Append task ID to the list of IDs var existingTaskIds = State . TaskIds . Value ; existingTaskIds += string . IsNullOrEmpty ( existingTaskIds ) ? taskId : $", { taskId } " ; State . TaskIds . Value = existingTaskIds ; return new StringValue { Value = taskId } ; } public override Empty UpdateTask ( TaskUpdateInput input ) { var task = State . Tasks [ input . TaskId ] ; if ( task == null ) { return new Empty ( ) ; // Handle case if task doesn't exist } task . Name = input . Name ?? task . Name ; task . Description = input . Description ?? task . Description ; task . Category = input . Category ?? task . Category ; task . Status = input . Status ?? task . Status ; task . UpdatedAt = Context . CurrentBlockTime . Seconds ; State . Tasks [ input . TaskId ] = task ; return new Empty ( ) ; } public override Empty DeleteTask ( StringValue input ) { State . Tasks . Remove ( input . Value ) ; State . TaskExistence . Remove ( input . Value ) ; // Remove task ID from the list of IDs var existingTaskIds = State . TaskIds . Value . Split ( ',' ) ; var newTaskIds = new List < string > ( existingTaskIds . Length ) ; foreach ( var taskId in existingTaskIds ) { if ( taskId != input . Value ) { newTaskIds . Add ( taskId ) ; } } State . TaskIds . Value = string . Join ( "," , newTaskIds ) ; return new Empty ( ) ; } public override TaskList ListTasks ( StringValue input ) { var owner = input . Value ; // Get the owner value from the input var taskList = new TaskList ( ) ; var taskIds = State . TaskIds . Value . Split ( ',' ) ; foreach ( var taskId in taskIds ) { var task = State . Tasks [ taskId ] ; if ( task != null && task . Owner == owner ) // Filter tasks by owner { taskList . Tasks . Add ( task ) ; } } return taskList ; } public override Task GetTask ( StringValue input ) { var task = State . Tasks [ input . Value ] ; if ( task == null ) { return new Task { TaskId = input . Value , Name = "Task not found." } ; } return task ; } public override BoolValue GetInitialStatus ( Empty input ) { return new BoolValue { Value = State . Initialized . Value } ; } } } Building Smart Contract ​ Build the smart contract code with the following command inside src folder: Terminal dotnet build You should see ToDoApp.dll.patched in the directory ToDoApp/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 ToDoApp.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 ToDo 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/todo/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 ToDo 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 ToDo smart contract for this tutorial. Step 1. Locate the File: Go to the src/hooks/useTodoSmartContract.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: useTodoSmartContract.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 ToDo Smart Contract //Replace with Address of Deployed Smart Contract const address = "your_deployed_todo_contract_address" ; // 2. get the ToDo contract const todoContract = chain ?. getContract ( address ) ; setSmartContract ( todoContract ) ; } catch ( error ) { console . log ( error , "====error" ) ; } } tip ℹ️ Note: You are to replace the address placeholder with your deployed ToDo smart contract address from "Deploy Smart Contract" step! example: //Replace with Address of Deployed Smart Contract const address = "your_deployed_todo__smart_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 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: useTodoSmartContract.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 ToDo smart contract including task management related functionalities. This setup will enable our frontend components to perform actions like Create Task , Edit Task , and Delete Task . 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 ToDo dApp. It allows users to connect their Portkey wallet with the ToDo 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. Update Connection Status : Updates the state to indicate that the wallet is connected. User Notification : Displays an alert to notify the user that their wallet is successfully connected. 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. Configure Create Task Form ​ Step 1: Locate the File Go to the src/pages/home/index.tsx file. This file contains all the functionalities like show user's Task, CreateTask, UpdateTask, DeleteTask and Filter all Tasks, etc. Step 2: Prepare Form to Create and Update Tasks Find the comment // Step D - Configure Todo Form . Replace the form variable with this code snippet: home/index.tsx // Step D - Configure Todo Form const form = useForm < z . infer < typeof formSchema >> ( { resolver : zodResolver ( formSchema ) , defaultValues : { name : "" , description : "" , } , } ) ; Here's what the function does: ​ Initializes a new form variable with default values needed to create a task. Fields include: name and description . Now the form is ready for users to fill in the necessary details. Check Contract Initialization ​ 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 initializeContract 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 , } ) ; } catch ( error : any ) { // Update Loading Message with Error toast . update ( initializeLoadingId as Id , { render : error . message , type : "error" , isLoading : false , } ) ; } finally { // Remove Loading Message removeNotification ( initializeLoadingId as Id ) ; } } ; Create a New Task ​ Write the function to Create a New Task ** The home/index.tsx file includes the code to create tasks. It allows users to create new tasks. Find the comment // step 3 - Create a New Task using Smart Contract . Replace the existing createNewTask function with this code snippet: home/index.tsx // step 3 - Create a New Task using Smart Contract const createNewTask = async ( values : { name : string ; description : string ; } ) => { let createLoadingId ; try { // Start Loading createLoadingId = toast . loading ( "Creating a New Task.." ) ; setFormLoading ( true ) ; // Prepare Arguments for Create a New Task const sendData = { name : values . name , description : values . description , category : selectedCategory ?. value , status : TASK_STATUS . pending , } ; // Call CreateTask Function of Smart Contract await smartContract ?. callSendMethod ( "CreateTask" , currentWalletAddress as string , sendData ) ; // Update Loading Message with Success toast . update ( createLoadingId , { render : "New Task Successfully Created" , type : "success" , isLoading : false , } ) ; // Get New Data from Contract getTodoData ( ) ; } catch ( error : any ) { // Update Loading Message with Error toast . update ( createLoadingId as Id , { render : error . message , type : "error" , isLoading : false , } ) ; } finally { // Close Form Modal handleCloseModal ( ) ; // Remove Loading Message removeNotification ( createLoadingId as Id ) ; setFormLoading ( false ) ; } } ; What This Function Does: ​ Creates an Object with Task Details : It prepares the data needed to create a new task. Calls Smart Contract Method : It interacts with the blockchain smart contract to create the new task using the prepared data. Next, we'll write the Update an Existing Task function. Update an Existing Task ​ Write the function for update an existing task. Scroll down to find the comment // step 4 - Update an Existing Task . Replace the existing updateTask function with this code snippet: home/index.tsx // step 4 - Update an Existing Task const updateTask = async ( values : { name : string ; description : string } ) => { let updateLoadingId ; try { // Start Loading updateLoadingId = toast . loading ( "Updating a Task.." ) ; setFormLoading ( true ) ; // Prepare Arguments for Update the Task const sendData = { taskId : updateId , name : values . name , description : values . description , category : selectedCategory ?. value , status : TASK_STATUS . pending , } ; // Call UpdateTask Function of Smart Contract await smartContract ?. callSendMethod ( "UpdateTask" , currentWalletAddress as string , sendData ) ; // Update Loading Message with Success toast . update ( updateLoadingId , { render : "Task Successfully Updated" , type : "success" , isLoading : false , } ) ; // Get New Data from Contract getTodoData ( ) ; } catch ( error : any ) { // Update Loading Message with Error toast . update ( updateLoadingId as Id , { render : error . message , type : "error" , isLoading : false , } ) ; } finally { // Close Form Modal handleCloseModal ( ) ; // Remove Loading Message removeNotification ( updateLoadingId as Id ) ; setFormLoading ( false ) ; } } ; What This Function Does: ​ Creates an Object with Updated Task Details : It prepares the data needed for the updated task details Calls Smart Contract Method : It interacts with the blockchain smart contract to update the existing task using the prepared data. Next, we'll write the Update Task Status (completeTask) function. Update the Task Status ​ Write the Function to update the task status (completeTask). Scroll down to find the comment // step 5- Update Status from Pending to Completed of the Task . Replace the existing completeTask function with the following code snippet: home/index.tsx // step 5- Update Status from Pending to Completed of the Task const completeTask = async ( data : ITodoObject ) => { let completeLoadingId ; try { // Start Loading completeLoadingId = toast . loading ( "Moving to Completed Task.." ) ; setUpdateId ( data . taskId ) ; // set Update Id for Loading on Button // Call UpdateTask Function of Smart Contract await smartContract ?. callSendMethod ( "UpdateTask" , currentWalletAddress as string , { ... data , status : TASK_STATUS . completed } ) ; // Update Loading Message with Success toast . update ( completeLoadingId , { render : "Task Moved to Completed" , type : "success" , isLoading : false , } ) ; // Get New Data from Contract await getTodoData ( ) ; } catch ( error : any ) { // Update Loading Message with Error toast . update ( completeLoadingId as Id , { render : error . message , type : "error" , isLoading : false , } ) ; } finally { setUpdateId ( null ) ; // Remove Loading Message removeNotification ( completeLoadingId as Id ) ; } } ; What This Function Does: ​ Ca
프로젝트로 돌아가기