Koilib Version 2 - Now compatible with Koinos Testnet V2

in #koilib2 years ago

Koinos Group did a great job by launching Koinos Testnet V2, which include new features like the use of protobuffers, and the VM Manager.

In my previous work I released a javascript library to interact with the first testnet. However, now the version 2 uses a complete different way of serializing data: Protobuffers. And this is the principal reason they had to launch a new blockchain. Now the challenge was to upgrade the library and make it compatible with the Testnet V2. I'm happy to announce that the upgrade of the JS library is already done and it also includes new features that make it easier to use than ever before.

But before going to the details of the new library, let's discuss about protobuffers.

Protobuffers

What is protobuffers? and why it is important? Protobuffers is a protocol to transform data into bytes in order to send messages between different services. We also want to send only the useful information.

For instance, let's say I have the following message to make a tranfer: {"from":"alice", "to": "bob", "value":1000}. If we assume that both sender and receiver of the message know how is the structure of a message then the words "from", "to", and "value" are redundant, thus they can be omitted during the transmission. We actually need just the important data, that is "alice", "bob", and 1000. Protobuffers will join these 3 values, put the corresponding delimiters of each one and create a set of bytes. The receiver, which already knows the structure of a transfer, will transform these bytes again in {"from":"alice", "to": "bob", "value":1000}.

Koinos Testnet V1 used Koinos Types, a protocol with the same idea as Protobuffers, with some differences in the way the bytes were created. However, Koinos Types required extra work in order to give support to different programming languages. Koinos Group started with C++ and Go, and I contributed with the version for Typescript. Protobuffers, on the other hand, has been written already for many different languages. The languages in the official page of Google are Java, Python, Objective-C, C++, Kotlin, Dart, Go, Ruby, and C#. But the community around the world have been created it for other languages like Javascript and Rust. So, in conclusion, Protobuffers gives more flexibility to create microservices in different programming languages.

Koilib Version 2

The Koinos Library for Javascript has now support for protobuffers, and it comes with new characteristics. The principal one is the way the contract functions are accessed. In the previous version a transfer was created in this way

// Old way to make a transfer - Koilib V1
const opTransfer = wallet.encodeOperation({
  name: "transfer",
  args: {
    from: "19T7nHRLK9iAUVjPkbsenfUzvbCdpBnARy",
    to: "172AB1FgCsYrRAW5cwQ8KjadgxofvgPFd6",
    value: BigInt(1000),
  },
});
const tx = await wallet.newTransaction({
  getNonce: true,
  operations: [opTransfer],
});
await wallet.signTransaction(tx);
await wallet.sendTransaction(tx);

In the new version we just call

// transfer - Koilib V2
await koin.transfer({
  from: "19T7nHRLK9iAUVjPkbsenfUzvbCdpBnARy",
  to: "172AB1FgCsYrRAW5cwQ8KjadgxofvgPFd6",
  value: "1000",
});

that's all. Behind this function several things happens, like the encoding using protobuffers, the creation of the operation, the creation of the transaction, the signature using the private key, and the connection with the JSON-RPC to broadcast the signed transaction.

This new design is inspired in the Ether.js library developed for Ethereum. There are 3 principal classes:

  • Provider: Class to communicate with the JSON-RPC. It contains functions like getBlock, getNonce, sendTransaction, readContract, etc.
  • Signer: Class containing the private key. It is used to create transactions and sign them. It also includes the function to decode transactions (from protobuf to a JSON).
  • Contract: Class with the definitions of the contract to interact with.

These 3 classes can work independently depending on the task you need to perform, but the common way to use the library is by linking the classes:

  • Provider is attached to the Signer
  • Signer and/or Provider are attached to the Contract

In this way you just use the contract instance, which internally will sign using the Signer and send to the blockchain using the Provider.

Preformat input/output

The library also includes the option to preformat the input or output of a contract function.

For instance, if in normal conditions we use the following function to read the balance

const { result } = await koin.balanceOf({
  owner: "19T7nHRLK9iAUVjPkbsenfUzvbCdpBnARy"
});
console.log(result);
// { value: "1000" }

with preformats we could simplify the code to

const { result } = await koin.balanceOf("19T7nHRLK9iAUVjPkbsenfUzvbCdpBnARy");
console.log(result);
// 1000

This is very useful because with protobuffers all messages are defined by JSONs, which is not always needed. Then, this feature can be used to simplify the code and make it more readable.

Wait to be mined

Another design pattern taken from Ethers.js is the "wait" function. As you know, when you submit a transaction it goes to the mempool, and will be there for several seconds until it is mined.

From client's perspective, when a transaction is submitted a "wait" function is returned. Then the client can call this function in order to wait for the transaction to be included in the blockchain. This function waits 10 seconds, and after that it enters in a loop, where it tries to get block id that contains that transaction every second.

