Demos Network Specifications
  • Introduction
    • What is Demos Network
    • Demos Network Architecture
  • FAQ
  • Cookbook
    • Project setup
      • Run the project (MacOS)
      • Run the project (Windows)
        • WSL 2 Setup on Windows (10 and 11 only)
        • Issue Troubleshooting
      • Run the project (Ubuntu)
  • SDK
    • Getting Started
    • WebSDK
      • Authentication
        • FIDO2 Passkeys
          • Under the Hood: FIDO2 Passkeys
      • NodeCalls
      • Transactions
        • Creating a transaction
        • Signing a transaction
        • Broadcasting a transaction
      • L2PS SDK
        • The l2ps module
        • Interacting with the L2PS
        • L2PS Messaging System
      • Instant Messaging
        • What is the Instant Messaging Protocol?
        • Architecture Overview
        • Encryption
        • Quickstart
        • Message Types
        • API Reference
        • FAQ
    • Cross Chain
      • General layout of the XM SDKs
      • EVM
      • BTC
      • Solana
      • MultiversX (EGLD)
      • NEAR
      • IBC
      • TON
      • XRPL
      • The XMScript
      • Identities
    • Demoswork
    • Cookbook
      • Demoswork
        • Creating work steps
        • Conditional Operation
        • Base Operation
        • Signing and broadcasting
      • Transactions
        • Crosschain Transaction
        • Native Transactions
      • SWAP
        • Crosschain SWAP
    • Web2
      • Quick Start
      • DAHR API Reference
        • Types
      • Making Requests
      • Identities
        • Twitter
        • GitHub
    • API Reference
    • Bridges
      • Rubic Bridge Test
    • Post Quantum Cryptography
  • Backend
    • Internal Mechanisms
      • Network Time Synchronization
      • Cross Context Identities
    • Global Change Registry
      • GCR Structure
      • How is GCR Synced?
    • Consensus Mechanism
      • Unparalleled Scalability
      • Decentralization in PoR-BFT
      • Enhanced Security
      • Comparative Advantage
      • Addressing Potential Criticisms
      • Conclusion
    • Communications Stack
    • L2PS (Subnet) Framework
      • How are L2PS transactions handled?
    • Miscellaneous
      • Browsing the Postgres DB via psql
    • Bridges
      • Rubic Bridge
    • Developers Testbed
      • Setting up the environment
      • Setting up the repository
      • Installing dependencies
      • Node Configuration
      • Running the node
  • Frontend
    • Demos Providers Discovery Mechanism
Powered by GitBook
On this page
  • Core Concepts
  • How Solana Handles Nonces
  • Setting up your wallet
  • Using the Sdk
  • Connecting your wallet
  • Sending SOL
  • Multi token send
  • Signing messages
  • Programs
  • When the IDL is available
  • When the IDL is not available
  • Resources
  • API Reference
  1. SDK
  2. Cross Chain

Solana

PreviousBTCNextMultiversX (EGLD)

Last updated 3 months ago

is a "high performance" network with roots in finance, smart contracts and NFTs. Solana has roots in other areas like gaming, but those won't be covered in this guide.

Core Concepts

Solana runs on the following core concepts:

Accounts

In Solana, accounts are used to store data. Each account has a unique address which can be used to access the stored data.

There are 3 types of accounts:

  1. Data accounts - they store data.

  2. Program accounts - they host program code

  3. Native accounts - native Solana programs, eg. the System account which is responsible for creating all accounts.

An account in Solana is like a file in a normal operating system, and it can contain any data as defined by a program.

The account you create via a wallet is categorized as a data account owned by the System program. An account hosting your program code is a program account owned by you (your account).

An account stores data that looks like this:

{
  data: bytes,
  executable: boolean,
  lamports: number, // balance
  owner: PublicKey
}

A lamport is the smallest unit of SOL (1 SOL = 1 billion lamports)

Programs

A program is a smart contract running on the Solana network.

Programs do not store data themselves, instead they store data in acccounts.

How Solana Handles Nonces

Contrary to other networks like Ethereum, Solana does not use an integer nonce. Instead, a recent block hash is used to invalidate old transactions (those signed more than 150 blocks ago). While this works well for most cases, it makes signing offline transactions impossible.

Enter durable nonces.

Durable nonces are 32-byte base58 encoded strings used in place of the recent block hash when signing a transaction. Durable nonces can only be advanced by broadcasting a transaction instruction to advance it. When signing a transaction using durable nonces, the first instruction is supposed to be the advance nonce instruction.

How do they work?

While durable nonces fix the initial problem of offline transactions, since these nonces are strings, we can't advance them locally and thus we lose the ability to sign multiple offline transactions at the same time using nonces.

Since a transaction needs to be broadcasted to advance the nonce, signing multiple transactions using a durable nonce would use the same value for all transactions causing only the first to be valid.

Setting up your wallet

The testnet faucet is empty (at the time of this writing), so you might need to use the devnet.

Using the Sdk

import { clusterApiUrl } from "@solana/web3.js"
import { SOLANA } from "@kynesyslabs/demosdk/xm-<localsdk|websdk>"

const testnet = clusterApiUrl("testnet")
// const devnet = clusterApiUrl("devnet")
// const mainnet = clusterApiUrl("mainnet-beta")

