3
tập trung vào
1444
Người theo dõi

Cách triển khai đặt lệnh trong các sàn giao dịch phi tập trung - Lấy Curve làm ví dụ

Được tạo ra trong: 2025-03-13 14:28:33, cập nhật trên: 2025-03-14 17:27:53
comments   1
hits   935

Tại sao tôi nên đặt hàng?

Trên thị trường tiền điện tử, cơ hội giao dịch thường thoáng qua, đặc biệt là cơ hội chênh lệch giá, có thể chỉ kéo dài trong vài phút. Nếu bạn dựa vào thao tác thủ công, người dùng có thể không nắm bắt được cơ hội tốt nhất kịp thời hoặc bỏ lỡ mức giá tốt nhất. Ví dụ, cách đây một thời gian, do tin tặc tấn công Bybit, USDe đã bị tách ra, khiến giá của nó biến động rất lớn. Vào thời điểm đó, tỷ lệ lợi nhuận hàng năm thông qua việc mua sUSDe và đổi lại nó đã vượt quá 300%. Cửa sổ lợi nhuận cao này thường kéo dài trong một thời gian rất ngắn và giao dịch thủ công rất khó theo kịp nhịp độ thị trường nếu không đặt lệnh trước. Do đó, chức năng đặt lệnh đã trở thành một công cụ quan trọng cho người dùng sàn giao dịch phi tập trung (DEX), cải thiện đáng kể hiệu quả giao dịch.

Các nguyên tắc và hạn chế của lệnh DEX

Nhiều DEX cung cấp chức năng đặt lệnh giới hạn, mỗi DEX có cách triển khai và cấu trúc phí khác nhau. Lấy Cow Swap và Odos làm ví dụ. Nguyên tắc cốt lõi là sử dụng chức năng tổng hợp để theo dõi tính thanh khoản và giá của nhiều DEX theo thời gian thực. Khi giá thị trường đạt đến điều kiện giới hạn, lệnh sẽ được người thực hiện kích hoạt và hợp đồng thông minh sẽ tự động thực hiện giao dịch và thanh toán phí gas. Cow cũng lưu trữ các lệnh của người dùng ngoài chuỗi, sau đó được khớp lệnh cạnh tranh bởi một nhóm các nút phi tập trung gọi là “Solvers”, nhưng cuối cùng được thực hiện trên chuỗi. Tóm lại, mặc dù GAS được miễn, nhưng lợi nhuận bổ sung do các giao dịch do các DEX này thực hiện có thể trang trải phí GAS cho bạn.

Nhưng điều này lại nảy sinh một vấn đề: nếu một trong các lệnh của bạn đang chờ xử lý ở mức giá 90U và trình tổng hợp theo dõi giá của một DEX nào đó đã giảm xuống còn 80U, thì nó sẽ thực hiện giao dịch cho bạn. Lệnh của bạn cuối cùng được thực hiện ở mức giá 90U, tạo ra lợi nhuận là 10U. Lợi nhuận này được phân phối như thế nào? Trong hoạt động thực tế, các nền tảng khác nhau xử lý theo cách khác nhau. Lấy Cow Swap làm ví dụ, cơ chế của nó quy định rõ ràng rằng khi giá thực hiện tốt hơn giá giới hạn, phần thặng dư tạo ra (tức là 10U) sẽ được chia giữa nền tảng và người dùng, trong đó Cow Swap lấy 50% và người dùng nhận được 50% còn lại. Odos sẽ gửi bất kỳ khoản thặng dư nào vào kho bạc. Về bản chất, lệnh của bạn sẽ được sàn giao dịch DEX phân bổ không rủi ro.