Example

Here is a complete example to get balance, mana, and make a transfer.

import { Signer, Contract, Provider, utils } from "koilib";

const provider = new Provider(["https://api.koinos.io:8080"]);
const privKeyWif = "5HzP7VXcKyzqQu2h42uENEjQMDfNuUk6jLQ57t8rfwNadtxzyqZ";
const signer = Signer.fromWif(privKeyWif);
signer.provider = provider;
const koinContract = new Contract({
  id: "19JntSm8pSNETT9aHTwAUHC5RMoaSmgZPJ",
  abi: utils.Krc20Abi,
  signer,
});
const koin = koinContract.functions;
const myAddress = signer.getAddress();
const receiver = "1BqtgWBcqm9cSZ97avLGZGJdgso7wx6pCA";

// optional: preformat input/output
koinContract.abi.methods.balanceOf.preformatInput = (owner) =>
  ({ owner });
koinContract.abi.methods.balanceOf.preformatOutput = (res) =>
  utils.formatUnits(res.value, 8);
koinContract.abi.methods.transfer.preformatInput = (input) => ({
  from: myAddress,
  to: input.to,
  value: utils.parseUnits(input.value, 8),
});

(async () => {
  // read the balance of sender
  bal1 = await koin.balanceOf(myAddress);
  console.log(bal1);
  console.log(`Balance of ${myAddress} is ${bal1.result} tKoin`);

  // read the balance of receiver
  bal2 = await koin.balanceOf(receiver);
  console.log(bal2);
  console.log(`Balance of ${receiver} is ${bal2.result} tKoin`);

  // get mana
  resMana1 = await provider.getAccountRc(myAddress);
  console.log(`Current mana of ${myAddress} is ${resMana1}`);

  // transfer tKoin
  resTransfer = await koin.transfer({
    to: receiver,
    value: "0.00000001",
  });
  console.log(resTransfer);
  txId = resTransfer.transaction.id;
  console.log("Transfer submitted to the mempool");
  console.log(`Transaction Id: ${txId}`);
  console.log("Now waiting to be mined...");

  // waiting to be mined
  blockId = await resTransfer.transactionResponse.wait();
  console.log(`Transaction mined in blockId ${blockId}`);

  // get block with the transaction
  resBlocks = await provider.getBlocksById([blockId]);
  console.log(resBlocks);
  blockHeight = resBlocks.block_items[0].block_height;
  console.log(`Block number ${blockHeight}`)

  // get new mana
  resMana2 = await provider.getAccountRc(myAddress);
  console.log(`New mana of ${myAddress} is ${resMana2}`);

  // check new balance of sender
  bal3 = await koin.balanceOf(myAddress);
  console.log(bal3);
  console.log(`New balance of ${myAddress} is ${bal3.result} tKoin`);

  // check new balance of receiver
  bal4 = await koin.balanceOf(receiver);
  console.log(bal4);
  console.log(`New balance of ${receiver} is ${bal4.result} tKoin`);
})();

More contracts and ABIs

In the previous sections I focused in the contract for the main token KOIN, how to transfer and get balance. However, it's important to note that this library can be used for any contract in the blockchain. You just have to define the ABI and add it in the constructor of the Contract Class.

For the ABI you need the .proto file and the library protobufjs. Also take into account that this ABI is not the same ABI used in koinos-cli. In particular, descriptors use different format (koilib using json format, cli using binary format). One of the tasks for future releases would be to research the possibility of using a single ABI format for both tools.

To learn more about Koilib V2 go to NPM and check the documentation https://www.npmjs.com/package/koilib

Sort:  

I've been getting into JS lately and damn, it feels so much different to be able to actually read this kind of posts and to actually understand what they talk about. Seems like Koin has a lot to offer and the tech behind it is top notch, this post made me go into coingecko and check the price and where can I buy some. I didn't have much hope for the project but that was mainly sentiment speaking, as I am a Hiver by heart and the very fact that the old Stinc is directly in charge of Koin made me not even want to research about it, but you changed that mindset, thanks man!

I hope you are doing great, been a long time since we spoke the last time.

Hi anomad 😀 thanks for reading my post.
Glad to hear that you will take a look to Koinos 👌
I'm doing great, thanks. With great expectations about this project.

What I like from Hive is the big community behind, which makes the crypto more strong 💪I hope we can achieve something similar in Koinos in the future. Step by step, this library will help to bootstrap many projects.

Congratulations @jga! You have completed the following achievement on the Hive blockchain and have been rewarded with new badge(s):

You distributed more than 36000 upvotes.
Your next target is to reach 37000 upvotes.

You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word STOP

Check out the last post from @hivebuzz:

Hive Power Up Day - December 1st 2021 - Become an Orca!