A 3.5MB Web3 Messenger: Indie Development on a Zero Budget

от автора

A WONDERFUL FUTURE

Technology is advancing at an astonishing rate. It seems like only yesterday that domestically produced KR1810VM86M microprocessors with a clock rate of just 8 megahertz appeared, forever dividing our lives into “before” and “after.” And a set of eight K565RU7 memory chips (similar to the Intel 41256) provided a RAM capacity of 256 kilobytes, a fantastic value for its time.

Back then, it seemed that with such rapid development, humanity was about to transcend the galaxy and rush to other worlds. Today, these figures only evoke a smile, but it was precisely with such advances in computing technology in the 1980s and 1990s that our journey into the future world of ones and zeros began.

I remember how, a couple of years after the release of OS DOS-6.22, I started the Windows 95 installation for the first time. I set my alarm two hours ahead so as not to miss the spectacular installation completion window, on my first DX386 with 40 MHz in turbo mode, and went to bed.

A little later, I was writing my first programs in Turbo Basic. And mind you, they were programs, not applications. After all, they didn’t require any drivers or installation packages. Everything ran in interpreter mode, that is, within the programming environment itself. The size of such programs never exceeded a few kilobytes.

HIGHER AND HIGHER

Time passed. The technological boom seemed endless. Processors, memory, the internet—everything was developing rapidly, and no one thought about limitations anymore. The first instant messengers appeared. ICQ, with its unique “cuckoo,” was heard in every office. I remember at some companies, department heads even fined their employees for using instant messengers on their work computers. The first programs for automating enterprise accounting appeared. 1C seemed to be familiar to everyone. So what, a built-in programming language with a Russian dialect—that’s no joke. Those were the days. Everything was spinning and sparkling inside system units, proudly standing on the shelves of computer stores. Gone are the Trident TVGA and Cirrus Logic computers, beloved by many gamers, with one megabyte of memory, Creative Sound Blaster audio, and DOOM for DOS/4GW.

Well, never mind the hardware. But let’s look at what’s happened to the software. It’s grown to gigantic proportions, eating up all the free space on the hard drive. I remember playing Alladdin before, and a few floppy disks were enough to load the game onto a virtual drive. Now, GTA5 requires about 100+ GB just for the minimum installation, and GTA6 is on the way. But I’m no longer a gamer; the times have changed.

Having written a bunch of applications in Visual Basic 6, I was shocked by the release of the new version with the .NET prefix, thinking Microsoft had gone crazy. What .NET? Isn’t what’s available enough for anyone? Now a modern studio from those same Microsoft developers weighs in at about 220 GB, and that’s despite the fact that Turbo Basic, which essentially made me a programmer, weighed only 950 kilobytes. That’s technology in all its glory, my friends.

CLEVER AND BOLD

Modern programmers are now releasing programs that consume hundreds of megabytes of memory and require powerful processors for simple tasks. This isn’t the 1990s, when a game engine, drivers, and the game itself had to fit into 640 KB of MS-DOS RAM.

Why is this happening? Is it the developer’s laziness or a conscious economic and technical choice. There are several reasons:

  • For businesses, it’s more important to launch a product before competitors.

  • Why use vector graphics if the user has 8 GB of RAM?

  • Writing cross-platform applications for different operating systems.

  • Why write something from scratch when there are already existing library support sets?

  • They write without optimization just to deliver the project, and then they’ll be screwed.

These days, installing a new application or deploying a cloud service is quite easy. But these developers, despite the fact that Nginx, Python, Node.js, and other applications weigh pennies, are often thousands of times larger. Consumers of such software are frankly reluctant to install new apps on their smartphones, complaining about a lack of free space.

There’s a strange trend: the larger the app size, the higher the hardware requirements, and vice versa: the more powerful the hardware, the larger the apps become. But when will this resource waste reach its limit?

I’m providing an example of the “Hello World” app code in Java in Android Studio, which, after building, weighs in at about 7 megabytes. But if you remove all the junk from the project, the size drops to 42 kilobytes!

