# Source: https://docs.near.org/tutorials/examples/count-near.md

---
id: count-near
title: Count on NEAR
description: "A simple counter on NEAR Protocol."
---





Our counter example is a friendly decentralized app that stores a number and exposes methods to `increment`,`decrement`, and `reset` it.

![img](/assets/docs/tutorials/examples/count-on-near-banner.png)

---

## Obtaining the Counter Example

You have two options to start the Counter Example.

1. You can use the app through `GitHub Codespaces`, which will open a web-based interactive environment.
2. Clone the repository locally and use it from your computer.

| Codespaces                                                                                                             | Clone locally                                  |
| ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/near-examples/counters) | 🌐 `https://github.com/near-examples/counters` |

---

## Structure of the Example

The example is divided in two main components:

1. The smart contract, available in two flavors: Rust and JavaScript
2. The frontend, that interacts with an already deployed contract.

<Tabs groupId="code-tabs">

  <TabItem value="js" label="🌐 JavaScript">

```bash
┌── sandbox-ts # sandbox testing
│    ├── src
│    │    └── main.ava.ts
│    ├── ava.config.cjs
│    └── package.json
├── src # contract's code
│    └── contract.ts
├── package.json # package manager
├── README.md
└── tsconfig.json # test script
```

  </TabItem>

  <TabItem value="rust" label="🦀 Rust">

```bash
┌── src # contract's code
│    └── lib.rs
├── tests # sandbox test
│    └── test_basics.rs
├── Cargo.toml # package manager
├── README.md
└── rust-toolchain.toml
```

  </TabItem>

</Tabs>

---

## Frontend

The counter example includes a frontend interface designed to interact seamlessly with an existing smart contract that has been deployed. This interface allows users to increase or decrease the counter as needed.

<hr class="subsection" />

### Running the Frontend

To start the frontend you will need to install the dependencies and start the server.

```bash
cd frontend
yarn
yarn dev
```

Go ahead and login with your NEAR account. If you don't have one, you will be able to create one in the moment. Once logged in, use the `+` and `-` buttons to increase and decrease the counter. Then, use the Gameboy buttons to reset it and make the counter blink an eye!

![img](/assets/docs/tutorials/examples/count-on-near.png)
_Frontend of the Counter_

<hr class="subsection" />

### Understanding the Frontend

