ký Sự Farmer - Nguyên lý hoạt động của Timelocks và Migrator trong các dự án Yield Farming trên BSC hiện nay

Xin chào những chàng trai đam mê Nông Nghiệp ( Farmers ) hôm này mình mang đến cho mọi người một số điểm cần lưu ý khi tăng gia sản xuất trên BSC (Binance Smart Chain) hiện nay. Vì mình đã bắt gặp một số trường hợp các dự án mọc lên với mục đích lừa đảo, chiếm đoạn tài sản của người tham gia.

Giới Thiệu

Thì trước khi đi vào vấn đề chính của bài viết ngày hôm này, mình cũng muốn nói qua một chút về trend Farming trên BSC cho những anh em nào chưa biết hoặc đang có ý đinh tham gia nhưng chưa tìm hiểu về nó. Thì Farming là một thành phần của Defi (Decentralized finance) nó cho phép các nhà đâu tư sinh lời từ tài sản crypto của mình. Sinh lời như thế nào thì đầu tiên các nhà đầu tư phải biến mình thành Farmer cái đã. Sau đó các Farmer sẽ đến các nền tảng Defi như Exchange hoặc Lending để cung cấp thanh khoản.

Khi đã cung cấp thanh khoản thì Farmer sẽ sở hữu được một loại token đó là LP token ( Liquidity Pools ) ví dụ như khi bạn Add Liquidity cho Pancake thì token nhận được sẽ là Cake-LP đây là một loại token quản trị nó giúp các Pairs quản lý được lượng token vào - ra của Pairs. Hình dung đơn giản giống như việc chúng ta đi gửi tiền vào ngân hàng và nhận về một cái sổ tiết kiệm vậy. Bạn có thể rút tiền ra bất cứ khi nào và khi bạn rút tiền ra thì cũng đồng nghĩa lượng LP token đó sẽ bị burn đi. Công việc add liquidity này cũng sinh lời nha, bảo giống với gửi tiết kiệm thì chắc chắn nó phải có tiền lãi rồi.

Sẽ có câu hỏi là vậy tiền lãi sinh ra từ đâu ra, thì giống như các ngân hàng họ đem đi cho vay để sinh lãi thì ở đây cũng vậy, các nền tảng Lengding thì mang tiền đi cho Vay - Borrow với lãi cao hơn và rồi chia lại cho người dùng. ví dụ như Venus đang cho Borrow cao hơn Lending:

Còn các nền tảng Exchange thì họ sẽ lấy tiền từ swap, các bạn có để ý mỗi khi bạn swap trên Pancake sẽ phải cống cho Pancake 0.2% amount swap. Thì như họ nói ở đây là 0.17% sẽ cho các nhà cung cấp thanh khoản, còn lại 0.03% là họ xung quỹ.

Rồi giờ thì mọi người đã hiểu nguyên lý tiền được sinh ra khi cung cấp thanh khoản rồi chứ. Nhưng đó mới chỉ là bước sinh lời đầu tiên Staking, còn Farming thì sẽ là bước tiếp theo này. Mình sẽ lấy một ví dụ đó là một đồng coin mới lên họ vừa muốn giữ chân các nhà cung cấp thanh khoản trong các Pairs trên Pancake, vừa muốn giá coin của họ tăng lên thì họ sẽ làm như thế này. Đó là họ sẽ tạo ra các Pool ( Pool ở đây chỉ lưu giữ một loại token không phải như Pairs là phải có 1 cặp 2 token ) chấp nhận tham số đầu vào là 1 loại LP token có thể là LP token của họ hoặc có thể cả những LP token của nền tảng khác. Và khi Farmer add LP token của mình vào các Pool Farm họ sẽ nhận lại được phần thưởng tích lũy tăng dần theo thời gian. Rồi giờ thì cung cấp thanh khoản cho họ vừa được ăn hoa hồng từ fee swap, fee borrow lại nhận thêm được phần thưởng từ Pool Farm vậy là lời kép rồi. Chính vì suy nghĩ này mà các nền tảng Farming đang thu hút được rất nhiều các Farmers tham gia, và như vậy token của họ sẽ luôn có thanh khoản trên các Exchange như PancakeSwap, Pancake Bunny, JulSwap,... Mà khi người dùng thấy được lợi nhuận sẽ swap từ các tài sản khác sang token của họ, vậy là giá token cũng sẽ tăng theo ( Còn tại sao lại tăng thì mọi người có thể đọc bài viết của mình về Uniswap để hiểu nguyên lý hoạt động của các sàn AMM ).

