Zero to One DApp Development Guide on Vite



  • Zero to One DApp Development Guide on Vite

    Introduction

    This article introduces how to develop DApp on Vite. It mainly focuses on the interactions between Vite smart contract and frontend web application. In the meantime, we also cover some key points that developers should pay attention to.

    Typically, readers should have the following skills: HTML/CSS/JS, VUE framework, Linux, basic understanding about smart contracts and Vite public chain. We have assumed that readers already have all above knowledge.

    What you can learn

    In this article, you will learn every step of DApp development on Vite public chain. If you are not familiar with Vite, see here for official technical documents.

    Content

    • Pre-preparation
    • Development steps
    • Contract debugging environment
    • Writing Vite smart contract
    • Creation and deployment of Vite smart contract
    • Calling Vite smart contract from frontend web application
    • DApp Debugging
    • Applying for listing DApp in Vite mobile wallet
    • Useful tips
    • Reference

    Pre-preparation

    • Purchase a server. One VPS with 2 CPUs and 4 GB memory is recommended
    • Install Vite full node
    • Configure node_config.json to enable WS API on the node:
     "WSEnabled": true,
     "WSHost": "0.0.0.0",
     "WSPort": 41420,
    
    • Configure node_config.json to enable vmLog for smart contract:
     // save vmlog for all contracts
    "VmLogAll":true
    Or
    // save vmlog for the specified contract by address
    "VmLogWhiteList":["vite_replaceWithYourContractAddress”] 
    
    • If you use a VPS (such as Alibaba Cloud or AWS), don’t forget to configure security rule to expose relevant ports. For example, 41420 for WS and 48132 for RPC.
    • Install Nginx on the server in order to deploy web application.
    • Register a domain name and bind to your DApp web application (If your DApp doesn’t need domain name, skip this step).
    • Buy some VITE coins. In Vite Pre-mainnet 10 VITE will be cost for deploying a smart contract. In addition, executing contract consumes quota, which must be obtained through staking VITE coins. The exact amount of staking depends on the complexity of the contract and the number of requests the contract is supposed to process per second.

    Development Steps

    • DApp functional design and smart contract design
    • Vue-based web application development and UI design
    • Smart contract writing and testing
    • Deployment of smart contract in test environment
    • DApp & smart contract integration and debugging
    • Testing contract in local browser using imported account
    • Testing in official test wallet
    • Debugging in official test wallet
    • Deployment of smart contract in the Pre-mainnet
    • Listing your DApp in Vite official wallet app

    Feel free to adjust the steps according to your actual demand

    Contract Debugging Environment

    The official document has mentioned two categories of local environments for debugging: development environment (installation package name begins with "contractdev") and test environment (installation package name begins with "contracttest"). Here I recommend test environment package. For contract development, you can use Vscode with Soliditypp plugin, which currently supports windows, linux and mac system. The Soliditypp plugin has integrated development environment, and a local node will launch automatically when you debug contract in the IDE.

    • Vscode Soliditypp plugin installation

    See plugin installation guide

    • Test environment

    After development is complete in Vscode, you may want to set up a Vite test environment node and deploy your contract. Test environment is closer to Vite pre-mainnet. In test environment, all interactions between front-end web application and smart contract need to be verified.
    To make it easy for developers to work in test environment, Vite dev team provides several scripts in installation package.
    See: Test environment

    • Pre-mainnet

    This is the production environment of Vite network. You need a full node to deploy your DApp in Vite Pre-mainnet. Refer to how to set up Vite full node.

    Note: ONLY deploy DApp to the Pre-mainnet after it has been fully tested in test environment.

    Writing Vite Smart Contract

    IDE

    • Soliditypp plugin of Vscode

    Programming language

    • The language of Vite smart contract is called Solidity++, which is an extension of Ethereum Solidity by adding asynchronous calls
    • Data types, functions, keywords

    If this is your first time to write smart contract, it is highly recommended you start with Ethereum because Ethereum has plenty of documentation while Vite official documents focus more on the difference between Solidity and Solidity++.
    Solidity is very suitable for beginners. After you learned the syntax of solidity, you should be good to start Vite smart contract programming.

    Common Solidity++ syntax

    • Define a method: onMessage
    onMessage BetAndRoll(uint16 rollTargets) payable {
     
     // msg.sender - caller's address
     // msg.amount - transfer amount
     // msg.tokenid - TokenId 
     
     // Get random numbers
     // uint64 randomNumber = random64();
     // uint64 nextRandom = nextrandom();
     
     // TODO add your logic here….
     
     // emit trigger event
     // emit win(betAddr, rollTargets, betAmount, rollNum, winAmount);
    }
    
    • Define a method to query contract's state off chain: getter
    Getter getTokenList() returns(tokenId[] memory) {
    Return tokens;
    }
    
    • Define an event: event
    event win(address indexed addr, uint256 rollTarget, uint256 betAmount, uint256 rollNum, uint256 winAmount);
    

    Reference link: https://vite.wiki/tutorial/contract/soliditypp.html

    Tips

    For DApps aim to be listed in official wallet, it is required to open the source code of smart contract. You can refer to the source code of existing smart contracts in Vite block explorer for your reference in development.

    You can refer to existing Ethereum smart contracts for common algorithms or code snippets on GitHub. They may be reused in Vite smart contract directly or after modified slightly.

    It is highly recommended to deploy the contract to test environment after all functions are implemented and all code pass compilation without error in Vscode.

    At this stage, it is necessary to pay attention to whether the quota consumed by each contract request is reasonable. If the cost is too high or exceeds expectation, you probably should optimize it, or even re-consider if the original business process is suitable for implementation in smart contract. In other words, the most effective way to lower quota consumption is to reduce complexity of the contract.

    Creation and deployment of Vite smart contract

    Create smart contract in development environment & test environment

    Use the official scripts to create contract

    See official document if you need more details

    In addition, "invalid command 'jq'" error may occur when executing the scripts on some servers. In this case, you need to install jq. Taking Ubuntu as an example, execute apt-get install jq.

    Create smart contract in the Pre-mainnet

    • Compile smart contract

    Compile contract by executing the following command (solppc is available in installation package of both development and test environment):

    ./solppc --abi --bin SimpleBet.solpp

    This will generate output in 3 parts:

    1. Binary:...// This is compiled code of the contract.
    2. OffChain Binary:... // This is compiled code of getter functions
    3. Contract JSON ABI:...// This is ABI of the contract
    • Create smart contract

    Vite official documents introduce two choices to create a contract:

    1. Via RPC API, not recommended.
    2. Via createContract method in vitejs, recommended.

    To create a smart contract in the Pre-mainnet, you need:

    1. Hold 10 VITE or more in the account for contract deployment (creating a smart contract in the Pre-mainnet costs 10 VITE)
    2. Stake at least 1,000 VITE for the account for obtaining sufficient quota (if you choose to use pow, check whether pow module is configured in PublicModules of node_config.json)
    3. Ignore times parameter or fill in a number between 10-100.

    Example:

    let Vite_TokenId = "tti_5649544520544f4b454e6e40";
    
    // the content of "Contract JSON ABI" generated from compilation. Note: this is a byte array (no quotes around)
    let newabi = abicode; 
    
    // the content of "Binary" generated from compilation
    let newhexcode = binary; 
    
    // create contract using account imported
    myAccount.createContract({
     abi:newabi,
     hexCode: newhexcode,
     confirmTimes: 2,????? // Confirmation number between 0 ~ 75
     // times: 0,??????????? // Quota multiply factor. Default is 0
     params: [],
     tokenId: Vite_TokenId,? // Default is the TokenId of VITE
     amount: '0',??????????????// Default is '0'
     fee: '10000000000000000000',?// Default is '10000000000000000000’, equivalent to 10 VITE
    }).then((accountBlock) => {
     // contract address
     let contractAddress = accountBlock.toAddress;
     console.log("contractAddress is " + contractAddress) ; 
    }).catch(err => {
     console.warn(err);
    });
    

    Calling Vite Smart Contract from Frontend Web Application

    1. Web application calls a method of smart contract
    2. Various events are triggered during execution of the method
    3. Web application captures the events separately and send feedback to users

    How to call smart contract

    • By importing an account in the code

    Recommended for debugging

    import WS_RPC from '@vite/vitejs-ws';
    import { client, account, hdAccount, constant } from '@vite/vitejs';
    
    let { Vite_TokenId } = constant;
    let provider = new WS_RPC("ws://example.com");
    let myClient = new client(provider);
    
    // import an account via private key
    let myAccount = new account({
     client: myClient,
     privateKey: 'your privateKey'
    });
    // or import an account via mnemonic phrase
    // let myHdAccount = new hdAccount({ 
    // client: myClient,
    // mnemonic: 'your mnemonic'
    // });
    // let myAccount = myHdAccount.getAccount()
    
    let abi = []; // contract ABI
    let contractAddress =""; // contract address
    
    let callContractBlock = await myAccount.callContract({
     accountAddress: myAccountParam.address,
     toAddress: contractAddress, // contract address
     tokenId: "tti_5649544520544f4b454e6e40", // TokenId
     amount: "0", // the amount of tokens to be sent
     abi: abi[1], // ABI of the method to be called
     methodName:"BetAndRoll", // method name
     params: [num], // parameter list
    });
    
    • By calling Vite bridge URI

    Recommended for calling DApp from Vite wallet. This will send transaction to smart contract through an account in wallet.
    See here for Vite bridge installation.

    import { abi as abiutils,utils } from '@vite/vitejs';
    import Bridge from "@vite/bridge";
    
     // get current account address by method `wallet.currentAddress`
    let address = ""; 
    
     // contract address
    let contractAddress = "";
    
    let abi = []; // contract ABI
    let num = 0; // parameter
    this.money = 0; // the amount to transfer. If TokenId is not specified, the transfer is done in VITE
    
    let bridge = new Bridge();
    
    // encode ABI, parameter list and method name into a function call
    const hexData=abiutils.encodeFunctionCall(abi[1], [num], 'BetAndRoll');
    // convert data format
    const base64Data=utils._Buffer.from(hexData,'hex').toString('base64');
    
    // Compose URI
    let uri3 = `vite:${contractAddress}/BetAndRoll?amount=${this.money}&data=`+base64Data;
    
    // Trigger Vite wallet to send the transaction (function call)
    bridge["wallet.sendTxByURI"]({uri:uri3, address:address}).then(accountBlock => {
     // Transaction is sent out successfully
     console.log(accountBlock);
    }).catch((err) => {
     // Transaction is cancelled
     console.log(err);
    });
    
    

    Query contract

    • Query states of contract

    Call getter methods

     // contract address
    let contractAddress = "vite_8a50b500773c7abe0ceeb7e6e25a97871868585159d8333cc0";
    let offchaincode=""; // the content of "OffChain Binary" generated in compilation 
    let abi = []; // contract ABI
    let params = []; // parameter list or empty array if no parameter
    
    // encode ABI and parameter list into a function call
    let data = abiutils.encodeFunctionCall(abi[2],params);
    let dataBase64 = utils._Buffer.from(data, 'hex').toString('base64');
    let result = await myClient.request('contract_callOffChainMethod',{
     'selfAddr':contractAddress,
     'offChainCode':offchaincode,
     'data':dataBase64
    });
    if (result) {
     let resultBytes = Buffer.from(result, 'base64').toString('hex');
     let outputs = [];
     for (let i = 0; i < abi.outputs.length; i++) {
     outputs.push(abi.outputs[i].type);
     }
     let offchainDecodeResult = abiutils.decodeParameters(outputs, resultBytes);
     let resultList=[];
     for (let i = 0; i < abi.outputs.length; i++) {
     if (abi.outputs[i].name) {
     resultList.push({'name':abi.outputs[i].name, 'value':offchainDecodeResult[i]});
     } else {
     resultList.push({'name':'', 'value':offchainDecodeResult[i]});
     }
     }
     // resultList is a list of states
     console.log(resultList);
    }
    

    Frequently used query code

    • Query quota
    import WS_RPC from '@vite/vitejs-ws';
    import { client, account, hdAccount, constant } from '@vite/vitejs';
    
    let { Vite_TokenId } = constant;
    let provider = new WS_RPC("ws://example.com");
    let myClient = new client(provider);
    
    myClient.pledge.getPledgeQuota("vite_8a50b500773c7abe0ceeb7e6e25a97871868585159d8333cc0").then((result) => {
     // result is quota value
    });
    
    • Query balance
    myClient.ledger.getAccountByAccAddr(currentAddr).then((result) => {
     // result is an account including balance
    });
    
    • Query block height
    myClient.ledger.getSnapshotChainHeight().then((result) => {
     // result is the latest snapshot block height
    });- 
    
    • Query vmlog event

    Make sure you have configured settings in node_config.json to keep vmlog.

    // get the latest N blocks for the given contract address
    let blockList = await myClient.ledger.getBlocksByAccAddr(contactAddr, offset, limit);
    
    // get vmlog of each block in a loop
    for (var i = 0; i < blockList.length; i++) {
     
     let contractTx = blockList[i];
     let contractBlockHash = contractTx.hash;
    
     let abi = []; // contract ABI
     let vmLogs = [];
     let vmLogList = await myClient.request('ledger_getVmLogList', contractBlockHash);
    
     // Note: no every block has vmlog data. For example, transfer transaction doesn't have vmlog.
     if (vmLogList) {
     vmLogList.forEach(vmLog => {
     let topics = vmLog.topics;
     for (let j = 0; j < abi.length; j++) {
     let abiItem = abi[j];
     if (abiutils.encodeLogSignature(abiItem) === topics[0]) { 
     let dataBytes = '';
     if (vmLog.data) {
     dataBytes = utils._Buffer.from(vmLog.data, 'base64');
     }
     let log ={topic: topics[0],args: abiutils.decodeLog(abiItem.inputs, dataBytes.toString('hex'), topics.slice(1)),event: abiItem.name}; 
     vmLogs.push(log);
     break;
     }
     }
     });
     }
     // events are saved in vmLogs
     console.log(vmLogs);
    }
    
    • Event subscription (Recommended)

    Event subscription is more efficient compared to polling. Detailed description and examples are provided in Vite official documents.

    Reference links:

    1. https://vite.wiki/api/rpc/subscribe.html
    2. https://vite.wiki/api/vitejs/client/subscribe.html

    DApp Debugging

    Local debugging

    • It is recommended to use a desktop browser like Google Chrome. You should turn on mobile view to debug compatibility issues.
    • Calling contract can only be done through callContract method of vitejs using a local account imported in the code.
    • Use test environment

    Debugging in Vite test wallet

    • Download Vite test wallet

    See here for additional information about Vite test wallet

    • Call bridge["wallet.sendTxByURI"] to talk to your contract
    • Deploy your smart contract to the Pre-mainnet after sufficient tests in test environment

    Applying for Listing DApp in Vite Mobile Wallet

    Listing process

    • The current process is not finalized and may change in the future. Contact Vite team for the latest process.

    See the current listing process

    Useful Tips

    How much VITE should I stake for my contract

    • This mainly depends on in how many TPS that your contract is supposed to execute. Vite quota model defines staking 10,000 VITE can give you 1 UT quota per second, which translates to 1 UTPS throughput. However, quota consumption in smart contract is often higher. Each contract response may consume 2-3 UT or more according to how complex your contract's business logic is. The complexity can be measured in lines of code executed. Therefore, you must evaluate the quota consumption of your contract and perform necessary optimization if the quota is cost too fast.
    • Assume your contract is called once a second and each response costs a quota of 3 UT, you should stake at least 30,000 VITE.
    • Always guarantee your contract is sufficiently tested in test environment before deployed to the Pre-mainnet, in the purpose of saving deployment cost.

    Take use of Vite Github repository

    • Vite official wiki is a good place to look for technical documents. However, if you do not find some answers, in this case, you can look into Vite Github repository. You may find some in-developing documents by searching keywords.
      You can also search for code examples and unit test cases, for reference of how to use the APIs. Never forget to star the repository:)

    Reference

    1. Vite dApp Development Guide: https://vite.wiki/tutorial/contract/dapp.html
    2. Quota: https://vite.wiki/tutorial/rule/quota.html
    3. Smart Contract: https://vite.wiki/tutorial/contract/contract.html
    4. VEP 6: Vite URI Formatting: https://vite.wiki/vep/vep-6.html
    5. VEP-12: The Implementation of Random Numbers in Vite: https://vite.wiki/vep/vep-12.html
    6. Vite RPC API: https://vite.wiki/api/rpc/
    7. ViteJS: https://vite.wiki/api/vitejs/

    All code in this article were used and tested in a real DApp

    Author: 闫冬(Dong YAN), founder of N4Q.org


Log in to reply