const instance = await SOLANA.create(testnet)

Connecting your wallet

Pass the base58 representation of your private key to .connectWallet:

await instance.connectWallet("25WecT1ApBVs9PEpNgsgEYJEjDMG...")
await instance.connectWallet()

// instance.wallet: PhantomProvider

Sending SOL

const signed_tx = await instance.preparePay(
    "tKeYE4wtowRb8yRroZShTipE18YVnqwXjsSAoNsFU6g",
    "0.1",
)

The signed transaction is a serialized form of itself (Uint8Array) that can now be sent to a DEMOS node for broadcasting.

Multi token send

const signed_txs = await instance.preparePays([
    {
        address: "tKeYE4wtowRb8yRroZShTipE18YVnqwXjsSAoNsFU6g",
        amount: "1",
    },
    {
        address: "CU3pJe9E3NxyBMWbTAJYjoahut9juerfmmjCin2g8ipG",
        amount: "2",
    },
])

The signed transactions will be signed using the recent block hash and therefore are only valid for the next few minutes.

Signing messages

const message = "Hello, world!"

// Signing
const signature = await instance.signMessage(message)

// Verifying signature
const verified = await instance.verifyMessage(
    message,
    signature,
    instance.getAddress(),
)

expect(verified).toBe(true)

Programs

To execute a program on solana, you need to have its address (program Id) and IDL.

On Solana, an IDL (interface definition language) is what an ABI is to an EVM smart contract. It is a programs's public interface. It define its methods, inputs and types.

When the IDL is available

Here's an example IDL of a program running on the Solana Mainnet: https://explorer.solana.com/address/MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD/anchor-program

// Getting the IDL
const idl = await instance.getProgramIdl(
    "MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD",
)

You can use the IDL to collect and convert user input to the type specified in the IDL.

The structure of the IDL

A typical IDL looks like this:

type Idl = {
    version: string
    name: string
    instructions: IdlInstruction[]
    accounts?: IdlAccountDef[]
    errors?: IdlErrorCode[]
    types?: IdlTypeDef[]
    constants?: IdlConstant[]
}

type IdlInstruction = {
    name: string
    accounts: IdlAccount[]
    args: IdlField[]
}

type IdlAccount = {
    name: string
    isMut: boolean
    isSigner: boolean
}

The instructions are a list of the methods defined on the program. An instruction can require arguments which are declared on the args property. When the instruction is reading data or modifying dadta, the data account's address is needed. If data is being modified, the private key of the account's owner is required to sign the transaction.

You can determine the number of signers required by checking how many accounts have a isSigner flag.

Invoking a program:

const programId = "MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD"
const programParams = {
    instruction: "deposit",
    idl: idl,
    args: {
        lamports: 100,
    },
    accounts: {
        // example account:
        receiver: "address",
        // other accounts here ...
    },
    feePayer: publicKey,
    signers: [Keypair, Keypair], // all signers
}

const signedTx = await instance.runAnchorProgram(programId, programParams)

After broadcasting the transaction to the network, you can await its confirmation and then read an account data.

await instance.provider.confirmTransaction(txhash, "finalized")

// account affected by program invocation
const modifiedAccount = new PublicKey(
    "5dDANLFBcmFyFQonFcJsE9i3YqK74JPAMAiL1WXmWKSL",
)

const account = await instance.fetchAccount(modifiedAccount, {
    idl: idl,
    name: "newAccount", // account name
    programId: "MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD", // optional
})

console.log(account.data)

The IDL and accountName are needed to deserialize the account data

When the IDL is not available

When you don't have the IDL, you need to know:

  1. The name of the instruction

  2. The index of the instruction on the program definition

  3. The proper format and type of the instruction parameters

  4. The accounts needed

  5. The signers needed by the instruction.

With all that in place, you can do the following:

const programId = "yourProgramId"
const account = new Keypair()

// accounts
const accounts = [
    {
        pubkey: account.publicKey,
        isSigner: true,
        isWritable: true,
    },
]

// parameters
const params = {
    space: 100,
}

const instructionIndex = 8
const instructionName = "ixName"

// the signed tx
const signedTx = await instance.runRawProgram(programId, {
    instructionName,
    instructionIndex,
    params,
    keys: accounts,
    feePayer: account.publicKey,
    signers: [account],
})

Resources

API Reference

[] | []

Durable nonces requires a separate nonce account which stores the current nonce value. The account can be created using the @solana/web3.js sdk .

[]

Install the to create a new wallet. Then export your Solana secret key by going to Settings > Manage Accounts > {Wallet Name} > Show Private Key.

Airdrop some test SOL from the for testing.

The solana sdk provides a utility function to get the .

On the browser, you can also try to connect to the browser extension by calling .connectWallet without any argument.

Solana
Accounts
Transactions
Programs (smart contracts)
Accounts - Solana Cookbook
Accounts - Solana Docs
as shown here
More on Durable Nonces
Phantom wallet extension
Solana Faucet
rpc url
Phantom
The Solana Cookbook
The Solana Program Library
ANCHOR - Solana Sealevel Framework
Javascript Client
Known Programs [Github]
Interacting with Custom Programs
https://kynesyslabs.github.io/demosdk-api-ref/classes/xmwebsdk.SOLANA.html