Sonic | Official Documentation
Official WebsiteExplorerFaucet
  • Welcome to Sonic
  • Users
    • Getting Started
      • Setting up your wallet
      • Bridging funds to Sonic
      • Join Sonic community!
  • Developers
    • Why Choose Sonic?
    • Getting Started
      • Setup local development for Sonic SVM
      • Build & Deploy Your First Program
    • Developer Tooling
      • Explorer
      • Faucet
      • Wallet Extensions
  • Additional Tools & Examples
  • Additional Resources
  • Architecture
    • Overview
    • Sonic SVM Whitepaper
    • Vision & Architecture
    • Clusters
    • HyperGrid Framework
      • HyperGrid Infrastructure
        • Architectural Overview
        • Grids and Network Relationships
          • Grids
      • Interoperability with Solana
        • Data Synchronization Between HyperGrid and Solana Base Layer
      • HyperGrid Shared State Network (HSSN)
      • HSSN Explorer Overview
      • HSSN Gas Fee Mechanism
      • Operator Guides
        • Deploying a New Grid
        • Deploying a Sonic RPC Node
        • Deploying an HSSN Validator
        • Mainnet
          • Deploying an HSSN Validator
      • Verifiable Compute & Zero-Knowledge Proofing on HyperGrid
    • Sorada
      • Introduction
      • Architecture
      • How to Deploy Sorada
      • Resources
    • Rush ECS Framework
      • Introduction
      • Features
      • Quickstart
      • Reference
      • Demo
  • RESOURCES
    • Audit Reports
    • We're Hiring!
Powered by GitBook
On this page
  • 1. Install CLI Tools
  • 2. Write Your Program
  • 3. Build Your Program
  • With Anchor
  • Without Anchor
  • 4. Deploy Your Program
  • With Anchor
  • Without Anchor
  • 5. Verify Deployment
  • Additional Tips:
  • Example: "Hello Sonic!" Program
  • With Solana Native Program
  • With Anchor Program
  • Run your dAPP on Sonic Devnet
  • With Solana Native Program dApp
  • With Anchor Program dApp
Edit on GitHub
  1. Developers
  2. Getting Started

Build & Deploy Your First Program

PreviousSetup local development for Sonic SVMNextDeveloper Tooling

Last updated 3 months ago

This guide provides a step-by-step overview of deploying a program on Sonic SVM. Familiarity with command-line tools is necessary.

1. Install CLI Tools

Ensure that the Solana command line tools are installed as you will be using these tools throughout the deployment process.

2. Write Your Program

Develop your program logic. For those using Rust with Anchor, input your program logic into the lib.rs file located in the src directory of your project. Confirm that your program compiles correctly and passes all tests.

3. Build Your Program

Compile your program to a BPF (Berkeley Packet Filter) executable, the format required for on-chain programs:

With Anchor

Run anchor build. manages the compilation details.

Without Anchor

Use cargo build-bpf for direct Rust usage.

4. Deploy Your Program

solana config set --url https://devnet.sonic.game

After deploying your building your program and configuring your RPC URL, you can deploy your program with the following command:

solana program deploy <PATH_TO_YOUR_COMPILED_PROGRAM>

After configuring your network, you may now deploy your program to Sonic. Use the following commands based on your setup:

With Anchor

If the Anchor CLI is installed, you can deploy your program with the following command. This handles the deployment automatically.

anchor deploy

Without Anchor

If you're using the native solana method to author your program, you can also use the Solana CLI to deploy your program.

5. Verify Deployment

Post-deployment, check that your program operates as intended. Interact with your program using Solana's web3.js library or the CLI tools to send transactions.

Additional Tips:

  • Keep your program's keypair secure for future upgrades or interactions.

  • Monitor the network and your program's performance, particularly if it gains widespread usage.

Example: "Hello Sonic!" Program

This example implements a simple Greeting Counter Program on Sonic.

With Solana Native Program

use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    program_error::ProgramError,
    pubkey::Pubkey,
};