Pancake Bunny

Goose Finance

Swamp Finance

Đối với những nền tảng không có Farming họ cũng vẫn có thể làm được điều này, đó chính là liên hệ với với các nền tảng Farming cho phép họ được tạo Pool trên đó, điều này tạo ra một sự hợp tác Win-Win cả hai cùng có lợi. Dưới đây là hình ảnh trên Pancake một lãi suất từ 100% -> 800% một năm sẽ tạo một sự hấp dẫn không hề nhỏ đến các farmers. Nhưng hãy nhớ rằng APY này là không cố định nó sẽ thay đổi theo tỷ lệ lượng tài sản thay đổi, khi lượng tài sản vào càng nhiều %APY cho từng đơn vị đóng góp sẽ càng giảm và ngược lại. Nên chúng ta sẽ thấy lúc ban đầu chưa có ai vào Pool thì hệ số này rất cao.

PancakeSwap

ValueDefi

Các lưu ý nên biết khi tham gia

Mức độ uy tín của dự án

Điều đầu tiên để suy nghĩ có nên tham gia vào dự án đó hay không là mức độ uy tín. Một dự án được partnerships bởi tối thiểu là 1 bên uy tín còn không phải vài bên có tên tuổi thì hẵng suy nghĩ tham gia. Vì các đối tác đã có name rồi thì họ sẽ chẳng tội gì mà tham gia với các bên có ý định làm ăn chộp giật. Để rồi mang tiếng về sau mà một khi đã có vết thì rất khó lấy lại được lòng tin.

Ví dụ như ở đây một nền tảng có thông báo là kết hợp với nhiều bên uy tín như thế này. Nhưng để chắc chắn chúng ta vẫn cần phải tìm kiếm các nguồn tin chính thống từ các bên uy tín này thông báo. Lúc đó mới đảm bảo rằng thông tin là chính xác.

Tài liệu dự án

Một dự án có dự định đi lâu dài sẽ thường chuẩn bị rất kỹ lưỡng về tài liệu như roadmap hợp lý, có light paper, white paper chi tiết, tài liệu docs ứng dụng đầy đủ... Đôi khi hơi mất công đọc qua một chút sẽ giúp ta có cái nhìn tổng quan về dự án, biết đâu sẽ tìm được những dự án tiềm năng. Mà điều quan trọng là ta đang đưa tiền cho họ đầu tư thì cũng nên có trách nhiệm với đông tiền của mình.

Smart Contract

Đây là một phần vô cùng quan trọng vì smart contract sẽ là linh hồn của dự án, giống như một ứng dụng có Frontend và Backend thì SmartContract sẽ là cái lõi Backend xử lý các tính toán và lưu trữ trên blockchain. Nếu cái lõi mà không tốt thì Frontend - giao diện có đẹp đến mấy cũng chẳng để làm gì cả.

Hiện nay có rất nhiều các nền tảng Farming kế thừa lại contract của Pancake hay xa hơn là ông tổ SushiSwap. Họ chỉ lấy về và mô đi phê một chút rồi đưa lên chạy, thì theo quan điểm cá nhân của mình đối với những dự án kiểu này chúng ta cần quan tâm đến MigratorTimelock contract:

  • Migrator
