Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

token: Add Zig implementation #15

Merged
merged 2 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
name: Run tests against Zig implementations
strategy:
matrix:
program: [helloworld, transfer-lamports, cpi]
program: [helloworld, transfer-lamports, cpi, token]
fail-fast: false
runs-on: ubuntu-latest
steps:
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,33 +197,39 @@ Token program.
| Language | CU Usage |
| --- | --- |
| Rust | 1115 |
| Zig | 165 |

* Initialize Account

| Language | CU Usage |
| --- | --- |
| Rust | 2071 |
| Zig | 189 |

* Mint To

| Language | CU Usage |
| --- | --- |
| Rust | 2189 |
| Zig | 215 |

* Transfer

| Language | CU Usage |
| --- | --- |
| Rust | 2208 |
| Zig | 205 |

* Burn

| Language | CU Usage |
| --- | --- |
| Rust | 2045 |
| Zig | 175 |

* Close Account

| Language | CU Usage |
| --- | --- |
| Rust | 1483 |
| Zig | 291 |
5 changes: 3 additions & 2 deletions test-zig.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#!/usr/bin/env bash

PROGRAM_NAME="$1"
ZIG="$2"
#ZIG="$2"
PARAMS=("$@")
ROOT_DIR="$(cd "$(dirname "$0")"; pwd)"
if [[ -z "$ZIG" ]]; then
ZIG="$ROOT_DIR/solana-zig/zig"
Expand All @@ -11,4 +12,4 @@ set -e
PROGRAM_DIR=$ROOT_DIR/$PROGRAM_NAME
cd $PROGRAM_DIR/zig
$ZIG build --summary all -freference-trace --verbose
SBF_OUT_DIR="$PROGRAM_DIR/zig/zig-out/lib" cargo test --manifest-path "$PROGRAM_DIR/Cargo.toml"
SBF_OUT_DIR="$PROGRAM_DIR/zig/zig-out/lib" cargo test --manifest-path "$PROGRAM_DIR/Cargo.toml" "${PARAMS[@]:2}"
2 changes: 0 additions & 2 deletions token/tests/assert_instruction_count.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![cfg(feature = "test-sbf")]

