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

---
id: donation
title: Donation
description: "Learn to build a donation smart contract that accepts NEAR tokens, tracks donations, and distributes funds to beneficiaries."
---





Our donation example enables to forward NEAR Tokens to an account while keeping track of it. It is one of the simplest examples on making a contract handle transfers.

![img](/assets/docs/tutorials/examples/donation.png)
_Frontend of the Donation App_

---

## Obtaining the Donation Example

You have two options to start the Donation 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/donation-examples) | 🌐 `https://github.com/near-examples/donation-examples.git` |

---

## 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
│    ├── model.ts
│    └── utils.ts
├── package.json # package manager
├── README.md
└── tsconfig.json # test script
```

  </TabItem>

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

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

  </TabItem>

</Tabs>

---

## Frontend

The donation example includes a frontend that interacts with an already deployed smart contract, allowing user to donate NEAR tokens to a faucet service.

<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, input the amount of NEAR you want to donate and press the donate button. You will be redirected to the NEAR Wallet to confirm the transaction. After confirming it, the donation will be listed in the "Latest Donations".

<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 `DonationsTable.jsx` and `DonationsForm.jsx` to understand how components are displayed and interacting with the contract.

<Language value="js" language="js">
  ```
import { utils } from "near-api-js";
import { useEffect, useState } from "react";
import { useWalletSelector } from '@near-wallet-selector/react-hook';
import { DonationNearContract } from "@/config";


const DonationsTable = () => {
  const { signedAccountId, viewFunction } = useWalletSelector();
  const [donations, setDonations] = useState([]);
  const [currentPage, setCurrentPage] = useState(1);
  const [lastPage, setLastPage] = useState(0);
  const donationsPerPage = 5;

  const getDonations = async (page) => {
    const number_of_donors = await viewFunction({
      contractId: DonationNearContract,
      method: "number_of_donors",
    });

    setLastPage(Math.ceil(number_of_donors / donationsPerPage));
    const fromIndex = (page - 1) * donationsPerPage;
    const donations = await viewFunction({
      contractId: DonationNearContract,
      method: "get_donations",
      args: {
        from_index: fromIndex.toString(),
        limit: donationsPerPage.toString(),
      },
    });
    return donations;
  };

  useEffect(() => {
    if (!signedAccountId) return;
    getDonations(currentPage).then((loadedDonations) =>
      setDonations(loadedDonations),
    );
  }, [signedAccountId, currentPage]);

  const goToNextPage = () => {
    setCurrentPage((prevPage) => prevPage + 1);
  };

  const goToPrevPage = () => {
    setCurrentPage((prevPage) => prevPage - 1);
  };

  return (
    <div>
      <table className="table table-striped">
        <thead>
          <tr>
            <th scope="col">User</th>
            <th scope="col">Total Donated Ⓝ</th>
          </tr>
        </thead>
        <tbody>
          {donations.map((donation) => (
            <tr key={donation.account_id}>
              <td>{donation.account_id}</td>
              <td>{utils.format.formatNearAmount(donation.total_amount)}</td>
            </tr>
          ))}
        </tbody>
      </table>
      <div>
        <button
          className={`btn btn-primary btn-sm ${currentPage === 1 ? "disabled" : ""}`}
          onClick={goToPrevPage}
          disabled={currentPage === 1}
        >
          Previous
        </button>
        <span className="mx-2">Page {currentPage}</span>
        <button
          className={`btn btn-primary btn-sm ${lastPage <= currentPage ? "disabled" : ""}`}
          onClick={goToNextPage}
          disabled={lastPage <= currentPage}
        >
          Next
        </button>
      </div>
    </div>
  );
};

export default DonationsTable;

```
  ```
import { utils } from "near-api-js";
import { useState } from "react";
import { useWalletSelector } from '@near-wallet-selector/react-hook';

import { DonationNearContract } from "@/config";

const DonationForm = ({ setMyDonation }) => {
  const { callFunction } = useWalletSelector();

  const [amount, setAmount] = useState(0);

  const setDonation = async (amount) => {
    let data = await fetch(
      "https://api.coingecko.com/api/v3/simple/price?ids=near&vs_currencies=usd",
    ).then((response) => response.json());
    const near2usd = data["near"]["usd"];
    const amount_in_near = amount / near2usd;
    const rounded_two_decimals = Math.round(amount_in_near * 100) / 100;
    setAmount(rounded_two_decimals);
  };

  const handleSubmit = async (event) => {
    event.preventDefault();

    let deposit = utils.format.parseNearAmount(amount.toString());

    callFunction({
        contractId: DonationNearContract,
        method: "donate",
        deposit,
      })
      .catch(() => {
        setMyDonation(-Number(amount));
      });
    
    setMyDonation(amount);
  };

  return (
    <>
      <div className="row mb-3">
        {[10, 20, 50, 100].map((amount) => (
          <div className="col-3" key={amount}>
            <button
              className="btn btn-outline-primary btn-block"
              onClick={() => setDonation(amount)}
            >
              $ {amount}
            </button>
          </div>
        ))}
      </div>
      <form onSubmit={handleSubmit}>
        <div className="mb-3">
          <label htmlFor="donation" className="form-label">
            Donation amount (in Ⓝ)
          </label>
          <div className="input-group">
            <input
              id="donation"
              value={amount}
              type="number"
              min="0"
              step="0.01"
              onChange={(e) => setAmount(e.target.value)}
              className="form-control"
            />
            <span className="input-group-text">Ⓝ</span>
          </div>
        </div>
        <button type="submit" className="btn btn-primary">
          Donate
        </button>
      </form>
    </>
  );
};