#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct GreetingAccount {
    pub counter: u32,
}

entrypoint!(process_instruction);

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    _instruction_data: &[u8],
) -> ProgramResult {
    
    msg!("Hello, Sonic World!");
    
    let accounts_iter = &mut accounts.iter();
    let account = next_account_info(accounts_iter)?;

    if account.owner != program_id {
        msg!("Greeted account does not have the correct program id");
        return Err(ProgramError::IncorrectProgramId);
    }

    let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
    greeting_account.counter += 1;
    greeting_account.serialize(&mut *account.data.borrow_mut())?;
    
    msg!("Greeted {} time(s)!", greeting_account.counter);
    Ok(())
}

With Anchor Program

use anchor_lang::prelude::*;

// !!! Replace with your program ID after running `anchor build` !!!
declare_id!("<REPLACE_WITH_YOUR_PROGRAM_ID>");

#[program]
pub mod hello_sonic_world {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>, authority: Pubkey) -> Result<()> {
        let greeting_account = &mut ctx.accounts.greeting_account;
        greeting_account.counter = 0;
        greeting_account.authority = authority;
        Ok(())
    }

    pub fn increment_greeting(ctx: Context<IncrementGreeting>) -> Result<()> {
        msg!("Hello, Sonic World!");

        let greeting_account = &mut ctx.accounts.greeting_account;
        greeting_account.counter += 1;

        msg!("Greeted {} time(s)!", greeting_account.counter);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = user, space = 8 + 4 + 32)]
    pub greeting_account: Account<'info, GreetingAccount>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct IncrementGreeting<'info> {
    #[account(mut, has_one = authority)]
    pub greeting_account: Account<'info, GreetingAccount>,
    pub authority: Signer<'info>,
}

#[account]
pub struct GreetingAccount {
    pub counter: u32,
    pub authority: Pubkey,
}

Run your dAPP on Sonic Devnet

Example "Hello World" application in TypeScript:

With Solana Native Program dApp

import {
  Connection,
  PublicKey,
  Keypair,
  Transaction,
  TransactionInstruction,
  SystemProgram,
  sendAndConfirmTransaction
} from '@solana/web3.js';
import bs58 from 'bs58';
import * as borsh from 'borsh';

class GreetingAccount {
  counter = 0;
  constructor(fields?: { counter: number }) {
    if (fields) {
      this.counter = fields.counter;
    }
  }
}

const GreetingSchema = new Map([
  [GreetingAccount, { kind: 'struct', fields: [['counter', 'u32']] }]
]);

const programId = new PublicKey('<REPLACE_WITH_YOUR_PROGRAM_ID>');
const connection = new Connection('https://devnet.sonic.game', 'confirmed');
const feePayer = Keypair.fromSecretKey(
  bs58.decode(
    '<REPLACE_WITH_YOUR_PRIVATE_KEY>'
  )
);

async function sayHello() {
  const GREETING_SIZE = borsh.serialize(
    GreetingSchema,
    new GreetingAccount()
  ).length;

  const greetedAccountKeypair = new Keypair();
  const greetedAccountPubkey = greetedAccountKeypair.publicKey;

  const lamports =
    await connection.getMinimumBalanceForRentExemption(GREETING_SIZE);

  const createGreetingAccountIx = SystemProgram.createAccount({
    fromPubkey: feePayer.publicKey,
    lamports,
    newAccountPubkey: greetedAccountPubkey,
    programId: programId,
    space: GREETING_SIZE
  });

  // Create greet instruction
  const greetIx = new TransactionInstruction({
    keys: [
      {
        pubkey: greetedAccountPubkey,
        isSigner: false,
        isWritable: true
      }
    ],
    programId
  });

  const transaction = new Transaction().add(createGreetingAccountIx, greetIx);

  const txHash = await sendAndConfirmTransaction(connection, transaction, [
    feePayer,
    greetedAccountKeypair
  ]);
  console.log(`Use 'solana confirm -v ${txHash}' to see the logs`);

  const greetingAccount = await connection.getAccountInfo(greetedAccountPubkey);
  // Deserialize the account data
  const deserializedAccountData = borsh.deserialize(
    GreetingSchema,
    GreetingAccount,
    greetingAccount!.data
  );

  console.log(
    'Sonic Greeting successful. Account data:',
    deserializedAccountData
  );
}