mod action;
use {
solana_program_test::{processor, tokio, ProgramTest},
Expand Down
24 changes: 24 additions & 0 deletions token/zig/build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const std = @import("std");
const solana = @import("solana-program-sdk");

pub fn build(b: *std.Build) !void {
const target = b.resolveTargetQuery(solana.sbf_target);
const optimize = .ReleaseFast;

//const dep_opts = .{ .target = target, .optimize = optimize };
//const solana_lib_dep = b.dependency("solana-program-library", dep_opts);
//const solana_lib_mod = solana_lib_dep.module("solana-program-library");

const program = b.addSharedLibrary(.{
.name = "spl_token",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});

//program.root_module.addImport("solana-program-library", solana_lib_mod);

_ = solana.buildProgram(b, program, target, optimize);

b.installArtifact(program);
}
38 changes: 38 additions & 0 deletions token/zig/build.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.{
.name = "solana-program-rosetta-token-zig",
// This is a [Semantic Version](https://semver.org/).
// In a future version of Zig it will be used for package deduplication.
.version = "0.13.0",

// This field is optional.
// This is currently advisory only; Zig does not yet do anything
// with this value.
.minimum_zig_version = "0.13.0",

// This field is optional.
// Each dependency must either provide a `url` and `hash`, or a `path`.
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
// Once all dependencies are fetched, `zig build` no longer requires
// internet connectivity.
.dependencies = .{
.@"solana-program-sdk" = .{
.url = "https://github.com/joncinque/solana-program-sdk-zig/archive/refs/tags/v0.15.0.tar.gz",
.hash = "1220c255d7d80a59251d901da4d2982eb660d099680c1207b14f51078987c655c979",
},
},

// Specifies the set of files and directories that are included in this package.
// Only files and directories listed here are included in the `hash` that
// is computed for this package.
// Paths are relative to the build root. Use the empty string (`""`) to refer to
// the build root itself.
// A directory listed here means that all files within, recursively, are included.
.paths = .{
// For example...
"build.zig",
"build.zig.zon",
"src",
"../../LICENSE",
"../../README.md",
},
}
140 changes: 140 additions & 0 deletions token/zig/src/error.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
const sol = @import("solana-program-sdk");

pub const TokenError = error{
NotRentExempt,
InsufficientFunds,
InvalidMint,
MintMismatch,
OwnerMismatch,
FixedSupply,
AlreadyInUse,
InvalidNumberOfProvidedSigners,
InvalidNumberOfRequiredSigners,
UninitializedState,
NativeNotSupported,
NonNativeHasBalance,
InvalidInstruction,
InvalidState,
Overflow,
AuthorityTypeNotSupported,
MintCannotFreeze,
AccountFrozen,
MintDecimalsMismatch,
NonNativeNotSupported,
// generic program errors
InvalidArgument,
InvalidInstructionData,
InvalidAccountData,
AccountDataTooSmall,
//InsufficientFunds,
IncorrectProgramId,
MissingRequiredSignature,
AccountAlreadyInitialized,
UninitializedAccount,
NotEnoughAccountKeys,
AccountBorrowFailed,
MaxSeedLengthExceeded,
InvalidSeeds,
BorshIoError,
AccountNotRentExempt,
UnsupportedSysvar,
IllegalOwner,
MaxAccountsDataAllocationsExceeded,
InvalidRealloc,
MaxInstructionTraceLengthExceeded,
BuiltinProgramsMustConsumeComputeUnits,
InvalidAccountOwner,
ArithmeticOverflow,
Immutable,
IncorrectAuthority,
};

pub fn logError(e: TokenError) void {
switch (e) {
TokenError.NotRentExempt => {
sol.log("Error: Lamport balance below rent-exempt threshold");
},
TokenError.InsufficientFunds => {
sol.log("Error: insufficient funds");
},
TokenError.InvalidMint => {
sol.log("Error: Invalid Mint");
},
TokenError.MintMismatch => {
sol.log("Error: Account not associated with this Mint");
},
TokenError.OwnerMismatch => {
sol.log("Error: owner does not match");
},
TokenError.FixedSupply => {
sol.log("Error: the total supply of this token is fixed");
},
TokenError.AlreadyInUse => {
sol.log("Error: account or token already in use");
},
TokenError.InvalidNumberOfProvidedSigners => {
sol.log("Error: Invalid number of provided signers");
},
TokenError.InvalidNumberOfRequiredSigners => {
sol.log("Error: Invalid number of required signers");
},
TokenError.UninitializedState => {
sol.log("Error: State is uninitialized");
},
TokenError.NativeNotSupported => {
sol.log("Error: Instruction does not support native tokens");
},
TokenError.NonNativeHasBalance => {
sol.log("Error: Non-native account can only be closed if its balance is zero");
},
TokenError.InvalidInstruction => {
sol.log("Error: Invalid instruction");
},
TokenError.InvalidState => {
sol.log("Error: Invalid account state for operation");
},
TokenError.Overflow => {
sol.log("Error: Operation overflowed");
},
TokenError.AuthorityTypeNotSupported => {
sol.log("Error: Account does not support specified authority type");
},
TokenError.MintCannotFreeze => {
sol.log("Error: This token mint cannot freeze accounts");
},
TokenError.AccountFrozen => {
sol.log("Error: Account is frozen");
},
TokenError.MintDecimalsMismatch => {
sol.log("Error: decimals different from the Mint decimals");
},
TokenError.NonNativeNotSupported => {
sol.log("Error: Instruction does not support non-native tokens");
},
TokenError.InvalidArgument => {},
TokenError.InvalidInstructionData => {},
TokenError.InvalidAccountData => {},
TokenError.AccountDataTooSmall => {},
TokenError.InsufficientFunds => {},
TokenError.IncorrectProgramId => {},
TokenError.MissingRequiredSignature => {},
TokenError.AccountAlreadyInitialized => {},
TokenError.UninitializedAccount => {},
TokenError.NotEnoughAccountKeys => {},
TokenError.AccountBorrowFailed => {},
TokenError.MaxSeedLengthExceeded => {},
TokenError.InvalidSeeds => {},
TokenError.BorshIoError => {},
TokenError.AccountNotRentExempt => {},
TokenError.UnsupportedSysvar => {},
TokenError.IllegalOwner => {},
TokenError.MaxAccountsDataAllocationsExceeded => {},
TokenError.InvalidRealloc => {},
TokenError.MaxInstructionTraceLengthExceeded => {},
TokenError.BuiltinProgramsMustConsumeComputeUnits => {},
TokenError.InvalidAccountOwner => {},
TokenError.ArithmeticOverflow => {},
TokenError.Immutable => {},
TokenError.IncorrectAuthority => {},
}
}
4 changes: 4 additions & 0 deletions token/zig/src/id.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const PublicKey = @import("solana-program-sdk").PublicKey;
pub const id = PublicKey.comptimeFromBase58("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
pub const native_mint_id = PublicKey.comptimeFromBase58("So11111111111111111111111111111111111111112");
pub const system_program_id = PublicKey.comptimeFromBase58("11111111111111111111111111111111");
Loading