Ngoài ra, để tiết kiệm phí giao dịch, các lệnh DEX là các giao dịch được tổng hợp, tức là nhiều giao dịch được đóng gói lại với nhau sau một thời gian và ETH có khối 12 giây, điều này sẽ dẫn đến việc bỏ lỡ một số cơ hội có thể xảy ra. Tất nhiên, DEX vẫn có nhiều ưu điểm như tìm kiếm nhiều đường dẫn hơn, khớp lệnh ngoại tuyến, tiết kiệm GAS, v.v., đủ dùng cho hầu hết người dùng.

Ưu điểm của việc đặt hàng bằng chương trình của riêng bạn

So với việc dựa vào các lệnh tổng hợp của DEX, giao dịch trực tiếp thông qua hợp đồng thông minh có những lợi thế riêng. Đầu tiên, người dùng có toàn quyền kiểm soát logic thực hiện lệnh và mọi khoản thu nhập. Thứ hai, việc tự đặt lệnh giúp bạn tránh được sự chậm trễ khi đóng gói các giao dịch tổng hợp và có thể phản ứng với những thay đổi của thị trường nhanh hơn, đặc biệt là nắm bắt cơ hội trong vòng 12 giây trong thời điểm biến động cao. Ngoài ra, các lệnh chờ tùy chỉnh có thể linh hoạt thiết lập các điều kiện phức tạp (như giao dịch danh mục đầu tư đa tài sản hoặc dừng lãi và dừng lỗ) mà không bị hạn chế bởi các chức năng được cài đặt sẵn của nền tảng. Tuy nhiên, điều này đòi hỏi một số kỹ năng lập trình nhất định và người dùng phải tự trả phí gas, đồng thời có thể có rủi ro bảo mật trên chuỗi. Do đó, việc tự đặt lệnh phù hợp với những người dùng có trình độ chuyên môn cao, có năng lực kỹ thuật vững chắc và theo đuổi lợi nhuận tối đa.

Bảo vệ khóa riêng tư

Nếu bạn muốn vận hành hợp đồng thông minh bằng chương trình của riêng mình, tính bảo mật của khóa riêng chắc chắn là mối quan tâm lớn nhất của bạn. Giải pháp tôi đưa ra là sử dụng Python để mã hóa khóa riêng của tôi ngoại tuyến và lưu trữ văn bản mã hóa được mã hóa trên máy chủ chạy máy chủ. Mật khẩu đã giải mã được truyền vào bằng cách sử dụng các tham số của robot nền tảng FMZ và chương trình chạy trên máy chủ và đọc và giải mã (có thể xóa sau khi chương trình chạy). Bằng cách này, ngay cả khi máy chủ của bạn bị hack, sẽ không có vấn đề gì, nhưng bạn vẫn cần phải cẩn thận để không bị rò rỉ tài khoản FMZ của mình. Vì nó chỉ liên quan đến một văn bản thuần túy ngoài mạng nên tính bảo mật là chấp nhận được. Mã cụ thể như sau, có thể chạy cục bộ ngoài lưới điện

from web3 import Web3  # Web3.py 是与以太坊区块链交互的Python库
import json  # 用于处理JSON数据
import time  # 用于设置时间间隔
import requests  # 用于发送HTTP请求
from cryptography.fernet import Fernet
import base64
import hashlib
from datetime import datetime
from hexbytes import HexBytes

def generate_key(password: str) -> bytes:
    """通过用户密码生成 AES 密钥"""
    return base64.urlsafe_b64encode(hashlib.sha256(password.encode()).digest())

def encrypt_private_key(private_key: str, password: str) -> str:
    """使用密码加密私钥"""
    key = generate_key(password)
    cipher = Fernet(key)
    return cipher.encrypt(private_key.encode()).decode()

def decrypt_private_key(encrypted_key: str, password: str) -> str:
    """使用密码解密私钥"""
    key = generate_key(password)
    cipher = Fernet(key)
    return cipher.decrypt(encrypted_key.encode()).decode()

def save_key_to_file(key, file_path):
    # 将加密密钥保存到txt文件
    with open(file_path, 'w') as file:
        file.write(key) 