package com.example.helloworld;import android.os.Bundle;import android.util.Log;import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {    private static final String TAG = "MyActivityTag";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.printStackTrace(); // Проверяем базовый класс        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        // Вывод строки "Hello World" в консоль Android (Logcat)        Log.d(TAG, "Hello World");    }}

I understand that many developers will probably start throwing slippers at me now. How can this be, they’ll say, after all, AppCompat + Materials is convenient, fast, and beautiful, plus it ensures backward compatibility across devices. For example, someone on Android 4.4 wants to use a modern app, but without AppCompat it won’t work. An exception will be thrown, and the app will crash. That’s right, gentlemen, it will crash. But the question is, who will want to use KitKat in 2026? The answer is simple: Google itself. It’s Google that’s doing everything it can to make you use its “Bibles” and bloat your apps. It’s tomorrow’s bread and butter for them. You bloat your apps, and Google is readying the next device with more memory.

Take Google’s Material Design as an example. This system has everything: ready-made component sets, shadow styles, and graphic assets. It sounds great, but the basic interface can be designed manually using standard tools. In this case, the application size will increase by only 200-300 kilobytes (the size of a single JPEG file), and you won’t have to burden your build with an extra 5 megabytes of library code. Sounds brilliant, right?

The same applies to working with sockets, databases, and cryptography. Low-level tools for these tasks weigh next to nothing, while providing maximum performance and reliability. For example, the OkHttp library is a powerful network engine that handles all the dirty work of working with sockets. Popular tools like Retrofit, Ktor Client, or Volley, on the other hand, are essentially just high-level add-ons. While convenient, they don’t add anything new to the application’s functionality.

I hope these examples have clearly illustrated the essence of true optimization in application development. There’s no point in measuring the performance of your code if the application itself is made of cinder blocks.

TELEGRAMS AND EVERYTHING…

Let’s return to the original topic. Since the article is titled “Web3 Messenger…,” I’ll smoothly get to the point, describing ready-made solutions designed for messaging. These are the so-called instant messengers. Take the beloved Telegram, for example. Its package size is about a hundred megabytes. But what’s inside? Pavel Durov, the author of the Telegram project, proudly declared that they don’t use third-party libraries and write all the components themselves. Yes, that’s true, and deserves respect. But there’s one small detail here. Why even write everything from scratch? After all, the operating system itself already has default modules that you can simply pull into your application. But this is the company’s policy, and therefore, from their perspective, it’s correct.

I’ll give you another example. When I first started developing my messenger, I needed to implement video calls over the P2P protocol. The first thing I looked at was WebRTC technology, as it seemed the ideal solution for video communication. But when I saw the size of this SDK, I was horrified – the raw size was almost 50 megabytes. Even using the stripped version, I still gained an extra 25 megabytes in my package. Even writing my own WebRTC engine in C++ isn’t guaranteed to be any smaller.

I chose the path of least resistance and maximum impact. I figured, since the WebRTC engine is built into the Chrome browser on Android, why not connect to it directly? By attaching Chrome to a WebView, I got this beautiful solution…

webView.setWebChromeClient(new WebChromeClient() {  @Override  public void onPermissionRequest(final PermissionRequest request) {    runOnUiThread(() -> request.grant(request.getResources()));  }});

Next, I initiated a connection to this library through a separate JavaScript class and voila, everything worked without problems:

    class CallManager {        constructor(localVideoSelector, remoteVideoSelector) {            this.localVideo = document.querySelector(localVideoSelector);            this.remoteVideo = document.querySelector(remoteVideoSelector);            this.peerConnection = null;            this.localStream = null;            this.remoteStream = null;            this.pendingCandidates = [];            this.config = { iceServers: [{ urls: "stun_address" }] };        }      //...

If you’re a Java programmer, and I’m sure you are, you’ll notice that the package size with this approach will increase by exactly “0” bytes instead of 25-50 megabytes.

Here’s a list of installation package sizes (APKs) for various messengers:

  • Telegram = 100 МБ.

  • WhatsApp = 112 МБ.

  • Viber = 167 МБ.

  • Signal = 65 МБ.

  • Discord = 130 МБ.

  • Elyon (Accord) = 3.5 МБ. (developer your humble servant)

With a total app size of 3.5 megabytes, I managed to squeeze in not only video calls but even my own crypto economy. Furthermore, I also implemented a full-fledged messenger with private channels, bots, and even built-in artificial intelligence. All this was achieved through integrations, external APIs, and hand-written code. The messenger’s capabilities were significantly expanded through the use of user bots. Interaction with external services turned the app into a platform with unlimited possibilities. And this, my friends, was all done on a zero-budget basis. I acted as both the project’s client and its implementer.

Web-3: What is it and why is it needed?

So, a little background. Web3 is a concept for a new generation of the internet. Its core idea is the decentralization of computing power. This internet allows, instead of using a single powerful server, to distribute the load across other computing units. Therefore, we are now dealing with blockchain technologies, where cryptographic addresses or wallets are used instead of traditional accounts (phone numbers or email addresses).

The most important criteria for the transition to Web3 are its speed and reliability. The integrity of all transactions conducted via blockchain allows, for example, financial transactions to be recorded without fear of counterfeiting.

Cryptocurrency itself is simply a consequence of the development of blockchain technology. It’s not hard to guess which came first: blockchain or Bitcoin.

HOW I USE IT

While developing my messenger, I faced many challenges. One of them was how to implement an internal payment system to provide access to restricted user resources. In other words, I needed to come up with a mechanism for monetizing paid subscriptions to private channels and other paid app services.

Access to such channels is usually closed to regular users. To view the content, you’ll need to pay for access. But even if the user’s wallet is empty, they can still receive donations or earn a few coins within the app. There are several ways to do this. One is to collect rewards from prize payouts by playing built-in games.

It’s clear that dealing with real money is difficult and dangerous. You need to register a business, calculate taxes, keep track of all users, and then transfer personal data to the relevant authorities. But I took a different approach. I launched my own crypto economy and issued my own “bitcoin” right within the messenger.

In reality, it all seems quite simple. Anyone can buy nominal cryptocurrency through a terminal at a nearby supermarket. For example, you can exchange Ethereum for the app’s coin by sending the Ethereum to the smart contract specified in the messenger profile. This smart contract will automatically transfer the received amount to the user’s wallet in the desired currency. The credited amount will now appear in the user’s account. There is no commission in the traditional sense, but there is a fee for so-called “gas.” “Gas” or “fuel” is the fee for a completed transaction to the blockchain itself in Ethereum. Incidentally, this is what miners earn when they register other people’s transactions, while chugging away on their video cards in the kitchen. “Gas” costs pennies. Even a single cent on the balance is enough for dozens of such transactions.

So, when a user subscribes to a private (paid) channel, their coins are deposited into the channel owner’s wallet. The beauty of web3 technology is that all transactions can be viewed on any blockchain online by entering the desired wallet address. Moreover, it’s transparent for all transactions over any period of time. No one knows the true wallet owners; it’s an anonymous system. Therefore, no restrictions apply to them.

Below is an example of how I use web3 for some tasks:

An example of creating a crypto wallet:

public string CreateWallet(){    var ecKey = EthECKey.GenerateKey();    string privateKey = ecKey.GetPrivateKey();    var account = new Account(privateKey);    return $"{account.Address}:{privateKey}";}

Here, after generating a unique key, a private key is created. The final wallet address is then extracted from the private key.

Now things get a little more complicated. Let’s get the balance (remaining balance) of the game contract wallet:

using System;using System.Numerics;using System.Threading.Tasks;public async Task<long> GetTreasuryBalance(){    var web3 = new Web3(url-RPC-server);    string treasuryBalAbi = "[здесь специальный код интерфейса смарт-контракта]]";    var treasuryBalFunc = web3.Eth.GetContract(treasuryBalAbi, GAMES_CONTRACT).GetFunction("treasuryBalance");    BigInteger totalTreasuryTokens = await treasuryBalFunc.CallAsync<BigInteger>();    decimal balanceDecimal = Web3.Convert.FromWei(totalTreasuryTokens);    long integerBalance = (long)Math.Truncate(balanceDecimal);        return integerBalance;}

As you can see from the code above, a special variable type, BigInteger, is used. Since web3 doesn’t support floating-point values, an integer type with a large number of zeros is used here. For example, my contract uses a whopping 18 zeros after the one. To reflect a balance of one coin, I would write: 10000000000000000000. This is a reversible value that can easily be converted to a decimal.

BUILT-IN WEB3 GAMES

Now I’ll tell you a little about a special feature that helps users not only spend their coins but also earn them. Considering that my cryptocurrency is virtual money and not real money, I decided to create online games where players can receive rewards for their winnings. For example, if you have a zero balance, then when you launch a game like roulette, you’ll enter demo mode. You can play endlessly, and it won’t affect your wallet balance. If you win ten times your initial deposit in demo mode, you’ll receive one real coin in your personal wallet. You can then play with the coins you’ve earned, which will have a real impact on your bankroll.

Currently, I’ve written several fairly simple arcade games in HTML format. Some of them have already been integrated with Web3. The following games are currently available:

  • BlackJack is an arcade card game (similar to “Ochko” or “21”);

  • Roulette is reminiscent of casino roulette with a wheel and bets;

  • Slots is a rather dumb game, in my opinion, where you spin three wheels for luck.

All these games were written in a couple of evenings, so please don’t criticize me too much for the poor graphics. The goal was to integrate them into the messenger economy and make betting possible. By the way, if you’re interested in improving these games or writing your own, I’d be happy to collaborate. Cookies and coffee are on me.

Below is a screenshot of the game “BlackJack.”

SECRET CHATS

My messenger is very different from the aforementioned services. One of its distinguishing features is the absence of a message cache on the backend. In other words, the service doesn’t store any user correspondence at all. The database only stores a compressed message digest, which is deleted immediately after the subscriber launches their messenger and reads the message addressed to them.

This approach prevents the database from becoming bloated and users from accidentally leaking their correspondence data. However, to ensure absolute secrecy, I also implemented an E2E encryption subsystem. This method uses cryptographic keys to encrypt messages and then transmits them between two users.

It operates on the principle of “end-to-end encryption” and works as follows. Private keys are stored on each user’s smartphone in a closed TEE (Trusted Execution Environment) storage. Public keys are stored on the backend server. As soon as one user activates a “secret chat,” their app immediately requests their interlocutor’s public key. The user then encrypts their message with their interlocutor’s public key and sends it to the server. Once the user logs in, they retrieve this encrypted message and decrypt it with their private key.

The rule here is that only a private key can decrypt a message encrypted with a public key. In practice, the keys don’t encrypt the message itself, but rather the password for another encryption algorithm, which encrypts the message itself. For example, a message is encrypted with the AES algorithm with a password, and the password itself is encrypted with the public key using the RSA algorithm. As a result, two messages are transmitted to the server: the first is the message encrypted with the AES algorithm, and the second is the AES password encrypted with the RSA algorithm. Or in another order, it doesn’t matter. This is a classic end-to-end encryption scheme. In this case, no one but the recipient will be able to read the encrypted message. So Pavel Durov was right when he said he doesn’t have the keys to users’ encrypted messages. They are stored by the users themselves.

Below is a sample code for generating keys and writing them to storage:

KEYS_HAS_UPDATED = true;try {    KeyPairGenerator generator = KeyPairGenerator.getInstance(            KeyProperties.KEY_ALGORITHM_RSA,             "AndroidKeyStore"     );    generator.initialize(new KeyGenParameterSpec.Builder(            "ALIAS",             KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_SIGN)            .setKeySize(2048)             .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)            .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)            .build());    KeyPair keyPair = generator.generateKeyPair();} catch (Exception e) {    e.printStackTrace(); }

