Panduan ini menjelaskan cara menambahkan token asli Solana, SOL, ke bursa kripto Anda.
Pengaturan Node
Kami sangat menyarankan untuk menyiapkan setidaknya dua node pada komputer/instans cloud berkualitas tinggi, segera melakukan pembaruan ke versi terbaru, dan memantau operasi layanan menggunakan alat pemantauan bawaan.
Pengaturan ini memungkinkan Anda:
- memiliki gateway yang dikelola sendiri ke kluster mainnet Solana untuk mendapatkan data dan mengirimkan transaksi penarikan
- memiliki kendali penuh atas seberapa banyak data blok historis yang disimpan
- menjaga ketersediaan layanan Anda meskipun salah satu node mengalami kegagalan
Node Solana membutuhkan daya komputasi yang cukup tinggi untuk menangani blok cepat dan TPS tinggi kami. Untuk persyaratan spesifik, silakan lihat rekomendasi perangkat keras.
Untuk menjalankan node api:
- Instal suite alat command-line Solana
- Jalankan validator dengan setidaknya parameter berikut:
solana-validator \--ledger <LEDGER_PATH> \--identity <VALIDATOR_IDENTITY_KEYPAIR> \--entrypoint <CLUSTER_ENTRYPOINT> \--expected-genesis-hash <EXPECTED_GENESIS_HASH> \--rpc-port 8899 \--no-voting \--enable-rpc-transaction-history \--limit-ledger-size \--known-validator <VALIDATOR_ADDRESS> \--only-known-rpc
Sesuaikan --ledger ke lokasi penyimpanan ledger yang Anda inginkan, dan --rpc-port
ke port yang ingin Anda ekspos.
Parameter --entrypoint dan --expected-genesis-hash bersifat spesifik untuk
kluster yang Anda ikuti.
Parameter saat ini untuk Mainnet
Parameter --limit-ledger-size memungkinkan Anda menentukan berapa banyak
shreds ledger yang disimpan node Anda di disk. Jika Anda
tidak menyertakan parameter ini, validator akan menyimpan seluruh ledger hingga
kehabisan ruang disk. Nilai default berupaya menjaga penggunaan disk ledger
di bawah 500GB. Penggunaan disk yang lebih banyak atau lebih sedikit dapat diminta
dengan menambahkan argumen pada --limit-ledger-size jika diinginkan. Periksa
solana-validator --help untuk nilai batas default yang digunakan oleh
--limit-ledger-size. Informasi lebih lanjut tentang memilih nilai batas kustom
tersedia di sini.
Menentukan satu atau lebih parameter --known-validator dapat melindungi Anda dari
booting menggunakan snapshot yang berbahaya.
Selengkapnya tentang manfaat booting dengan known validator
Parameter opsional yang perlu dipertimbangkan:
--private-rpcmencegah port RPC Anda dipublikasikan untuk digunakan oleh node lain--rpc-bind-addressmemungkinkan Anda menentukan alamat IP yang berbeda untuk mengikat port RPC
Restart Otomatis dan Pemantauan
Kami menyarankan untuk mengonfigurasi setiap node Anda agar restart secara otomatis saat keluar, guna memastikan Anda melewatkan sesedikit mungkin data. Menjalankan perangkat lunak Solana sebagai layanan systemd adalah salah satu opsi terbaik.
Untuk pemantauan, kami menyediakan
solana-watchtower,
yang dapat memantau validator Anda dan mendeteksi apakah proses solana-validator
tidak berjalan dengan baik. Alat ini dapat dikonfigurasi langsung untuk memberi
tahu Anda melalui Slack, Telegram, Discord, atau Twilio. Untuk detailnya,
jalankan solana-watchtower --help.
solana-watchtower --validator-identity <YOUR VALIDATOR IDENTITY>
Anda dapat menemukan informasi lebih lanjut tentang praktik terbaik untuk Solana Watchtower di sini dalam dokumentasi.
Pengumuman Rilis Perangkat Lunak Baru
Kami merilis perangkat lunak baru secara rutin (sekitar 1 rilis/minggu). Terkadang versi terbaru mencakup perubahan protokol yang tidak kompatibel, sehingga memerlukan pembaruan perangkat lunak yang tepat waktu untuk menghindari kesalahan dalam pemrosesan blok.
Pengumuman rilis resmi kami untuk semua jenis rilis (normal dan keamanan)
dikomunikasikan melalui saluran discord bernama
#mb-announcement (mb adalah singkatan dari mainnet-beta).
Seperti halnya validator yang di-stake, kami mengharapkan setiap validator yang dioperasikan oleh bursa untuk diperbarui sesegera mungkin dalam satu atau dua hari kerja setelah pengumuman rilis normal. Untuk rilis terkait keamanan, tindakan yang lebih mendesak mungkin diperlukan.
Kesinambungan Ledger
Secara default, setiap node Anda akan melakukan boot dari snapshot yang disediakan
oleh salah satu known validator Anda. Snapshot ini mencerminkan kondisi rantai
saat ini, tetapi tidak memuat ledger historis yang lengkap. Jika salah satu node
Anda keluar dan melakukan boot dari snapshot baru, mungkin akan terdapat celah
dalam ledger di node tersebut. Untuk mencegah masalah ini, tambahkan parameter
--no-snapshot-fetch pada perintah solana-validator Anda untuk menerima data
ledger historis, bukan snapshot.
Jangan gunakan parameter --no-snapshot-fetch saat boot awal karena tidak
mungkin melakukan boot node dari genesis block. Sebaliknya, lakukan boot dari
snapshot terlebih dahulu, lalu tambahkan parameter --no-snapshot-fetch untuk
reboot berikutnya.
Penting untuk dicatat bahwa jumlah ledger historis yang tersedia bagi node Anda dari seluruh jaringan terbatas pada setiap saat. Setelah beroperasi, jika validator Anda mengalami downtime yang signifikan, validator tersebut mungkin tidak dapat menyusul jaringan dan perlu mengunduh snapshot baru dari known validator. Dengan melakukan ini, validator Anda akan memiliki celah dalam data ledger historisnya yang tidak dapat diisi.
Meminimalkan Eksposur Port Validator
Validator memerlukan berbagai port UDP dan TCP yang terbuka untuk lalu lintas masuk dari semua validator Solana lainnya. Meskipun ini adalah mode operasi yang paling efisien dan sangat disarankan, validator dapat dibatasi sehingga hanya memerlukan lalu lintas masuk dari satu validator Solana lainnya.
Pertama, tambahkan argumen --restricted-repair-only-mode. Ini akan menyebabkan
validator beroperasi dalam mode terbatas di mana ia tidak akan menerima push dari
validator lainnya, melainkan harus terus-menerus melakukan polling ke validator
lain untuk mendapatkan blok. Validator hanya akan mengirimkan paket UDP ke
validator lain menggunakan port Gossip dan ServeR ("serve repair"), dan hanya
menerima paket UDP pada port Gossip dan Repair-nya.
Port Gossip bersifat dua arah dan memungkinkan validator Anda tetap terhubung dengan seluruh kluster. Validator Anda mengirimkan pada ServeR untuk membuat permintaan perbaikan guna mendapatkan blok baru dari seluruh jaringan, karena Turbine kini dinonaktifkan. Validator Anda kemudian akan menerima respons perbaikan pada port Repair dari validator lain.
Untuk lebih membatasi validator agar hanya meminta blok dari satu atau lebih
validator, pertama tentukan identity pubkey untuk validator tersebut dan tambahkan
argumen --gossip-pull-validator PUBKEY --repair-validator PUBKEY untuk setiap
PUBKEY. Ini akan menyebabkan validator Anda menjadi beban sumber daya bagi setiap
validator yang Anda tambahkan, jadi lakukan ini dengan hemat dan hanya setelah
berkonsultasi dengan validator target.
Validator Anda sekarang seharusnya hanya berkomunikasi dengan validator yang tercantum secara eksplisit dan hanya pada port Gossip, Repair, dan ServeR.
Menyiapkan Akun Deposit
Akun Solana tidak memerlukan inisialisasi onchain; begitu berisi sejumlah SOL, akun tersebut sudah ada. Untuk menyiapkan akun deposit bagi bursa Anda, cukup buat keypair Solana menggunakan salah satu alat wallet kami.
Kami menyarankan penggunaan akun deposit unik untuk setiap pengguna Anda.
Akun Solana harus dibuat bebas rent dengan menyimpan saldo setara rent selama
2 tahun dalam SOL. Untuk menemukan saldo minimum bebas rent bagi akun deposit
Anda, lakukan kueri pada
endpoint getMinimumBalanceForRentExemption:
curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id": 1,"method": "getMinimumBalanceForRentExemption","params": [0]}'
Hasil
{ "jsonrpc": "2.0", "result": 890880, "id": 1 }
Akun Offline
Anda mungkin ingin menyimpan kunci untuk satu atau lebih akun koleksi secara offline demi keamanan yang lebih baik. Jika demikian, Anda perlu memindahkan SOL ke akun hot menggunakan metode offline kami.
Mendengarkan Deposit
Ketika pengguna ingin menyetorkan SOL ke bursa Anda, instruksikan mereka untuk mengirim transfer ke alamat deposit yang sesuai.
Migrasi Transaksi Berversi
Ketika jaringan Mainnet mulai memproses transaksi berversi, bursa HARUS melakukan perubahan. Jika tidak ada perubahan yang dilakukan, deteksi deposit tidak akan lagi berfungsi dengan benar karena pengambilan transaksi berversi atau blok yang berisi transaksi berversi akan mengembalikan kesalahan.
-
{"maxSupportedTransactionVersion": 0}Parameter
maxSupportedTransactionVersionharus ditambahkan ke permintaangetBlockdangetTransactionuntuk menghindari gangguan pada deteksi deposit. Versi transaksi terbaru adalah0dan harus ditentukan sebagai nilai versi transaksi maksimum yang didukung.
Penting untuk dipahami bahwa transaksi berversi memungkinkan pengguna membuat transaksi yang menggunakan kumpulan kunci akun lain yang dimuat dari tabel lookup alamat onchain.
-
{"encoding": "jsonParsed"}Saat mengambil blok dan transaksi, sekarang disarankan untuk menggunakan encoding
"jsonParsed"karena menyertakan semua kunci akun transaksi (termasuk yang berasal dari tabel lookup) dalam daftar"accountKeys"pesan. Hal ini memudahkan penyelesaian perubahan saldo yang dirinci dalampreBalances/postBalancesdanpreTokenBalances/postTokenBalances.Jika encoding
"json"digunakan sebagai gantinya, entri dalampreBalances/postBalancesdanpreTokenBalances/postTokenBalancesmungkin merujuk pada kunci akun yang TIDAK ada dalam daftar"accountKeys"dan perlu diselesaikan menggunakan entri"loadedAddresses"dalam metadata transaksi.
Poll untuk Blok
Untuk melacak semua akun deposit di bursa Anda, lakukan poll untuk setiap blok yang dikonfirmasi dan periksa alamat yang relevan, menggunakan layanan JSON-RPC dari node API Solana Anda.
- Untuk mengidentifikasi blok yang tersedia, kirimkan permintaan
getBlocks, dengan meneruskan blok terakhir yang telah Anda proses sebagai parameter start-slot:
curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id": 1,"method": "getBlocks","params": [160017005, 160017015]}'
Hasil
{"jsonrpc": "2.0","result": [160017005, 160017006, 160017007, 160017012, 160017013, 160017014, 160017015],"id": 1}
Tidak setiap slot menghasilkan blok, sehingga mungkin terdapat celah dalam urutan bilangan bulat tersebut.
- Untuk setiap blok, minta isinya dengan permintaan
getBlock:
Tips Pengambilan Blok
{"rewards": false}
Secara default, blok yang diambil akan mengembalikan informasi tentang biaya validator pada setiap blok dan hadiah staking pada batas epoch. Jika Anda tidak memerlukan informasi ini, nonaktifkan dengan parameter "rewards".
{"transactionDetails": "accounts"}
Secara default, blok yang diambil akan mengembalikan banyak informasi transaksi dan metadata yang tidak diperlukan untuk melacak saldo akun. Atur parameter "transactionDetails" untuk mempercepat pengambilan blok.
curl https://api.devnet.solana.com -X POST -H 'Content-Type: application/json' -d '{"jsonrpc": "2.0","id": 1,"method": "getBlock","params": [166974442,{"encoding": "jsonParsed","maxSupportedTransactionVersion": 0,"transactionDetails": "accounts","rewards": false}]}'
Hasil
{"jsonrpc": "2.0","result": {"blockHeight": 157201607,"blockTime": 1665070281,"blockhash": "HKhao674uvFc4wMK1Cm3UyuuGbKExdgPFjXQ5xtvsG3o","parentSlot": 166974441,"previousBlockhash": "98CNLU4rsYa2HDUyp7PubU4DhwYJJhSX9v6pvE7SWsAo","transactions": [... (omit){"meta": {"err": null,"fee": 5000,"postBalances": [1110663066,1,1040000000],"postTokenBalances": [],"preBalances": [1120668066,1,1030000000],"preTokenBalances": [],"status": {"Ok": null}},"transaction": {"accountKeys": [{"pubkey": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde","signer": true,"source": "transaction","writable": true},{"pubkey": "11111111111111111111111111111111","signer": false,"source": "transaction","writable": false},{"pubkey": "G1wZ113tiUHdSpQEBcid8n1x8BAvcWZoZgxPKxgE5B7o","signer": false,"source": "lookupTable","writable": true}],"signatures": ["2CxNRsyRT7y88GBwvAB3hRg8wijMSZh3VNYXAdUesGSyvbRJbRR2q9G1KSEpQENmXHmmMLHiXumw4dp8CvzQMjrM"]},"version": 0},... (omit)]},"id": 1}
Bidang preBalances dan postBalances memungkinkan Anda melacak perubahan saldo di setiap akun tanpa harus mengurai seluruh transaksi. Keduanya mencantumkan saldo awal dan akhir setiap akun dalam lamport, yang diindeks ke daftar accountKeys. Misalnya, jika alamat deposit yang diminati adalah G1wZ113tiUHdSpQEBcid8n1x8BAvcWZoZgxPKxgE5B7o, transaksi ini merepresentasikan transfer sebesar 1040000000 - 1030000000 = 10.000.000 lamport = 0,01 SOL
Jika Anda memerlukan informasi lebih lanjut tentang jenis transaksi atau detail lainnya, Anda dapat meminta blok dari RPC dalam format biner, dan mengurainya menggunakan Rust SDK atau Javascript SDK kami.
Riwayat Alamat
Anda juga dapat melakukan kueri riwayat transaksi dari alamat tertentu. Ini umumnya bukan metode yang layak untuk melacak semua alamat deposit Anda di semua slot, tetapi mungkin berguna untuk memeriksa beberapa akun dalam periode waktu tertentu.
- Kirim permintaan
getSignaturesForAddresske node API:
curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id": 1,"method": "getSignaturesForAddress","params": ["3M2b3tLji7rvscqrLAHMukYxDK2nB96Q9hwfV6QkdzBN",{"limit": 3}]}'
Hasil
{"jsonrpc": "2.0","result": [{"blockTime": 1662064640,"confirmationStatus": "finalized","err": null,"memo": null,"signature": "3EDRvnD5TbbMS2mCusop6oyHLD8CgnjncaYQd5RXpgnjYUXRCYwiNPmXb6ZG5KdTK4zAaygEhfdLoP7TDzwKBVQp","slot": 148697216},{"blockTime": 1662064434,"confirmationStatus": "finalized","err": null,"memo": null,"signature": "4rPQ5wthgSP1kLdLqcRgQnkYkPAZqjv5vm59LijrQDSKuL2HLmZHoHjdSLDXXWFwWdaKXUuryRBGwEvSxn3TQckY","slot": 148696843},{"blockTime": 1662064341,"confirmationStatus": "finalized","err": null,"memo": null,"signature": "36Q383JMiqiobuPV9qBqy41xjMsVnQBm9rdZSdpbrLTGhSQDTGZJnocM4TQTVfUGfV2vEX9ZB3sex6wUBUWzjEvs","slot": 148696677}],"id": 1}
- Untuk setiap tanda tangan yang dikembalikan, dapatkan detail transaksi dengan mengirimkan permintaan
getTransaction:
curl https://api.devnet.solana.com -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1,"method":"getTransaction","params":["2CxNRsyRT7y88GBwvAB3hRg8wijMSZh3VNYXAdUesGSyvbRJbRR2q9G1KSEpQENmXHmmMLHiXumw4dp8CvzQMjrM",{"encoding":"jsonParsed","maxSupportedTransactionVersion":0}]}'
Hasil
{"jsonrpc": "2.0","result": {"blockTime": 1665070281,"meta": {"err": null,"fee": 5000,"innerInstructions": [],"logMessages": ["Program 11111111111111111111111111111111 invoke [1]","Program 11111111111111111111111111111111 success"],"postBalances": [1110663066, 1, 1040000000],"postTokenBalances": [],"preBalances": [1120668066, 1, 1030000000],"preTokenBalances": [],"rewards": [],"status": {"Ok": null}},"slot": 166974442,"transaction": {"message": {"accountKeys": [{"pubkey": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde","signer": true,"source": "transaction","writable": true},{"pubkey": "11111111111111111111111111111111","signer": false,"source": "transaction","writable": false},{"pubkey": "G1wZ113tiUHdSpQEBcid8n1x8BAvcWZoZgxPKxgE5B7o","signer": false,"source": "lookupTable","writable": true}],"addressTableLookups": [{"accountKey": "4syr5pBaboZy4cZyF6sys82uGD7jEvoAP2ZMaoich4fZ","readonlyIndexes": [],"writableIndexes": [3]}],"instructions": [{"parsed": {"info": {"destination": "G1wZ113tiUHdSpQEBcid8n1x8BAvcWZoZgxPKxgE5B7o","lamports": 10000000,"source": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde"},"type": "transfer"},"program": "system","programId": "11111111111111111111111111111111"}],"recentBlockhash": "BhhivDNgoy4L5tLtHb1s3TP19uUXqKiy4FfUR34d93eT"},"signatures": ["2CxNRsyRT7y88GBwvAB3hRg8wijMSZh3VNYXAdUesGSyvbRJbRR2q9G1KSEpQENmXHmmMLHiXumw4dp8CvzQMjrM"]},"version": 0},"id": 1}
Mengirim Penarikan
Untuk mengakomodasi permintaan penarikan SOL dari pengguna, Anda harus membuat transaksi transfer Solana, dan mengirimkannya ke node API untuk diteruskan ke klaster Anda.
Sinkron
Mengirim transfer sinkron ke klaster Solana memungkinkan Anda memastikan dengan mudah bahwa transfer berhasil dan telah difinalisasi oleh klaster.
Alat baris perintah Solana menawarkan perintah sederhana, solana transfer, untuk membuat, mengirimkan, dan mengonfirmasi transaksi transfer. Secara default, metode ini akan menunggu dan melacak kemajuan di stderr hingga transaksi difinalisasi oleh klaster. Jika transaksi gagal, metode ini akan melaporkan semua error transaksi.
solana transfer <USER_ADDRESS> <AMOUNT> --allow-unfunded-recipient --keypair <KEYPAIR> --url http://localhost:8899
Solana Javascript SDK menawarkan pendekatan serupa untuk ekosistem JS. Gunakan SystemProgram untuk membangun transaksi transfer, dan kirimkan menggunakan metode sendAndConfirmTransaction.
Asinkron
Untuk fleksibilitas yang lebih besar, Anda dapat mengirimkan transfer penarikan secara asinkron. Dalam kasus ini, Anda bertanggung jawab untuk memverifikasi bahwa transaksi berhasil dan telah difinalisasi oleh klaster.
Catatan: Setiap transaksi berisi blockhash terkini untuk menunjukkan aktualitasnya. Sangat penting untuk menunggu hingga blockhash ini kedaluwarsa sebelum mencoba kembali transfer penarikan yang tampaknya belum dikonfirmasi atau difinalisasi oleh klaster. Jika tidak, Anda berisiko melakukan pengeluaran ganda. Lihat selengkapnya tentang kedaluwarsa blockhash di bawah ini.
Pertama, dapatkan blockhash terkini menggunakan endpoint getFees atau perintah CLI:
solana fees --url http://localhost:8899
Pada alat baris perintah, tambahkan argumen --no-wait untuk mengirim transfer secara asinkron, dan sertakan blockhash terkini Anda dengan argumen --blockhash:
solana transfer <USER_ADDRESS> <AMOUNT> --no-wait --allow-unfunded-recipient --blockhash <RECENT_BLOCKHASH> --keypair <KEYPAIR> --url http://localhost:8899
Anda juga dapat membangun, menandatangani, dan membuat serial transaksi secara manual, lalu mengirimkannya ke klaster menggunakan endpoint JSON-RPC sendTransaction.
Konfirmasi Transaksi & Finalitas
Dapatkan status sekumpulan transaksi menggunakan endpoint JSON-RPC getSignatureStatuses. Bidang confirmations melaporkan berapa banyak blok yang dikonfirmasi yang telah berlalu sejak transaksi diproses. Jika confirmations: null, transaksi tersebut telah difinalisasi.
curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["4cdd1oX7cfVALfr26tP52BZ6cSzrgnNGtYD7BFhm6FFeZV5sPTnRvg6NRn8yC6DbEikXcrNChBM5vVJnTgKhGhVu","5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7"]]}'
Hasil
{"jsonrpc": "2.0","result": {"context": {"slot": 82},"value": [{"slot": 72,"confirmations": 10,"err": null,"status": {"Ok": null}},{"slot": 48,"confirmations": null,"err": null,"status": {"Ok": null}}]},"id": 1}
Kedaluwarsa Blockhash
Anda dapat memeriksa apakah blockhash tertentu masih valid dengan mengirimkan permintaan getFeeCalculatorForBlockhash dengan blockhash sebagai parameter. Jika nilai respons adalah null, blockhash telah kedaluwarsa, dan transaksi penarikan yang menggunakan blockhash tersebut tidak akan pernah berhasil.
Memvalidasi Alamat Akun yang Diberikan Pengguna untuk Penarikan
Karena penarikan bersifat tidak dapat dibatalkan, sebaiknya validasi alamat akun yang diberikan pengguna sebelum mengotorisasi penarikan guna mencegah kehilangan dana pengguna secara tidak sengaja.
Verifikasi dasar
Alamat Solana adalah array 32 byte, yang dikodekan dengan alfabet base58 bitcoin. Hasilnya berupa string teks ASCII yang cocok dengan ekspresi reguler berikut:
[1-9A-HJ-NP-Za-km-z]{32,44}
Pemeriksaan ini saja tidak cukup karena alamat Solana tidak memiliki checksum, sehingga kesalahan ketik tidak dapat terdeteksi. Untuk memvalidasi input pengguna lebih lanjut, string dapat didekode dan panjang array byte yang dihasilkan dikonfirmasi sebesar 32. Namun, ada beberapa alamat yang dapat didekode menjadi 32 byte meskipun terdapat kesalahan ketik seperti satu karakter yang hilang, karakter yang terbalik, dan huruf kapital yang diabaikan.
Verifikasi lanjutan
Karena kerentanan terhadap kesalahan ketik yang dijelaskan di atas, disarankan agar saldo dikueri untuk alamat penarikan kandidat dan pengguna diminta untuk mengonfirmasi niatnya jika saldo non-nol ditemukan.
Pemeriksaan pubkey ed25519 yang valid
Alamat akun normal di Solana adalah string berenkode Base58 dari kunci publik ed25519 256-bit. Tidak semua pola bit merupakan kunci publik yang valid untuk kurva ed25519, sehingga memungkinkan untuk memastikan alamat akun yang diberikan pengguna setidaknya merupakan pubkey ed25519 yang benar.
Java
Berikut adalah contoh Java untuk memvalidasi alamat yang diberikan pengguna sebagai pubkey ed25519 yang valid:
Contoh kode berikut mengasumsikan Anda menggunakan Maven.
pom.xml:
<repositories>...<repository><id>spring</id><url>https://repo.spring.io/libs-release/</url></repository></repositories>...<dependencies>...<dependency><groupId>io.github.novacrypto</groupId><artifactId>Base58</artifactId><version>0.1.3</version></dependency><dependency><groupId>cafe.cryptography</groupId><artifactId>curve25519-elisabeth</artifactId><version>0.1.0</version></dependency><dependencies>
import io.github.novacrypto.base58.Base58;import cafe.cryptography.curve25519.CompressedEdwardsY;public class PubkeyValidator{public static boolean verifyPubkey(String userProvidedPubkey){try {return _verifyPubkeyInternal(userProvidedPubkey);} catch (Exception e) {return false;}}public static boolean _verifyPubkeyInternal(String maybePubkey) throws Exception{byte[] bytes = Base58.base58Decode(maybePubkey);return !(new CompressedEdwardsY(bytes)).decompress().isSmallOrder();}}
Jumlah Minimum Deposit & Penarikan
Setiap deposit dan penarikan SOL harus lebih besar atau sama dengan saldo minimum yang bebas sewa untuk akun di alamat dompet (akun SOL dasar yang tidak menyimpan data), saat ini: 0,000890880 SOL
Demikian pula, setiap akun deposit harus mengandung setidaknya saldo ini.
curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id": 1,"method": "getMinimumBalanceForRentExemption","params": [0]}'
Hasil
{ "jsonrpc": "2.0", "result": 890880, "id": 1 }
Biaya Prioritas dan Unit Komputasi
Pada periode permintaan tinggi, ada kemungkinan transaksi kedaluwarsa sebelum validator menyertakan transaksi tersebut dalam blok mereka karena mereka memilih transaksi lain dengan nilai ekonomi yang lebih tinggi. Transaksi yang valid di Solana dapat tertunda atau dibatalkan jika Biaya Prioritas tidak diimplementasikan dengan benar.
Biaya Prioritas adalah biaya tambahan yang dapat ditambahkan di atas Biaya Transaksi dasar untuk memastikan penyertaan transaksi dalam blok dalam situasi ini dan membantu memastikan keterjangkauannya.
Biaya prioritas ini ditambahkan ke transaksi dengan menambahkan instruksi Compute Budget khusus yang menetapkan biaya prioritas yang ingin dibayar.
Catatan Penting
Kegagalan mengimplementasikan instruksi ini dapat mengakibatkan gangguan jaringan dan transaksi yang dibatalkan. Sangat disarankan agar setiap bursa yang mendukung Solana menggunakan biaya prioritas untuk menghindari gangguan.
Apa itu Biaya Prioritas?
Biaya Prioritas dihargai dalam micro-lamport per Unit Komputasi (misalnya, jumlah kecil SOL) yang ditambahkan di awal transaksi agar secara ekonomi menarik bagi node validator untuk disertakan dalam blok di jaringan.
Berapa Besar Biaya Prioritas yang Harus Ditetapkan?
Metode untuk menetapkan biaya prioritas Anda harus melibatkan kueri biaya prioritas terkini untuk menetapkan biaya yang kemungkinan besar menarik bagi jaringan. Menggunakan metode RPC getRecentPrioritizationFees, Anda dapat melakukan kueri biaya prioritas yang diperlukan untuk menempatkan transaksi dalam blok terkini.
Strategi penetapan harga untuk biaya prioritas ini akan bervariasi berdasarkan kasus penggunaan Anda. Tidak ada cara baku untuk melakukannya. Salah satu strategi untuk menetapkan Biaya Prioritas Anda mungkin adalah menghitung tingkat keberhasilan transaksi Anda, lalu meningkatkan Biaya Prioritas berdasarkan kueri ke API biaya transaksi terkini dan menyesuaikannya. Penetapan harga untuk Biaya Prioritas akan bersifat dinamis berdasarkan aktivitas di jaringan dan penawaran yang ditempatkan oleh peserta lain, yang hanya dapat diketahui setelah fakta terjadi.
Salah satu tantangan dalam menggunakan panggilan API getRecentPrioritizationFees adalah bahwa panggilan tersebut mungkin hanya mengembalikan biaya terendah untuk setiap blok. Ini sering kali bernilai nol, yang bukan merupakan perkiraan yang sepenuhnya berguna tentang Biaya Prioritas yang harus digunakan agar tidak ditolak oleh node validator.
API getRecentPrioritizationFees mengambil pubkey akun sebagai parameter, lalu mengembalikan nilai tertinggi dari biaya prioritas minimum untuk akun-akun tersebut. Jika tidak ada akun yang ditentukan, API akan mengembalikan biaya terendah untuk masuk ke blok, yang biasanya nol (kecuali blok penuh).
Bursa dan aplikasi harus melakukan kueri endpoint RPC dengan akun yang akan dikunci-tulis oleh transaksi. Endpoint RPC akan mengembalikan max(account_1_min_fee, account_2_min_fee, ... account_n_min_fee), yang seharusnya menjadi titik dasar bagi pengguna untuk menetapkan biaya prioritas untuk transaksi tersebut.
Ada berbagai pendekatan untuk menetapkan Biaya Prioritas dan beberapa API pihak ketiga tersedia untuk menentukan biaya terbaik yang harus diterapkan. Mengingat sifat jaringan yang dinamis, tidak akan ada cara yang "sempurna" untuk menetapkan harga Biaya Prioritas Anda, dan analisis yang cermat harus diterapkan sebelum memilih jalan ke depan.
Cara Mengimplementasikan Biaya Prioritas
Menambahkan biaya prioritas pada transaksi terdiri dari menambahkan dua instruksi Compute Budget di awal transaksi tertentu:
- satu untuk menetapkan harga unit komputasi, dan
- satu lagi untuk menetapkan batas unit komputasi
Di sini, Anda juga dapat menemukan panduan developer yang lebih lengkap tentang cara menggunakan biaya prioritas yang mencakup informasi lebih lanjut tentang mengimplementasikan biaya prioritas.
Buat instruksi setComputeUnitPrice untuk menambahkan Biaya Prioritas di atas Biaya Transaksi Dasar (5.000 lamport).
// import { ComputeBudgetProgram } from "@solana/web3.js"ComputeBudgetProgram.setComputeUnitPrice({ microLamports: number });
Nilai yang diberikan dalam micro-lamport akan dikalikan dengan anggaran Unit Komputasi (CU) untuk menentukan Biaya Prioritas dalam lamport. Misalnya, jika anggaran CU Anda adalah 1 juta CU, dan Anda menambahkan 1 microLamport/CU, Biaya Prioritas akan menjadi 1 lamport (1 juta * 0,000001). Total biaya kemudian akan menjadi 5.001 lamport.
Untuk menetapkan anggaran unit komputasi baru untuk transaksi, buat instruksi setComputeUnitLimit
// import { ComputeBudgetProgram } from "@solana/web3.js"ComputeBudgetProgram.setComputeUnitLimit({ units: number });
Nilai units yang diberikan akan menggantikan nilai anggaran komputasi default dari runtime Solana.
Tetapkan CU minimum yang diperlukan untuk transaksi
Transaksi harus meminta jumlah minimum unit komputasi (CU) yang diperlukan untuk eksekusi guna memaksimalkan throughput dan meminimalkan biaya keseluruhan.
Anda dapat mengetahui CU yang dikonsumsi oleh transaksi dengan mengirimkan transaksi di klaster Solana yang berbeda, seperti devnet. Misalnya, transfer token sederhana membutuhkan 300 CU.
// import { ... } from "@solana/web3.js"const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({// note: set this to be the lowest actual CU consumed by the transactionunits: 300});const addPriorityFee = ComputeBudgetProgram.setComputeUnitPrice({microLamports: 1});const transaction = new Transaction().add(modifyComputeUnits).add(addPriorityFee).add(SystemProgram.transfer({fromPubkey: payer.publicKey,toPubkey: toAccount,lamports: 10000000}));
Biaya Prioritas dan Durable Nonce
Jika pengaturan Anda menggunakan Durable Nonce Transactions, penting untuk mengimplementasikan Prioritization Fees dengan benar dikombinasikan dengan Durable Transaction Nonces guna memastikan transaksi berhasil. Kegagalan dalam hal ini akan menyebabkan transaksi Durable Nonce yang dimaksud tidak terdeteksi sebagai transaksi tersebut.
Jika Anda MENGGUNAKAN Durable Transaction Nonces, instruksi AdvanceNonceAccount HARUS ditentukan PERTAMA dalam daftar instruksi, bahkan ketika instruksi compute budget digunakan untuk menentukan priority fees.
Anda dapat menemukan contoh kode khusus menggunakan durable nonces dan priority fees secara bersamaan dalam panduan developer ini.
Mendukung Standar SPL Token
SPL Token adalah standar untuk pembuatan dan pertukaran token terbungkus/sintetis di blockchain Solana.
Alur kerja SPL Token mirip dengan token SOL asli, tetapi ada beberapa perbedaan yang akan dibahas di bagian ini.
Token Mints
Setiap jenis SPL Token dideklarasikan dengan membuat sebuah mint account. Akun ini menyimpan metadata yang mendeskripsikan fitur token seperti pasokan, jumlah desimal, dan berbagai otoritas yang mengendalikan mint. Setiap SPL Token account mereferensikan mint yang terkait dan hanya dapat berinteraksi dengan SPL Token dari jenis tersebut.
Menginstal Alat CLI spl-token
SPL Token accounts dikueri dan dimodifikasi menggunakan utilitas baris perintah spl-token. Contoh-contoh yang disediakan di bagian ini memerlukan pemasangannya di sistem lokal.
spl-token didistribusikan dari Rust
crates.io melalui utilitas baris perintah cargo Rust.
Versi terbaru cargo dapat diinstal menggunakan satu baris perintah yang praktis untuk platform Anda di rustup.rs. Setelah cargo terinstal, spl-token dapat diperoleh dengan perintah berikut:
cargo install spl-token-cli
Anda kemudian dapat memeriksa versi yang terinstal untuk memverifikasi
spl-token --version
Yang seharusnya menghasilkan sesuatu seperti
spl-token-cli 2.0.1
Pembuatan Akun
SPL Token accounts memiliki persyaratan tambahan yang tidak dimiliki oleh akun System Program asli:
- SPL Token accounts harus dibuat sebelum sejumlah token dapat
didepositkan. Token accounts dapat dibuat secara eksplisit dengan perintah
spl-token create-account, atau secara implisit oleh perintahspl-token transfer --fund-recipient .... - SPL Token accounts harus tetap bebas sewa selama masa keberadaannya dan oleh karena itu memerlukan sejumlah kecil token SOL asli yang didepositkan saat pembuatan akun. Untuk SPL Token accounts, jumlahnya adalah 0,00203928 SOL (2.039.280 lamport).
Baris Perintah
Untuk membuat SPL Token account dengan properti berikut:
- Terkait dengan mint yang diberikan
- Dimiliki oleh keypair akun pendanaan
spl-token create-account <TOKEN_MINT_ADDRESS>
Contoh
spl-token create-account AkUFCWTXb3w9nY2n6SFJvBV6VwvFUCe4KBMCcgLsa2ir
Memberikan output yang mirip dengan:
Creating account 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkVSignature: 4JsqZEPra2eDTHtHpB4FMWSfk3UgcCVmkKkP7zESZeMrKmFFkDkNd91pKP3vPVVZZPiu5XxyJwS73Vi5WsZL88D7
Atau untuk membuat SPL Token account dengan keypair tertentu:
solana-keygen new -o token-account.jsonspl-token create-account AkUFCWTXb3w9nY2n6SFJvBV6VwvFUCe4KBMCcgLsa2ir token-account.json
Memberikan output yang mirip dengan:
Creating account 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkVSignature: 4JsqZEPra2eDTHtHpB4FMWSfk3UgcCVmkKkP7zESZeMrKmFFkDkNd91pKP3vPVVZZPiu5XxyJwS73Vi5WsZL88D7
Memeriksa Saldo Akun
Baris Perintah
spl-token balance <TOKEN_ACCOUNT_ADDRESS>
Contoh
solana balance 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV
Memberikan output yang mirip dengan:
0
Transfer Token
Akun sumber untuk transfer adalah actual token account yang berisi jumlah tersebut.
Namun, alamat penerima bisa berupa akun wallet biasa. Jika associated token account untuk mint yang diberikan belum ada untuk wallet tersebut, transfer akan membuatnya asalkan argumen --fund-recipient disertakan.
Baris Perintah
spl-token transfer <SENDER_ACCOUNT_ADDRESS> <AMOUNT> <RECIPIENT_WALLET_ADDRESS> --fund-recipient
Contoh
spl-token transfer 6B199xxzw3PkAm25hGJpjj3Wj3WNYNHzDAnt1tEqg5BN 1
Memberikan output yang mirip dengan:
6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkVTransfer 1 tokensSender: 6B199xxzw3PkAm25hGJpjj3Wj3WNYNHzDAnt1tEqg5BNRecipient: 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkVSignature: 3R6tsog17QM8KfzbcbdP4aoMfwgo6hBggJDVy7dZPVmH2xbCWjEj31JKD53NzMrf25ChFjY7Uv2dfCDq4mGFFyAj
Penyetoran
Karena setiap pasangan (wallet, mint) memerlukan akun terpisah di onchain. Disarankan agar alamat untuk akun-akun ini diturunkan dari wallet deposit SOL menggunakan skema
Associated Token Account
(ATA) dan bahwa hanya deposit dari alamat ATA yang diterima.
Pemantauan transaksi deposit harus mengikuti metode block polling yang dijelaskan di atas. Setiap blok baru harus dipindai untuk menemukan transaksi yang berhasil yang menyertakan alamat token account pengguna dan bursa.
Kolom preTokenBalances dan postTokenBalances dari metadata transaksi harus digunakan untuk menentukan perubahan saldo efektif. Kolom-kolom ini mencakup token mint, pemilik token account (alamat wallet), serta saldo token account sebelum dan sesudah transaksi.
Jika token account dibuat sebagai bagian dari transaksi (misalnya saat menerima token untuk pertama kalinya), token account tersebut tidak akan muncul dalam array preTokenBalances karena belum ada sebelum transaksi. Dalam skenario ini, Anda harus memperlakukan saldo awal sebagai nol saat menghitung jumlah deposit. Akun yang baru dibuat hanya akan muncul dalam array postTokenBalances dengan saldo akhirnya setelah transaksi selesai.
Contoh 1: Transfer Token Tunggal
Detail transaksi di bawah ini menunjukkan contoh transaksi yang menyertakan satu instruksi transfer token.
Transaksi ini mentransfer 100 unit dasar token (tidak disesuaikan dengan desimal mint) dan menyertakan akun-akun berikut:
- Pengirim (pemilik):
4fvXFPXSL9i7VbiRzoizuW4bhn1dMvRgQzQ6VevssYxw - Token Account Pengirim:
6zhjktfYBRUp7fgXLoWU7GFFrCuZa9iQkYTQzDzuvsAS - Token Account Penerima:
G5nNekUhhWFqJAiCMpKHootZ5Bfa7MXwuQ5vvKcvuxKM - ID Token Extension Program:
TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
Perhatikan bahwa akun penerima (pemilik) dan mint account tidak diperlukan dalam instruksi transfer token. Sebagai referensi, keduanya tercantum di sini karena alamatnya disertakan dalam metadata transaksi yang telah diuraikan.
- Penerima (pemilik):
8fjS2shNWY8xniiEMLNk1Aek4MAu8Qp2LCXJckVwTD4n - Mint:
Fx1JZFeYbCxLrMv7422YSxpr7YzcsAgpU1MkjZTyCKi2
{"blockTime": "1741240211","meta": {"computeUnitsConsumed": "1551","err": null,"fee": "5000","innerInstructions": [],"loadedAddresses": {"readonly": [],"writable": []},"logMessages": ["Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [1]","Program log: Instruction: Transfer","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1551 of 200000 compute units","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success"],"postBalances": ["994375240", "2074080", "2074080", "1141440"],"postTokenBalances": [{"accountIndex": 1,"mint": "Fx1JZFeYbCxLrMv7422YSxpr7YzcsAgpU1MkjZTyCKi2","owner": "4fvXFPXSL9i7VbiRzoizuW4bhn1dMvRgQzQ6VevssYxw","programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","uiTokenAmount": {"amount": "0","decimals": 2,"uiAmount": null,"uiAmountString": "0"}},{"accountIndex": 2,"mint": "Fx1JZFeYbCxLrMv7422YSxpr7YzcsAgpU1MkjZTyCKi2","owner": "8fjS2shNWY8xniiEMLNk1Aek4MAu8Qp2LCXJckVwTD4n","programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","uiTokenAmount": {"amount": "100","decimals": 2,"uiAmount": "1","uiAmountString": "1"}}],"preBalances": ["994380240", "2074080", "2074080", "1141440"],"preTokenBalances": [{"accountIndex": 1,"mint": "Fx1JZFeYbCxLrMv7422YSxpr7YzcsAgpU1MkjZTyCKi2","owner": "4fvXFPXSL9i7VbiRzoizuW4bhn1dMvRgQzQ6VevssYxw","programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","uiTokenAmount": {"amount": "100","decimals": 2,"uiAmount": "1","uiAmountString": "1"}},{"accountIndex": 2,"mint": "Fx1JZFeYbCxLrMv7422YSxpr7YzcsAgpU1MkjZTyCKi2","owner": "8fjS2shNWY8xniiEMLNk1Aek4MAu8Qp2LCXJckVwTD4n","programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","uiTokenAmount": {"amount": "0","decimals": 2,"uiAmount": null,"uiAmountString": "0"}}],"rewards": [],"status": {"Ok": null}},"slot": "3916","transaction": {"message": {"accountKeys": ["4fvXFPXSL9i7VbiRzoizuW4bhn1dMvRgQzQ6VevssYxw","6zhjktfYBRUp7fgXLoWU7GFFrCuZa9iQkYTQzDzuvsAS","G5nNekUhhWFqJAiCMpKHootZ5Bfa7MXwuQ5vvKcvuxKM","TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"],"addressTableLookups": [],"header": {"numReadonlySignedAccounts": 0,"numReadonlyUnsignedAccounts": 1,"numRequiredSignatures": 1},"instructions": [{"accounts": [1, 2, 0],"data": "3WBgs5fm8oDy","programIdIndex": 3,"stackHeight": null}],"recentBlockhash": "8soh8j2dkEniZW6Jpx9cJaWtnvrGoGUqpbaUVwUkX5R3"},"signatures": ["3vr6Gj3GnBQmsZW1TtBJ3hvfFMi3h9BxLs2oaZkV41LRWeGWPVmeo16JTN8MdP3ypU5VgWAziYUjybhyZoisryQ6"]},"version": "0"}
Contoh 2: Membuat Token Account dan Transfer
Detail transaksi di bawah ini menunjukkan contoh transaksi di mana token account penerima dibuat dalam transaksi yang sama dengan transfer token.
Perhatikan bahwa array preTokenBalances tidak menyertakan token account penerima karena belum ada sebelum transaksi. Token account penerima hanya muncul dalam array postTokenBalances dengan saldo akhirnya setelah transaksi selesai.
{"blockTime": "1740541705","meta": {"computeUnitsConsumed": "17416","err": null,"fee": "5000","innerInstructions": [{"index": 0,"instructions": [{"accounts": [4],"data": "84eT","programIdIndex": 7,"stackHeight": 2},{"accounts": [0, 1],"data": "11119ExAoTptm6xKUTUcw2V69MKmyEdDmRins3j3bK43o9nHeiYUtSiaT9pc292PhNQvxj","programIdIndex": 3,"stackHeight": 2},{"accounts": [1],"data": "P","programIdIndex": 7,"stackHeight": 2},{"accounts": [1, 4],"data": "6b8ZSccu4ezujyhGG8KNmg75iCWbQRyjxeSfi38u8ED8N","programIdIndex": 7,"stackHeight": 2}]}],"loadedAddresses": {"readonly": [],"writable": []},"logMessages": ["Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]","Program log: Create","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]","Program log: Instruction: GetAccountDataSize","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 928 of 394613 compute units","Program return: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb qgAAAAAAAAA=","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success","Program 11111111111111111111111111111111 invoke [2]","Program 11111111111111111111111111111111 success","Program log: Initialize the associated token account","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]","Program log: Instruction: InitializeImmutableOwner","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 487 of 388755 compute units","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [2]","Program log: Instruction: InitializeAccount3","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1440 of 385879 compute units","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success","Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 15865 of 400000 compute units","Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [1]","Program log: Instruction: Transfer","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1551 of 384135 compute units","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success"],"postBalances": ["994375240","2074080","2074080","1","1461600","731913600","0","1141440"],"postTokenBalances": [{"accountIndex": 1,"mint": "3RPRXBsdwyHhs2UnTWXoHp6Frwv4eWEbA55qCzbs9nxK","owner": "EzrmgRNGN9duiDAk3ABSC8eKhd1b2EUFwXVrYZDJw4hQ","programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","uiTokenAmount": {"amount": "100","decimals": 2,"uiAmount": "1","uiAmountString": "1"}},{"accountIndex": 2,"mint": "3RPRXBsdwyHhs2UnTWXoHp6Frwv4eWEbA55qCzbs9nxK","owner": "CbJNxBnU9ZWnQq12aVHhbze9nubbDVDV5rYVEqz9qFaS","programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","uiTokenAmount": {"amount": "0","decimals": 2,"uiAmount": null,"uiAmountString": "0"}}],"preBalances": ["996454320","0","2074080","1","1461600","731913600","0","1141440"],"preTokenBalances": [{"accountIndex": 2,"mint": "3RPRXBsdwyHhs2UnTWXoHp6Frwv4eWEbA55qCzbs9nxK","owner": "CbJNxBnU9ZWnQq12aVHhbze9nubbDVDV5rYVEqz9qFaS","programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","uiTokenAmount": {"amount": "100","decimals": 2,"uiAmount": "1","uiAmountString": "1"}}],"rewards": [],"status": {"Ok": null}},"slot": "81051","transaction": {"message": {"accountKeys": ["CbJNxBnU9ZWnQq12aVHhbze9nubbDVDV5rYVEqz9qFaS","571u96hRRmxbRCTmp5oqC5WpJfvZhPaSXEbihLVCR5wQ","8y8KjtZN9tyGeAeKwr8doSpbBVVgfsZMtMjCGUDH7mmU","11111111111111111111111111111111","3RPRXBsdwyHhs2UnTWXoHp6Frwv4eWEbA55qCzbs9nxK","ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL","EzrmgRNGN9duiDAk3ABSC8eKhd1b2EUFwXVrYZDJw4hQ","TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"],"addressTableLookups": [],"header": {"numReadonlySignedAccounts": 0,"numReadonlyUnsignedAccounts": 5,"numRequiredSignatures": 1},"instructions": [{"accounts": [0, 1, 6, 4, 3, 7],"data": "1","programIdIndex": 5,"stackHeight": null},{"accounts": [2, 1, 0],"data": "3WBgs5fm8oDy","programIdIndex": 7,"stackHeight": null}],"recentBlockhash": "77QC38Q2hKFYZzUXk8JWmsAqGNKhw4k2Lm2XVUme9uqP"},"signatures": ["4kuGhMeZxBHgEtej4Uv4n2arhe3jqT2GdTDPFri4JLFXYgcAtbeeXdBdzvG98HENe1tZSZqyFkm3SEvB6CfCMaM9"]},"version": "0"}
Contoh 3: Ubah Pemilik Token Account
Detail transaksi di bawah ini menunjukkan contoh transaksi di mana kolom owner dari token account diubah.
Menerima deposit dengan mengizinkan deposan untuk mengalihkan kepemilikan token account (dengan mengubah kolom owner) sangat tidak disarankan.
Jika Anda memilih untuk mendukung ini sebagai metode deposit, Anda harus memverifikasi bahwa kolom owner baru dalam postTokenBalances cocok dengan alamat wallet yang dikendalikan bursa Anda dan memiliki kunci privatnya.
Jika deposan mengubah owner dari token account ke alamat yang bukan wallet (seperti alamat token account lain), dana tersebut bisa menjadi tidak dapat diakses secara permanen.
{"blockTime": "1740598556","meta": {"computeUnitsConsumed": "1167","err": null,"fee": "5000","innerInstructions": [],"loadedAddresses": {"readonly": [],"writable": []},"logMessages": ["Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [1]","Program log: Instruction: SetAuthority","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1167 of 200000 compute units","Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success"],"postBalances": ["996479120", "2039280", "1141440"],"postTokenBalances": [{"accountIndex": 1,"mint": "ELRBdV4gcuxqYb6jHkV4ySJ7dwYx9344cgFNzUSww1ra","owner": "A9FK8XxT2Hfefz8H3vQJHLwvbibGQJWErBsqMumgUYeP","programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","uiTokenAmount": {"amount": "100","decimals": 2,"uiAmount": "1","uiAmountString": "1"}}],"preBalances": ["996484120", "2039280", "1141440"],"preTokenBalances": [{"accountIndex": 1,"mint": "ELRBdV4gcuxqYb6jHkV4ySJ7dwYx9344cgFNzUSww1ra","owner": "DLvpDgEABKfEaRDz5Qh9tSrJhuZzsiiZMcYXmvdek1zV","programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","uiTokenAmount": {"amount": "100","decimals": 2,"uiAmount": "1","uiAmountString": "1"}}],"rewards": [],"status": {"Ok": null}},"slot": "137902","transaction": {"message": {"accountKeys": ["DLvpDgEABKfEaRDz5Qh9tSrJhuZzsiiZMcYXmvdek1zV","5Qj4uNGuAEBdryPg8k2UTewpnNfYAc9Ux9fCcDrNAjGs","TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"],"addressTableLookups": [],"header": {"numReadonlySignedAccounts": 0,"numReadonlyUnsignedAccounts": 1,"numRequiredSignatures": 1},"instructions": [{"accounts": [1, 0],"data": "bmb6sys4wqZErNeiV7hrM4vQVHF8AVBhi3XeR5TgbQM68MH","programIdIndex": 2,"stackHeight": null}],"recentBlockhash": "CvTdX9MSYkqFMkALUHeGPMQN5yBeUdJptRdce2qMEkPr"},"signatures": ["3rHUaKMh4KDDfdaATAL4J5WDEV7oFm7ykkNaMf1Eo5EwvDUjLE6dWsbxNDmyENrhb2w5gE4KqRxZ3ZwQxuM18SVR"]},"version": "0"}
Kalkulasi Deposit Token
Untuk melacak deposit token secara akurat, Anda harus membandingkan kolom preTokenBalances dan postTokenBalance dalam metadata transaksi. Kolom-kolom ini menunjukkan saldo token dan pemilik token account sebelum dan sesudah transaksi, memungkinkan Anda untuk menghitung jumlah pasti token yang ditransfer. Pendekatan ini memastikan Anda menangkap perubahan saldo yang sebenarnya.
- Jika kolom
ownerdaripreTokenBalancesdanpostTokenBalancestetap sama, hitung selisih antara kolomamount. - Jika kepemilikan token account berubah (kolom
owneryang berbeda antarapreTokenBalancesdanpostTokenBalances), dan pemilik baru dalampostTokenBalancecocok dengan alamatowneryang diharapkan bursa Anda, maka pertimbangkan seluruh saldo yang ditampilkan dalam kolomamountdaripostTokenBalancessebagai jumlah yang didepositkan.
"meta": {// --snip--"postBalances": ["994375240", "2074080", "2074080", "1141440"],"postTokenBalances": [{"accountIndex": 1,"mint": "Fx1JZFeYbCxLrMv7422YSxpr7YzcsAgpU1MkjZTyCKi2","owner": "4fvXFPXSL9i7VbiRzoizuW4bhn1dMvRgQzQ6VevssYxw","programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","uiTokenAmount": {"amount": "0","decimals": 2,"uiAmount": null,"uiAmountString": "0"}},{"accountIndex": 2,"mint": "Fx1JZFeYbCxLrMv7422YSxpr7YzcsAgpU1MkjZTyCKi2","owner": "8fjS2shNWY8xniiEMLNk1Aek4MAu8Qp2LCXJckVwTD4n","programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","uiTokenAmount": {"amount": "100","decimals": 2,"uiAmount": "1","uiAmountString": "1"}}],"preBalances": ["994380240", "2074080", "2074080", "1141440"],"preTokenBalances": [{"accountIndex": 1,"mint": "Fx1JZFeYbCxLrMv7422YSxpr7YzcsAgpU1MkjZTyCKi2","owner": "4fvXFPXSL9i7VbiRzoizuW4bhn1dMvRgQzQ6VevssYxw","programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","uiTokenAmount": {"amount": "100","decimals": 2,"uiAmount": "1","uiAmountString": "1"}},{"accountIndex": 2,"mint": "Fx1JZFeYbCxLrMv7422YSxpr7YzcsAgpU1MkjZTyCKi2","owner": "8fjS2shNWY8xniiEMLNk1Aek4MAu8Qp2LCXJckVwTD4n","programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","uiTokenAmount": {"amount": "0","decimals": 2,"uiAmount": null,"uiAmountString": "0"}}],// --snip--}
Penarikan
Alamat penarikan yang diberikan pengguna harus berupa alamat dompet SOL mereka.
Sebelum mengeksekusi transfer penarikan, exchange harus memeriksa alamat tersebut sebagaimana dijelaskan di atas. Selain itu, alamat ini harus dimiliki oleh System Program dan tidak memiliki data akun. Jika alamat tidak memiliki saldo SOL, konfirmasi pengguna harus diperoleh sebelum melanjutkan penarikan. Semua alamat penarikan lainnya harus ditolak.
Dari alamat penarikan, Associated Token Account (ATA) untuk mint yang sesuai diturunkan dan transfer diterbitkan ke akun tersebut melalui instruksi TransferChecked. Perlu dicatat bahwa alamat ATA mungkin belum ada, di mana exchange harus mendanai akun atas nama pengguna. Untuk akun SPL Token, mendanai akun penarikan akan memerlukan 0.00203928 SOL (2.039.280 lamport).
Template perintah spl-token transfer untuk penarikan:
spl-token transfer --fund-recipient <exchange token account> <withdrawal amount> <withdrawal address>
Pertimbangan Lainnya
Freeze Authority
Untuk alasan kepatuhan regulasi, entitas penerbit SPL Token dapat secara opsional memilih untuk memegang "Freeze Authority" atas semua akun yang dibuat terkait dengan mint-nya. Hal ini memungkinkan mereka untuk membekukan aset di akun tertentu sesuai keinginan, membuat akun tidak dapat digunakan hingga dicairkan. Jika fitur ini digunakan, pubkey dari freeze authority akan terdaftar di mint account SPL Token.
Dukungan Dasar untuk Standar SPL Token-2022 (Token Extensions)
SPL Token-2022 adalah standar terbaru untuk pembuatan dan pertukaran token wrapped/sintetis di blockchain Solana.
Juga dikenal sebagai "Token Extensions", standar ini berisi banyak fitur baru yang dapat diaktifkan secara opsional oleh pembuat token dan pemegang akun. Fitur-fitur ini mencakup transfer rahasia, biaya transfer, penutupan mint, metadata, permanent delegates, immutable ownership, dan masih banyak lagi. Silakan lihat panduan ekstensi untuk informasi lebih lanjut.
Jika exchange Anda mendukung SPL Token, tidak banyak pekerjaan tambahan yang diperlukan untuk mendukung SPL Token-2022:
- alat CLI bekerja secara mulus dengan kedua program mulai dari versi 3.0.0.
preTokenBalancesdanpostTokenBalancesmencakup saldo SPL Token-2022- RPC mengindeks akun SPL Token-2022, tetapi harus dikueri secara terpisah dengan
program id
TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
Associated Token Account bekerja dengan cara yang sama, dan menghitung dengan tepat jumlah deposit SOL yang diperlukan untuk akun baru.
Namun karena adanya ekstensi, akun mungkin lebih besar dari 165 byte, sehingga mungkin memerlukan lebih dari 0.00203928 SOL untuk didanai.
Sebagai contoh, program Associated Token Account selalu menyertakan ekstensi "immutable owner", sehingga akun membutuhkan minimal 170 byte, yang memerlukan 0.00207408 SOL.
Pertimbangan Khusus Ekstensi
Bagian sebelumnya menguraikan dukungan paling dasar untuk SPL Token-2022. Karena ekstensi memodifikasi perilaku token, exchange mungkin perlu mengubah cara mereka menangani token.
Dimungkinkan untuk melihat semua ekstensi pada mint atau token account:
spl-token display <account address>
Biaya Transfer
Token dapat dikonfigurasi dengan biaya transfer, di mana sebagian token yang ditransfer ditahan di tujuan untuk pengumpulan di masa mendatang.
Jika exchange Anda mentransfer token-token ini, perlu diketahui bahwa tidak semua token akan tiba di tujuan karena adanya jumlah yang ditahan.
Dimungkinkan untuk menentukan biaya yang diharapkan selama transfer untuk menghindari kejutan:
spl-token transfer --expected-fee <fee amount> --fund-recipient <exchange token account> <withdrawal amount> <withdrawal address>
Mint Close Authority
Dengan ekstensi ini, pembuat token dapat menutup mint, asalkan pasokan token adalah nol.
Ketika mint ditutup, mungkin masih ada token account kosong yang ada, dan token account tersebut tidak lagi dikaitkan dengan mint yang valid.
Aman untuk menutup token account tersebut:
spl-token close --address <account address>
Transfer Rahasia
Mint dapat dikonfigurasi untuk transfer rahasia, sehingga jumlah token dienkripsi, tetapi pemilik akun tetap bersifat publik.
Exchange dapat mengonfigurasi token account untuk mengirim dan menerima transfer rahasia, guna menyembunyikan jumlah pengguna. Tidak diwajibkan untuk mengaktifkan transfer rahasia pada token account, sehingga exchange dapat memaksa pengguna untuk mengirim token secara non-rahasia.
Untuk mengaktifkan transfer rahasia, akun harus dikonfigurasi untuk itu:
spl-token configure-confidential-transfer-account --address <account address>
Dan untuk melakukan transfer:
spl-token transfer --confidential <exchange token account> <withdrawal amount> <withdrawal address>
Selama transfer rahasia, kolom preTokenBalance dan postTokenBalance
tidak akan menunjukkan perubahan. Untuk menyapu akun deposit, Anda harus mendekripsi
saldo baru guna menarik token:
spl-token apply-pending-balance --address <account address>spl-token withdraw-confidential-tokens --address <account address> <amount or ALL>
Status Akun Default
Mint dapat dikonfigurasi dengan status akun default, sehingga semua token account baru dibekukan secara default. Pembuat token ini mungkin mengharuskan pengguna untuk melalui proses terpisah untuk mencairkan akun.
Non-Transferable
Beberapa token tidak dapat ditransfer, tetapi masih dapat dibakar dan akunnya dapat ditutup.
Permanent Delegate
Pembuat token dapat menunjuk permanent delegate untuk semua token mereka. Permanent delegate dapat mentransfer atau membakar token dari akun mana pun, yang berpotensi mencuri dana.
Ini adalah persyaratan hukum untuk stablecoin di yurisdiksi tertentu, atau dapat digunakan untuk skema penarikan kembali token.
Waspadai bahwa token-token ini mungkin ditransfer tanpa sepengetahuan exchange Anda.
Transfer Hook
Token dapat dikonfigurasi dengan program tambahan yang harus dipanggil selama transfer, untuk memvalidasi transfer atau menjalankan logika lainnya.
Karena runtime Solana mengharuskan semua akun diteruskan secara eksplisit ke program, dan transfer hook memerlukan akun tambahan, exchange perlu membuat instruksi transfer secara berbeda untuk token-token ini.
CLI dan pembuat instruksi seperti
createTransferCheckedWithTransferHookInstruction menambahkan akun tambahan
secara otomatis, tetapi akun tambahan juga dapat ditentukan secara eksplisit:
spl-token transfer --transfer-hook-account <pubkey:role> --transfer-hook-account <pubkey:role> ...
Memo Wajib pada Transfer
Pengguna dapat mengonfigurasi token account mereka untuk mewajibkan memo pada transfer.
Exchange mungkin perlu menambahkan instruksi memo sebelum mentransfer token kembali kepada pengguna, atau mereka dapat mengharuskan pengguna untuk menambahkan instruksi memo sebelum mengirim ke exchange:
spl-token transfer --with-memo <memo text> <exchange token account> <withdrawal amount> <withdrawal address>
Menguji Integrasi
Pastikan untuk menguji alur kerja lengkap Anda di devnet dan testnet Solana
clusters sebelum beralih ke produksi di mainnet.
Devnet paling terbuka dan fleksibel, serta ideal untuk pengembangan awal, sementara
testnet menawarkan konfigurasi cluster yang lebih realistis. Baik devnet maupun testnet
mendukung faucet, jalankan solana airdrop 1 untuk mendapatkan beberapa SOL devnet atau testnet
untuk pengembangan dan pengujian.
Is this page helpful?