def load_key_from_file(file_path):
    # 从txt文件读取加密密钥
    with open(file_path, 'r') as file:
        return str(file.read())

def main():
    encrypt_key = encrypt_private_key('my_private_key', 'password') # my_private_key是自己的私钥,password是自己设置的密码
    save_key_to_file(encrypt_key,'encrypt_key.txt')
    print("加密后的私钥", encrypt_key)
    decrypt_key = decrypt_private_key(load_key_from_file('encrypt_key.txt'), 'password')
        print("解密的私钥", decrypt_key)

Chuẩn bị trước khi liên kết ETH

Web3.py là một thư viện Python mạnh mẽ để tương tác với mạng Ethereum. Cài đặt bằng lệnh sau: pip install web3. Chức năng của nó là đơn giản hóa việc giao tiếp giữa các nhà phát triển và các nút Ethereum, đồng thời hỗ trợ các hoạt động như truy vấn số dư, gọi hợp đồng thông minh và gửi giao dịch. Ví dụ, việc kiểm tra số dư tài khoản chỉ cần vài dòng mã, khiến Web3.py trở thành công cụ lý tưởng để xây dựng DApp hoặc tự động hóa giao dịch.

python
from web3 import Web3
w3 = Web3(Web3.HTTPProvider('你的RPC地址'))
balance = w3.eth.get_balance('0x某个地址')
print(w3.from_wei(balance, 'ether'))

RPC (Remote Procedure Call) là giao diện truyền thông do nút Ethereum cung cấp, tương tác với blockchain bằng cách gửi các yêu cầu JSON thông qua giao thức HTTP hoặc WebSocket. Ví dụ, eth_blockNumber có thể truy vấn chiều cao khối mới nhất. Do chi phí chạy một nút cục bộ cao nên các nhà phát triển thường dựa vào nhà cung cấp RPC của bên thứ ba. Những lựa chọn phổ biến bao gồm:

  • Infura: Dịch vụ mặc định của MetaMask, dễ sử dụng nhưng có hạn mức miễn phí thấp (100.000 yêu cầu mỗi ngày).
  • Alchemy: Hiệu suất vượt trội, dung lượng trống cao và hỗ trợ nhiều tính năng hơn.
  • QuickNode: Phù hợp với yêu cầu hiệu suất cao, nhưng thiên về người dùng trả phí.
from web3 import Web3
w3 = Web3(Web3.HTTPProvider('https://eth-mainnet.g.alchemy.com/v2/你的API密钥'))
print(w3.is_connected())

Nên sử dụng Alchemy. So với Infura của MetaMask, Alchemy cung cấp hạn ngạch miễn phí cao hơn. Sau khi đăng ký, bạn có thể lấy địa chỉ RPC, chẳng hạn như https://eth-mainnet.g.alchemy.com/v2/khóa API của bạn và định cấu hình thành Web3.py để sử dụng.

Địa chỉ hợp đồng đường cong và ABI

Lấy nhóm Crve của sDAI/sUSDe làm ví dụ https://curve.fi/dex/ethereum/pools/factory-stable-ng-102/swap/, bạn có thể dễ dàng tìm thấy địa chỉ của hai mã thông báo và địa chỉ của nhóm. Cách triển khai đặt lệnh trong các sàn giao dịch phi tập trung - Lấy Curve làm ví dụ

ABI định nghĩa cách tương tác với hợp đồng, vì vậy cũng cần phải có được nó. Xem hợp đồng trên ethscan https://etherscan.io/address/0x167478921b907422f8e88b43c4af2b8bea278d3a#code. Bạn có thể xem abi trên trang hợp đồng và sao chép trực tiếp.

Liên kết hợp đồng để có giá

Đầu tiên, liên kết ví ETH. Nếu địa chỉ ví của bạn được in ra, điều đó có nghĩa là thành công.

def main():
    # 文件路径
    file_path = 'encrypted_key.txt'

    # 从文件中读取加密的私钥
    encrypted_private_key = load_key_from_file(file_path)
    private_key = decrypt_private_key(encrypted_private_key, Password) #Password为密码,定义为策略的参数
    web3 = Web3(Web3.HTTPProvider(HTTPProvider)) # HTTPProvider为RPC的链接,定义为参数
    account = web3.eth.account.from_key(private_key)
    address = account.address  # 获取账户的公开地址
    Log('链接账户', address)

Sau đây là quá trình lấy giá. Cuối cùng, không tính đến phí GAS, khoản đầu tư hiện tại là 100.000 SDAI sẽ mang lại lợi nhuận là 335U sau một tuần. Có thể trông có vẻ hơi phức tạp, nhưng thực ra không khó hiểu chút nào.

    # --------------- 合约设置 ---------------
    # Curve.fi sDAI/sUSDe 池合约地址和ABI
    pool_address = '0x167478921b907422F8E88B43C4Af2B8BEa278d3A'  # Curve池子的合约地址
    # 以下是简化的ABI,仅包含我们需要的函数
    pool_abi = json.loads('''[{"stateMutability":"view","type":"function","name":"get_dy","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"dx","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]}]''')
    # 创建池子合约对象
    pool_contract = web3.eth.contract(address=pool_address, abi=pool_abi)

    # ERC20 代币标准合约ABI
    erc20_abi = json.loads('''[
        {"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"type":"function"},
        {"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"type":"function"},
        {"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"}
    ]''')

    sdai_address = '0x83F20F44975D03b1b09e64809B757c47f942BEeA'  # sDAI代币的合约地址
    susde_address = '0x9D39A5DE30e57443BfF2A8307A4256c8797A3497'  # sUSDE代币的合约地址
    # 池子中代币的索引
    SDAI_INDEX = 0  # sDAI代币在池子中的索引
    SUSDE_INDEX = 1  # sUSDE代币在池子中的索引
    # 创建代币合约对象
    sdai_contract = web3.eth.contract(address=sdai_address, abi=erc20_abi)
    susde_contract = web3.eth.contract(address=susde_address, abi=erc20_abi)
    SUSDE_PRICE = 1.1623 #这个价格是ethena官网价格,1周后可赎回
    SDAI_PRICE = 1.15 #sDAI是收益代币,价值会累计,目前价格1.15

    try:
        SDAI_DECIMALS = sdai_contract.functions.decimals().call()
        SUSDE_DECIMALS = susde_contract.functions.decimals().call()
    except:
        # 如果无法获取,假设为标准的18位精度
        SDAI_DECIMALS = 18
        SUSDE_DECIMALS = 18
    amount_in = 100000
    amount_out = pool_contract.functions.get_dy(
                    SDAI_INDEX,  # 输入代币索引
                    SUSDE_INDEX,  # 输出代币索引
                    int(amount_in *  10**SDAI_DECIMALS)   # 输入数量(wei)
                ).call()
    profit =  SUSDE_PRICE * amount_out / 10**SUSDE_DECIMALS -  amount_in * SDAI_PRICE
    Log(round(profit, 2), round(amount_out / 10**SUSDE_DECIMALS, 2))

Chương trình đầy đủ

Cuối cùng, chúng tôi sử dụng thăm dò để liên tục lấy giá và đặt lệnh khi đạt được lợi nhuận mong đợi. Lưu ý mã nàyĐây chỉ là một mã mẫu, đừng sử dụng trực tiếpNgười đọc có thể gặp phải nhiều vấn đề khác nhau trong thực tế, nhưng AI hiện tại rất mạnh mẽ và về cơ bản có thể trả lời nhiều câu hỏi khác nhau. Nó cũng có thể trực tiếp giúp viết mã. Trình chỉnh sửa mã của FMZ cũng tích hợp ChatGPT, có thể được sử dụng thường xuyên hơn.

def execute_trade(amount_in, min_amount_out, direction):
    gas_price = web3.eth.gas_price
    index_in = SUSDE_INDEX
    index_out = SDAI_INDEX
    if direction == 'buy':
        index_in = SDAI_INDEX
        index_out = SUSDE_INDEX
    # 第二步:执行代币交换交易
    swap_tx = pool_contract.functions.exchange(
        index_in,  # 输入代币索引
        index_out,  # 输出代币索引
        int(amount_in*10**SDAI_DECIMALS),  # 输入数量
        int(min_amount_out*10**SUSDE_DECIMALS)  # 最小输出数量(考虑滑点)
    ).build_transaction({
        'from': address,  # 交易发送方
        'gas': 600000,  # gas限制
        'gasPrice': int(2*gas_price) ,
        'nonce': web3.eth.get_transaction_count(address),  # 获取新的nonce值
    })
    
    # 签名并发送交换交易
    signed_swap_tx = web3.eth.account.sign_transaction(swap_tx, private_key)
    swap_tx_hash = web3.eth.send_raw_transaction(signed_swap_tx.rawTransaction)
    
    Log(f"交换交易已提交,交易哈希: {swap_tx_hash.hex()}")

def get_buy_profit(amount_in):
    amount_out = pool_contract.functions.get_dy(
                    SDAI_INDEX,  # 输入代币索引
                    SUSDE_INDEX,  # 输出代币索引
                    int(amount_in *  10**SDAI_DECIMALS)   # 输入数量(wei)
                ).call()
    return  SUSDE_PRICE * amount_out / 10**SUSDE_DECIMALS -  amount_in * SDAI_PRICE, amount_out / 10**SUSDE_DECIMALS

def main():
    while True:
        try:
            sdai_balance = sdai_contract.functions.balanceOf(address).call() / 10**SDAI_DECIMALS
            susde_balance = susde_contract.functions.balanceOf(address).call() / 10**SUSDE_DECIMALS
            amount_in = 100000 #交易的DAI数量
            profit, amount_out = get_buy_profit(amount_in)
            LogStatus(f"SDAI数量:{sdai_balance}, SUSDE数量:{susde_balance}, 收益:{profit}")
            if profit > 1000 and sdai_balance > amount_in: #利润空间
                Log("\n开始执行SDAI->SUSDE交易...")
                execute_trade(amount_in, 0.999*amount_out, 'buy') #一定要设置滑点
            wait_time = 3  # 等待时间(秒)
            time.sleep(wait_time)
            
        except Exception as e:
            # 全局错误处理
            print(f"程序发生错误: {e}")
            print("60秒后重试...")
            time.sleep(60)  # 出错后等待更长时间

Nhắc nhở rủi ro

Hoạt động trên chuỗi tương đối rủi ro đối với người mới bắt đầu. Ngoài rủi ro rò rỉ khóa riêng tư được đề cập ở trên, còn có nhiều rủi ro khác:

  • Robot MEV phải thiết lập giá trị đầu ra tối thiểu min_amount_out khi thực hiện giao dịch để đảm bảo lợi nhuận ngay cả trong trường hợp xấu nhất, nếu không chúng sẽ bị MEV khai thác. Hôm nay, một người đã sử dụng 220.000 USDC để đổi lấy chỉ 5272 USDT trên Uniswap. Lý do là amountOutMinimum được đặt thành 0.
  • Lỗi chiến lược, giống như API trao đổi, nếu có lỗi trong giao dịch chương trình trên chuỗi, GAS sẽ thường xuyên bị tiêu thụ.

Đối với người mới tham gia giao dịch theo chuỗi, họ cần phải học những điều cơ bản: hiểu các khái niệm như Gas, trượt giá, MEV, v.v. Luôn bắt đầu với số tiền nhỏ và tăng dần lên. Theo dõi các giao dịch bằng cách sử dụng công cụ như Etherscan. Tốt hơn là bỏ lỡ một cơ hội còn hơn là phải chịu rủi ro mất vốn.