September 2, 2021

My first Solana Project 😍

So, I've decided to participate in Solana Hackathon. Here I'm going to write down my journey. Part 1 - "Hello world".

So, the first thing to do is to install Solana.

sh -c "$(curl -sSfL https://release.solana.com/v1.7.11/install)"

from the official guide. And update PATH accordingly.

Then let's download the hello-world example. I'm not going to follow it though. Because it uses server-side JavaScript client, and I want to have a browser-side client.

So, skipping CLI part of a readme, straight to building the on-chain part:

npm run build:program-rust

While it is building, let's have a look what we actually have there.

The on-chain program starts with some imports and entrypoint specification. Straightforward.

Ok, we are ready do deploy. So, at first we need to start a local Solana "cluster", consisting of our own host. I did that by launching solana-test-validator in tmux.

Now, it is useful to familiarize yourself with your wallet id, which can be obtained in this way:

$ solana config get
Config File: $HOME/.config/solana/cli/config.yml
RPC URL: http://localhost:8899
WebSocket URL: ws://localhost:8900/ (computed)
Keypair Path: $HOME/.config/solana/id.json
Commitment: confirmed

$ solana-keygen pubkey $HOME/.config/solana/id.json # Keypair Path
9FRakBFwajAdRhfqwLFWAWUuEySs7rcRviMA5xnrHqST

By default your key does not have any money, but because the cluster is yours, you can fund it πŸ’ΈπŸ’·πŸ€‘

$ solana airdrop 100
$ solana balance
100 SOL

Now we have enough resources to deploy the application. The built process has already generated a random "account" for our program. Account is just an "address" of a program, it's ID, or whatever. It is a random ID which Solana and other participants will use to refer to our program. This is how to get it:

$ solana-keygen pubkey dist/program/helloworld-keypair.json
3cbqMCdkwiTbWyCv3i7gss8STqGw6ggzvg8ztt5msnD4

And now we can deploy our binary, and assign it that program ID.

$ solana program deploy $HOME/example-helloworld/dist/program/helloworld.so --program-id dist/program/helloworld-keypair.json
Program Id: 3cbqMCdkwiTbWyCv3i7gss8STqGw6ggzvg8ztt5msnD4

Great!. Something has happened. Now, let's have some fun.

First thing is to forward your ports, because my Solana runs on a remote host, and there is no way to setup a custom RPC address, only "localhost" in the wallet.

(localhost) $ ssh -L 8899:127.0.0.1:8899 MY.IP.ADD.RESS

BTW. Wallet. Just install Phantom wallet in your browser. Set network to be 127.0.0.1:8899 and import your key (private key is a contents of $$HOME/.config/solana/id.json) on your remote host.

Sorry, guys, can not resist a temptation:

Airdrop 100 makes you feel happy :) Haha!

So, we are almost there. The last thing to do is to make a JavaScript call to your on-chain program.

Some trivial JavaScript to make it work was:

<html>
        <head>
                <script src="https://unpkg.com/@solana/web3.js@latest/lib/index.iife.js"></script>
        </head>
        <body>
                <button id="btn-connect" disabled>Connect</button>
                <span id="connection-status"></span>|
                <button id="btn-send" disabled>Send</button>
                <script type="text/javascript">
window.addEventListener('load', function() {
        const btn_connect = window.document.getElementById("btn-connect");
        btn_connect.disabled = false;
        btn_connect.addEventListener('click', () => {
                const connection_status = window.document.getElementById("connection-status");
                connection_status.innerHTML = "Connecting";
                window.solana.on("connect", () => {
                        connection_status.innerHTML = `Connected as ${solana.publicKey.toString()}`;
                        const btn_send = document.getElementById("btn-send");
                        btn_send.disabled = false;
                        btn_send.addEventListener('click', async () => {
                                const connection = new solanaWeb3.Connection("http://127.0.0.1:8899");
                                const instruction = new solanaWeb3.TransactionInstruction({
                                        keys: [{pubkey: new solanaWeb3.PublicKey("9FRakBFwajAdRhfqwLFWAWUuEySs7rcRviMA5xnrHqST"), isSigner: false, isWritable: true}], // All instructions are hellos
                                        programId: new solanaWeb3.PublicKey("3cbqMCdkwiTbWyCv3i7gss8STqGw6ggzvg8ztt5msnD4"),
                                        // data: Buffer.alloc(0),
                                });
                                const bh = (
                                              await connection.getRecentBlockhash() ).blockhash;
                                console.log(bh);
                                const transaction = new solanaWeb3.Transaction({
                                        feePayer: window.solana.publicKey,
                                        recentBlockhash: bh,
                                });
                                transaction.add(instruction);
                                const signedTransaction = await window.solana.signTransaction(transaction);
                                await connection.sendRawTransaction(signedTransaction.serialize());
                                alert('done');
                        });
                });
                window.solana.connect();
        });
});
                </script>
        </body>
</html>

Sorry for the codestyle, it is really highly experimental.

I found those resources very useful:

Hope you found your answers here!

Well, we did something wrong, but our message eventually reached the cluster, because messages are from there.

The second part is ready!