// MasterChef.sol

    interface IMigratorChef {
        // Perform LP token migration from legacy PancakeSwap to CakeSwap.
        // Take the current LP token address and return the new LP token address.
        // Migrator should have full access to the caller's LP token.
        // Return the new LP token address.
        //
        // XXX Migrator must have allowance access to PancakeSwap LP tokens.
        // CakeSwap must mint EXACTLY the same amount of CakeSwap LP tokens or
        // else something bad will happen. Traditional PancakeSwap does not
        // do that so be careful!
        function migrate(IBEP20 token) external returns (IBEP20);
    }
    
    ...
    
    // Migrate lp token to another lp contract. Can be called by anyone. We trust that migrator contract is good.
    function migrate(uint256 _pid) public {
        require(address(migrator) != address(0), "migrate: no migrator");
        PoolInfo storage pool = poolInfo[_pid];
        IBEP20 lpToken = pool.lpToken;
        uint256 bal = lpToken.balanceOf(address(this));
        lpToken.safeApprove(address(migrator), bal);
        IBEP20 newLpToken = migrator.migrate(lpToken);
        require(bal == newLpToken.balanceOf(address(this)), "migrate: bad");
        pool.lpToken = newLpToken;
    }

Bản thân trong interface IMigratorChef thì họ cũng nói là chức năng nay sử dụng để đổi token LP trong Pool, cái này cũng được kế thừa gốc từ SushiSwap mục đích là phòng trường hợp token LP gặp vấn đề cần phải thay thế địa chỉ contract mới hoặc nền tảng nấp cấp lên version 2, version 3 gì đó thì sử dụng nó để thay đổi. Nhưng nó cũng sẽ có mặt trái là nếu người Owner là một người có suy nghĩ xấu và muốn chiếm đoạt số token trong các Pool thì sao. Khi đó Owner sẽ có thể đổi token LP trong Pool sang một lại token mà họ có toàn quyền Owner, lúc này học thích transfer, burn, mint tùy thích. Rồi họ chuyển luôn tài sản của người dùng trong các Pool ra ví riêng vậy là toi rồi. Cùng nhìn qua contract Implement của Migrator nhá

// PancakeMigrator.sol

    pragma solidity =0.6.6;

    import '@uniswap/lib/contracts/libraries/TransferHelper.sol';

    import './interfaces/IPancakeMigrator.sol';
    import './interfaces/V1/IUniswapV1Factory.sol';
    import './interfaces/V1/IUniswapV1Exchange.sol';
    import './interfaces/IPancakeRouter01.sol';
    import './interfaces/IERC20.sol';

    contract PancakeMigrator is IPancakeMigrator {
        IUniswapV1Factory immutable factoryV1;
        IPancakeRouter01 immutable router;

        constructor(address _factoryV1, address _router) public {
            factoryV1 = IUniswapV1Factory(_factoryV1);
            router = IPancakeRouter01(_router);
        }

        // needs to accept ETH from any v1 exchange and the router. ideally this could be enforced, as in the router,
        // but it's not possible because it requires a call to the v1 factory, which takes too much gas
        receive() external payable {}

        function migrate(address token, uint amountTokenMin, uint amountETHMin, address to, uint deadline)
            external
            override
        {
            IUniswapV1Exchange exchangeV1 = IUniswapV1Exchange(factoryV1.getExchange(token));
            uint liquidityV1 = exchangeV1.balanceOf(msg.sender);
            require(exchangeV1.transferFrom(msg.sender, address(this), liquidityV1), 'TRANSFER_FROM_FAILED');
            (uint amountETHV1, uint amountTokenV1) = exchangeV1.removeLiquidity(liquidityV1, 1, 1, uint(-1));
            TransferHelper.safeApprove(token, address(router), amountTokenV1);
            (uint amountTokenV2, uint amountETHV2,) = router.addLiquidityETH{value: amountETHV1}(
                token,
                amountTokenV1,
                amountTokenMin,
                amountETHMin,
                to,
                deadline
            );
            if (amountTokenV1 > amountTokenV2) {
                TransferHelper.safeApprove(token, address(router), 0); // be a good blockchain citizen, reset allowance to 0
                TransferHelper.safeTransfer(token, msg.sender, amountTokenV1 - amountTokenV2);
            } else if (amountETHV1 > amountETHV2) {
                // addLiquidityETH guarantees that all of amountETHV1 or amountTokenV1 will be used, hence this else is safe
                TransferHelper.safeTransferETH(msg.sender, amountETHV1 - amountETHV2);
            }
        }
    }

Nó sẽ mapping 1:1 sang và Owner LP token mới lại là của admin nghe đã thấy không tín rồi. Để tránh trường hợp xấu kể trên thì các nền tảng sẽ tạo niềm tin với người dùng bằng cách chuyển Owner của MasterChef cho một thằng Timelock. Mọi người có thể đọc bài báo cáo audit Timelock contract của Compund trên Openzeppelin (Compound Finance – Timelock Audit) để hiểu rõ hơn về contract Timelock này.

  • Timelock contract

Contract này sẽ giúp chuyển trạng thái của hệ thống từ instant/forced sang warning/opt-out. Tác dụng của contract này như sau, đó là MasterChef sẽ được chuyển quyền Owner sang cho Timelock contract lúc này admin vẫn sẽ có thể thao tác được đến Masterchef, nhưng tất cả các thao tác sẽ bị xếp vào hàng đợi và bị delay mất một khoảng thời gian, phải đủ điều kiện sau khoảng delay thì thao tác đó mới được phép gọi hàm executeTransaction để thực thi. Điều này giúp người dùng có thể nhận thấy được các dấu hiệu sai trái của hệ thống, mà từ đó xem xét nên tiếp tục Farming hay thoát ra. Vì mảng hàng đợi thao tác là biến public nên ai cũng có thể xem được mapping (bytes32 => bool) public queuedTransactions Do con tract khá dài nên ai muốn xem chi tiết có thể xem tại đây Timelock Contract còn mình chỉ viết các biến và hàm chính để mọi người dễ hình dung.

// Timelock.sol

    uint public constant GRACE_PERIOD = 14 days;
    uint public constant MINIMUM_DELAY = 6 hours;
    uint public constant MAXIMUM_DELAY = 30 days;

    mapping (bytes32 => bool) public queuedTransactions;

    ...

    function queueTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public returns (bytes32) {
        require(msg.sender == admin, "Timelock::queueTransaction: Call must come from admin.");
        require(eta >= getBlockTimestamp().add(delay), "Timelock::queueTransaction: Estimated execution block must satisfy delay.");

        bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
        queuedTransactions[txHash] = true;

        emit QueueTransaction(txHash, target, value, signature, data, eta);
        return txHash;
    }
    
    ...
    
    function executeTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public payable returns (bytes memory) {
        require(msg.sender == admin, "Timelock::executeTransaction: Call must come from admin.");

        bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
        require(queuedTransactions[txHash], "Timelock::executeTransaction: Transaction hasn't been queued.");
        require(getBlockTimestamp() >= eta, "Timelock::executeTransaction: Transaction hasn't surpassed time lock.");
        require(getBlockTimestamp() <= eta.add(GRACE_PERIOD), "Timelock::executeTransaction: Transaction is stale.");

        queuedTransactions[txHash] = false;

        bytes memory callData;

        if (bytes(signature).length == 0) {
            callData = data;
        } else {
            callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);
        }

        // solium-disable-next-line security/no-call-value
        (bool success, bytes memory returnData) = target.call.value(value)(callData);
        require(success, "Timelock::executeTransaction: Transaction execution reverted.");

        emit ExecuteTransaction(txHash, target, value, signature, data, eta);

        return returnData;
    }

Vì vậy trước khi vào Farm mọi người có thể để ý một chút là check qua xem Owner của MasterChef đã được chuyển về Timelock chưa. Bằng cách lên bscscan.com và vào phần Read contract để kiểm tra điều này mình sẽ ví dụ Pancake nhá.

Muốn Farm được thì chắc chắn token sẽ phải được chuyển Owner sang cho MasterChef. Đầu tiên vào Cake token -> đến phần Read contract -> tìm đến owner

https://bscscan.com/token/0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82#readContract

Rồi giờ thì check xem ông owner này có phải MasterChef không. Vào contract -> code để xem name contract

https://bscscan.com/address/0x73feaa1ee314f8c655e354234017be2193c9e24e#code

Ok đúng anh MasterChef rồi giờ thì xem Owner của anh là ai. Vào Read contract -> tìm đến owner

Truy cập đến contract owner này để xem thông tin

https://bscscan.com/address/0xa1f482dc58145ba2210bc21878ca34000e2e8fe4#code