The frontend is a [Next.JS](https://nextjs.org/) project generated by [create-near-app](https://github.com/near/create-near-app). Check `_app.js` and `index.js` to understand how components are displayed and interacting with the contract.

<Language value="js" language="js">
  ```
import '@/styles/globals.css';
import '@near-wallet-selector/modal-ui/styles.css';

import { setupMyNearWallet } from '@near-wallet-selector/my-near-wallet';
import { setupMeteorWallet } from '@near-wallet-selector/meteor-wallet';
import { setupMeteorWalletApp } from '@near-wallet-selector/meteor-wallet-app';
import { setupBitteWallet } from '@near-wallet-selector/bitte-wallet';
import { setupEthereumWallets } from '@near-wallet-selector/ethereum-wallets';
import { setupHotWallet } from '@near-wallet-selector/hot-wallet';
import { setupLedger } from '@near-wallet-selector/ledger';
import { setupSender } from '@near-wallet-selector/sender';
import { setupHereWallet } from '@near-wallet-selector/here-wallet';
import { setupNearMobileWallet } from '@near-wallet-selector/near-mobile-wallet';
import { setupWelldoneWallet } from '@near-wallet-selector/welldone-wallet';
import { WalletSelectorProvider } from '@near-wallet-selector/react-hook';
import { wagmiAdapter, web3Modal } from '@/wallets/web3modal';
import { Navigation } from '@/components/Navigation';
import { NetworkId, CounterContract } from '@/config';

const walletSelectorConfig = {
  network: NetworkId,
  createAccessKeyFor: CounterContract,
  modules: [
    setupEthereumWallets({ wagmiConfig: wagmiAdapter.wagmiConfig, web3Modal }),
    setupBitteWallet(),
    setupMeteorWallet(),
    setupMeteorWalletApp({contractId: CounterContract}),
    setupHotWallet(),
    setupLedger(),
    setupSender(),
    setupHereWallet(),
    setupNearMobileWallet(),
    setupWelldoneWallet(),
    setupMyNearWallet(),
  ],
}

export default function App({ Component, pageProps }) {

  return (
    <WalletSelectorProvider config={walletSelectorConfig}>
      <Navigation />
      <Component {...pageProps} />
    </WalletSelectorProvider>
  );
}
```
  ```
import { useEffect, useState } from 'react';

import styles from '@/styles/app.module.css';
import { useWalletSelector } from '@near-wallet-selector/react-hook';
import { CounterContract } from '@/config';


export default function Home() {
	const { signedAccountId, callFunction, viewFunction } = useWalletSelector();
  const [number, setNumber] = useState(0);
  const [numberIncrement, setNumberIncrement] = useState(0);

  const [leftEyeVisible, setLeftEyeVisible] = useState(true);
  const [rightEyeVisible, setRightEyeVisible] = useState(true);
  const [tongueVisible, setTongueVisible] = useState(false);
  const [dotOn, setDotOn] = useState(true);

  const [globalInterval, setGlobalInterval] = useState(null);

  useEffect(() => { 
    fetchNumber();

    // Fetch the number every two seconds
    let interval = setInterval(fetchNumber, 1500); 
    setGlobalInterval(interval);

    return () => clearInterval(interval);
  }, [])

  useEffect(() => {
    // interrupt the constant fetching of the number
    clearInterval(globalInterval);

    // Debounce the increment call until the user stops clicking
    const getData = setTimeout(() => {
      if (numberIncrement === 0) return;

      setNumberIncrement(0);

      // Try to increment the counter, fetch the number afterwords
      callFunction({ contractId: CounterContract, method: 'increment', args: { number: numberIncrement } })
        .finally(() => {
          fetchNumber();
          let interval = setInterval(fetchNumber, 1500) 
          setGlobalInterval(interval);
        })

    }, 500)

    return () => clearTimeout(getData);
  }, [numberIncrement])

  const fetchNumber = async () => {
    setDotOn(true);
    console.log("fetching number")
    const num = await viewFunction({ contractId: CounterContract, method: "get_num" });
    setNumber(num);
    setDotOn(false);
  }

  const call = (method) => async () => {
    const methodToState = {
      increment: () => {
        setNumberIncrement(numberIncrement + 1)
        setNumber(number + 1)
      },
      decrement: () => {
        setNumberIncrement(numberIncrement - 1)
        setNumber(number - 1)
      },
      reset: async () => {
        setNumberIncrement(0)
        setNumber(0)
        callFunction({ contractId: CounterContract, method: 'reset' }).then(async () => {
          await fetchNumber();
        })
      },
    }

    methodToState[method]?.();
  }

  return (
    <main className={styles.main}>
      <h2 className='title'>This global counter lives in the NEAR blockchain!</h2>
      {!signedAccountId && <div className="sign-in" >
        <p>You'll need to sign in to interact with the counter:</p>
      </div>}
      <div className="scene">
        <div className="gameboy">
          <div className="body-shape shadow"></div>
          <div className="body-shape side"></div>
          <div className="body-shape front">
            <div className="screen">
              <div className={dotOn ? 'dot on' : 'dot off'}></div>
              <div className="face">
                <div className="eyes-row">
                  <div id="left" className={leftEyeVisible ? 'closed eye' : 'closed'}>
                    <div className="pupil"></div>
                  </div>
                  <div id="right" className={rightEyeVisible ? 'closed eye' : 'closed'}>
                    <div className="pupil"></div>
                  </div>
                </div>
                <div className="mouth-row">
                  <div className={`mouth ${number >= 0 ? 'smile' : 'cry'}`}></div>
                  <div className={`tongue ${tongueVisible ? "show" : ""}`}></div>
                </div>
              </div>
              <div id="show" className="number">{number}</div>
            </div>
            <div className="buttons">
              <div className="row">
                <button id="plus" className="interact arrows" onClick={call('increment')} disabled={!signedAccountId}>
                  <div className="left">
                  </div>
                  <div className="updown">
                  </div>
                </button>
                <button id="minus" className="interact arrows" onClick={call('decrement')} disabled={!signedAccountId}>
                  <div className="right">
                  </div>
                </button>
              </div>
              <div className="selects row">
                <div className="ab">
                  <button id="a" className="interact r a" onClick={call('reset')} disabled={!signedAccountId}>RS</button>
                  <button id="b" className="r b" onClick={() => setRightEyeVisible(!rightEyeVisible)}>RE</button>
                  <button id="c" className="r c" onClick={() => setLeftEyeVisible(!leftEyeVisible)}>LE</button>
                  <button id="d" className="r d" onClick={() => setTongueVisible(!tongueVisible)}>L</button>
                </div>
              </div>
            </div>
          </div>
        </div>

      </div>
    </main>
  );
}
```
</Language>

---

## Smart Contract

The contract presents 4 methods: `get_num`, `increment`, `decrement`, and `reset`. The method `get_num` retrieves the current value, and the rest modify it.

<CodeTabs>
  <Language value="js" language="ts">
    ```
@NearBindgen({})
class Counter {
  val: number = 0;

  static schema = {
    number: 'number'
  }

  @view({}) // Public read-only method: Returns the counter value.
  get_num(): number {
    return this.val
  }

  @call({}) // Public method: Increment the counter.
  increment({ number = 1 }: { number: number }) {
    this.val += number;
    near.log(`Increased number to ${this.val}`)
  }

  @call({}) // Public method: Decrement the counter.
  decrement({ number = 1 }: { number: number }) {
    this.val -= number;
    near.log(`Decreased number to ${this.val}`)
  }

  @call({}) // Public method - Reset to zero.
  reset() {
    this.val = 0;
    near.log(`Reset counter to zero`)
  }
}
```
  </Language>
  <Language value="rust" language="rust">
    ```
#[near(contract_state)]
#[derive(Default)]
pub struct Counter {
    val: i8,
}

// Implement the contract structure
#[near]
impl Counter {
    // Public read-only method: Returns the counter value.
    pub fn get_num(&self) -> i8 {
        return self.val;
    }

    // Public method: Increment the counter.
    pub fn increment(&mut self, number: Option<i8>) {
        self.val += number.unwrap_or(1);
        log!("Increased number to {}", self.val);
    }

    // Public method: Decrement the counter.
    pub fn decrement(&mut self, number: Option<i8>) {
        self.val -= number.unwrap_or(1);
        log!("Decreased number to {}", self.val);
    }

    // Public method - Reset to zero.
    pub fn reset(&mut self) {
        self.val = 0;
        log!("Reset counter to zero");
    }
}

/*
```
  </Language>
</CodeTabs>

---

### Testing the Contract

The contract readily includes a set of unit and sandbox testing to validate its functionality. To execute the tests, run the following commands:

<Tabs groupId="code-tabs">
  <TabItem value="js" label="🌐 JavaScript">

```bash
cd contract-ts
yarn
yarn test
```

  </TabItem>
  <TabItem value="rust" label="🦀 Rust">
  
  ```bash
  cd contract-rs
  cargo test
  ```

  </TabItem>

</Tabs>

:::tip
The `integration tests` use a sandbox to create NEAR users and simulate interactions with the contract.
:::

<hr class="subsection" />

### Deploying the Contract to the NEAR network

In order to deploy the contract you will need to create a NEAR account.

<Tabs groupId="cli-tabs">
  <TabItem value="short" label="Short">

  ```bash
  # Create a new account pre-funded by a faucet
  near create-account <accountId> --useFaucet
  ```
  </TabItem>

  <TabItem value="full" label="Full">

  ```bash
  # Create a new account pre-funded by a faucet
  near account create-account sponsor-by-faucet-service <my-new-dev-account>.testnet autogenerate-new-keypair save-to-keychain network-config testnet create
  ```
  </TabItem>
</Tabs>

Go into the directory containing the smart contract (`cd contract-ts` or `cd contract-rs`), build and deploy it:

<Tabs groupId="code-tabs">

  <TabItem value="js" label="🌐 JavaScript">

    ```bash
    npm run build
    near deploy <accountId> ./build/counter.wasm
    ```

  </TabItem>
  <TabItem value="rust" label="🦀 Rust">
  
  ```bash
  cargo near deploy build-non-reproducible-wasm <accountId>
  ```

  </TabItem>

</Tabs>

:::tip
To interact with your contract from the [frontend](#frontend), simply replace the value of the `testnet` key in the `config.js` file.
:::


<hr class="subsection" />

### CLI: Interacting with the Contract

To interact with the contract through the console, you can use the following commands.

#### Get the current number of the counter

<Tabs groupId="cli-tabs">
  <TabItem value="short" label="Short">

  ```bash
  near view counter.near-examples.testnet get_num
  ```
  </TabItem>

  <TabItem value="full" label="Full">

  ```bash
   near contract call-function as-read-only counter.near-examples.testnet get_num json-args {} network-config testnet now
  ```
  </TabItem>
</Tabs>

<hr class="subsection" />

#### Increment the counter

<Tabs groupId="cli-tabs">
  <TabItem value="short" label="Short">

  ```bash
  # Replace <accountId> with your account ID
  near call counter.near-examples.testnet increment --accountId <accountId>
  ```
  </TabItem>

  <TabItem value="full" label="Full">

  ```bash
  # Replace <accountId> with your account ID
  near contract call-function as-transaction counter.near-examples.testnet increment json-args {} prepaid-gas '30.0 Tgas' attached-deposit '0 NEAR' sign-as aha_6.testnet network-config testnet sign-with-keychain send
  ```
  </TabItem>
</Tabs>

<hr class="subsection" />

#### Decrement the counter

<Tabs groupId="cli-tabs">
  <TabItem value="short" label="Short">

  ```bash
  # Replace <accountId> with your account ID
  near call counter.near-examples.testnet decrement --accountId <accountId>
  ```
  </TabItem>

  <TabItem value="full" label="Full">

  ```bash
  # Replace <accountId> with your account ID
  near contract call-function as-transaction counter.near-examples.testnet decrement json-args {} prepaid-gas '30.0 Tgas' attached-deposit '0 NEAR' sign-as aha_6.testnet network-config testnet sign-with-keychain send
  ```
  </TabItem>
</Tabs>

<hr class="subsection" />

#### Reset the counter to zero

<Tabs groupId="cli-tabs">
  <TabItem value="short" label="Short">

  ```bash
  # Replace <accountId> with your account ID
  near call counter.near-examples.testnet reset --accountId <accountId>
  ```
  </TabItem>

  <TabItem value="full" label="Full">

  ```bash
  # Replace <accountId> with your account ID
  near contract call-function as-transaction counter.near-examples.testnet reset json-args {} prepaid-gas '30.0 Tgas' attached-deposit '0 NEAR' sign-as aha_6.testnet network-config testnet sign-with-keychain send
  ```
  </TabItem>
</Tabs>

:::tip
If you're using your own account, replace `counter.near-examples.testnet` with your `accountId`.
:::

---

## Moving Forward

A nice way to learn is by trying to expand the contract. Modify it by adding a parameter to `increment` and `decrement`,
so the user can choose by how much to change the value. For this, you will need to use knowledge from the [anatomy](../../smart-contracts/anatomy/anatomy.md)
and [storage](../../smart-contracts/anatomy/storage.md) sections.

<MovingForwardSupportSection />

:::note Versioning for this article

At the time of this writing, this example works with the following versions:

- near-cli: `4.0.13`
- node: `18.19.1`
- rustc: `1.77.0`

:::