Trong bài viết trước, chúng ta đã hoàn thiện hệ thống kiểm soát rủi ro của sàn giao dịch, còn trong bài này sẽ hướng dẫn tích hợp ví của sàn vào chuỗi Solana. Mô hình tài khoản, lưu trữ nhật ký và cơ chế xác nhận của Solana khác rất nhiều so với các chuỗi dựa trên Ethereum. Nếu cứ áp dụng theo cách của Ethereum, rất dễ gặp phải các vấn đề không mong muốn. Dưới đây chúng ta sẽ tổng hợp lại các ý tưởng chính để ghi nhận toàn diện về Solana.
Hiểu rõ đặc điểm riêng của Solana
Mô hình tài khoản của Solana
Solana sử dụng mô hình tách biệt giữa chương trình và dữ liệu, chương trình có thể dùng chung, còn dữ liệu của chương trình được lưu trữ riêng biệt qua các tài khoản PDA (Program Derived Address). Vì chương trình là dùng chung, nên cần Token Mint để phân biệt các Token khác nhau. Tài khoản Token Mint lưu trữ siêu dữ liệu toàn cục của token như quyền đúc (mint_authority), tổng cung (supply), số thập phân (decimals),
Mỗi token có một địa chỉ Mint duy nhất làm định danh, ví dụ USDC trên mạng chính của Solana có địa chỉ EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.
Trên Solana có hai bộ chương trình Token: SPL Token và SPL Token-2022. Mỗi loại Token đều có ATA (Associated Token Account) riêng để lưu trữ số dư của người dùng. Khi chuyển token, thực chất là gọi chương trình tương ứng để chuyển token giữa các tài khoản ATA.
Giới hạn nhật ký của Solana
Trên Ethereum, ta phân tích nhật ký chuyển khoản để lấy dữ liệu chuyển token. Còn với Solana, nhật ký thực thi không được lưu giữ vĩnh viễn theo mặc định, và nhật ký không thuộc trạng thái sổ cái (state) — cũng không có bộ lọc Bloom cho nhật ký — và có thể bị cắt bớt trong quá trình thực thi.
Vì vậy, không thể dựa vào “quét nhật ký” để đối chiếu nạp rút, mà phải dùng getBlock hoặc getSignaturesForAddress để phân tích lệnh.
Xác nhận và tổ chức lại khối của Solana
Thời gian tạo khối của Solana khoảng 400ms, sau 32 xác nhận (khoảng 12 giây) sẽ đạt trạng thái finalized. Nếu yêu cầu về thời gian thực không quá cao, có thể chỉ tin tưởng vào các khối đã finalized.
Để có độ chính xác cao hơn, cần xử lý khả năng xảy ra tổ chức lại khối (reorg), dù ít xảy ra. Tuy nhiên, do cơ chế đồng thuận của Solana không dựa vào parentBlockHash để tạo chuỗi, không thể dùng cách như Ethereum (so sánh parentBlockHash và blockHash trong database để phát hiện phân nhánh).
Vậy làm thế nào để xác định khối bị tổ chức lại?
Trong quá trình quét cục bộ, ta cần ghi lại blockhash của slot. Nếu phát hiện cùng slot mà blockhash thay đổi, tức là đã xảy ra rollback.
Hiểu rõ các đặc điểm của Solana, từ đó bắt đầu thực hiện, trước tiên cần chỉnh sửa cấu trúc dữ liệu trong database:
Thiết kế bảng dữ liệu
Vì Solana có hai loại Token, nên trong bảng tokens cần thêm trường token_type để phân biệt SPL Token và SPL Token-2022.
Dù địa chỉ của Solana khác Ethereum, nhưng vẫn có thể dùng BIP32, BIP44 để khai thác, chỉ khác về đường dẫn. Do đó, vẫn dùng bảng wallets cũ, nhưng để hỗ trợ ánh xạ ATA và theo dõi quét khối của Solana, cần thêm 3 bảng sau:
| Tên bảng | Trường chính | Mô tả |
|---|---|---|
| solana_slots | slot, block_hash, status, parent_slot | Lưu trữ slot, giúp phát hiện phân nhánh và rollback |
| solana_transactions | tx_hash, slot, to_addr, token_mint, amount, type | Chi tiết giao dịch nạp/rút, tx_hash duy nhất để theo dõi hai chiều |
| solana_token_accounts | wallet_id, wallet_address, token_mint, ata_address | Lưu ánh xạ ATA của người dùng, giúp tra cứu tài khoản nội bộ qua ata_address |
Trong đó:
Chi tiết định nghĩa các bảng xem tại db_gateway/database.md
Xử lý nạp tiền của người dùng
Việc xử lý nạp tiền đòi hỏi quét liên tục dữ liệu trên chuỗi Solana, có hai phương pháp chính:
Phương pháp 1: Quét chữ ký của địa chỉ, gọi getSignaturesForAddress( với tham số là địa chỉ người dùng (có thể là ATA hoặc programID). Phương thức này lấy danh sách chữ ký mới nhất của địa chỉ đó, sau đó dùng getTransaction) để lấy dữ liệu giao dịch. Phương pháp này phù hợp khi số lượng tài khoản hoặc dữ liệu ít.
Phương pháp 2: Quét khối, liên tục lấy slot mới, gọi getBlock(slot) để lấy toàn bộ dữ liệu giao dịch, sau đó phân tích các lệnh trong transaction.message.instructions và meta.innerInstructions. Phương pháp này phù hợp khi số lượng tài khoản lớn.
Lưu ý: Với lưu lượng giao dịch lớn của Solana, TPS cao, trong môi trường sản xuất có thể gặp tình trạng phân tích chậm hơn tốc độ tạo khối. Lúc này cần dùng message queue như Kafka hoặc RabbitMQ để lọc các chuyển token tiềm năng, đẩy vào hàng đợi để xử lý chính xác sau này. Một số dữ liệu nóng cần lưu trong Redis để tránh tắc nghẽn hàng đợi. Nếu số địa chỉ người dùng quá lớn, có thể phân mảnh theo ATA, nhiều consumer xử lý các phân mảnh khác nhau để tăng hiệu quả.
Ngoài ra, có thể dùng dịch vụ Indexer của các nhà cung cấp RPC thứ ba, hỗ trợ webhook, theo dõi tài khoản, lọc nâng cao, phù hợp với lượng dữ liệu lớn.
Quy trình quét khối
Chúng ta dùng phương pháp 2, mã nguồn chính nằm trong module scan/solana-scan gồm blockScanner.ts và txParser.ts, quy trình chính như sau:
1. Giai đoạn đồng bộ ban đầu, bổ sung các khối lịch sử (performInitialSync)
2. Giai đoạn quét mới (scanNewSlots)
3. Phân tích khối (txParser.parseBlock)
4. Phân tích lệnh (txParser.parseInstruction)
Xử lý rollback:
Chương trình liên tục lấy slot đã finalized, nếu slot ≤ finalizedSlot thì đánh dấu finalized, còn các slot trong confirmed thì so sánh blockhash để phát hiện rollback.
Ví dụ mã chính:
// blockScanner.ts - quét một slot
async function scanSingleSlot(slot: number) {
const block = await solanaClient.getBlock(slot);
if (!block) {
await insertSlot({ slot, status: 'skipped' });
return;
}
const finalizedSlot = await getCachedFinalizedSlot();
const status = slot <= finalizedSlot ? 'finalized' : 'confirmed';
await processBlock(slot, block, status);
}
// txParser.ts - phân tích lệnh chuyển khoản
for (const tx of block.transactions) {
if (tx.meta?.err) continue; // bỏ qua giao dịch thất bại
const instructions = [
...tx.transaction.message.instructions,
...(tx.meta.innerInstructions ?? []).flatMap(i => i.instructions)
];
for (const ix of instructions) {
// Chuyển SOL
if (ix.programId === SYSTEM_PROGRAM_ID && ix.parsed?.type === 'transfer') {
if (monitoredAddresses.has(ix.parsed.info.destination)) {
// xử lý
}
}
// Chuyển Token
if (ix.programId === TOKEN_PROGRAM_ID || ix.programId === TOKEN_2022_PROGRAM_ID) {
if (ix.parsed?.type === 'transfer' || ix.parsed?.type === 'transferChecked') {
const ataAddress = ix.parsed.info.destination;
const walletAddress = ataToWalletMap.get(ataAddress);
if (walletAddress && monitoredAddresses.has(walletAddress)) {
// xử lý
}
}
}
}
}
Sau khi quét ra các giao dịch nạp, dựa trên cơ chế an toàn của DB Gateway + ký xác thực, dữ liệu sẽ được ghi vào bảng dòng tiền (credits).
Rút tiền
Quy trình rút tiền của Solana tương tự EVM, nhưng có điểm khác:
Quy trình rút tiền
Hình minh họa:
![image-20240930222847819.png]
Thực tế, lấy blockhash sau kiểm tra rủi ro sẽ hợp lý hơn.
Mã ký ký giao dịch:
Ví dụ:
// Lệnh chuyển SOL
const instruction = getTransferSolInstruction({
source: hotWalletSigner,
destination: solanaAddress.to,
amount: BigInt(amount)
});
// Lệnh chuyển Token
const instruction = getTransferInstruction({
source: sourceAta,
destination: destAta,
authority: hotWalletSigner,
amount: BigInt(amount)
});
// Xây dựng message
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
tx => setTransactionMessageFeePayerSigner(hotWalletSigner, tx),
tx => setTransactionMessageLifetimeUsingBlockhash({ blockhash, lastValidBlockHeight }),
tx => appendTransactionMessageInstruction(instruction)
);
// Ký và gửi
const signedTx = await signTransactionMessageWithSigners(transactionMessage);
const signedTransaction = getBase64EncodedWireTransaction(signedTx);
Gửi giao dịch:
const solanaRpc = chainConfigManager.getSolanaRpc();
const txSignature = await solanaRpc.sendTransaction(signedTransaction, ...);
Các mã nguồn chính nằm trong:
Hai điểm cần tối ưu:
Tổng kết
Việc tích hợp Solana vào sàn không làm thay đổi kiến trúc tổng thể, chỉ cần thích nghi với mô hình tài khoản, cấu trúc giao dịch và cơ chế xác nhận của nó.
Trong xử lý nạp, cần duy trì bảng ánh xạ ATA → ví, theo dõi biến động blockhash để phát hiện reorg, cập nhật trạng thái giao dịch.
Trong rút, lấy recentBlockhash mới, phân biệt Token và Token-2022 để xây dựng giao dịch phù hợp.
Bài viết liên quan
Forward Industries Cấp Vốn $27.4M để Mua Lại Cổ Phiếu, Tăng Cường Tập Trung vào Kho Bạc Solana
Claude AI Dự đoán Giá của Solana và XRP Nếu Clarity Act Không Được Thông qua năm 2026
Solana lần đầu tiên vươn lên dẫn đầu về khối lượng giao dịch stablecoin