Đúng rồi chính là Timelock, tiện thể đọc cả code cho chắc nhá. Mà Mọi người cũng chú ý là những bên mà contract còn không cả verify thì cần phải cẩn thận đấy. Vì để có được nút tích xanh thế kia thì khi verify, bscscan sẽ compiler lại code mà người dùng đẩy lên rồi so sánh với bytecode của contract xem có đúng hay. Nên hoàn toàn yên tâm code trong phần view code là trùng khớp với contract đã được deploy.

Fee transactions

Tiếp theo là về vấn đề Fee giao dịch, đây cũng là vấn đề khá quan trọng trong công cuộc canh tác của các anh em Farmers. Trước kia khi trend Defi vô cùng mạnh mẽ trên Ethereum vì khi đó Fee giao dịch còn rẻ do giá ETH còn thấp. Giờ đây khi ETH lên đến 2k1$ thì việc Farming trên Ethereum là điều xa xỉ, cứ nhè nhẹ vài chục, vài trăm, thậm chí cả nghìn đô với các transaction tạo contract thì thử hỏi có đau lòng không chứ. Và từ đó trend Farming được move dần sang BSC và bây giờ chúng ta của hiện tại cũng đang dần cảm nhận được sự đắt đỏ đi lên, khi mà tại thời điểm mình viết bài này BNB đã lên đến hơn 400$.

Nhưng BSC sẽ khác với ETH hiện tại, vì hiện tại ETH vẫn đang sử dụng PoC nó rất chậm nên nếu ta để Gas Price thấp thì không biết đến bao giờ transaction được confirm. Trong khi BSC thì dùng PoS vốn dĩ nó đã rất nhanh nên nếu Gas Price có thấp đi chẳng nữa nó vẫn nhanh hơn nhiều ETH. Nên chúng ta có thể thoải mái hạ thấp Gas Price xuống mức rất thấp mình đã thử và thấy tốc độ vẫn rất chi là ok.

Do minh phát hiện thấy rằng là mình dùng Metamask trên Browser của máy tính, thì nó sẽ thường astimate Gase Price rất thấp nên fee đâu đó chỉ khoảng 0,1 -> 1$ thôi. Nhưng cứ sử dụng Dapp Browser của Metamask thì nó astimate Gase Price rất cao từ 180 -> 300 Gwei, nên fee giao dịch cứ phải gọi là chát dần đều. Nhất là mấy quả add liquidity nó thay đổi nhiều storage nên Gaslimit rất lớn, lại cộng thêm Gas Price cao nữa thì ối dồi ôi. Ví dụ đây mình thử add liquidity một lượng nho nhỏ

Thì mình khuyên mọi người có thể mạnh dạn vào chỉnh sửa -> nâng cao và hạ xuống 30, 20 hoặc để luôn 10Gwei nó vẫn chạy băng băng

Nên anh các bạn nào mà vốn bé nên để ý cái này vì không quá tội lãi farm không đủ tiền fee đâu.

Chiến lược farm

Chiến lược farm của mình cũng đơn giản lắm chỗ nào có lợi nhuận cao thì mình tham gia thôi. Nhưng phải chọn những nền tảng uy tín để farm chứ đừng vì lợi nhuận quá khủng mà đâm đầu vào luôn không kiểm tra dự án. Chính vì suy nghĩ nay mà những dự án lừa đảo lúc đầu họ thường để APY rất rất cao đánh vào lòng tham của anh em Farmers rồi khi lượng tiền đủ lớn họ xả hàng và biến mất. Cái gì to quá cũng nên đặt câu hỏi lãi vậy tiền đâu mà trả. Vậy nên ăn ít tý nhưng chắc còn hơn ăn nhiều mà chả được mấy mà có khi còn mất cả vốn luôn.

Kết luận

Trên đây là kinh nghiệm của mình trong quá trình Farming trên BSC, bài viết vẫn còn nhiều quan điểm cá nhân rất mong sẽ nhận được các ý kiến đóng góp từ các Farmers chân chính. Nếu bạn nào thấy hay thì upvote cho mình nhá xin chào và hẹn gặp lại mọi người trong những bài viết ký sự hoặc công nghệ tiếp theo nha.


All Rights Reserved