aelf 백서

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

net Contract and sets it in the state. By following these steps, we'll configure the Portkey provider to connect users' wallets to your app and interact with the multi-token smart contract including NFT related functionalities. This setup will enable our frontend components to perform actions like create NFTs , validate NFTs , and transfer NFTs . 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 NFT dApp. It allows users to connect their Portkey wallet with the NFT 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 NFT Form Code ​ Step 1: Locate the File Go to the src/pages/create-nft/index.tsx file. This file is the Create NFTs page where users can enter details like the tokenName , symbol , totalSupply and decimals . Step 2: Prepare Form to Create NFTs Find the comment // Step D - Configure NFT Form . Replace the form variable with this code snippet: create-nft/index.tsx // Step D - Configure NFT Form const form = useForm < z . infer < typeof formSchema >> ( { resolver : zodResolver ( formSchema ) , defaultValues : { tokenName : "" , symbol : "" , totalSupply : "" , decimals : "" , } , } ) ; Here's what the function does: ​ Initializes a new form variable with default values needed to create a nft. Fields include: tokenName , symbol , totalSupply , and decimals . Now the form is ready for users to fill in the necessary details for their NFT function interaction. Create NFT Collection ​ Let's write the functions to Create New NFT Collection on the aelf mainchain and the dAppChain. Step 1: Write the function to Create New NFT Collection on the MainChain The create-nft/index.tsx file includes the code to create NFTs. It allows users to create new NFTs. Find the comment // step 1 - Create New NFT Collection on the mainchain . Replace the existing createNftCollectionOnMainChain function with this code snippet: create-nft/index.tsx // step - 1 Create New NFT Collection on the mainchain const createNftCollectionOnMainChain = async ( values : { tokenName : string ; symbol : string ; totalSupply : string ; decimals : string ; } ) => { let createLoadingId ; try { createLoadingId = toast . loading ( "Creating NFT Collection.." ) ; // Create an object with the necessary information for the new NFT collection. const createNtfInput : INftInput = { tokenName : values . tokenName , // Name of the nft Collection symbol : values . symbol , // Symbol of the token (You have to get it from your PortKey wallet on NFT seed from NFT section) totalSupply : values . totalSupply , // Total supply of the token decimals : values . decimals , // Decimals of the token issuer : currentWalletAddress , // Address of the token issuer isBurnable : true , // Indicates if the token can be burned issueChainId : sidechain_from_chain_id , // ID of the issuing chain owner : currentWalletAddress , // Owner's wallet address } ; // Call the smart contract method to create the new NFT collection on the main chain. const result = await mainChainSmartContract ?. callSendMethod ( "Create" , currentWalletAddress , createNtfInput ) ; // Log the result of the creation for debugging purposes. console . log ( "========= result of createNewNft =========" , result ) ; toast . update ( createLoadingId , { render : "NFT Collection Created Successfully On MainChain" , type : "success" , isLoading : false , } ) ; removeNotification ( createLoadingId ) ; // Return the input data for further use. return createNtfInput ; } catch ( error : any ) { // If there's an error, log it and alert the user. console . error ( error . message , "=====error" ) ; toast . update ( createLoadingId , { render : error . message , type : "error" , isLoading : false , } ) ; removeNotification ( createLoadingId ) ; return "error" ; } } ; tip ℹ️ Note: You need to get symbol from the Portkey wallet. Follow Steps to get NFT symbol from Portkey Wallet: Open Portkey Wallet. Go to the NFTs tab. You will find the SEED that you already got from the above seed generation step. Click on the SEED to see details. You will find the Token Symbol inside the Token Creation via This Seed section. Copy and use that value of the token symbol. What This Function Does: ​ Creates an Object with NFT Details : It prepares the data needed to create a new NFT collection. Calls Smart Contract Method : It interacts with the blockchain smart contract to create the new NFT collection using the prepared data. Logs Information : It logs the result for debugging purposes. Return Values of Object : It returns necessary values as a object. Next, we'll write the Validate Collection Info Exist function. Step 2: Write the validates collection info exist function Scroll up to find the comment // step 2 - Validate Collection information exist . Replace the existing validateNftCollectionInfo function with this code snippet: create-nft/index.tsx // step 2 - Validate Collection information exist // This function validates if the token collection information already exists on the main blockchain. const validateNftCollectionInfo = async ( values : INftInput ) => { let validateLoadingId try { // Start Loading before initiate the transaction validateLoadingId = toast . loading ( < CustomToast title = "Transaction is getting validated on aelf blockchain. Please wait!" message = "Validation means transaction runs through a consensus algorithm to be selected or rejected. Once the status changes process will complete. It usually takes some time in distributed systems." / > ) ; // Create an object with the necessary information for token validation. const validateInput = { symbol : values . symbol , // Symbol of the token tokenName : values . tokenName , // Name of the token totalSupply : values . totalSupply , // Total supply of the token decimals : values . decimals , // Decimals of the token issuer : currentWalletAddress , // Address of the token issuer isBurnable : true , // Indicates if the token can be burned issueChainId : sidechain_from_chain_id , // ID of the issuing chain owner : currentWalletAddress , // Owner's wallet address } ; // get mainnet contract const aelfTokenContract = await getTokenContract ( aelf , wallet ) ; // prepare Sign the transaction using contract method (ValidateTokenInfoExists Function) const signedTx = aelfTokenContract . ValidateTokenInfoExists . getSignedTx ( validateInput ) ; // send the transaction using signed Transaction const { TransactionId : VALIDATE_TXID } = await aelf . chain . sendTransaction ( signedTx ) ; // get Validate Result let VALIDATE_TXRESULT = await aelf . chain . getTxResult ( VALIDATE_TXID ) ; // we need to wait till our latest index Hight grater than or equal to our Transaction block number let heightDone = false ; while ( ! heightDone ) { // get latest index Hight const sideIndexMainHeight = await GetParentChainHeight ( ) ; if ( // check the latest index Hight is grater than or equal sideIndexMainHeight >= VALIDATE_TXRESULT . Transaction . RefBlockNumber ) { VALIDATE_TXRESULT = await aelf . chain . getTxResult ( VALIDATE_TXID ) ; heightDone = true ; } } console . log ( "VALIDATE_TXRESULT" , VALIDATE_TXRESULT ) ; // Update the Loading Message toast . update ( validateLoadingId , { render : "Validating Token Successfully Executed" , type : "success" , isLoading : false , } ) ; // Remove the Loading Message removeNotification ( validateLoadingId ) ; // Return necessary details. return { transactionId : VALIDATE_TXID , signedTx : signedTx , BlockNumber : VALIDATE_TXRESULT . BlockNumber , } ; } catch ( error : any ) { // If there's an error, log it and alert the user. console . error ( error . message , "=====error in validateTokenInfoExist" ) ; toast . update ( validateLoadingId , { render : error . message , type : "error" , isLoading : false , } ) ; removeNotification ( validateLoadingId ) ; return "error" ; } } ; What This Function Does: ​ Creates an Object with Validate Collection Details : It prepares the data needed to validate the token information. Calls Smart Contract Method : It interacts with the multi-token smart contract method to check if the token information already exists using the prepared data. Return Values : It returns necessary values as an object. Next, we'll write the Get the parent chain height function. Step 3: Write the get the parent chain height function Scroll up to find the comment // Step 3: Get the parent chain height . Replace the existing GetParentChainHeight function with the following code snippet: create-nft/index.tsx // Step 3: Get the parent chain height // This function fetches the current height of the parent blockchain. const GetParentChainHeight = async ( ) => { try { const tdvwCrossChainContract = await getCrossChainContract ( tdvw , wallet ) ; // Call the smart contract method to get the parent chain height. const result = await tdvwCrossChainContract . GetParentChainHeight . call ( ) // Return the parent chain height if it exists, otherwise return an empty string. return result ? ( result . value as string ) : "" ; } catch ( error : any ) { // If there's an error, log it and return an error status. console . error ( error , "=====error in GetParentChainHeight" ) ; return "error" ; } } ; What This Function Does: ​ Calls Smart Contract Method : It interacts with the side chain smart contract method to fetch the current height of the parent blockchain. Returns Parent Chain's Height : It returns the parent chain's height if it exists. Next, we'll write the Fetch the Merkle path function. Step 4: Write the fetch the merkle path function Scroll up to find the comment // step 4 - Fetch the merkle path by transaction Id . Replace the existing getMerklePathByTxId function with this code snippet: create-nft/index.tsx // step 4 - Fetch the merkle path by transaction Id const getMerklePathByTxId = async ( aelf : any , txId : string ) => { try { const { MerklePathNodes } = await aelf . chain . getMerklePathByTxId ( txId ) ; const formattedMerklePathNodes = MerklePathNodes . map ( ( { Hash , IsLeftChildNode , } : { Hash : string , IsLeftChildNode : boolean , } ) => ( { hash : Hash , isLeftChildNode : IsLeftChildNode , } ) ) ; return { merklePathNodes : formattedMerklePathNodes } ; } catch ( error ) { console . error ( "Error fetching Merkle path:" , error ) ; throw new Error ( "Failed to get Merkle path by transaction ID." ) ; } } ; What This Function Does: ​ Fetches Merkle Path : It sends a request to fetch the merkle path using the transaction ID. Parses Response : It parses the response from the server as JSON. Returns Merkle Path Nodes : It extracts and returns the merkle path of the nodes from the JSON response. Handles Errors : If an error occurs, it clears the transaction status and logs the error. Next, we'll write the Create a Collection on the cross-chain function. Step 5: Write a function to create a collection on the side chain Scroll up to find the comment // step 5 - Create a collection on the dAppChain . Replace the existing createCollectionOnSideChain function with this code snippet: create-nft/index.tsx // step 5 - Create a collection on the dAppChain const createCollectionOnSideChain = async ( transactionId : string , signedTx : string , BlockNumber : number ) => { let crossChainLoadingId ; try { crossChainLoadingId = toast . loading ( "Creating Collection on SideChain..." ) ; const merklePath = await getMerklePathByTxId ( aelf , transactionId ) ; const tdvwTokenContract = await getTokenContract ( tdvw , wallet ) ; const CROSS_CHAIN_CREATE_TOKEN_PARAMS = { fromChainId : mainchain_from_chain_id , parentChainHeight : "" + BlockNumber , // @ts-ignore transactionBytes : Buffer . from ( signedTx , "hex" ) . toString ( "base64" ) , merklePath , } ; const signedTx2 = await tdvwTokenContract . CrossChainCreateToken . getSignedTx ( CROSS_CHAIN_CREATE_TOKEN_PARAMS ) ; let done = false ; while ( ! done ) { try { await delay ( 10000 ) ; const { TransactionId } = await tdvw . chain . sendTransaction ( signedTx2 ) ; const txResult = await tdvw . chain . getTxResult ( TransactionId ) ; if ( txResult . Status === "SUCCESS" || txResult . Status === "MINED" ) { done = true ; setIsNftCollectionCreated ( true ) ; toast . update ( crossChainLoadingId , { render : "Collection was Created Successfully On SideChain" , type : "success" , isLoading : false , } ) ; removeNotification ( crossChainLoadingId ) ; toast . info ( "You Can Create NFT now" ) ; setTransactionStatus ( false ) ; } } catch ( err : any ) { console . log ( err ) ; if ( err . Error . includes ( "Cross chain verification failed." ) ) { console . log ( "Exit." ) ; done = true ; } } } return "success" ; } catch ( error : any ) { toast . update ( crossChainLoadingId , { render : error . message , type : "error" , isLoading : false , } ) ; removeNotification ( validateLoadingId ) ; return "error" ; } } ; What This Function Does: ​ Displays Loading Toast : Shows a notification indicating the creation process of the collection on the dAppChain. Fetches Merkle Path : Retrieves the merkle path using the provided transactionId. Prepares and Signs Transaction : Constructs parameters for the cross-chain transaction and signs it. Sends Transaction and Checks Status : Sends the signed transaction and polls for its status every 10 seconds. Updates the notification and state, if successful. Handles Errors : Logs errors and returns "error" if something goes wrong. Final Return : Returns "success" upon successful completion. Create NFT Token ​ Step 1: Write a Function to create NFTs on the mainchain Now, let's write the create NFTs on mainchain function. Scroll down to find the comment // step 6 - Create an NFT on the mainchain . Replace the existing createNFTOnMainChain function with this code snippet: create-nft/index.tsx // step 6 - Create an NFT on the mainchain const createNFTOnMainChain = async ( values : { tokenName : string ; symbol : string ; totalSupply : string ; } ) => { let createMainChainNFTLoadingId ; try { createMainChainNFTLoadingId = toast . loading ( "Creating NFT on MainChain..." ) ; // Preparing Parameter for Create Function const createNtfMainChainInput = { tokenName : values . tokenName , symbol : values . symbol , totalSupply : values . totalSupply , issuer : currentWalletAddress , isBurnable : true , issueChainId : sidechain_from_chain_id , owner : currentWalletAddress , externalInfo : { } , } ; const resultMainchain = await mainChainSmartContract ?. callSendMethod ( "Create" , currentWalletAddress , createNtfMainChainInput ) ; console . log ( "========= result of createNewNft =========" , resultMainchain ) ; toast . update ( createMainChainNFTLoadingId , { render : "NFT Created Successfully on MainChain" , type : "success" , isLoading : false , } ) ; removeNotification ( createMainChainNFTLoadingId ) ; return "success" ; } catch ( error : any ) { if ( ! createMainChainNFTLoadingId ) { return "error" ; } toast . update ( createMainChainNFTLoadingId , { render : error . message , type : "error" , isLoading : false , } ) ; removeNotification ( createMainChainNFTLoadingId , 5000 ) ; return "error" ; } } ; What this function does: ​ Displays Loading Toast: Shows a notification indicating the creation process of the NFT on the mainchain. Prepares Parameters: Constructs input parameters for creating the NFT, including token details and the issuer's information. Calls Smart Contract: Sends a request to the mainchain smart contract to create the NFT using the prepared parameters. Handles Success: Updates the notification to show successful NFT creation. Handles Errors: Displays an error message if the operation fails and logs the error. Final Return: Returns "success" if the NFT is created successfully; otherwise, returns "error" . Step 2: Write the Function for Validate NFT Info Exist Now, let's write the Validate NFT Info Exist function. Scroll down to find the comment // step 7 - Validate an NFT token on the mainchain . Replace the existing validateNftToken function with this code snippet: create-nft/index.tsx // step 7 - Validate an NFT token on the maincgit stashhain const validateNftToken = async ( values : INftParams ) => { let validateNFTLoadingId ; try { // Start Loading before initiate the transaction validateNFTLoadingId = toast . loading ( < CustomToast title = "Transaction is getting validated on aelf blockchain. Please wait!" message = "Validation means transaction runs through a consensus algorithm to be selected or rejected. Once the status changes process will complete. It usually takes some time in distributed systems." / > ) ; // Create an object with the necessary information for token validation. const validateInput = { symbol : values . symbol , tokenName : values . tokenName , totalSupply : values . totalSupply , issuer : currentWalletAddress , isBurnable : true , issueChainId : sidechain_from_chain_id , owner : currentWalletAddress , externalInfo : { } , } ; // get mainnet contract const aelfTokenContract = await getTokenContract ( aelf , wallet ) ; // prepare Sign the transaction using contract method (ValidateTokenInfoExists Function) const signedTx = aelfTokenContract . ValidateTokenInfoExists . getSignedTx ( validateInput ) ; // send the transaction using signed Transaction const { TransactionId : VALIDATE_TXID } = await aelf . chain . sendTransaction ( signedTx ) ; await delay ( 3000 ) ; // get Validate Result let VALIDATE_TXRESULT = await aelf . chain . getTxResult ( VALIDATE_TXID ) ; await delay ( 3000 ) ; // if dAppChain inde
프로젝트로 돌아가기