Did you know that Chrome and other browsers have a built in speech-to-text API?
I thought I could use this to create an online chat room using web3 serverless technology. The result…
https://jamesbachini.github.io/Talking-Smart-Contracts

The frontend is hosted on Github pages and the backend is just a permissionless, immutable smart contract hosted on Stellar, a decentralized blockchain network.
Welcome to the future, let’s dive in.
The ChatRoom Contract
This contract only needed to be simple and fire an event whenever a public function is called.
#![no_std]
use soroban_sdk::{contract, contractimpl, Address, Env, Symbol, symbol_short};
#[contract]
pub struct TalkingContracts;
#[contractimpl]
impl TalkingContracts {
pub fn talk(env: Env, me: Address, msg: Symbol) {
me.require_auth();
env.events().publish((me.clone(),), msg);
}
}
We are accepting an address and message in the form of a Symbol. This is then pushed out as an event with the topic set to the address and the value set to the message.
The code for this along with unit tests is all open source on Github:
https://github.com/jamesbachini/Talking-Smart-Contracts/blob/main/contract/src/lib.rs
I deployed this using the Soroban Playground web app at: https://soropg.com/?codeUrl=https%3A%2F%2Fraw.githubusercontent.com%2Fjamesbachini%2FTalking-Smart-Contracts%2Fmain%2Fcontract%2Fsrc%2Flib.rs

Backend storage done. Now let’s move on to the frontend.
I’ll go through the highlights but the full code is here: https://github.com/jamesbachini/Talking-Smart-Contracts/blob/main/index.html
We are importing the Stellar SDK and then using it to generate a new address each time someone refreshes the page. This is then funded with tesnet XLM using friendbot.
const kp = StellarSdk.Keypair.random();
await fetch(`https://friendbot.stellar.org/?addr=${kp.publicKey()}`);
We then have this function that gets pooled for new messages once every ten seconds:
async function fetchMessages () {
try {
const latest = await rpc.getLatestLedger();
const fromLedg = latest.sequence - 8000;
const evResp = await rpc.getEvents({
startLedger: fromLedg,
filters: [{ type: 'contract', contractIds: [contractId] }],
});
const msgs = evResp.events.map(ev => {
const hexPub = ev.topic[0]._value._value._value.toString('hex');
const stellar = StellarSdk.StrKey.encodeEd25519PublicKey(hexToUint8Array(hexPub));
return {
txHash: ev.txHash?.toString?.(),
addr : stellar,
msg : ev.value?._value?.toString?.().split('_').join(' ')
};
});
renderChat(msgs);
} catch (e) {
console.error('fetchMessages() failed', e);
}
}
And finally the sendMessage function to put messages into transactions and send them to a RPC node, which acts as our entry point to the decentralized network.
async function sendMessage (spokenText, keypair) {
const sanitizedStr = spokenText
.split(' ').join('_')
.replace(/[^a-zA-Z0-9_]/g, '')
.slice(0, 32);
const account = await rpc.getAccount(keypair.publicKey());
let tx = new StellarSdk.TransactionBuilder(account, {
fee: StellarSdk.BASE_FEE,
networkPassphrase
})
.addOperation(
contract.call(
'talk',
StellarSdk.Address.fromString(keypair.publicKey()).toScVal(),
StellarSdk.nativeToScVal(sanitizedStr, { type: 'symbol' })
)
)
.setTimeout(30)
.build();
tx = await rpc.prepareTransaction(tx);
tx.sign(keypair);
const res = await rpc.sendTransaction(tx);
console.log('☑ Message sent. txHash:', res.hash);
return res.hash;
}
This is a simple, fun example of what is possible with web3 serverless architecture. No databases, no servers, just a single index.html file and a 13 line smart contract ❤️