Bu kılavuz, Solana'nın yerel token'ı SOL'u kripto para borsanıza nasıl ekleyeceğinizi açıklamaktadır.
Node Kurulumu
Yüksek kaliteli bilgisayarlara/bulut örneklerine en az iki node kurmanızı, yeni sürümlere zamanında güncelleme yapmanızı ve hizmet operasyonlarını yerleşik bir izleme aracıyla takip etmenizi şiddetle öneririz.
Bu kurulum size şunları sağlar:
- veri almak ve para çekme işlemlerini göndermek için Solana mainnet kümesine kendi yönettiğiniz bir ağ geçidine sahip olmak
- ne kadar geçmiş blok verisinin saklanacağı üzerinde tam kontrol sahibi olmak
- bir node arızalansa bile hizmet erişilebilirliğinizi sürdürmek
Solana node'ları, hızlı bloklarımızı ve yüksek TPS'yi işleyebilmek için görece yüksek hesaplama gücü gerektirir. Spesifik gereksinimler için lütfen donanım önerilerine bakın.
Bir api node'u çalıştırmak için:
- Solana komut satırı araç paketini yükleyin
- validator'ı en az aşağıdaki parametrelerle başlatın:
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
--ledger seçeneğini istediğiniz defter depolama konumuna, --rpc-port seçeneğini ise açmak istediğiniz porta göre özelleştirin.
--entrypoint ve --expected-genesis-hash parametreleri, katıldığınız kümeye özgüdür.
Mainnet için güncel parametreler
--limit-ledger-size parametresi, node'unuzun diskte kaç defter shred'i saklayacağını belirlemenize olanak tanır. Bu parametreyi eklemezseniz validator, disk alanı tükenene kadar tüm defteri saklar. Varsayılan değer, defter disk kullanımını 500 GB'ın altında tutmaya çalışır. İstenirse --limit-ledger-size seçeneğine bir bağımsız değişken ekleyerek daha fazla veya daha az disk kullanımı talep edilebilir. --limit-ledger-size tarafından kullanılan varsayılan sınır değeri için solana-validator --help komutunu çalıştırın. Özel bir sınır değeri seçimi hakkında daha fazla bilgiye
buradan ulaşabilirsiniz.
Bir veya daha fazla --known-validator parametresi belirtmek, sizi kötü amaçlı bir anlık görüntüden önyüklemeye karşı koruyabilir.
Bilinen validator'larla önyüklemenin değeri hakkında daha fazla bilgi
Değerlendirmeye alınabilecek isteğe bağlı parametreler:
--private-rpc, RPC portunuzun diğer node'lar tarafından kullanılmak üzere yayımlanmasını engeller--rpc-bind-address, RPC portunu bağlamak için farklı bir IP adresi belirlemenize olanak tanır
Otomatik Yeniden Başlatma ve İzleme
Mümkün olduğunca az veri kaybetmek için her node'unuzu çıkışta otomatik olarak yeniden başlayacak şekilde yapılandırmanızı öneririz. Solana yazılımını bir systemd servisi olarak çalıştırmak bunun için mükemmel bir seçenektir.
İzleme amacıyla, validator'ınızı izleyebilen ve solana-validator sürecinin sağlıksız olduğunu tespit edebilen
solana-watchtower aracını sunuyoruz.
Bu araç, Slack, Telegram, Discord veya Twilio üzerinden sizi uyaracak şekilde doğrudan yapılandırılabilir. Ayrıntılar için solana-watchtower --help komutunu çalıştırın.
solana-watchtower --validator-identity <YOUR VALIDATOR IDENTITY>
Şu konular hakkında daha fazla bilgi edinebilirsiniz: Solana Watchtower için en iyi uygulamalar bu dokümanlarda.
Yeni Yazılım Sürüm Duyuruları
Sık sık yeni yazılım yayınlıyoruz (haftada yaklaşık 1 sürüm). Bazen yeni sürümler uyumsuz protokol değişiklikleri içerir; bu durum, blok işlemede hata oluşmaması için yazılımın zamanında güncellenmesini zorunlu kılar.
Her türlü sürüm (normal ve güvenlik) için resmi sürüm duyurularımız, #mb-announcement adlı bir discord kanalı aracılığıyla iletilmektedir (mb, mainnet-beta anlamına gelir).
Stake edilmiş validator'larda olduğu gibi, borsa tarafından işletilen validator'ların da normal bir sürüm duyurusunun ardından bir ila iki iş günü içinde güncellenmesini bekliyoruz. Güvenlikle ilgili sürümler için daha acil önlem alınması gerekebilir.
Defter Sürekliliği
Varsayılan olarak, her node'unuz bilinen validator'larınızdan biri tarafından sağlanan bir anlık görüntüden önyükleme yapar. Bu anlık görüntü zincirin mevcut durumunu yansıtır; ancak eksiksiz geçmiş defteri içermez. Node'larınızdan biri kapanıp yeni bir anlık görüntüden yeniden başlarsa o node'un defterinde bir boşluk oluşabilir. Bu sorunu önlemek için solana-validator komutunuza --no-snapshot-fetch parametresini ekleyerek anlık görüntü yerine geçmiş defter verisi alın.
İlk önyüklemenizde --no-snapshot-fetch parametresini kullanmayın; zira genesis bloğundan itibaren node'u tamamen önyüklemek mümkün değildir. Bunun yerine önce bir anlık görüntüden önyükleme yapın, ardından yeniden başlatmalar için --no-snapshot-fetch parametresini ekleyin.
Ağın geri kalanından node'larınıza sunulan geçmiş defter miktarının her an sınırlı olduğunu göz önünde bulundurmak önemlidir. Çalışır durumdayken validator'larınız önemli bir kesinti yaşarsa ağa yetişemeyebilir ve bilinen bir validator'dan yeni bir anlık görüntü indirmeleri gerekebilir. Bu durumda validator'larınızın geçmiş defter verilerinde doldurulamayan bir boşluk oluşacaktır.
Validator Port Maruziyetini En Aza İndirme
validator, tüm diğer Solana validator'larından gelen gelen trafik için çeşitli UDP ve TCP portlarının açık olmasını gerektirir. Bu en verimli çalışma modu olup güçlü şekilde önerilse de validator'ı yalnızca tek bir Solana validator'ından gelen gelen trafiği gerektirecek şekilde kısıtlamak mümkündür.
Önce --restricted-repair-only-mode bağımsız değişkenini ekleyin. Bu, validator'ın kısıtlı modda çalışmasına neden olur; bu modda validator diğer validator'lardan push almaz, bunun yerine bloklar için diğer validator'ları sürekli olarak sorgulamak zorunda kalır. validator yalnızca Gossip ve ServeR ("serve repair") portlarını kullanarak diğer validator'lara UDP paketleri iletir ve yalnızca kendi Gossip ile Repair portlarında UDP paketleri alır.
Gossip portu çift yönlüdür ve validator'ınızın kümenin geri kalanıyla iletişimde kalmasını sağlar. Turbine artık devre dışı olduğundan validator'ınız, ağın geri kalanından yeni bloklar almak üzere onarım istekleri göndermek için ServeR üzerinden iletim yapar. validator'ınız ardından diğer validator'lardan Repair portu üzerinden onarım yanıtları alır.
validator'ı yalnızca bir veya daha fazla validator'dan blok isteyecek şekilde daha da kısıtlamak için önce hedef validator'ın kimlik pubkey'ini belirleyin ve her PUBKEY için --gossip-pull-validator PUBKEY --repair-validator PUBKEY bağımsız değişkenlerini ekleyin. Bu işlem, eklediğiniz her validator üzerinde kaynak tüketimine yol açacağından lütfen bunu yalnızca gerektiğinde ve hedef validator ile görüştükten sonra yapın.
validator'ınız artık yalnızca açıkça listelenen validator'larla ve yalnızca Gossip, Repair ve ServeR portları üzerinden iletişim kuruyor olmalıdır.
Yatırım Hesaplarının Kurulumu
Solana hesapları zincir üzerinde herhangi bir başlatma gerektirmez; bir miktar SOL içerdiklerinde otomatik olarak var olurlar. Borsanız için bir yatırım hesabı oluşturmak üzere cüzdan araçlarımızdan herhangi birini kullanarak bir Solana keypair oluşturmanız yeterlidir.
Her kullanıcınız için benzersiz bir yatırım hesabı kullanmanızı öneririz.
Solana hesaplarının rent'ten muaf olabilmesi için SOL cinsinden 2 yıllık rent miktarı kadar bakiye içermesi gerekir. Yatırım hesaplarınız için minimum rent muafiyeti bakiyesini öğrenmek üzere
getMinimumBalanceForRentExemption endpoint'ini sorgulayın:
curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id": 1,"method": "getMinimumBalanceForRentExemption","params": [0]}'
Sonuç
{ "jsonrpc": "2.0", "result": 890880, "id": 1 }
Çevrimdışı Hesaplar
Daha fazla güvenlik için bir veya daha fazla tahsilat hesabının anahtarlarını çevrimdışı tutmak isteyebilirsiniz. Bu durumda, çevrimdışı yöntemlerimizi kullanarak SOL'u sıcak hesaplara taşımanız gerekecektir.
Yatırımları Dinleme
Bir kullanıcı borsanıza SOL yatırmak istediğinde, uygun yatırım adresine transfer göndermesini isteyin.
Versiyonlanmış İşlem Migrasyonu
Mainnet ağı versiyonlanmış işlemleri işlemeye başladığında, borsaların değişiklik yapması ZORUNLUDUR. Herhangi bir değişiklik yapılmazsa, versiyonlanmış bir işlemin veya versiyonlanmış işlemler içeren bir bloğun getirilmesi hata döndüreceğinden yatırım tespiti artık düzgün çalışmayacaktır.
-
{"maxSupportedTransactionVersion": 0}Yatırım tespitinin kesintisiz çalışması için
maxSupportedTransactionVersionparametresiningetBlockvegetTransactionisteklerine eklenmesi zorunludur. En güncel işlem versiyonu0'dır ve desteklenen maksimum işlem versiyonu değeri olarak belirtilmelidir.
Versiyonlanmış işlemlerin, kullanıcıların zincir üzerindeki adres arama tablolarından yüklenen başka bir hesap anahtarları kümesi kullanan işlemler oluşturmasına olanak tanıdığını anlamak önemlidir.
-
{"encoding": "jsonParsed"}Bloklar ve işlemler getirilirken artık
"jsonParsed"encoding kullanılması önerilmektedir; çünkü bu yöntem, tüm işlem hesabı anahtarlarını (arama tablolarındakileri de dahil olmak üzere) mesajın"accountKeys"listesine ekler. Bu sayedepreBalances/postBalancesvepreTokenBalances/postTokenBalancesalanlarında belirtilen bakiye değişikliklerini çözmek kolaylaşır."json"encoding kullanıldığında isepreBalances/postBalancesvepreTokenBalances/postTokenBalancesiçindeki girdiler,"accountKeys"listesinde YER ALMAYAN ve işlem meta verilerindeki"loadedAddresses"girdileri kullanılarak çözülmesi gereken hesap anahtarlarına başvurabilir.
Bloklar İçin Yoklama
Borsanızdaki tüm yatırım hesaplarını takip etmek için Solana API node'unuzun JSON-RPC servisini kullanarak onaylanan her bloğu yoklayın ve ilgilendiğiniz adresleri inceleyin.
- Hangi blokların mevcut olduğunu belirlemek için, halihazırda işlediğiniz son bloğu start-slot parametresi olarak geçirerek bir
getBlocksisteği gönderin:
curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id": 1,"method": "getBlocks","params": [160017005, 160017015]}'
Sonuç
{"jsonrpc": "2.0","result": [160017005, 160017006, 160017007, 160017012, 160017013, 160017014, 160017015],"id": 1}
Her slot bir blok üretmez, dolayısıyla tam sayı dizisinde boşluklar olabilir.
- Her blok için içeriğini bir
getBlockisteğiyle talep edin:
Blok Getirme İpuçları
{"rewards": false}
Varsayılan olarak, getirilen bloklar her blok için validator ücretleri ve epoch sınırlarındaki staking ödülleri hakkında bilgi döndürür. Bu bilgiye ihtiyaç duymuyorsanız "rewards" parametresiyle devre dışı bırakın.
{"transactionDetails": "accounts"}
Varsayılan olarak, getirilen bloklar hesap bakiyelerini takip etmek için gerekli olmayan çok sayıda işlem bilgisi ve meta verisi döndürür. Blok getirme işlemini hızlandırmak için "transactionDetails" parametresini ayarlayın.
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}]}'
Sonuç
{"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}
preBalances ve postBalances alanları, tüm işlemi ayrıştırmak zorunda kalmadan her hesaptaki bakiye
değişikliklerini takip etmenizi sağlar. Bu alanlar, accountKeys
listesiyle indekslenmiş olarak her hesabın başlangıç ve bitiş bakiyelerini
lamport cinsinden listeler. Örneğin, ilgilenilen para yatırma adresi
G1wZ113tiUHdSpQEBcid8n1x8BAvcWZoZgxPKxgE5B7o ise, bu işlem
1040000000 - 1030000000 = 10.000.000 lamport = 0,01 SOL tutarında bir
transfer temsil etmektedir.
İşlem türü veya diğer ayrıntılar hakkında daha fazla bilgiye ihtiyaç duyarsanız, bloğu RPC'den ikili biçimde talep edebilir ve Rust SDK ya da Javascript SDK'mızdan birini kullanarak ayrıştırabilirsiniz.
Adres Geçmişi
Belirli bir adresin işlem geçmişini de sorgulayabilirsiniz. Bu yöntem genellikle tüm para yatırma adreslerinizi tüm slot'lar boyunca takip etmek için uygun bir yöntem değildir; ancak belirli bir zaman dilimi için birkaç hesabı incelemek amacıyla yararlı olabilir.
- API düğümüne bir
getSignaturesForAddressisteği gönderin:
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}]}'
Sonuç
{"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}
- Döndürülen her imza için, bir
getTransactionisteği göndererek işlem ayrıntılarını alın:
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}]}'
Sonuç
{"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}
Para Çekme İşlemleri Gönderme
Kullanıcının SOL çekme talebini karşılamak için bir Solana transfer işlemi oluşturmanız ve bunu kümenize iletilmek üzere API düğümüne göndermeniz gerekmektedir.
Senkron
Solana kümesine senkron bir transfer göndermek, bir transferin başarılı olduğunu ve küme tarafından sonuçlandırıldığını kolayca doğrulamanızı sağlar.
Solana'nın komut satırı aracı, transfer işlemlerini oluşturmak, göndermek ve
onaylamak için basit bir komut sunar: solana transfer. Bu yöntem varsayılan
olarak, işlem küme tarafından sonuçlandırılana kadar bekler ve stderr üzerinde
ilerlemeyi takip eder. İşlem başarısız olursa, işlem hatalarını raporlar.
solana transfer <USER_ADDRESS> <AMOUNT> --allow-unfunded-recipient --keypair <KEYPAIR> --url http://localhost:8899
Solana Javascript SDK,
JS ekosistemi için benzer bir yaklaşım sunar. Bir transfer işlemi oluşturmak
için SystemProgram'ı kullanın ve sendAndConfirmTransaction
yöntemiyle gönderin.
Asenkron
Daha fazla esneklik için para çekme transferlerini asenkron olarak gönderebilirsiniz. Bu durumlarda, işlemin başarılı olduğunu ve küme tarafından sonuçlandırıldığını doğrulamak sizin sorumluluğunuzdadır.
Not: Her işlem, etkinliğini belirtmek için bir son blockhash içerir. Onaylanmamış veya küme tarafından sonuçlandırılmamış gibi görünen bir para çekme transferini yeniden denemeden önce bu blockhash'in süresinin dolmasını beklemeniz kritik öneme sahiptir. Aksi takdirde çift harcama riskiyle karşılaşabilirsiniz. Daha fazla bilgi için aşağıdaki blockhash sona erme bölümüne bakın.
Önce,
getFees uç noktasını veya CLI komutunu kullanarak son bir blockhash alın:
solana fees --url http://localhost:8899
Komut satırı aracında, bir transferi asenkron olarak göndermek için --no-wait
bağımsız değişkenini geçirin ve --blockhash bağımsız değişkeniyle son
blockhash'inizi ekleyin:
solana transfer <USER_ADDRESS> <AMOUNT> --no-wait --allow-unfunded-recipient --blockhash <RECENT_BLOCKHASH> --keypair <KEYPAIR> --url http://localhost:8899
Ayrıca işlemi manuel olarak oluşturabilir, imzalayabilir ve serileştirebilir;
ardından JSON-RPC sendTransaction uç noktasını kullanarak
kümeye gönderebilirsiniz.
İşlem Onayları ve Kesinleşme
getSignatureStatuses JSON-RPC uç noktasını kullanarak
bir işlem grubunun durumunu alın.
confirmations alanı, işlem işlendikten bu yana kaç adet
onaylanmış blok geçtiğini raporlar. confirmations: null ise
işlem kesinleşmiş demektir.
curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["4cdd1oX7cfVALfr26tP52BZ6cSzrgnNGtYD7BFhm6FFeZV5sPTnRvg6NRn8yC6DbEikXcrNChBM5vVJnTgKhGhVu","5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7"]]}'
Sonuç
{"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}
Blockhash Sona Ermesi
Belirli bir blockhash'in hâlâ geçerli olup olmadığını, blockhash'i parametre
olarak ileterek bir getFeeCalculatorForBlockhash
isteği göndererek kontrol edebilirsiniz. Yanıt değeri null ise blockhash
süresi dolmuş demektir ve söz konusu blockhash'i kullanan para çekme işlemi
hiçbir zaman başarılı olamaz.
Para Çekme İşlemleri İçin Kullanıcı Tarafından Sağlanan Hesap Adreslerinin Doğrulanması
Para çekme işlemleri geri alınamaz olduğundan, kullanıcı fonlarının yanlışlıkla kaybolmasını önlemek amacıyla para çekme işlemini yetkilendirmeden önce kullanıcı tarafından sağlanan hesap adresini doğrulamak iyi bir uygulama olabilir.
Temel Doğrulama
Solana adresleri, bitcoin base58 alfabesiyle kodlanmış 32 baytlık bir dizidir. Bu, aşağıdaki düzenli ifadeyle eşleşen bir ASCII metin dizesiyle sonuçlanır:
[1-9A-HJ-NP-Za-km-z]{32,44}
Bu kontrol tek başına yetersizdir; zira Solana adresleri sağlama toplamı içermez, dolayısıyla yazım hataları tespit edilemez. Kullanıcı girişini daha fazla doğrulamak için dize çözümlenebilir ve elde edilen bayt dizisinin uzunluğunun 32 olduğu doğrulanabilir. Ancak, tek bir eksik karakter, ters çevrilmiş karakterler veya büyük/küçük harf görmezden gelme gibi yazım hatalarına rağmen 32 bayta çözümlenebilen bazı adresler de mevcuttur.
Gelişmiş Doğrulama
Yukarıda açıklanan yazım hatası açığı nedeniyle, aday para çekme adresleri için bakiye sorgulanması ve sıfır olmayan bir bakiye keşfedildiğinde kullanıcının niyetini onaylaması istenmesi tavsiye edilir.
Geçerli ed25519 pubkey Kontrolü
Solana'daki normal bir hesabın adresi, 256 bitlik bir ed25519 genel anahtarının Base58 ile kodlanmış bir dizesidir. Tüm bit desenleri ed25519 eğrisi için geçerli genel anahtarlar değildir; bu nedenle kullanıcı tarafından sağlanan hesap adreslerinin en azından geçerli ed25519 genel anahtarları olduğundan emin olmak mümkündür.
Java
Kullanıcı tarafından sağlanan bir adresi geçerli bir ed25519 genel anahtarı olarak doğrulamaya ilişkin bir Java örneği aşağıda verilmiştir:
Aşağıdaki kod örneği, Maven kullandığınızı varsaymaktadır.
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();}}
Minimum Para Yatırma ve Çekme Tutarları
SOL için her para yatırma ve çekme işlemi, cüzdan adresindeki hesabın minimum kira muafiyeti bakiyesine (veri içermeyen temel bir SOL hesabı) eşit veya bundan büyük olmalıdır. Mevcut değer: 0,000890880 SOL
Benzer şekilde, her para yatırma hesabı en az bu bakiyeyi içermelidir.
curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id": 1,"method": "getMinimumBalanceForRentExemption","params": [0]}'
Sonuç
{ "jsonrpc": "2.0", "result": 890880, "id": 1 }
Önceliklendirme Ücretleri ve Hesaplama Birimleri
Yüksek talep dönemlerinde, bir validator daha yüksek ekonomik değere sahip diğer işlemleri seçtiği için bir işlemin bloğa eklenmeden sona ermesi mümkündür. Önceliklendirme Ücretleri doğru şekilde uygulanmadığında Solana üzerindeki geçerli işlemler gecikebilir veya düşürülebilir.
Önceliklendirme Ücretleri, işlemlerin bloklar içine alınmasını güvence altına almak ve bu gibi durumlarda teslimatı sağlamaya yardımcı olmak amacıyla temel İşlem Ücretine ek olarak eklenebilen ilave ücretlerdir.
Bu öncelik ücretleri, istenen öncelik ücretini belirleyen özel bir Compute Budget talimatı eklenerek işleme dahil edilir.
Önemli Not
Bu talimatların uygulanmaması ağ kesintilerine ve işlem düşmelerine yol açabilir. Solana'yı destekleyen her borsanın kesintileri önlemek amacıyla öncelik ücretlerini kullanması şiddetle tavsiye edilir.
Önceliklendirme Ücreti Nedir?
Önceliklendirme Ücretleri, ağdaki bloklar içinde validator düğümlerinin işlemleri dahil etmesini ekonomik açıdan cazip kılmak amacıyla işlemlere eklenen mikro-lamport/Hesaplama Birimi (örneğin küçük miktarda SOL) cinsinden fiyatlandırılır.
Önceliklendirme Ücreti Ne Kadar Olmalıdır?
Önceliklendirme ücretinizi belirlemek için kullanılan yöntem, ağ için cazip
olması muhtemel bir ücret belirlemek amacıyla son önceliklendirme ücretlerini
sorgulamayı kapsamalıdır.
getRecentPrioritizationFees RPC
yöntemini kullanarak, son bir blokta işlemin yer alması için gereken
önceliklendirme ücretlerini sorgulayabilirsiniz.
Bu öncelik ücretlerinin fiyatlandırma stratejisi kullanım senaryonuza göre farklılık gösterir. Bunu yapmanın standart bir yolu yoktur. Önceliklendirme Ücretlerinizi belirlemeye yönelik bir strateji; işlem başarı oranınızı hesaplamak, ardından son işlem ücretleri API'sine yönelik bir sorguya karşın Önceliklendirme Ücretinizi artırmak ve buna göre ayarlamak olabilir. Önceliklendirme Ücretleri fiyatlandırması, ağdaki aktiviteye ve diğer katılımcıların tekliflerine bağlı olarak dinamik bir yapıda olacak ve yalnızca gerçekleştikten sonra bilinebilecektir.
getRecentPrioritizationFees API çağrısının kullanımındaki zorluklardan biri,
her blok için yalnızca en düşük ücreti döndürebilmesidir. Bu değer çoğunlukla
sıfır olacaktır; bu da validator düğümleri tarafından reddedilmemek için
kullanılacak Önceliklendirme Ücretinin tam anlamıyla yararlı bir tahmini
değildir.
getRecentPrioritizationFees API, parametre olarak hesapların pubkey değerlerini
alır ve ardından bu hesaplar için minimum önceliklendirme ücretlerinin en
yükseğini döndürür. Hesap belirtilmediğinde API, bloğa dahil olmak için gereken
en düşük ücreti döndürür; bu değer genellikle sıfırdır (blok dolu olmadıkça).
Borsalar ve uygulamalar, bir işlemin yazma kilidi uygulayacağı hesaplarla birlikte
RPC uç noktasını sorgulamalıdır. RPC uç noktası
max(account_1_min_fee, account_2_min_fee, ... account_n_min_fee) değerini
döndürür; bu değer, kullanıcının söz konusu işlem için önceliklendirme ücretini
belirlemesinde temel nokta olmalıdır.
Önceliklendirme Ücretlerini belirlemeye yönelik farklı yaklaşımlar mevcuttur ve uygulanacak en iyi ücreti belirlemek için bazı üçüncü taraf API'leri bulunmaktadır. Ağın dinamik yapısı göz önüne alındığında, Önceliklendirme ücretlerinizi fiyatlandırmanın "mükemmel" bir yolu olmayacaktır; bu nedenle bir yol seçmeden önce dikkatli bir analiz yapılmalıdır.
Önceliklendirme Ücretleri Nasıl Uygulanır?
Bir işleme öncelik ücreti eklemek, söz konusu işleme iki Compute Budget talimatı önceden eklenmesinden oluşur:
- birincisi hesaplama birimi fiyatını belirlemek için,
- diğeri ise hesaplama birimi limitini belirlemek için
Burada, öncelik ücretlerinin nasıl kullanılacağına dair daha fazla bilgi içeren daha ayrıntılı bir geliştirici kılavuzuna da ulaşabilirsiniz.
Temel İşlem Ücretinin (5.000 Lamport) üzerine bir Önceliklendirme Ücreti eklemek
için bir setComputeUnitPrice talimatı oluşturun.
// import { ComputeBudgetProgram } from "@solana/web3.js"ComputeBudgetProgram.setComputeUnitPrice({ microLamports: number });
Mikro-lamport cinsinden sağlanan değer, Önceliklendirme Ücretini Lamport
cinsinden belirlemek için Hesaplama Birimi (HB) bütçesiyle çarpılır. Örneğin,
HB bütçeniz 1M HB ise ve 1 mikroLamport/HB eklerseniz, Önceliklendirme Ücreti
1 lamport olur (1M * 0,000001). Toplam ücret ise 5001 lamport olacaktır.
İşlem için yeni bir hesaplama birimi bütçesi belirlemek amacıyla bir
setComputeUnitLimit talimatı oluşturun.
// import { ComputeBudgetProgram } from "@solana/web3.js"ComputeBudgetProgram.setComputeUnitLimit({ units: number });
units değeri, Solana çalışma ortamının varsayılan hesaplama bütçesi değerinin
yerine geçecektir.
İşlem için Gereken En Düşük HB Miktarını Belirleyin
İşlemlerin verimliliği en üst düzeye çıkarmak ve genel ücretleri en aza indirmek için yürütme için gereken minimum hesaplama birimi (HB) miktarını talep etmesi gerekir.
Bir işlemin tükettiği HB miktarını, işlemi devnet gibi farklı bir Solana kümesinde göndererek öğrenebilirsiniz. Örneğin, basit bir token transferi 300 HB tüketir.
// 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}));
Önceliklendirme Ücretleri ve Kalıcı Nonce'lar
Kurulumunuz Dayanıklı Nonce İşlemleri kullanıyorsa, başarılı işlemler sağlamak amacıyla Önceliklendirme Ücretlerini Dayanıklı İşlem Nonce'larıyla birlikte doğru şekilde uygulamak önemlidir. Aksi takdirde, hedeflenen Dayanıklı Nonce işlemleri bu şekilde algılanmayacaktır.
AdvanceNonceAccount talimatı, compute budget talimatları öncelik ücretlerini belirtmek için kullanılsa bile, talimat listesinde İLK olarak belirtilmek ZORUNDADIR. Bu durum Dayanıklı İşlem Nonce'ları KULLANIYOR olmanız halinde geçerlidir.
Bu geliştirici kılavuzunda dayanıklı nonce'lar ve öncelik ücretlerini birlikte kullanan belirli bir kod örneği bulabilirsiniz.
SPL Token Standardının Desteklenmesi
SPL Token, Solana blok zincirinde sarılı/sentetik token oluşturma ve değişimi için kullanılan standarttır.
SPL Token iş akışı, yerel SOL token'larınkine benzerdir; ancak bu bölümde ele alınacak birkaç farklılık mevcuttur.
Token Mint'leri
Her bir SPL Token türü, bir mint account oluşturularak tanımlanır. Bu account; arz, ondalık basamak sayısı ve mint üzerinde kontrole sahip çeşitli yetkiler gibi token özelliklerini açıklayan meta verileri depolar. Her SPL Token account, ilişkili mint'ini referans alır ve yalnızca o türdeki SPL Token'larla etkileşime girebilir.
spl-token CLI Aracının Yüklenmesi
SPL Token account'ları, spl-token komut satırı aracı kullanılarak sorgulanır ve değiştirilir. Bu bölümde verilen örnekler, aracın yerel sisteme yüklenmiş olmasını gerektirir.
spl-token, Rust cargo komut satırı aracı aracılığıyla Rust crates.io üzerinden dağıtılmaktadır. cargo'nun en son sürümü, platformunuza özel kullanışlı bir tek satırlık komutla rustup.rs adresinden yüklenebilir. cargo yüklendikten sonra spl-token aşağıdaki komutla edinilebilir:
cargo install spl-token-cli
Ardından yüklü sürümü doğrulamak için kontrol edebilirsiniz
spl-token --version
Sonuç aşağıdakine benzer bir çıktı olmalıdır
spl-token-cli 2.0.1
Account Oluşturma
SPL Token account'larının, yerel System Program account'larında bulunmayan ek gereksinimleri vardır:
- SPL Token account'larına token yatırılabilmesi için önce oluşturulmaları gerekir. Token account'ları,
spl-token create-accountkomutuyla açıkça veyaspl-token transfer --fund-recipient ...komutuyla örtük olarak oluşturulabilir. - SPL Token account'larının var oldukları süre boyunca kira muafiyeti korunmalıdır; bu nedenle account oluşturulurken küçük bir miktarda yerel SOL token'ı yatırılması gerekmektedir. SPL Token account'ları için bu miktar 0,00203928 SOL (2.039.280 lamport)'tur.
Komut Satırı
Aşağıdaki özelliklere sahip bir SPL Token account'u oluşturmak için:
- Belirtilen mint ile ilişkilendirilmiş
- Finansman account'ının keypair'i tarafından sahiplenilen
spl-token create-account <TOKEN_MINT_ADDRESS>
Örnek
spl-token create-account AkUFCWTXb3w9nY2n6SFJvBV6VwvFUCe4KBMCcgLsa2ir
Aşağıdakine benzer bir çıktı üretir:
Creating account 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkVSignature: 4JsqZEPra2eDTHtHpB4FMWSfk3UgcCVmkKkP7zESZeMrKmFFkDkNd91pKP3vPVVZZPiu5XxyJwS73Vi5WsZL88D7
Ya da belirli bir keypair ile SPL Token account'u oluşturmak için:
solana-keygen new -o token-account.jsonspl-token create-account AkUFCWTXb3w9nY2n6SFJvBV6VwvFUCe4KBMCcgLsa2ir token-account.json
Aşağıdakine benzer bir çıktı üretir:
Creating account 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkVSignature: 4JsqZEPra2eDTHtHpB4FMWSfk3UgcCVmkKkP7zESZeMrKmFFkDkNd91pKP3vPVVZZPiu5XxyJwS73Vi5WsZL88D7
Account Bakiyesini Kontrol Etme
Komut Satırı
spl-token balance <TOKEN_ACCOUNT_ADDRESS>
Örnek
solana balance 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV
Aşağıdakine benzer bir çıktı üretir:
0
Token Transferleri
Transfer için kaynak account, miktarı içeren gerçek token account'tur.
Ancak alıcı adresi normal bir cüzdan account'u olabilir. Söz konusu cüzdan için belirtilen mint'e ait bir associated token account henüz mevcut değilse, --fund-recipient argümanı sağlandığı takdirde transfer bu account'u oluşturacaktır.
Komut Satırı
spl-token transfer <SENDER_ACCOUNT_ADDRESS> <AMOUNT> <RECIPIENT_WALLET_ADDRESS> --fund-recipient
Örnek
spl-token transfer 6B199xxzw3PkAm25hGJpjj3Wj3WNYNHzDAnt1tEqg5BN 1
Aşağıdakine benzer bir çıktı üretir:
6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkVTransfer 1 tokensSender: 6B199xxzw3PkAm25hGJpjj3Wj3WNYNHzDAnt1tEqg5BNRecipient: 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkVSignature: 3R6tsog17QM8KfzbcbdP4aoMfwgo6hBggJDVy7dZPVmH2xbCWjEj31JKD53NzMrf25ChFjY7Uv2dfCDq4mGFFyAj
Yatırma
Her (cüzdan, mint) çifti zincir üzerinde ayrı bir account gerektirdiğinden, bu account'ların adreslerinin Associated Token Account (ATA) şeması kullanılarak SOL yatırma cüzdanlarından türetilmesi ve yalnızca ATA adreslerinden gelen yatırmaların kabul edilmesi önerilir.
Yatırma işlemlerinin izlenmesi, yukarıda açıklanan blok yoklama yöntemini izlemelidir. Her yeni blok; kullanıcının ve borsanın token account adresleri dahil başarılı işlemler için taranmalıdır.
İşlemin meta verilerindeki preTokenBalances ve postTokenBalances alanları, etkin bakiye değişimini belirlemek için kullanılmalıdır. Bu alanlar; token mint'ini, token account sahibini (cüzdan adresi) ve işlem öncesi ile sonrasındaki token account bakiyelerini içerir.
İşlemin bir parçası olarak bir token account oluşturulursa (örneğin ilk kez token alınırken), işlem öncesinde mevcut olmadığından preTokenBalances dizisinde görünmez. Bu senaryoda, yatırma tutarları hesaplanırken başlangıç bakiyesini sıfır olarak ele almalısınız. Yeni oluşturulan account, yalnızca işlem tamamlandıktan sonraki nihai bakiyesiyle postTokenBalances dizisinde görünecektir.
Örnek 1: Tek Token Transferi
Aşağıdaki işlem detayı, tek bir token transfer talimatı içeren bir işlem örneğini göstermektedir.
İşlem, token'ın 100 temel birimini (mint ondalığı için düzeltilmemiş) transfer eder ve aşağıdaki account'ları içerir:
- Gönderen (sahip):
4fvXFPXSL9i7VbiRzoizuW4bhn1dMvRgQzQ6VevssYxw - Gönderen Token Account'u:
6zhjktfYBRUp7fgXLoWU7GFFrCuZa9iQkYTQzDzuvsAS - Alıcı Token Account'u:
G5nNekUhhWFqJAiCMpKHootZ5Bfa7MXwuQ5vvKcvuxKM - Token Extension Program ID'si:
TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
Alıcı (sahip) account'unun ve mint account'unun bir token transfer talimatında gerekli olmadığına dikkat edin. Referans olması açısından, ayrıştırılmış işlem meta verilerinde adreslerin yer alması nedeniyle burada listelenmiştir.
- Alıcı (sahip):
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"}
Örnek 2: Token Account Oluşturma ve Transfer
Aşağıdaki işlem detayı, alıcı token account'unun bir token transferiyle aynı işlemde oluşturulduğu bir işlem örneğini göstermektedir.
preTokenBalances dizisinin, işlem öncesinde mevcut olmadığı için alıcı token account'unu içermediğine dikkat edin. Alıcı token account'u yalnızca işlem tamamlandıktan sonraki nihai bakiyesiyle postTokenBalances dizisinde görünür.
{"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"}
Örnek 3: Token Account Sahibini Değiştirme
Aşağıdaki işlem detayı, token account'unun owner alanının değiştirildiği bir işlem örneğini göstermektedir.
Yatırma yöntemi olarak token account'larının sahipliğinin devredilmesine (owner alanının değiştirilmesi yoluyla) izin vermek kesinlikle tavsiye edilmez.
Bunu bir yatırma yöntemi olarak desteklemeyi tercih ederseniz, postTokenBalances içindeki yeni owner alanının borsanızın kontrol ettiği ve özel anahtarına sahip olduğu bir cüzdan adresiyle eşleştiğini doğrulamalısınız.
Bir yatırımcı, token account'unun owner'ını cüzdan olmayan bir adresle (örneğin başka bir token account adresi) değiştirirse, fonlar kalıcı olarak erişilemez hale gelebilir.
{"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"}
Token Yatırma Hesaplaması
Token yatırmalarını doğru şekilde takip etmek için işlem meta verilerindeki preTokenBalances ve postTokenBalance alanlarını karşılaştırmalısınız. Bu alanlar, işlem öncesi ve sonrasındaki token bakiyelerini ve token account sahibini göstererek transfer edilen token miktarını tam olarak hesaplamanıza olanak tanır. Bu yaklaşım, gerçek bakiye değişikliklerini yakalamanızı sağlar.
preTokenBalancesvepostTokenBalancesalanlarındakiowneralanı aynı kalırsa,amountalanları arasındaki farkı hesaplayın.- Token account sahipliği değişirse (
preTokenBalancesilepostTokenBalancesarasında farklıowneralanı) vepostTokenBalanceiçindeki yeni sahip borsanızın beklenenowneradresiyle eşleşiyorsa,postTokenBalancesiçindekiamountalanında gösterilen bakiyenin tamamını yatırılan tutar olarak kabul edin.
"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--}
Para Çekme
Kullanıcının belirttiği para çekme adresi, SOL cüzdan adresi olmalıdır.
Bir para çekme transferi gerçekleştirilmeden önce, borsa adresi yukarıda açıklandığı şekilde kontrol etmelidir. Bunun yanı sıra bu adres, System Program tarafından sahip olunmalı ve herhangi bir hesap verisi içermemelidir. Adresin SOL bakiyesi yoksa, para çekme işlemine devam etmeden önce kullanıcı onayı alınmalıdır. Diğer tüm para çekme adresleri reddedilmelidir.
Para çekme adresinden, doğru mint için Associated Token Account (ATA) türetilir ve transfer, bir TransferChecked talimatı aracılığıyla söz konusu hesaba gönderilir. ATA adresinin henüz mevcut olmayabileceğini unutmayın; bu durumda borsa, hesabı kullanıcı adına fonlamalıdır. SPL Token hesapları için para çekme hesabının fonlanması 0.00203928 SOL (2.039.280 lamport) gerektirecektir.
Para çekme için spl-token transfer komut şablonu:
spl-token transfer --fund-recipient <exchange token account> <withdrawal amount> <withdrawal address>
Diğer Hususlar
Dondurma Yetkisi
Yasal uyumluluk nedeniyle, bir SPL Token ihraç eden kuruluş, mint'iyle ilişkili olarak oluşturulan tüm hesaplar üzerinde isteğe bağlı olarak "Dondurma Yetkisi" tutmayı seçebilir. Bu, söz konusu hesaptaki varlıkları istedikleri zaman dondurmasına ve çözülene kadar hesabı kullanılamaz hale getirmesine olanak tanır. Bu özellik kullanılıyorsa, dondurma yetkisinin pubkey'i SPL Token'ın mint hesabında kayıtlı olacaktır.
SPL Token-2022 (Token Extensions) Standardı için Temel Destek
SPL Token-2022, Solana blok zincirinde sarılmış/sentetik token oluşturma ve değişimi için en yeni standarttır.
"Token Extensions" olarak da bilinen bu standart, token oluşturucuların ve hesap sahiplerinin isteğe bağlı olarak etkinleştirebileceği birçok yeni özellik içerir. Bu özellikler arasında gizli transferler, transfer ücretleri, mint kapatma, meta veri, kalıcı delegeler, değiştirilemez sahiplik ve çok daha fazlası yer almaktadır. Daha fazla bilgi için lütfen uzantı kılavuzuna bakın.
Borsanız SPL Token'ı destekliyorsa, SPL Token-2022'yi desteklemek için fazladan çok fazla çalışma gerekmez:
- CLI aracı, sürüm 3.0.0'dan itibaren her iki programla da sorunsuz çalışır.
preTokenBalancesvepostTokenBalances, SPL Token-2022 bakiyelerini içerir- RPC, SPL Token-2022 hesaplarını indeksler; ancak bunların
TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEbprogram id'si ile ayrı olarak sorgulanması gerekir
Associated Token Account aynı şekilde çalışır ve yeni hesap için gerekli SOL depozito miktarını doğru şekilde hesaplar.
Ancak uzantılar nedeniyle hesaplar 165 bayttan daha büyük olabilir; dolayısıyla fonlanmaları için 0.00203928 SOL'dan daha fazlası gerekebilir.
Örneğin, Associated Token Account programı her zaman "immutable owner" uzantısını içerir; bu nedenle hesaplar en az 170 bayt kaplar ve bu da 0.00207408 SOL gerektirir.
Uzantıya Özgü Hususlar
Önceki bölüm, SPL Token-2022 için en temel desteği özetlemektedir. Uzantılar token'ların davranışını değiştirdiğinden, borsaların token'ları nasıl işlediğini değiştirmesi gerekebilir.
Bir mint veya token account üzerindeki tüm uzantıları görmek mümkündür:
spl-token display <account address>
Transfer Ücreti
Bir token, transfer ücreti ile yapılandırılabilir; bu durumda transfer edilen token'ların bir kısmı gelecekteki tahsilat için hedefte alıkonulur.
Borsanız bu token'ları transfer ediyorsa, alıkonulan miktar nedeniyle tamamının hedefe ulaşmayabileceğine dikkat edin.
Sürprizlerden kaçınmak için transfer sırasında beklenen ücreti belirtmek mümkündür:
spl-token transfer --expected-fee <fee amount> --fund-recipient <exchange token account> <withdrawal amount> <withdrawal address>
Mint Kapatma Yetkisi
Bu uzantıyla birlikte, token oluşturucu token arzı sıfır olması koşuluyla bir mint'i kapatabilir.
Bir mint kapatıldığında, boş token account'lar hâlâ mevcut olabilir ve bunlar artık geçerli bir mint ile ilişkilendirilmeyecektir.
Bu token account'ları kapatmak güvenlidir:
spl-token close --address <account address>
Gizli Transfer
Mint'ler gizli transferler için yapılandırılabilir; böylece token miktarları şifrelenir ancak hesap sahipleri hâlâ kamuya açık kalır.
Borsalar, kullanıcı miktarlarını gizlemek amacıyla token account'larını gizli transfer gönderip almak için yapılandırabilir. Token account'larında gizli transferlerin etkinleştirilmesi zorunlu değildir; dolayısıyla borsalar kullanıcıları token'ları gizli olmayan şekilde göndermeye zorlayabilir.
Gizli transferleri etkinleştirmek için hesabın buna göre yapılandırılması gerekir:
spl-token configure-confidential-transfer-account --address <account address>
Transfer gerçekleştirmek için:
spl-token transfer --confidential <exchange token account> <withdrawal amount> <withdrawal address>
Gizli bir transfer sırasında preTokenBalance ve postTokenBalance alanları herhangi bir değişiklik göstermez. Depozito hesaplarını taramak için token'ları çekmek amacıyla yeni bakiyenin şifresini çözmeniz gerekir:
spl-token apply-pending-balance --address <account address>spl-token withdraw-confidential-tokens --address <account address> <amount or ALL>
Varsayılan Hesap Durumu
Mint'ler varsayılan bir hesap durumuyla yapılandırılabilir; böylece tüm yeni token account'lar varsayılan olarak dondurulur. Bu token oluşturucular, kullanıcıların hesabı çözündürmek için ayrı bir süreçten geçmesini gerektirebilir.
Transfer Edilemez
Bazı token'lar transfer edilemez; ancak yine de yakılabilir ve hesap kapatılabilir.
Kalıcı Delege
Token oluşturucular, tüm token'ları için kalıcı bir delege atayabilir. Kalıcı delege, herhangi bir hesaptan token transfer edebilir veya yakabilir; bu da potansiyel olarak fonların çalınmasına yol açabilir.
Bu, belirli yargı bölgelerinde stabilcoinler için yasal bir gereklilik olabilir ya da token geri alım planları için kullanılabilir.
Bu token'ların borsanızın bilgisi olmadan transfer edilebileceğine dikkat edin.
Transfer Hook
Token'lar, transferi doğrulamak veya başka bir mantık yürütmek amacıyla transferler sırasında çağrılması gereken ek bir programla yapılandırılabilir.
Solana çalışma zamanı tüm hesapların bir programa açıkça aktarılmasını gerektirdiğinden ve transfer hook'ları ek hesaplar gerektirdiğinden, borsa bu token'lar için transfer talimatlarını farklı şekilde oluşturmalıdır.
CLI ve createTransferCheckedWithTransferHookInstruction gibi talimat oluşturucular, ekstra hesapları otomatik olarak ekler; ancak ek hesaplar açıkça da belirtilebilir:
spl-token transfer --transfer-hook-account <pubkey:role> --transfer-hook-account <pubkey:role> ...
Transfer Sırasında Zorunlu Açıklama Notu
Kullanıcılar, token account'larını transfer sırasında açıklama notu (memo) gerektirecek şekilde yapılandırabilir.
Borsaların token'ları kullanıcılara geri transfer etmeden önce bir memo talimatı eklemesi gerekebilir ya da kullanıcıların borsaya gönderim yapmadan önce bir memo talimatı eklemesini zorunlu kılabilirler:
spl-token transfer --with-memo <memo text> <exchange token account> <withdrawal amount> <withdrawal address>
Entegrasyonun Test Edilmesi
Mainnet'te üretime geçmeden önce tam iş akışınızı Solana devnet ve testnet kümelerinde test ettiğinizden emin olun.
Devnet en açık ve esnek olanıdır; başlangıç geliştirmesi için idealdir. Testnet ise daha gerçekçi küme yapılandırması sunar. Hem devnet hem de testnet bir faucet destekler; geliştirme ve test için biraz devnet veya testnet SOL edinmek üzere solana airdrop 1 komutunu çalıştırın.
Is this page helpful?