Introduction_To_HyperSDK
Introduction_To_HyperSDK
scratch on Avalanche, providing developers a foundation to build the fastest blockchains in the
world, out-of-the-box.
Creating custom Virtual Machines (VMs) is one of the most powerful ways to build on
Avalanche. HyperSDK is designed to simplify and accelerate custom VM development, making
it safer and easier to launch your own optimized blockchain.
Though still raw and evolving, HyperSDK represents the next step in empowering crypto-native
developers with open source blockchain technology. With this launch, builders can collaborate
on and experiment with building the next generation of high-performance, interconnected,
optimized blockchains.
In addition to making the process of building subnets on Avalanche faster and simpler,
HyperSDK also offers developers a suite of monitoring and analysis tools to ensure optimal
performance. With HyperSDK, developers can easily identify and address performance issues,
keeping their subnets running smoothly and efficiently.
Overall, HyperSDK is a powerful tool for developers looking to build optimized subnets on the
Avalanche network. By leveraging its features and design methodology, developers can
accelerate their development process and create high-performance subnets for a variety of
blockchain-based applications.
Terminology
HyperSDK: a framework for building high-performance blockchains on Avalanche
HyperVM: Avalanche Virtual Machine built using the HyperSDK
HyperChain: HyperVM deployed on the Avalanche Network
// Exmample - version/version.go
package version
import "github.com/ava-labs/avalanchego/version"
Constant
The constants module holds the key values that will be accessed throughout the HyperVM,
including VM metadata, name, HRP, symbol, Chain ID, and others.
// consts/consts.go
package consts
import (
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/vms/platformvm/warp"
"github.com/ava-labs/hypersdk/chain"
"github.com/ava-labs/hypersdk/codec"
"github.com/ava-labs/hypersdk/consts"
)
// information about our VM
const (
HRP = "token"
Name = "TokenVM"
Symbol = "TKNVM"
)
The HRP , Name , and Symbol constants define information about the TokenVM, including its
Human-Readable Part (HRP), name, and symbol.
The ID variable is a unique identifier for the TokenVM, which is generated by hashing the
name byte slice.
The ActionRegistry and AuthRegistry variables are codec type parsers that can be used to
parse and serialize Action and Auth types respectively, which are custom types defined by
the chain package. These variables are instantiated in the controller/registry package
and set to values based on the types of messages and data that are expected.
Utils
This module defines two functions, Address (to get an address from a public key) and
ParseAddress (to parse an address from a string).
// utils/utils.go
package utils
import (
// here should go your module name, like:
// __your_module__/consts
"github.com/rafael-abuawad/tokenvm/consts"
"github.com/ava-labs/hypersdk/crypto"
)
func Address(pk crypto.PublicKey) string {
return crypto.Address(consts.HRP, pk)
}
The Address function takes a public key of type crypto.PublicKey and returns a string
representation of the address that corresponds to the HRP (Human Readable Part) defined in
the consts package.
Both functions rely on the crypto package provided by the hypersdk to handle cryptographic
operations. The Address function can be used to generate an address from a public key, while
the ParseAddress function can be used to parse an address and retrieve the corresponding
public key.
Authentication
The auth module is an important component that allows users to securely access our HyperVM
using their private key. For those new to blockchain development, the ED25519 algorithm might
sound complicated, but in simple terms, it's just a cryptographic key pair consisting of a public
key and a private key. We'll use this key pair to authenticate and authorize user requests to
interact with the HyperVM.
The ED25519 algorithm uses EdDSA and Curve25519, which are elliptic curve signing and key
exchange algorithms respectively, to generate the key pair. This ensures that user requests are
secure and cannot be tampered with by anyone who doesn't have access to the private key.
Overall, the auth module provides a straightforward and robust mechanism for user
authentication and access control in our HyperVM.
Auth is also going to use two helper functions as demonstrated in the helpers.go example
below. One to access the actor and one to get the signer.
The module defines an ED25519 struct that implements the chain.Auth interface, which
specifies methods for verifying and authorizing actions on the ledger. The ED25519 struct
contains the public key of the signer, and the signature of the action, both of which are used to
verify the authenticity of the action.
The module also defines several helper functions for working with ED25519 instances, such
as GetActor and GetSigner , which extract the public key of the signer from
an ED25519 instance.
As you can see, the folder not only contains methods to manage private keys with the elliptic
curve algorithm, but also methods like Refund and Deduct that interact directly with the native
token of our HyperVM. This is all fully customizable.
RPC Client
So with all this, we need a way to communicate with the Avalanche network. That’s where our
RPC files come in. This code provides an RPC client with several functions that can be used to
interact with the network, such as querying the balance of an address, or waiting for a
transaction to be confirmed.
Genesis() : This function retrieves the Genesis block of the Avalanche chain. It returns the
Genesis block as a genesis.Genesis object.
Tx() : This function takes in the ID of a transaction and retrieves information about that
transaction. It returns a tuple consisting of a boolean indicating whether the transaction exists or
not, a boolean indicating whether the transaction was successful or not, a timestamp of when
the transaction was created, and an error (if any).
Asset() : This function takes in the ID of an asset and retrieves information about that asset. It
returns a tuple consisting of a boolean indicating whether the asset exists or not, the metadata
associated with the asset as a byte array, the total supply of the asset, the address of the owner
of the asset, a boolean indicating whether the asset is warped, and an error (if any).
Balance() : This function takes in an address and an asset ID and retrieves the balance of that
address for that asset. It returns the balance as a uint64 and an error (if any).
Orders() : This function takes in a string representing a trading pair and retrieves all the orders
associated with that trading pair. It returns an array of orderbook orders and an error (if any).
Loan() : This function takes in an asset ID and a destination ID and returns the amount of that
asset that is currently lent out to that destination.
WaitForBalance() : This function takes in an address, an asset ID, and a minimum balance
and waits until the balance of the address for the asset exceeds the minimum balance.
WaitForTransaction() : This function takes in a transaction ID and waits until that transaction
is confirmed or rejected.
Order Books
So what is an order book? An order book is essentially a list of buy and sell orders that are
placed by traders for a particular cryptocurrency or trading pair. Each order in the book typically
contains the amount of the cryptocurrency the trader wants to buy or sell and the price at which
they are willing to buy or sell it. This is one such example that can be used for your custom
subnet.
The type Order defines a struct that represents a single order placed by a trader. It includes
fields such as order ID, owner, input and output ticks, and remaining quantity.
The type OrderBook defines another struct that represents the order book data structure. It
includes fields such as a controller, a map of orders, a map of order-to-pair, and a mutex. It also
includes methods to add, remove, and update orders in the order book, as well as to get the list
of orders for a specific pair.
The func New is a constructor function that returns a new OrderBook instance. It takes a
controller instance and a list of tracked pairs, and initializes a map of orders for each pair.
The func (o *OrderBook) Add is a method of the OrderBook struct that adds a new order to
the order book. It takes an order ID, an actor (the owner), and an action (which includes the
order details such as input and output ticks). It then pushes the order onto the corresponding
heap in the orders map.
The func (o *OrderBook) Remove is a method of the OrderBook struct that removes an order
from the order book. It takes an order ID, looks up the corresponding pair, and then removes
the order from the corresponding heap.
The func (o *OrderBook) UpdateRemaining is a method of the OrderBook struct that updates
the remaining quantity of an order in the order book. It takes an order ID and the new remaining
quantity, looks up the corresponding pair and order, and then updates the remaining quantity of
the order.
MODE="run-single" ./scripts/run.sh
./scripts/build.sh
If you encounter a permissions denied error, run the scripts with the sudo command (e.g.,
sudo ./scripts/run.sh ).
Import the demo private key included in the project using: