Lewati ke konten
Teknologi

Sesempit mungkin di rantai, selebih-lebihnya di luar

Fungsi transfer dan pencatatan saldo dijalankan SPL Token-2022. Program Anchor AsetHoki hanya menjadi lapisan konfigurasi. Semakin sedikit yang ditulis sendiri, semakin sedikit yang bisa salah secara permanen.

Komponen inti

AsetHoki Mint

Alamat mint Token-2022 kanonis yang mengidentifikasi aset ini.

Akun treasury

Dompet terpisah untuk alokasi Ekosistem, pengembangan, kemitraan, vesting tim, komunitas, dan kepatuhan.

Ekosistem Access Service

Layanan backend yang menanyakan RPC/indexer Solana lalu memulangkan status kelayakan.

Wallet Binding

Pemetaan aman antara akun Ekosistem terautentikasi dan alamat dompet Solana yang terverifikasi.

Config PDA

Menyimpan admin, alamat mint, treasury, suplai total, dan ambang akses Ekosistem.

Pemantauan

Pemantauan transaksi, peringatan treasury, kesehatan RPC, status sinkronisasi dompet, dan pencatatan insiden.

On-chain vs off-chain

Kepemilikan token berada di rantai. Otorisasi Ekosistem, kontrak pelanggan, penagihan langganan, dan aturan bisnis rinci tetap di luar rantai. Ini menekan biaya transaksi dan mencegah setiap penyesuaian kebijakan Ekosistem berubah menjadi pemutakhiran program blockchain.

Program Anchor

Konfigurasi dan ambang akses

Karena seluruh suplai dibuat satu kali lewat Token-2022, program akses tidak memerlukan fungsi mint imbalan yang dapat menambah suplai.

programs/asethoki_access/src/lib.rs · Rust / Anchor
use anchor_lang::prelude::*;

declare_id!("AHoKi1111111111111111111111111111111111111");

pub const DECIMALS: u8 = 9;
pub const MAX_SUPPLY_TOKENS: u64 = 8_888_888;

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

    pub fn initialize_config(
        ctx: Context<InitializeConfig>,
        basic_threshold: u64,
        pro_threshold: u64,
        enterprise_threshold: u64,
    ) -> Result<()> {
        require!(basic_threshold > 0, AsetHokiError::InvalidThreshold);
        require!(basic_threshold < pro_threshold, AsetHokiError::InvalidThreshold);
        require!(pro_threshold < enterprise_threshold, AsetHokiError::InvalidThreshold);

        let cfg = &mut ctx.accounts.config;
        cfg.admin = ctx.accounts.admin.key();
        cfg.mint = ctx.accounts.mint;
        cfg.treasury = ctx.accounts.treasury;
        cfg.max_supply_tokens = MAX_SUPPLY_TOKENS;
        cfg.basic_threshold = basic_threshold;
        cfg.pro_threshold = pro_threshold;
        cfg.enterprise_threshold = enterprise_threshold;
        cfg.bump = ctx.bumps.config;
        Ok(())
    }

    pub fn update_thresholds(
        ctx: Context<UpdateThresholds>,
        basic_threshold: u64,
        pro_threshold: u64,
        enterprise_threshold: u64,
    ) -> Result<()> {
        require!(basic_threshold > 0, AsetHokiError::InvalidThreshold);
        require!(basic_threshold < pro_threshold, AsetHokiError::InvalidThreshold);
        require!(pro_threshold < enterprise_threshold, AsetHokiError::InvalidThreshold);

        let cfg = &mut ctx.accounts.config;
        cfg.basic_threshold = basic_threshold;
        cfg.pro_threshold = pro_threshold;
        cfg.enterprise_threshold = enterprise_threshold;
        Ok(())
    }
}

#[account]
pub struct AsetHokiConfig {
    pub admin: Pubkey,
    pub mint: Pubkey,
    pub treasury: Pubkey,
    pub max_supply_tokens: u64,
    pub basic_threshold: u64,
    pub pro_threshold: u64,
    pub enterprise_threshold: u64,
    pub bump: u8,
}

Ambang divalidasi menaik (basic < pro < enterprise) dan admin diikat lewat has_one pada UpdateThresholds — tanpa itu siapa pun yang menandatangani bisa menulis ulang kebijakan akses seluruh Ekosistem.

Penerbitan

Mencetak 8.888.888 lalu menutup pintunya

scripts/deploy-mint.ts · TypeScript
import { Connection, Keypair, clusterApiUrl } from "@solana/web3.js";
import {
  TOKEN_2022_PROGRAM_ID, AuthorityType,
  createMint, getOrCreateAssociatedTokenAccount, mintTo, setAuthority,
} from "@solana/spl-token";

const DECIMALS = 9;
const TOTAL_SUPPLY = 8_888_888n;

const mint = await createMint(
  connection, payer, mintAuthority.publicKey, freezeAuthority,
  DECIMALS, undefined, undefined, TOKEN_2022_PROGRAM_ID,
);

const baseUnits = TOTAL_SUPPLY * (10n ** BigInt(DECIMALS));
await mintTo(connection, payer, mint, treasuryAta.address,
             mintAuthority, baseUnits, [], undefined, TOKEN_2022_PROGRAM_ID);

// Suplai dibuat tetap: cabut mint authority setelah seluruh suplai dicetak.
await setAuthority(connection, payer, mint, mintAuthority,
                   AuthorityType.MintTokens, null, [], undefined,
                   TOKEN_2022_PROGRAM_ID);
Contoh, bukan kode siap mainnet

Cuplikan di atas memperlakukan 8.888.888 sebagai suplai tetap dan memakai clusterApiUrl("devnet") beserta keypair yang dihasilkan di tempat. Penerapan sungguhan memerlukan signer yang aman, pengujian, audit keamanan, serta tinjauan desain operasional dan regulasi.

Bila mint authority justru ingin dipertahankan untuk kebutuhan tertentu, desain tata kelola, batas mint, multisig, dan kontrol suplai harus dibuat berbeda — dan klaim “suplai tetap” harus dicabut dari seluruh materi.

Sisi Ekosistem

Membaca saldo tanpa menyentuh token

src/akses/asethoki.ts · TypeScript
export async function getAsetHokiAccessLevel(
  connection: Connection, walletAddress: string, mintAddress: string,
) {
  const owner = new PublicKey(walletAddress);
  const mint  = new PublicKey(mintAddress);

  const accounts = await connection.getParsedTokenAccountsByOwner(owner, {
    programId: TOKEN_2022_PROGRAM_ID,
  });

  let balance = 0;
  for (const item of accounts.value) {
    const info = item.account.data.parsed.info;
    if (info.mint === mint.toBase58()) {
      balance += Number(info.tokenAmount.uiAmount || 0);
    }
  }

  if (balance >= 5000) return { level: "Enterprise",   balance };
  if (balance >= 500)  return { level: "Professional", balance };
  if (balance >= 100)  return { level: "Basic",        balance };
  return { level: "Trial", balance };
}
Untuk produksi, ini belum cukup

Hasil RPC sebaiknya dikombinasikan dengan caching, percobaan ulang, pemeriksaan finalitas, pemantauan, dan masa tenggang — agar perubahan saldo tidak mendadak mengganggu operasional perusahaan pengguna. Pemadaman RPC harus jatuh ke mode terdegradasi yang terdefinisi, bukan ke penolakan akses.

Keamanan

Daftar periksa

Aset kripto tidak mengenal pembatalan: tidak ada chargeback, tidak ada pemulihan. Kontrol berikut diterapkan sebelum mainnet, bukan sesudah.

KontrolYang harus dipastikan
Verifikasi suplai tetapSetelah mint 8.888.888 selesai, pastikan mint authority benar-benar sudah dicabut bila suplai tetap adalah kebijakan final.
Multisig treasuryTreasury besar tidak boleh dikendalikan satu private key.
Freeze authorityTentukan secara eksplisit apakah dipertahankan, dipindahkan ke multisig, atau dicabut.
Audit penerapanCatat alamat mint, program ID, treasury, authority, signature transaksi, dan konfigurasi ambang.
Keamanan dompetJangan menyimpan private key pengguna di basis data biasa; pakai non-kustodial, MPC, atau kustodian yang sesuai.
Fail-safe EkosistemMasa tenggang dan mekanisme cadangan bila RPC gagal atau data saldo sementara tidak tersedia.
VestingKontrak vesting atau proses berkunci waktu untuk alokasi tim dan kontributor.
Audit independenAudit smart contract oleh pihak ketiga sebelum dipakai di mainnet.
Batas laju imbalanPembatasan laju dan alur persetujuan untuk distribusi imbalan.
Redundansi RPCRPC/indexer ganda beserta pemantauannya untuk verifikasi saldo.