2 releases

0.1.1 Jun 16, 2024
0.1.0 Jun 16, 2024

#8 in #znap


Used in znap-lang

Apache-2.0

45KB
1K SLoC

Watch the demo

Znap

Watch the demo

Performance-first Rust Framework to build APIs compatible with the Solana Actions Spec.

Tutorials

Znap is an innovative Rust-based framework designed to simplify the creation of Solana Actions on the Solana blockchain.

  • Rust eDSL for writing Solana actions
  • Macro collection
  • CLI and workspace management for developing complete Solana actions

If you're familiar with developing using the Anchor framework, then the experience will be familiar.

Getting Started

  1. cargo install znap-cli
  2. znap init <my-project-name>
  3. cd <my-project-name>
  4. znap new <collection-name>

Packages

Package Description Version Docs
znap Znap framework's core library to create Solana actions Crates.io Docs.rs
znap-syn Parsing and generating code for macros in Rust Crates.io Docs.rs
znap-macros Macro collection for creating Solana actions Crates.io Docs.rs
znap-cli Znap CLI to interact with a znap workspace. Crates.io Docs.rs

Example

use solana_sdk::{
    message::Message, native_token::LAMPORTS_PER_SOL, pubkey::Pubkey, system_instruction::transfer,
    transaction::Transaction,
};
use std::str::FromStr;
use znap::prelude::*;

#[collection]
pub mod my_actions {
    use super::*;

    pub fn send_donation(ctx: Context<SendDonationAction>) -> Result<ActionTransaction> {
        let account_pubkey = Pubkey::from_str(&ctx.payload.account)
            .or_else(|_| Err(Error::from(ActionError::InvalidAccountPublicKey)))?;
        let receiver_pubkey = Pubkey::from_str(&ctx.params.receiver_address)
            .or_else(|_| Err(Error::from(ActionError::InvalidReceiverPublicKey)))?;
        let transfer_instruction = transfer(
            &account_pubkey,
            &receiver_pubkey,
            ctx.query.amount * LAMPORTS_PER_SOL,
        );
        let transaction_message = Message::new(&[transfer_instruction], None);
        let transaction = Transaction::new_unsigned(transaction_message);

        Ok(ActionTransaction {
            transaction,
            message: Some("send donation to alice".to_string()),
        })
    }
}

#[derive(Action)]
#[action(
    icon = "https://media.discordapp.net/attachments/1205590693041541181/1212566609202520065/icon.png?ex=667eb568&is=667d63e8&hm=0f247078545828c0a5cf8300a5601c56bbc9b59d3d87a0c74b082df0f3a6d6bd&=&format=webp&quality=lossless&width=660&height=660",
    title = "Send a Donation to {{params.receiver_address}}",
    description = "Send a donation to {{params.receiver_address}} using the Solana blockchain via a Blink.",
    label = "Send",
    link = {
        label = "Send 1 SOL",
        href = "/api/send_donation/{{params.receiver_address}}?amount=1",
    },
    link = {
        label = "Send 5 SOL",
        href = "/api/send_donation/{{params.receiver_address}}?amount=5",
    },
    link = {
        label = "Send SOL",
        href = "/api/send_donation/{{params.receiver_address}}?amount={amount}",
        parameter = { label = "Amount in SOL", name = "amount" }
    },
)]
#[query(amount: u64)]
#[params(receiver_address: String)]
pub struct SendDonationAction;

#[derive(ErrorCode)]
enum ActionError {
    #[error(msg = "Invalid account public key")]
    InvalidAccountPublicKey,
    #[error(msg = "Invalid receiver public key")]
    InvalidReceiverPublicKey,
}

Dependencies

~2.7–9.5MB
~99K SLoC