export default DonationForm;

```
</Language>

An interesting aspect of the donation example is that it showcases how to retrieve a result after being redirected to the
NEAR wallet to accept a transaction.

---

## Smart Contract

The contract exposes methods to donate tokens (`donate`), and methods to retrieve the recorded donations (e.g. `get_donation_for_account`).

<CodeTabs>
  <Language value="js" language="ts">
    ```
  init({ beneficiary }: { beneficiary: string }) {
    this.beneficiary = beneficiary
  }

  @call({ payableFunction: true })
  donate() {
    // Get who is calling the method and how much $NEAR they attached
    let donor = near.predecessorAccountId();
    let donationAmount: bigint = near.attachedDeposit() as bigint;

    let donatedSoFar = this.donations.get(donor, { defaultValue: BigInt(0) })
    let toTransfer = donationAmount;

    // This is the user's first donation, lets register it, which increases storage
    if (donatedSoFar == BigInt(0)) {
      assert(donationAmount > STORAGE_COST, `Attach at least ${STORAGE_COST} yoctoNEAR`);

      // Subtract the storage cost to the amount to transfer
      toTransfer -= STORAGE_COST
    }

    // Persist in storage the amount donated so far
    donatedSoFar += donationAmount
    this.donations.set(donor, donatedSoFar)
    near.log(`Thank you ${donor} for donating ${donationAmount}! You donated a total of ${donatedSoFar}`);

    // Send the money to the beneficiary
    const promise = near.promiseBatchCreate(this.beneficiary)
    near.promiseBatchActionTransfer(promise, toTransfer)

```
  </Language>
  <Language value="rust" language="rust">
    ```
    #[payable]
    pub fn donate(&mut self) -> String {
        // Get who is calling the method and how much NEAR they attached
        let donor: AccountId = env::predecessor_account_id();
        let donation_amount = env::attached_deposit();

        require!(
            donation_amount > STORAGE_COST,
            format!(
                "Attach at least {} yoctoNEAR to cover for the storage cost",
                STORAGE_COST
            )
        );

        let mut donated_so_far: NearToken = self
            .donations
            .get(&donor)
            .cloned()
            .unwrap_or(NearToken::from_near(0));

        let to_transfer = if donated_so_far.is_zero() {
            // This is the user's first donation, lets register it, which increases storage
            // Subtract the storage cost to the amount to transfer
            donation_amount.saturating_sub(STORAGE_COST).to_owned()
        } else {
            donation_amount
        };

        // Persist in storage the amount donated so far
        donated_so_far = donated_so_far.saturating_add(donation_amount);

        self.donations.insert(donor.clone(), donated_so_far);

        log!(
            "Thank you {} for donating {}! You donated a total of {}",
            donor.clone(),
            donation_amount,
            donated_so_far
        );

        // Send the NEAR to the beneficiary
        Promise::new(self.beneficiary.clone()).transfer(to_transfer);

        // Return the total amount donated so far
        donated_so_far.to_string()
    }

    pub fn get_donation_for_account(&self, account_id: AccountId) -> Donation {
        let amount = self
            .donations
            .get(&account_id)
            .cloned()
            .unwrap_or(NearToken::from_near(0))
            .as_yoctonear();

        Donation {
            account_id: account_id.clone(),
            total_amount: U128::from(amount),
        }
```
  </Language>
</CodeTabs>

<hr class="subsection" />

### 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/donation.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 variable `CONTRACT_NAME` in the `index.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 donations

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

  ```bash
  near view donation.near-examples.testnet get_donations '{"from_index": "0","limit": "10"}'
  ```
  </TabItem>

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

  ```bash
  near contract call-function as-read-only donation.near-examples.testnet get_donations json-args '{"from_index": "0","limit": "10"}' network-config testnet now
  ```
  </TabItem>
</Tabs>

<hr class="subsection" />

#### Get beneficiary

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

  ```bash
  near view donation.near-examples.testnet get_beneficiary
  ```
  </TabItem>

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

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

<hr class="subsection" />

#### Get number of donors

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

  ```bash
  near view donation.near-examples.testnet number_of_donors
  ```
  </TabItem>

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

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

<hr class="subsection" />

#### Get donation for an account

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

  ```bash
  # Require accountId
  near view donation.near-examples.testnet get_donation_for_account '{"account_id":<accountId>}'
  ```
  </TabItem>

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

  ```bash
  # Require accountId
  near contract call-function as-read-only donation.near-examples.testnet get_donation_for_account json-args '{"account_id":<accountId>}' network-config testnet now
  ```
  </TabItem>
</Tabs>

<hr class="subsection" />

#### Donate to the contract

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

  ```bash
  # Replace <accountId> with your account ID
  # Require deposit
  near call donation.near-examples.testnet donate --accountId <accountId> --deposit 0.1
  ```
  </TabItem>

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

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

<hr class="subsection" />

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

---

## Moving Forward

A nice way to learn is by trying to expand a contract. Modify the donation example so it accumulates the tokens in the contract
instead of sending it immediately. Then, make a method that only the `beneficiary` can call to retrieve the tokens.

<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`

:::