https://solscan.io/tx/5CpvpQuG8pU3x6xz3fmryqwtQkstnk4jQTP95ZgzPBAzhZipEGnpD8YnHxASsHkChotvihSxrjboret3YYD82u6z
https://solscan.io/tx/4Axs7CTRZNPeSWVqtYaP96KdB7hNafHq9AfUJenqVdP2oeZ1P9ggTfUu7zytvgDw1fGULGXYUqSwkNfEgsXMncPM
https://solscan.io/tx/TjN1kWn8MabXisVeKq37DXDDMaGKaLKSoztXUSxV8SfMzyfpi2T1rRGQeX3dAH41ygTuGb4zTfRKocpNq6FZaXH
import os
import time
import base58
from solders.pubkey import Pubkey
from solders.keypair import Keypair
from solders.transaction import Transaction
from solders.message import Message
from solders.compute_budget import set_compute_unit_price
from solana.rpc.api import Client
from solana.rpc.types import TxOpts
from solana.rpc.commitment import Confirmed
from spl.token.client import Token
from spl.token.constants import TOKEN_PROGRAM_ID
from spl.token.instructions import get_associated_token_address, create_associated_token_account, transfer_checked, TransferCheckedParams
from decimal import Decimal
# --- 1. 配置区域 ---
# --- 请在这里修改您的转账信息 ---
# 使用公共 RPC 节点
RPC_ENDPOINT = "<https://api.mainnet-beta.solana.com>"
# 要转账的代币的 Mint Address
TOKEN_MINT_ADDRESS = Pubkey.from_string("9raUVuzeWUk53co63M4WXLWPWE4Xc6Lpn7RS9dnkpump")
PRIVATE_KEY_STRING= "PRIVATE_KEY_STRING"
# 转账配置列表
TRANSFERS_CONFIG = [
{"address": "8PnZWXHbJ7KDdVUnawABRPKwTxfmLiGRFPBTC87X7uqC", "amount": 0.11},
{"address": "EBwyugmbUKMTUrtCq6aRTsyvfMGwJzp5yDRPrgNSqbHm", "amount": 0.12},
{"address": "ENfD5o8xpfaANVTqwYf9DFQmHyC8ECnodvoxdNnZhZfJ", "amount": 0.13},
{"address": "DEZA8LEEViuUD724gzPY8YdoM8PJ1woFssj4jrKENyqv", "amount": 0.14},
{"address": "5iMiVc8hiEBub5RPjV7izouwyEJDPgFTnyT4tasNpdbL", "amount": 0.15},
{"address": "Cm8GVbuayT55vnQhcnJmcKPaB5gvuPin67GnohordbHB", "amount": 0.16},
{"address": "2GQTbSr7EtBor7QnD7gz7XpSkNF36pMXE9uAX9akFjKt", "amount": 0.17},
{"address": "85M5nYP3ouHhdZjDdZh4W2HBn5DHB3kD1EHYiVNvNjyZ", "amount": 0.18},
{"address": "GWJHAbXhgxdXoEWDHKBrzBB7pytbVzoipUQ4C8UNkniU", "amount": 0.19},
{"address": "5w7psSQdRhEg6bhfjFQUs74ysB7KQdydKDhQcY3YpQXJ", "amount": 0.2},
{"address": "5yogefKsED8oaBFcaSH92WSE8HvsrNwMUis7QZbG6aPZ", "amount": 0.21},
{"address": "DEZA8LEEViuUD724gzPY8YdoM8PJ1woFssj4jrKENyqv", "amount": 0.22},
{"address": "6yuUhK4MVh24nNnuYbSpviuoVFD4dZNqYdL7YPC7sFmU", "amount": 0.23},
{"address": "ErdEeyoLaCkjnYZSG42JvbgRTrCLnFy7utw4ynbt9Fsq", "amount": 0.24},
{"address": "DEZA8LEEViuUD724gzPY8YdoM8PJ1woFssj4jrKENyqv", "amount": 0.25},
{"address": "5kek95xeUw2WeNbjgAsSJkUHnLbXgMgDuA5uU4o9K9M1", "amount": 0.26},
{"address": "Z8wPQd3CZ6gYg9oHYsfKsZ6nyesSPCpwneXUW566y5U", "amount": 0.27},
{"address": "G9HGnQJ1ahax2TCeczr5AZm27XPrkMUQ2f7EitAmALfs", "amount": 0.28},
{"address": "DEZA8LEEViuUD724gzPY8YdoM8PJ1woFssj4jrKENyqv", "amount": 0.29},
]
# 优先费 (Micro Lamports)
PRIORITY_FEE_MICRO_LAMPORTS = 0
#单交易空投笔数
BATCH_SIZE = 9
# --- 配置区域结束 ---
def load_keypair_from_base58(private_key_b58: str) -> Keypair:
try:
keypair_bytes = base58.b58decode(private_key_b58)
if len(keypair_bytes) != 64:
raise ValueError(f"私钥解码后的长度应为64字节,实际为 {len(keypair_bytes)} 字节。")
return Keypair.from_bytes(keypair_bytes)
except Exception as e:
print(f"错误:无法从Base58字符串加载密钥对。请检查.env文件中的私钥。")
raise e
def main():
"""主执行函数"""
print("--- Solana SPL 代币批量转账脚本 (兼容新版 solana-py) ---")
# --- 新增:定义批量大小 ---
# 根据计算,9 是一个在最坏情况下(所有接收者都需要创建ATA)也安全的值
try:
sender_keypair = load_keypair_from_base58(PRIVATE_KEY_STRING)
client = Client(RPC_ENDPOINT)
except Exception as e:
print(f"初始化失败:{e}")
return
print(f"发送方地址: {sender_keypair.pubkey()}")
print(f"代币地址: {TOKEN_MINT_ADDRESS}")
print(f"共计 {len(TRANSFERS_CONFIG)} 笔转账任务,将以每批 {BATCH_SIZE} 笔进行处理")
print("-" * 20)
try:
token_client = Token(
conn=client,
pubkey=TOKEN_MINT_ADDRESS,
program_id=TOKEN_PROGRAM_ID,
payer=sender_keypair
)
mint_info = token_client.get_mint_info()
decimals = mint_info.decimals
print(f"代币小数位数: {decimals}")
sender_ata = get_associated_token_address(sender_keypair.pubkey(), TOKEN_MINT_ADDRESS)
print(f"发送方代币账户 (ATA): {sender_ata}")
# --- 核心改动:对转账任务进行分批处理 ---
total_batches = (len(TRANSFERS_CONFIG) + BATCH_SIZE - 1) // BATCH_SIZE
for i in range(0, len(TRANSFERS_CONFIG), BATCH_SIZE):
batch_num = (i // BATCH_SIZE) + 1
batch_config = TRANSFERS_CONFIG[i:i + BATCH_SIZE]
print(f"\\n--- 正在处理批次 {batch_num}/{total_batches} (共 {len(batch_config)} 笔转账) ---")
# 1. 将当前批次的指令收集到一个列表中
instructions = []
if PRIORITY_FEE_MICRO_LAMPORTS > 0:
instructions.append(set_compute_unit_price(PRIORITY_FEE_MICRO_LAMPORTS))
print(f"已添加优先费: {PRIORITY_FEE_MICRO_LAMPORTS} micro-lamports")
print("正在为当前批次的每个接收者生成转账指令...")
for transfer_info in batch_config:
try:
recipient_pubkey = Pubkey.from_string(transfer_info["address"])
# <--- 浮点精度修正
# 使用 Decimal 确保精度,先转为字符串再转 Decimal 是最安全的方式
amount_decimal = Decimal(str(transfer_info["amount"]))
amount_in_smallest_unit = int(amount_decimal * (10 ** decimals))
# ---> 浮点精度修正结束
print(f" -> 任务: 向 {recipient_pubkey} 转账 {amount_decimal} 个代币")
recipient_ata = get_associated_token_address(recipient_pubkey, TOKEN_MINT_ADDRESS)
recipient_ata_info = client.get_account_info(recipient_ata).value
if recipient_ata_info is None:
print(f" 接收者 ATA ({recipient_ata}) 不存在,将添加 '创建 ATA' 指令。")
instructions.append(
create_associated_token_account(
payer=sender_keypair.pubkey(),
owner=recipient_pubkey,
mint=TOKEN_MINT_ADDRESS
)
)
instructions.append(
transfer_checked(
TransferCheckedParams(
program_id=token_client.program_id,
source=sender_ata,
mint=TOKEN_MINT_ADDRESS,
dest=recipient_ata,
owner=sender_keypair.pubkey(),
amount=amount_in_smallest_unit,
decimals=decimals,
signers=[]
)
)
)
except Exception as e:
print(f"处理转账任务 {transfer_info} 时出错: {e}")
continue
# 2. 获取最新区块哈希 (!!! 必须在每个批次循环内部获取)
print("正在获取最新区块哈希...")
latest_blockhash = client.get_latest_blockhash(commitment=Confirmed).value.blockhash
# 3. 创建 Message 和 Transaction
message = Message.new_with_blockhash(
instructions,
sender_keypair.pubkey(),
latest_blockhash
)
transaction = Transaction([sender_keypair], message, latest_blockhash)
# 4. 发送交易
print("正在发送交易到 Solana 网络...")
opts = TxOpts(skip_preflight=False, preflight_commitment=Confirmed)
tx_signature = client.send_transaction(transaction, opts=opts).value
print("-" * 20)
print(f"✅ 批次 {batch_num} 交易已成功发送!")
print(f" 交易签名: {tx_signature}")
print(f" 在 Solscan 上查看: <https://solscan.io/tx/{tx_signature}>")
print("正在等待交易确认...")
client.confirm_transaction(tx_signature, commitment=Confirmed)
print(f"🎉 批次 {batch_num} 交易已确认!")
# 在批次之间短暂暂停,避免对 RPC 节点造成过大压力
if batch_num < total_batches:
time.sleep(2)
print("\\n--- 所有批次处理完毕,批量转账完成 ---")
except Exception as e:
print(f"\\n❌ 执行过程中发生错误: {e}")
if __name__ == "__main__":
main()