CONCLUSIONS

The main idea behind this article was to introduce the reader to the practical use of new blockchain-based Web3 technology, using my messenger “Elyon” as an example. I tried to explain how easy it is to implement your own economy in your projects and make them paid. With their own smart contract with their own cryptocurrency, any developer can implement paid services without interacting with federal payment systems.

The exchange handles deposits and withdrawals of real money. There, you buy nominal cryptocurrency and exchange it for any other token by specifying the contract address. Withdrawals are roughly the same. You submit a withdrawal order, pay a nominal transaction fee, and transfer the coins back to your real crypto wallet. Then, through the same exchange, you can withdraw your coins in any currency worldwide!

I also shared my perspective on why apps can be unnecessarily large and pointed out the shortcomings of developers writing clean code instead of using complex libraries. I believe that the usability of apps depends largely on their optimization, which is often ruined by excessive use of add-ons [IMHO].

If you’re interested in this topic and would like to join my project, I’d be delighted. Send me a private message, and we’ll discuss the details.

P.S.

My messenger still has many interesting features, but describing them all in one article would be too expensive. You can download the working APK file from my project website and see for yourself that everything works perfectly. This project is fully functional and awaits its regular users. There is no content moderation, no censorship, and no intrusive rules.

Please don’t be too harsh on me for the unprofessional presentation. I’m not a writer, but I wanted to share my ideas with the Khabr audience.

I wish you all success and patience!

ссылка на оригинал статьи https://habr.com/ru/articles/1054174/