How to enable donations on any website using the MultiversX (Elrond) blockchain and EGLD tokens
Tags: astro, elrond, javascript, blockchain
Published: 2022-08-28 23:49:00

The MultiversX (Elrond) blockchain is a layer one solution that is performant and cheap. It is a complete blockchain solution so that anyone can build on it. 

I want to show you how simple it is to prepare a website widget that will allow getting donations in EGLD, which is the native token of the MultiversX (Elrond) blockchain. 

Please refer to the official MultiversX (Elrond) docs if you want to read more: [https://docs.multiversx.com/](https://docs.multiversx.com/).

For the demo and example, I will use [Astro](https://astro.build/) and one of its ready-to-use themes, and I will generate a static website. Why Astro? Because I think it will be quick to bootstrap a static blog example with it. But of course, it can be anything. Static site generator, Solid.js, what have you. For React-based websites please check the: [MultiversX (Elrond) Nextjs dApp template](https://github.com/xdevguild/nextjs-dapp-template). 

The point of this article is to show you how to prepare a simple widget, even on a static HTML website.

### First, let's answer the question, why do we want such a tool?

You probably know services like 'buy me a coffee'. They are excellent forms of catching attention and making your user base support you with real money. The same can work with cryptocurrencies. In this case, the EGLD token.

When it comes to blockchains and native tokens, there is always some community around them, especially when building tools, managing projects or writing articles, creating content on social media, etc. Such a user base requires a lot of custom websites, blogs, and landing pages. In such a case, you can always provide a way of supporting your project with real money.

### What will we build?

The app will be a static frontend-only website—just an example for demo purposes. It will be a blog where one of its pages will allow users to donate some EGLD tokens. The users will send them to a predefined wallet address using the [Maiar](https://maiar.com/) mobile wallet. If you don't know what it is, don't worry. You can read more about it on its website. It is a standard mobile app that serves as a crypto wallet that can store information about MultiversX (Elrond), Bitcoin, Ethereum, and Binance Coin assets.

So the functionality of our donate widget will be pretty straightforward. We will display the QR code where the users can log in with their Maiar mobile apps. Then they can prepare, sign, and send the transaction. We will predefine one price that users can choose for this demo. So I think it could be 0.5 EGLD. You will be able to change that or even add more options. All is just a static website and JavaScript. 

After the transaction is done, the user will get the 'receipt' with the link to the MultiversX blockchain explorer. Remember that the functionality here can be extended, and you can add more logic, like some giveaways, free stuff, newsletters signings, and whatever you only can think of. 

### How will we build it?

The MultiversX (Elrond) ecosystem is rich in a lot of developer tools. There is a Typescript/JavaScript SDK called [sdk-js](https://docs.multiversx.com/sdk-and-tools/sdk-js/), or I should write the set of libraries, not only the sdk-js. So that's cool, but the problem here is that the SDK and all the libs have a lot of functionality that we don't need, and they require building steps to make them work with the browser. This is why the [elven.js](https://github.com/juliancwirko/elven.js) tool exists.

The elven.js is a script to be used in browsers. It is a simple wrapper script over the sdk-js libraries. It is prebuilt, so you don't need any build steps. All in one, plug-n-play solution. We will use it for this task. Read more about elven.js in this introduction: [How to Interact With the MultiversX (Elrond) Blockchain in a Simple Static Website](https://hackernoon.com/how-to-interact-with-the-elrond-blockchain-in-a-simple-static-website).

### Astro initialization?

First, we need a website. As mentioned above, I will use [astro.build](https://astro.build/) with a default blog template. You can scaffold the project using npm with the command:

```bash
npm init astro -- --template blog
```
You will get a fully functional blog with a simple design, but this isn't important now. For simplicity, let's clean the index page content, and I think we can use the index page and implement the donate functionality there. You can also create a separate page for that. It doesn't matter in this case. The whole process will be similar.

You will find the whole demo website with the widget in the [GitHub repository](https://github.com/juliancwirko/elrond-donate-widget-demo).

Ok, now let's see how to use the elven.js script and build the donate widget.

### Elven.js initialization

In a standard static website, you can import components from the CDN or local file. Check the example here: [Elven.js (StackBlitz)](https://stackblitz.com/edit/web-platform-d4rx5v?file=index.html%3AL96-L96).

But with Astro, we will install elven.js using npm. You can add it by:

```bash
npm install elven.js
```
Remember to run the command in the newly created Astro project.

After the elven.js is installed, we need to initialize it. I will create a separate JavaScript file called `elven-init.mjs`. I will put it in the `pages` folder, next to our index page. This will be our whole logic for the donate widget. Then in the `index.astro`, I will import it. So the index file will look similar to this: 

```html
---
import BaseHead from '../components/BaseHead.astro';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
import { SITE_TITLE, SITE_DESCRIPTION } from '../config';
---

<!DOCTYPE html>
<html lang="en-us">
    <head>
        <BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
    </head>
    <body>
        <Header />
        <main>
            <p><strong>MultiversX (Elrond) donate widget with <a href="https://github.com/juliancwirko/elven.js">Elven.js</a></strong></p>
            <p><strong>No real money here!</strong></p>
            <p>All works on the devnet, but it is ready for mainnet usage!</p>
            <div id="elrond-donate-widget-container">
            </div>
        </main>
        <Footer />
        <script>
            import './elven-init.mjs'
        </script>
    </body>
</html>
```

As you can see here, we have two crucial code sections. The empty div with the id `elrond-donate-widget-container` and then the script import. We are importing the previously created `elven-init.mjs` file.

Let's see what should land in the `elven-init.mjs` custom file.

First of all, we need to import the required components from `elven.js`:

```javascript
import {
  ElvenJS,
  Transaction,
  Address,
  TransactionPayload,
  TokenPayment,
} from "elven.js";
```
Then below that, we will need to initialize the `elven.js`. We can do this like that:

```javascript
const initElven = async () => {
  await ElvenJS.init({
    apiUrl: "https://devnet-api.multiversx.com",
    chainType: "devnet",
    apiTimeout: 10000,
    onLoggedIn: () => { uiLoggedInState(true); uiSpinnerState(false); },
    onLoginPending: () => { uiSpinnerState(true); },
    onLogout: () => { uiLoggedInState(false); uiSpinnerState(false); },
    onTxStarted: () => { uiSpinnerState(true); },
    onTxFinalized: (tx) => { tx?.hash && updateTxHashContainer(tx.hash); uiSpinnerState(false); }
  });
};
initElven();
```
The `ElvenJS.init` function is async, so we need to wrap it and call the wrapper function below. The `ElvenJS.init` takes the network configuration—the API endpoint, chain type, and API timeout. The `uiLoggedInState` function is a helper function responsible for UI state changes. It will also be added to the `elven-init.mjs` for simplicity, but you can keep it in a separate file. It is a simple DOM manipulation function and looks like:

```javascript
const uiLoggedInState = (loggedIn) => {
  const loginMaiarButton = window.document.getElementById(
    "button-login-mobile"
  );
  const logoutButton = document.getElementById("button-logout");
  const txButton = document.getElementById("button-tx");
  if (loggedIn) {
    loginMaiarButton.style.setProperty('display',"none");
    logoutButton.style.setProperty('display', 'block');
    txButton.style.setProperty('display', 'block');
  } else {
    loginMaiarButton.style.setProperty('display',"block");
    logoutButton.style.setProperty('display', 'none');
    txButton.style.setProperty('display', 'none');
  }
};
```

### Login using elven.js

After the initialization, we can start building the login functionality. We need a couple of buttons in our `index.astro` page file. As you probably know already, looking at the `uiLoggedInState`. 

We can add them below the `elrond-donate-widget-container` div. It will look like this: 

```html
<button class="button" id="button-tx" style="display: none;">Donate!</button>
<button class="button" id="button-login-mobile" style="display: none;">Connect!</button>
<button class="button" id="button-logout" style="display: none;">Disconnect</button>
```

So we have three buttons, all are hidden initially. In the init function, we set the UI state, so all will be displayed as it should be. We will also need some CSS for the buttons and the containers, but let's leave it now. You can check that in the repository.

Ok, now that we have the button for triggering the login with Maiar mobile app, let's add a click listener. It will initialize the Maiar mobile app login, showing the QR code, and then you will need to scan it with your Maiar wallet. Don't worry. You can also do this on the devnet. You will only need some EGLD from the MultiversX (Elrond) faucet. You will find it in the MultiversX (Elrond) Web Wallet. Choose the [devnet wallet](https://devnet-wallet.multiversx.com/) or [mainnet wallet](https://wallet.multiversx.com/) if required. Of course, on the mainnet, you will need to buy some EGLD. You can log in there using the Maiar mobile app the same way we will use it for the donate widget. In the devnet wallet, you will find the faucet option to get 30 fake EGLD tokens.

Ok, so let's go back to our login button and click listener. It will look like this: 

```javascript
document
  .getElementById("button-login-mobile")
  .addEventListener("click", async () => {
    try {
      await ElvenJS.login("maiar-mobile", {
        qrCodeContainerId: "elrond-donate-widget-container"
      });
    } catch (e) {
      console.log("Login: Something went wrong, try again!", e?.message);
    }
  });
```
The main function here is the `ElvenJS.login('maiar-mobile', {...})`.  What is important here is that we will pass the id for the QR code container. In our case, it is `elrond-donate-widget-container`. We also used another UI helper here with the loading spinner text. Don't worry about it. It will also be in the `elven-init.mjs` file. It is responsible for UI loading states, indicating, and nothing more.

The Maiar mobile auth uses WalletConnect under the hood. This is why we need some callbacks here when we log in and out (This will probably be moved to the init function in the future).

### Make a transaction with elven.js

After the login is triggered, you will get the QR code. When you confirm the login using the Maiar mobile app, you will get a button to make the transaction. The transaction trigger code looks like this:

```javascript
const egldTransferAddress = 'erd17a4wydhhd6t3hhssvcp9g23ppn7lgkk4g2tww3eqzx4mlq95dukss0g50f';
const donatePrice = 0.5;

document.getElementById('button-tx').addEventListener('click', async () => {
  updateTxHashContainer(false);
  const demoMessage = 'MultiversX (Elrond) donate demo!';

  const tx = new Transaction({
    nonce: ElvenJS.storage.get('nonce'),
    receiver: new Address(egldTransferAddress),
    gasLimit: 50000 + 1500 * demoMessage.length,
    chainID: 'D',
    data: new TransactionPayload(demoMessage),
    value: TokenPayment.egldFromAmount(donatePrice),
    sender: new Address(ElvenJS.storage.get('address')),
  });

  try {
    await ElvenJS.signAndSendTransaction(tx);
  } catch (e) {
    throw new Error(e?.message);
  }
});
```
A couple of things here. First, we have two variables, the wallet address to which the EGLD tokens will be sent and the value which will be sent. We are preparing the transaction here using the `Transaction` class. We need to pass on a couple of things here. The address, the value, gas limit, nonce, etc. All of these are wrapped with helpers that are exported from sdk-js SDK. You will find more info about them in the [sdk-js cookbook](https://docs.multiversx.com/sdk-and-tools/sdk-js/sdk-js-cookbook). Oh, and we also use `ElvenJS.storage` to get some data from the localStorage. This is provided by elven.js.

Then it is enough to use the `ElvenJS.signAndSendTransaction(tx)` to sign and send the transaction. You will need to approve the transaction in the Maiar mobile app wallet.

After the transaction is ready, you will get the transaction hash, and in this demo, there will be a link to the MultiversX (Elrond) explorer. We use the `updateTxHashContainer` UI helper to build and update the UI. You will find it also in the `elven-init.mjs`.

### Logout

There is, of course, an option to log out and clear all the data in the browser. To do that, you will need to use:

```javascript
document.getElementById('button-logout').addEventListener('click', async () => {
  try {
    await ElvenJS.logout();
  } catch (e) {
    console.error(e.message);
  }
});
```

So we use `ElvenJS.logout()` and then trigger all the UI helpers. 

This is all that you need to prepare the widget. Please check it live at: [elrond-donate-widget-demo.netlify.app](https://elrond-donate-widget-demo.netlify.app/).

### How to use it with the mainnet?

You would need to do a couple of things to use it on the MultiversX (Elrond) mainnet with real EGLD. First of all, remember to change your wallet address. Of course, you can have the same address on the mainnet, but be sure you have used the proper one.

Then you would need to configure your ElvenJS.init function like that:

```javascript
await ElvenJS.init({
  apiUrl: 'https://api.multiversx.com',
  chainType: 'mainnet',
  apiTimeout: 10000,
  onLoggedIn: () => { uiLoggedInState(true); uiSpinnerState(false); },
  onLoginPending: () => { uiSpinnerState(true); },
  onLogout: () => { uiLoggedInState(false); uiSpinnerState(false); },
  onTxStarted: () => { uiSpinnerState(true); },
  onTxFinalized: (tx) => { tx?.hash && updateTxHashContainer(tx.hash); uiSpinnerState(false); }
});
```

And that's it. You are ready to go with the mainnet.

### Summary

A simple donate widget shows how helpful is the elven.js script. It can do much more, you can not only transfer EGLD tokens, but you can also make transactions to your custom smart contracts. And there will be more, all simplified.

Check out these links:
- [elvenjs.com](https://www.elvenjs.com) - docs and examples
- [elven.js](https://github.com/juliancwirko/elven.js) - GitHub repository
- [MultiversX (Elrond) donate widget](https://github.com/juliancwirko/elrond-donate-widget-demo) - the repository of described here demo, with a live website link

Let me know what you think about elven.js and this example. You will find me on [Twitter](https://twitter.com/theJulianIo). Also, check out my website: [julian.io](https://www.julian.io/).