How to enable donations on any website using the MultiversX (Elrond) blockchain and EGLD tokens
Julian.io
Posted on August 28, 2022
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/.
For the demo and example, I will use Astro 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.
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 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, 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 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.
Astro initialization?
First, we need a website. As mentioned above, I will use astro.build with a default blog template. You can scaffold the project using npm with the command:
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.
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).
But with Astro, we will install elven.js using npm. You can add it by:
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:
---
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
:
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:
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:
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:
<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 or mainnet wallet 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:
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:
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. 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:
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.
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:
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 - docs and examples
- elven.js - GitHub repository
- MultiversX (Elrond) donate widget - 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. Also, check out my website: julian.io.
Posted on August 28, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.