Skip to content

This is frontend which is built as an example of dapp for NCD Level 2. Check videos in README for more info

Notifications You must be signed in to change notification settings

Learn-NEAR/NCD.L2.sample--lottery

 
 

Repository files navigation

🎓 NCD.L2.sample--lottery dapp

This repository contains a complete frontend applications (Vue.js, React, Angular) to work with NCD.L1.sample--lottery smart contract targeting the NEAR platform:

  1. Vue.Js (main branch)
  2. React (react branch)
  3. Angular (angular branch)

The example here is playful. It's a toy involving a lottery. The goal of this repository is to make it as easy as possible to get started writing frontend with Vue.js, React and Angular for AssemblyScript contracts built to work with NEAR Protocol.

⚠️ Warning

Any content produced by NEAR, or developer resources that NEAR provides, are for educational and inspiration purposes only. NEAR does not encourage, induce or sanction the deployment of any such applications in violation of applicable laws or regulations.

⚡ Usage

image

Video demo UI walkthrough

You can use this app with contract id which were deployed by creators of this repo, or you can use it with your own deployed contractId. If you are using not yours contractId some functions of the lottery contract will not work because they are set to work only if owner called this functions.

Example of such function:

image

And some functions, like reset, you can call only from CLI. so to restart lottery you will need CLI.

To get possibility to work with the full functionality of the smart contract, you need to paste your contractId inside UI of deployed dapp. Before pasting id make sure that you deployed correct smart contract, in other case this code may not work as expected.

Link to smart contract repo

How to correctly deploy NCD.L1.sample--lottery smart contract (video tutorial)

After you deployed your contract, you need to paste id in one of deployed dapps

Try VueJs deployed app

Try React deployed app

Try Angular deployed app or you can clone the repo and put contract ids inside .env file :

...
VUE_APP_CONTRACT_ID = "dev-1638894261685-83136914267549"
...

After you input your values inside .env file, you need to :

  1. Install all dependencies
npm install

or

yarn
  1. Run the project locally
npm run serve

or

yarn serve

Other commands:

Compiles and minifies for production

npm run build

or

yarn build

Lints and fixes files

npm run lint

or

yarn lint

👀 Code walkthrough for Near university students

Vue.Js

React

Angular

We are using near-api-js to work with NEAR blockchain. In /services/near.js we are importing classes, functions and configs which we are going to use:

import { keyStores, Near, Contract, WalletConnection, utils } from "near-api-js";

Then we are connecting to NEAR:

// connecting to NEAR, new NEAR is being used here to awoid async/await
export const near = new Near({
    networkId: process.env.VUE_APP_networkId,
    keyStore: new keyStores.BrowserLocalStorageKeyStore(),
    nodeUrl: process.env.VUE_APP_nodeUrl,
    walletUrl: process.env.VUE_APP_walletUrl,
});

and creating wallet connection

export const wallet = new WalletConnection(near, "NCD.L2.sample--lottery");

After this by using Composition API we need to create useWallet() function and use inside signIn() and signOut() functions of wallet object. By doing this, login functionality can now be used in any component.

And also we in return statement we are returning wallet object, we are doing this to call wallet.getAccountId() to show accountId in /components/PageTitle.vue

useWallet() code :

export const useWallet = () => {
    const accountId = ref('')
    accountId.value = wallet.getAccountId()
    const err = ref(null)
  
    onMounted(async () => {
      try {
        accountId.value = wallet.getAccountId()
      } catch (e) {
        err.value = e;
        console.error(err.value);
      }
    });
  
    const handleSignIn = () => {
      wallet.requestSignIn({
        contractId: CONTRACT_ID,
        methodNames: [] // add methods names to restrict access
      })
    };
  
    const handleSignOut = () => {
      wallet.signOut()
      accountId.value = wallet.getAccountId()
    };
  
    return {
      accountId,
      signIn: handleSignIn,
      signOut: handleSignOut
    }
  }

To work with smart contract we will create separate useLottery() function with Composition API to split the logic. We are loading the contract inside /services/near.js:

function getLotteryContract() {
  return new Contract(
    wallet.account(), // the account object that is connecting
    CONTRACT_ID, // name of contract you're connecting to
    {
      viewMethods: ['get_owner', 'get_winner', 'get_pot', 'get_fee', 'get_fee_strategy', 'get_has_played',
        'get_last_played', 'get_active', 'explain_fees', 'explain_lottery'], // view methods do not change state but usually return a value
      changeMethods: ['play', 'configureLottery', 'configureFee', 'reset'] // change methods modify state
    }
  )
}

const contract = getLotteryContract()

and we are creating function to export for each contract function

example of a call with no params:

//function to get all messages from thanks contract
export const getMessages = async () => {
    return await thanksContract.list()
}

example of call with params

//function to configure Lottery
export const configureLottery = async (chance) => {
  return await contract.configure_lottery(
    { chance:chance },
    gas
  )
}


Then in composables/near.js we are just importing all logic from services/near.js:

import {
    wallet,
    CONTRACT_ID,
    getOwner,
    getWinner,
    getPot,
    getFee,
    getFeeStrategy,
    getHasPlayed,
    getLastPlayed,
    getActive,
    getExplainFees,
    getExplainLottery,
    play,
    reset
  } from "../services/near";

and using it to store some state of contracts and to call contracts functions:

export const useLottery = () => {
      const  owner = ref("")
      const  winner = ref('')
      const  pot = ref('')
      const  fee = ref('')
      const  feeStrategy = ref('')
      const  hasPlayed = ref(null)
      const  lastPlayed = ref(null)
      const  active = ref(null)
      const  feesExplanation =  ref('')
      const  lotteryExplanation  = ref('')
      const  apiError = ref(null);

      onMounted(async () => {
          try {
            updateValues()
          }
          catch (e) {
            apiError.value = e;
            console.log(apiError.value);
          }
      })

      const updateValues = async () => {
        try {
          owner.value = await getOwner()
          winner.value = await getWinner()
          pot.value = await getPot()
          fee.value = await getFee()
          feeStrategy.value = FeeStrategies[await getFeeStrategy()]
          hasPlayed.value = wallet.getAccountId() && await getHasPlayed(wallet.getAccountId())
          lastPlayed.value = await getLastPlayed()
          active.value = await getActive()
          feesExplanation.value = await getExplainFees()
          lotteryExplanation.value = await getExplainLottery()
        } catch (e) {
          apiError.value = e;
          console.log(apiError.value);
        }
      }

      const handlePlay = async () => {
        fee.value = await getFee()
        hasPlayed.value = await getHasPlayed(wallet.getAccountId())
        await play(fee.value,hasPlayed.value);
      };

      const handleReset = async () => {
        reset();
      };

      return {
        owner,
        winner,
        pot,
        fee,
        feeStrategy,
        hasPlayed,
        lastPlayed,
        active,
        feesExplanation,
        lotteryExplanation,
        apiError,
        play:handlePlay,
        reset:handleReset,
        update: updateValues
      };
  };

Inside components we are using the same useWallet() and useContracts() functions to manage state of dapp. /components/Summarize.vue as an example :

    import { useWallet } from "@/composables/near"
import { useLottery } from "@/composables/near"
export default {
  setup(){
    const  { owner, winner, pot, fee, feeStrategy,hasPlayed, lastPlayed, active, feesExplanation, lotteryExplanation,  play,  reset}  = useLottery();
    const { accountId, signIn,  signOut } = useWallet();
    return  {
        owner,
        winner,
        pot,
        fee,
        feeStrategy,
        hasPlayed,
        lastPlayed,
        active,
        feesExplanation,
        lotteryExplanation,
        play,
        reset,
        accountId,
        signIn,
        signOut
    }
  }
}

Releases

No releases published

Packages

No packages published

Languages

  • Vue 77.4%
  • JavaScript 20.8%
  • HTML 1.3%
  • Other 0.5%