Showing Posts From

Solana

BIP39 助记词生成 Solana 地址:SLIP-10 + Ed25519 全流程

BIP39 助记词生成 ETH 地址靠 secp256k1 + keccak256,走 Solana 就完全换了一套——Ed25519 + SLIP-0010,最后不做 hash,直接 Base58 编码公钥。 全流程 助记词 (Mnemonic) │ PBKDF2-HMAC-SHA512 ▼ Seed (64 字节) │ SLIP-0010 (Ed25519) ▼ Master Key │ 按路径 m/44'/501'/0'/0' 派生 ▼ Ed25519 私钥 (32 字节) │ Ed25519 公钥算法 ▼ 公钥 (32 字节) │ Base58 编码 ▼ Solana 地址和 BTC/ETH 唯一相同的只有第一步"助记词转 seed",之后全变了。 第一步:助记词 → seed 标准 BIP39,PBKDF2-HMAC-SHA512: password = 助记词字符串 salt = "mnemonic" + passphrase iters = 2048 output = 64 字节Python: from mnemonic import Mnemonicmnemo = Mnemonic("english") seed = mnemo.to_seed( "abandon abandon abandon abandon abandon abandon " "abandon abandon abandon abandon abandon about", passphrase="", ) print(seed.hex())第二步:seed → Master Key(SLIP-10 Ed25519) Solana 用 SLIP-0010(Ed25519 版本),和 BIP32 的 secp256k1 分道扬镳: I = HMAC-SHA512(key="ed25519 seed", data=seed) IL = master private key (32 字节) IR = master chain code (32 字节)第三步:派生路径 Solana 默认路径: m/44'/501'/0'/0'44':BIP44 501':Solana 的 coin type 0':account 0':change每一级都是 hardened derivation(' 表示 + 2³¹)。Ed25519 只支持 hardened 派生,非 hardened 会直接报错。 第四步:公钥 & 地址 私钥经 Ed25519 算出 32 字节公钥。地址 = Base58(公钥),就这么简单:没有 SHA-256 double hash 没有 RIPEMD-160 没有 keccak 没有 checksum(Base58 本身没自带校验,也没有像 BTC 那样附 4 字节 hash)Python 一把梭 bip_utils 把上面所有细节封好了: from bip_utils import Bip39SeedGenerator, Bip44, Bip44Coinsmnemonic = ("abandon abandon abandon abandon abandon abandon " "abandon abandon abandon abandon abandon about")seed = Bip39SeedGenerator(mnemonic).Generate()bip44 = Bip44.FromSeed(seed, Bip44Coins.SOLANA) account = bip44.Purpose().Coin().Account(0).Change(Bip44Changes.CHAIN_EXT).AddressIndex(0)print("地址:", account.PublicKey().ToAddress()) print("私钥:", account.PrivateKey().Raw().ToHex())Phantom / Solflare 里的第一个账号导出出来应该跟上面一样。 常见误区 Solana 地址和 ETH 地址长得像 其实完全不同:ETH 地址:40 字符 hex + 0x 前缀,checksum 在 EIP-55 里靠大小写实现 Solana 地址:Base58 编码的 32 字节公钥,长度 32~44 字符,无固定前缀Solana 私钥文件是 64 字节而不是 32 Solana 的钱包 JSON(Phantom 导出)通常是 64 字节:前 32 是私钥 seed、后 32 是公钥。生成时: priv32 = account.PrivateKey().Raw().ToBytes() pub32 = account.PublicKey().RawUncompressed().ToBytes()[-32:] keypair_bytes = priv32 + pub32 # 64 字节导入 solana-cli 或 Phantom 时用这个格式。 Ed25519 派生路径可以省略部分层级 Phantom 早期用 m/44'/501'/0'(只三层)而非 m/44'/501'/0'/0'——同一助记词在这两种路径下算出来的地址不同。发现"钱包地址对不上"时先检查是不是路径差异,试试:m/44'/501'/0' — Phantom "legacy" m/44'/501'/0'/0' — 现在的默认一句话总结 Solana 地址生成 = BIP39 seed → SLIP-10 Ed25519 派生 → Base58(公钥)。和 EVM 完全两套加密路径,别拿 ETH 的经验类比。用 bip_utils 三行搞定,别自己实现 Ed25519。

查 Solana 钱包交易:Solscan API vs 原生 RPC

Solana 生态里,Solscan 是最常用的区块浏览器(类似以太坊的 Etherscan)。除了网页查询,它也有 API——加上 Solana 原生 RPC,就够做钱包监控 / 交易分析 / DeFi 数据抓取了。 Solscan 网页能查什么交易:交易 hash → 转账明细、手续费、状态 钱包地址:余额、SPL Token、NFT、历史交易 区块:高度、出块时间、确认数 代币:合约详情、持币地址、24h 交易量 NFT:铸造、转移 DeFi:部分 DEX / 质押 / 借贷协议数据日常查东西直接搜地址或 hash 就行。要批量、定时、集成到自己系统里就得走 API。 Solscan Pro API 老公共 API public-api.solscan.io 现在已经不推荐了,改用 Pro API pro-api.solscan.io(免费额度也有)。 账户交易列表: GET https://pro-api.solscan.io/v2.0/account/transactions?address=<WALLET>&limit=10 Header: token: <API_KEY>账户详情(余额、类型): GET https://pro-api.solscan.io/v2.0/account/detail?address=<WALLET>代币持仓: GET https://pro-api.solscan.io/v2.0/account/token-accounts?address=<WALLET>去 pro-api.solscan.io 申请免费 API Key。速率限制看套餐,免费大概 60 次/分钟。 Solana 原生 RPC(更灵活) 不想被限流、想拿完整交易数据,走 JSON-RPC。任何 Solana 节点都支持。 列钱包最近交易签名: POST https://api.mainnet-beta.solana.com Content-Type: application/json{ "jsonrpc": "2.0", "id": 1, "method": "getSignaturesForAddress", "params": [ "<WALLET>", { "limit": 20, "commitment": "finalized" } ] }查单笔交易详情: { "jsonrpc": "2.0", "id": 1, "method": "getTransaction", "params": [ "<SIGNATURE>", { "encoding": "jsonParsed", "maxSupportedTransactionVersion": 0 } ] }jsonParsed 编码会把系统程序、Token 程序的指令解析成人可读的 JSON,比 base58 好读多了。 Python 版本:定时监控新交易 import time import requestsRPC = "https://api.mainnet-beta.solana.com" WALLET = "<你的钱包地址>"seen = set()def rpc(method, params): r = requests.post(RPC, json={ "jsonrpc": "2.0", "id": 1, "method": method, "params": params, }, timeout=10) return r.json().get("result")def poll(): sigs = rpc("getSignaturesForAddress", [WALLET, {"limit": 20}]) or [] for s in reversed(sigs): sig = s["signature"] if sig in seen: continue seen.add(sig) tx = rpc("getTransaction", [ sig, {"encoding": "jsonParsed", "maxSupportedTransactionVersion": 0}, ]) if not tx: continue block_time = tx.get("blockTime") err = tx["meta"]["err"] print(f"新交易 {sig[:16]}... block_time={block_time} err={err}") # 这里根据业务解析 innerInstructions 判断是转账 / swap / mintwhile True: try: poll() except Exception as e: print("poll error:", e) time.sleep(15)要点:seen 记忆已处理签名,避免重复 reversed() 让最老的先出,保持时间顺序 生产上把 seen 落地到 Redis / SQLite,重启不丢免费 RPC 的坑 api.mainnet-beta.solana.com 是 Solana Labs 的公共节点,速率限制很紧,高频请求会 429。生产环境走托管 RPC:Helius — 免费 10 万请求/月 QuickNode Alchemy Solana Chainstack免费额度足够个人项目。 拿 SPL Token 余额 { "jsonrpc": "2.0", "id": 1, "method": "getTokenAccountsByOwner", "params": [ "<WALLET>", { "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" }, { "encoding": "jsonParsed" } ] }programId 是 SPL Token 程序的地址,返回该钱包持有的所有 SPL Token 账户,包含 mint 地址、余额、decimals。 一句话总结 Solscan API 好用但有限流,Solana 原生 RPC 更自由。核心组合 getSignaturesForAddress + getTransaction,生产环境别用免费公共节点,走 Helius / QuickNode。