sayHello()
  .then(() => console.log('Done'))
  .catch(console.error);

With Anchor Program dApp

import {
  Connection,
  PublicKey,
  Keypair,
  Transaction,
  SystemProgram,
  sendAndConfirmTransaction
} from '@solana/web3.js';
import { Program, AnchorProvider, web3 } from '@project-serum/anchor';
import { IDL } from './idl/hello_sonic_world.json'; // Make sure you have the correct IDL file

const programId = new PublicKey('<REPLACE_WITH_YOUR_PROGRAM_ID>');
const connection = new Connection('https://devnet.solana.com', 'confirmed');
const feePayer = Keypair.fromSecretKey(
  bs58.decode('<REPLACE_WITH_YOUR_PRIVATE_KEY>')
);

// Anchor setup
const wallet = new AnchorProvider(connection, feePayer, {
  preflightCommitment: 'confirmed',
});

const program = new Program(IDL, programId, wallet);

async function sayHello() {
  // Create the greeting account
  const greetedAccountKeypair = Keypair.generate();
  const greetedAccountPubkey = greetedAccountKeypair.publicKey;

  const lamports = await connection.getMinimumBalanceForRentExemption(
    8 + 4 + 32 // space for the account (discriminator, counter, and authority)
  );

  const createGreetingAccountIx = SystemProgram.createAccount({
    fromPubkey: feePayer.publicKey,
    lamports,
    newAccountPubkey: greetedAccountPubkey,
    programId: program.programId,
    space: 8 + 4 + 32, // size of the GreetingAccount (8 discriminator + 4 counter + 32 authority)
  });

  const transaction = new Transaction().add(createGreetingAccountIx);

  await sendAndConfirmTransaction(connection, transaction, [
    feePayer,
    greetedAccountKeypair,
  ]);

  console.log(`Greeting account created with public key: ${greetedAccountPubkey.toBase58()}`);

  // Initialize the greeting account
  await program.rpc.initialize(feePayer.publicKey, {
    accounts: {
      greetingAccount: greetedAccountPubkey,
      user: feePayer.publicKey,
      systemProgram: SystemProgram.programId,
    },
    signers: [greetedAccountKeypair, feePayer],
  });

  console.log('Greeting account initialized');

  // Increment the greeting counter
  await program.rpc.incrementGreeting({
    accounts: {
      greetingAccount: greetedAccountPubkey,
      authority: feePayer.publicKey,
    },
  });

  console.log('Greeting incremented');

  // Fetch the account data
  const account = await program.account.greetingAccount.fetch(
    greetedAccountPubkey
  );

  console.log('Greeting successful. Account data:', account);
}

sayHello()
  .then(() => console.log('Done'))
  .catch(console.error);

Running the above script [either with Solana Native, or with Anchor] programs should output the following:

Use 'solana confirm -v TsCwj8s8meQFSfqUKdHqDQVzfUbqRcugP2gJ5kaGCj4v4D7aKvohqQQncvUFunqZVH9sS6jhESMjwe6SHGPfrXf' to see the logs
Sonic Greeting successful. Account data: GreetingAccount { counter: 1 }
Done

Before deploying your program, ensure your CLI is set to the network using the following command:

Ensure that you have enough SOL in your wallet to cover deployment costs. You can get some devnet tokens from the .

If you are building with , you may use the variant below. Please remember to change the program ID after building your program with anchor build before deploying it.

You can find an example of the executed transaction . The program address for this program is .

Anchor
Sonic faucet
Anchor
here
here
Sonic Devnet