Các sàn phi tập trung chắc hẳn đã không còn xa lạ với các bạn đang tìm hiểu về blockchain. Mỗi sàn thường sẽ giao dịch trên một mạng blockchain cụ thể. Ví dụ như sàn Uniswap thì chạy trên mạng Ethereum, hay sàn PancakeSwap thì chạy trên mạng Binance.
Đây là giao diện mua bán của sàn PancakeSwap
Ngoài giao diện đẹp dễ sử dụng, họ còn cung cấp các document phục vụ cho các bạn dev. Mình đã thử xem tài liệu họ cung cấp thì thấy khá hay ho. Từ đó các bạn có thể tạo ra một con sniper bot, tự động chờ có cặp tiền mới vừa được list lên sàn là bot có thể mua ngay và luôn. Mình thử tạo con bot giống vậy nhé.
1. Phát họa flow
Khi một ông A nào đã phát triển xong 1 đồng token, và ông A đã đẩy lên mạng Binance. Rồi sau đó ông A vào PancakeSwap tạo một cặp thanh khoản. Thì khi ông A tạo sẽ gọi đến một hàm là createPair()
. Khi hàm này chạy nó sẽ tạo ra một event. Con bot của mình sẽ kết nối và lắng nghe event. Ngay khi có tín hiệu thì mình có thể thực hiện các logic khác như check thanh khoản hoặc lấy giá hoặc buy token đó ngay và luôn.
2. Bắt đầu code
2.1 Cài đặt
Về cơ bản có thể sẽ cần 2 gói sau
npm install ethers
npm install Web3
2.2 Kết nối
Import các thư viện cần sử dụng vào
const ethers = require('ethers');
const Web3 = require('Web3');
const fs = require('fs');
Có nhiều cách để kết nối với ví của bạn. Ở đây mình sẽ để cả 2 cách luôn
■Cách 1: Sử dụng key là chuỗi từ khóa bí mật
// Đây là thông tin provider của network bạn muốn kết nối. Trong ví dụ là của testnet BSC. Những thông tin này bạn có thể tìm đơn giản trên document của họ
const providerPath = "wss://speedy-nodes-nyc.moralis.io/236c39c2ed0cb45e1ad960dd/bsc/testnet/ws"
const provider = new ethers.providers.WebSocketProvider(providerPath);
// mnemonic là từ khóa bí mất khi bạn tạo ví. Có thể là 12 từ hoặc 24 từ
const mnemonic = "rebuild broom xxx xxx xxx";
let wallet, account;
async function init() {
// trong 1 cái ví bạn tưởng tượng thường có nhiều ngăn. Ở đây cũng vậy, wallet điện tử cũng sẽ có nhiều ngăn, một ngăn tương đương với một address khác nhau.
// "m/44'/60'/0'/0/0" là chỉ ra mình muốn lấy address ở vị trí đầu tiên index = 0
// nếu bạn muốn trỏ đến address vị trí thứ 2 thì sẽ là "m/44'/60'/0'/0/1"
wallet = ethers.Wallet.fromMnemonic(mnemonic, "m/44'/60'/0'/0/0");
// bắt đầu connect với ví trên blockchain
account = wallet.connect(provider);
}
async function main() {
await init();
}
main();
■Cách 2: Sử dụng key là file json
const providerPath = "wss://speedy-nodes-nyc.moralis.io/236c39c2ed0cb45e1ad960dd/bsc/testnet/ws"
const provider = new ethers.providers.WebSocketProvider(providerPath);
const keystore = (fs.readFileSync("yourFilePath", 'utf8')).toString();
let wallet, account;
async function init() {
wallet = await ethers.Wallet.fromEncryptedJson(keystore, "yourPassword");
account = wallet.connect(provider);
}
async function main() {
await init();
}
main();
Ok, về cơ bản đã kết nối với ví xong. Nếu bạn muốn check xem trong ví còn bao nhiêu tiền thì có thể sử dụng dòng code sau:
// connect
// ...
// get your balance
async function getBalance() {
const balance = await account.getBalance();
const ethBalance = ethers.utils.formatUnits(balance, "ether");
console.log(`
ACCOUNT INFO
=================
Address: ${account.address}
Balance: ${ethBalance} ${addresses.SYMBOL}
`);
}
async function main() {
await init();
await getBalance();
}
main();
2.3 Lắng nghe sự kiện tạo cặp thanh khoản
Đến phần chính rồi, bây giờ chúng ta thử code hàm lắng nghe và print ra các cặp vừa được list sàn nhé.
Để lắng nghe thì mình sẽ sử dụng event PairCreated
. Cách sử dụng các bạn có thể tham khảo thêm trên document https://docs.pancakeswap.finance/code/smart-contracts/pancakeswap-exchange/v2/factory-v2#events
let factory;
async function init() {
factory = new ethers.Contract(
addresses.factory,
[
'event PairCreated(address indexed token0, address indexed token1, address pair, uint)'
],
account
);
}
async function listenNewPair() {
factory.on('PairCreated', async (token0, token1, pairAddress) => {
// khi có cặp list sàn, thì hàm này sẽ được chạy và print cho chúng ta thông tin của cặp đó.
// token0: là địa chỉ của token mới được tạo hoặc cũng có thế là BNB
// token1: là địa chỉ của token mới được tạo hoặc cũng có thể là BNB
// nghĩa là nếu token0 là địa chỉ của BNB thì token1 là địa chỉ của token mới được tạo và ngược lại
// pairAddress: là địa chỉ của cặp thanh khoản
console.log(`
=================
token0: ${token0}
token1: ${token1}
pairAddress: ${pairAddress}
=================
`);
}
}
Output có dạng như sau:
=================
token0: 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c
token1: 0xE323xxxxx
pairAddress: 0x99D88xxxxx
=================
2.4 Verify
async function listenNewPair() {
factory.on('PairCreated', async (token0, token1, pairAddress) => {
console.log(`
=================
token0: ${token0}
token1: ${token1}
pairAddress: ${pairAddress}
=================
`);
const BNB = "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c";
let tokenIn, tokenOut;
if(token0 === BNB) {
tokenIn = token0;
tokenOut = token1;
}
if(token1 == BNB) {
tokenIn = token1;
tokenOut = token0;
}
//The quote currency is not BNB
if(typeof tokenIn === 'undefined') {
return;
}
}
}
2.5 Chốt kèo - buy token
let router;
async function init() {
// ...
// ...
router = new ethers.Contract(
addresses.router,
[
'function getAmountsOut(uint amountIn, address[] memory path) public view returns (uint[] memory amounts)',
'function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts)'
],
account
);
}
async function listenNewPair() {
factory.on('PairCreated', async (token0, token1, pairAddress) => {
// ...
// ...
// Mình muốn mua token mới với 0.1BNB
const amountIn = ethers.utils.parseUnits('0.1', 'ether');
const amounts = await router.getAmountsOut(amountIn, [tokenIn, tokenOut]);
const amountOutMin = amounts[1].sub(amounts[1].div(10));
const tx = await router.swapExactETHForTokens(
amountOutMin,
[tokenIn, tokenOut],
addresses.recipient,
Date.now() + 1000 * 60 * 10, //10 minutes
{
gasPrice: provider.getGasPrice(),
gasLimit: 2100000
}
);
const receipt = await tx.wait();
}
}
Hàm swapExactETHForTokens
là đổi BNB hoặc ETH ra token. Ngoài ra còn có những hàm khác như swapExactTokensForETH
là đổi token ra ETH, hoặc swapExactTokensForTokens
đổi token A qua token B. Bạn có thể tham khảo thêm các hàm ở document https://docs.pancakeswap.finance/code/smart-contracts/pancakeswap-exchange/v2/router-v2
3. Tổng kết
Con bot có thể hỗ trợ bạn mua ngay lập tức ngay khi cặp tiền bạn đang săn vừa list sàn. Nhưng cũng sẽ có rủi ro là đôi khi fake token được list ngay trước cặp tiền real vài giây và bạn có thể bị bắt nhầm token mong muốn. Nên hãy verify hết sức cẩn thận trước khi buy nhé.