This tutorial explains how to build an application that listens for chat messages and parses them when they arrive. When it receives a chat message with a special message inside, it sends its own transaction out onto the network to celebrate.
This covers sending and receiving transactions, UI components and the /lib
sub-directory of your module.
Navigate into your /mods
directory and create a folder with the name tutorial02
. Within that directory create the file tutorial02.js
.
Copy the text below into this this file:
var ModTemplate = require('../../lib/templates/modtemplate');
const MainUI = require('./lib/main');
class Tutorial02 extends ModTemplate {
constructor(app) {
super(app);
this.name = "Tutorial02";
this.slug = "tutorial02";
this.description = "Transactions and UI Components";
this.ui = new MainUI(this.app, this);
return this;
}
}
module.exports = Tutorial02;
Notice above the addition of a UI component named MainUI
on line 2, which pulls code from the ./lib/main
.
Saito modules can include a /lib
directory which contains subclasses and template files, which is where our UI component will be created later in this tutorial.
In our constructor, we assign this.ui
to the MainUI
component (line 14). We then update the default render()
function (by including the following modified render()
definition in our Tutorial02
class) to make this UI component to render itself to the screen:
async render() {
this.ui.render();
}
The second function we will add is responsible for sending a transaction, and is a useful reference for the data structure of transactions and the steps required to form and propogate them.
See below for a breakdown of what's going on here.
async sendTutorial02Transaction() {
let newtx = await this.app.wallet.createUnsignedTransaction();
newtx.msg = {
module: this.name,
data: {
random : Math.random()
}
};
await newtx.sign();
this.app.network.propagateTransaction(newtx);
}
this.app.wallet.createUnsignedTransaction()
We use the function createUnsignedTransaction()
from app.wallet
to create and return a transaction.
This function is normally provided with the address to which you want to send the transaction, and can optionally be provided with fee information. Since none of this information is being provided it defaults to creating a transaction that is addressed to the sender.
newtx.msg = {
module: this.name,
data: {
random : Math.random()
}
};
We then fill out the msg
field to contain the information we want to include in the transaction. You can provide whatever information you want -- in this case we'll just generate a random number so that we can see our application is updating and sending a unique transaction every time it is asked.
await newtx.sign();
this.app.network.propagateTransaction(newtx);
Finally we sign the transaction before sending it out into the network. propagateTransaction()
lives on the network object and broadcasts a transaction to any peers that want to receive transactions.
app
ObjectNote that most of the functions that our module needs live on the app
object submitted as input to the constructor. app
contains a number of subclasses (.wallet
, .storage
, .network
, .blockchain
) containing functions to perform useful Web 3 procedures like broadcasting transactions or returning addresses.
If you are creating a transaction, for instance, you'd want functions that live in the .wallet
object.
Recall that our UI component was defined via:
const MainUI = require('./lib/main');
so the next step is to create a /lib
directory in our module folder and populate it with a file named main.js
.
The content of /lib/main.js
is provided below:
const Tutorial02MainTemplate = require('./main.template');
class Tutorial02Main {
constructor(app, mod) {
this.app = app;
this.mod = mod;
this.name = "Tutorial02Main";
}
render() {
if (document.querySelector("body")) {
document.querySelector("body").innerHTML = Tutorial02MainTemplate();
}
let btn = document.querySelector('.tutorial02-button');
if (btn) {
btn.onclick = (e) => {
alert("sending a transaction!");
this.mod.sendTutorial02Transaction();
}
}
}
}
module.exports = Tutorial02Main;
UI Components in Saito typically have two functions: a render(app, mod)
function which writes content to the screen, and an attachEvents(app, mod)
function for UI logic.
In this situation our module is so simple we only define render()
.
Note that this main.js
file relies on one more file: main.template.js
, which simply defines the HTML which will structure the UI. The contents of /lib/main.template.js
are:
module.exports = () => {
return `
<div id="tutorial02-main" class="saito-container">
<h2>Click to Send Transaction</h2>
<input type="button" class="tutorial02-button" value="Click Me!" />
</div>
`;
};
When the render()
function is executed, the module checks for the existence of an HTML document and writes the HTML returned from its template file into the BODY of that document. This includes a button with the class tutorial02-button
to which it attaches the event.
Once the button is clicked, the code in our UIComponent executes and we trigger an alert to notify the user. After that, we call the function sendTutorial02Transaction()
in our main module file. This way of doing things allows UI Components to access any functions that exist in their application module, as well as any functions that are provided by the core Saito classes.
Recompile your application and visit the /tutorial02
module in your browser. If you are running a standard local node, you can navigate to it via: http://localhost:12101/tutorial02.
You will see the button appear and if you click on it you'll get the alert message and your browser will send a transaction into the network.
If you'd like to confirm your transaction was sent, make sure you are running the explorer
module. Visit to see a list of the latest blocks your machine has produced.
On a standard local node, your block explorer can be found at http://localhost:12101/explorer.
You should be able to navigate to the latest block and will be able to find your transaction listed in that block, as per the image above. You should be able to see the data that your module inserted into your transaction has been included and can be viewed on the blockchain.
In our next tutorial, we will modify this application to show how to listen to these transactions and process then when we receive them over the network.
tutorial02
code can be referenced here.