- vừa được xem lúc

Tìm hiểu về các luồng thực thi hàm trên smartcontract của Pancakeswap khi thêm, rút thanh khoản ( Add/Remove Liquidity)

0 0 10

Người đăng: Thuy Do

Theo Viblo Asia

ADD LIQUIDITY I.Luồng thực hiện function AddLiquidity Các bước để add liquidity : Approve số lượng token tự tạo cho phép router sử dụng . Có thể approve trên testnet.bscscan hoặc remix. Các coin như ETH,BTC,DAI… thì không cần approve. Approve trên testnet.bscscan thì cần verify contract trước.

Gọi hàm addLiquidity

1._addLiquidity: tính lượng token được add vào liquidity 2.safeTransferFrom: chuyển token an toàn vào địa chỉ to 3.pairFor: lấy địa chỉ LP token 4.mint: trả về địa chỉ to lượng LP token mint ra sau khi add liquidity với cặp token

STT Input Nội dung Input 1 address tokenA Địa chỉ token A 2 address tokenB Địa chỉ token B 3 uint amountADesired Số lượng token A muốn add liquidity 4 uint amountBDesired Số lượng token B muốn add liquidity 5 uint amountAMin Số lượng token A tối thiểu được add vào liquidity 6 uint amountBMin Số lượng token B tối thiểu được add vào liquidity 7 address to Địa chỉ nhận liquidity token trả về 8 uint deadline Thời gian tối đa thực hiện function STT Output Nội dung Output 1 uint amountA Số lượng token A được add vào liquidity 2 uint amountB Số lượng token B được add vào liquidity 3 uint liquidity Số lượng LP token được trả về ví

II.Nội dung function AddLiquidity: (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);

Gọi hàm _addLiquidity trả về kết quả là số lượng token A và token B trong pool vừa tạo gán trong 2 biến amountA và amount.(*) address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB);

Địa chỉ LP token trả về gán vào biến pair TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA); TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB); Chuyển số lượng token A là amountA, token B với số lượng amountB từ địa chỉ đang gọi hàm đến địa chỉ LP token vừa tạo ra ở trên liquidity = IPancakePair(pair).mint(to); Gọi hàm mint trong PancakePair để tạo LP token với số lượng lưu trong biến liquidity và chuyển tới địa chỉ ví là to

III.Nội dung chi tiết các hàm liên quan: library PancakeLibrary

sortTokens : Sắp xếp token STT Input Nội dung Input 1 address tokenA Địa chỉ token A 2 address tokenB Địa chỉ token B STT Output Nội dung Output 1 address token0 Địa chỉ thứ 1 sau khi sắp xếp 2 address token1 Địa chỉ thứ 2 sau khi sắp xếp

Nôi dung function: require(tokenA != tokenB, 'PancakeLibrary: IDENTICAL_ADDRESSES'); kiểm tra yêu cầu 2 token phải khác nhau nếu không báo lỗi (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); So sánh thứ tự địa chỉ token theo a-z,a-9 rồi sắp xếp và gán vào biến token 0 và token1 require(token0 != address(0), 'PancakeLibrary: ZERO_ADDRESS'); kiểm tra yêu cầu địa chỉ thứ 1 sau sắp xếp có tồn tại hại không, nếu không báo lỗi

pairFor: lấy địa chỉ LP token STT Input Nội dung Input 1 address factory Địa chỉ contract factory 2 address tokenA Địa chỉ token A 3 address tokenB Địa chỉ token B STT Output Nội dung Output 1 address pair Địa chỉ của LP token

Nôi dung function: Tính toán ra địa chỉ của LP token mà không phải gọi hàm từ ngoài vào giúp tiếp kiệm gas

getReserve: lấy số dư Token STT Input Nội dung Input 1 address factory Địa chỉ contract factory 2 address tokenA Địa chỉ token A 3 address tokenB Địa chỉ token B STT Output Nội dung Output 1 uint reserveA Số dư token A 2 uint reserveB Số dư token B

Nôi dung function: (address token0,) = sortTokens(tokenA, tokenB); Sắp xếp 2 token pairFor(factory, tokenA, tokenSăpB); Tính địa chỉ LP token (uint reserve0, uint reserve1,) = IPancakePair(pairFor(factory, tokenA, tokenB)).getReserves(); Lấy số dư của 2 token (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); Sắp xếp thứ tự 2 số dư này tương ứng với thứ tự token đã sắp xếp

quote STT Input Nội dung Input 1 uint amountA Số lượng tokenA cần qui đổi 2 uint reserveA Số dư token A 3 uint reserveB Số dư token B STT Output Nội dung Output 1 uint amountB Số dư token B qui đổi ra

Nôi dung function: require(amountA > 0, 'PancakeLibrary: INSUFFICIENT_AMOUNT'); require(reserveA > 0 && reserveB > 0, 'PancakeLibrary: INSUFFICIENT_LIQUIDITY'); Điều kiện yêu cầu số lượng token A nhập vào >0, số dư 2 token trong ví>0 amountB = amountA.mul(reserveB) / reserveA; Tính ra số lượng token B theo công thức PancakeRouter _addLiquidity: tính lượng token được add vào liquidity STT Input Nội dung Input 1 address tokenA Địa chỉ token A 2 address tokenB Địa chỉ token B 3 uint amountADesired Số lượng token A muốn add liquidity 4 uint amountBDesired Số lượng token B muốn add liquidity 5 uint amountAMin Số lượng token A tối thiểu được add vào liquidity 6 uint amountBMin Số lượng token B tối thiểu được add vào liquidity STT Output Nội dung Output 1 uint amountA Số lượng token A được add vào liquidity 2 uint amountB Số lượng token B được add vào liquidity

Nội dung function:

if (IPancakeFactory(factory).getPair(tokenA, tokenB) == address(0)) { IPancakeFactory(factory).createPair(tokenA, tokenB);

Kiểm tra xem token A và token B đã được tạo pair hay chưa nếu chưa sẽ gọi hàm createPair ở contract factory để tạo pair (uint reserveA, uint reserveB) = PancakeLibrary.getReserves(factory, tokenA, tokenB); Lấy số dư của 2 token if (reserveA == 0 && reserveB == 0) { (amountA, amountB) = (amountADesired, amountBDesired); Nếu cả 2 token có số dư =0 thì hàm trả ra số lượng token được add liquidity bằng số lượng input đã nhập } else { uint amountBOptimal = PancakeLibrary.quote(amountADesired, reserveA, reserveB); if (amountBOptimal <= amountBDesired) { require(amountBOptimal >= amountBMin, 'PancakeRouter: INSUFFICIENT_B_AMOUNT'); (amountA, amountB) = (amountADesired, amountBOptimal); Nếu ít nhất 1 token có số dư khác 0 thì tính khối lượng qui đổi số lượng tokenB tối ưu từ số lượng tokenA mong muốn. Nếu kết quả nhỏ hơn số lượng tokenB mong muốn và không nhỏ hơn số lượng tokenB tối thiểu thì số lượng tokenB tối ưu này được add liquidity cùng với số lượng tokenA đã nhập vào } else { uint amountAOptimal = PancakeLibrary.quote(amountBDesired, reserveB, reserveA); assert(amountAOptimal <= amountADesired); require(amountAOptimal >= amountAMin, 'PancakeRouter: INSUFFICIENT_A_AMOUNT'); (amountA, amountB) = (amountAOptimal, amountBDesired); } Nếu không thì tính tiếp số lượng tokenA tối ưu qui đổi từ số lượng tokenB mong muốn. Kiểm tra xem kết quả trả ra phải nhỏ hơn số lượng token Among muốn nếu không sẽ revert Kiểm tra tiếp yêu cầu kết quả trả ra phải lớn hơn số lượng tokenA tối thiểu thì revert và báo lỗi. Sau đó thì số tokenA tối ưu này sẽ được add liquidity cùng với số lượng tokenB đã nhập vào library TransferHelper safeTransferFrom: chuyển token an toàn STT Input Nội dung Input 1 address token Địa chỉ token 2 address from Địa chỉ chuyển token 3 address to Địa chỉ nhận token 4 uint256 value Số lượng token chuyển STT Output Nội dung Output 1 uint amountA Số lượng token A được add vào liquidity 2 uint amountB Số lượng token B được add vào liquidity

Nội dung function:

 (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); require( success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper::transferFrom: transferFrom failed' );

Gọi hàm chuyển token transfer qua giao thức call địa chị token . Hàm trả ra 2 kết quả bao gồm success là true nếu gọi hàm call thành công, false nếu không gọi được hàm và data là dữ liệu dạng bytes Kiểm tra yêu cầu phải gọi hàm thành công và không có dữ liệu data trả về hoặc decode data trả về true , nếu không sẽ báo lỗi và revert

PancakePair 4.1 mint : trả về địa chỉ to lượng LP token mint ra sau khi add liquidity với cặp token STT Input Nội dung Input 1 address to Địa chỉ nhận LP token STT Output Nội dung Output 1 uint liquidity Số lượng LP token được mint ra

Nội dung function:

 (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings uint balance0 = IERC20(token0).balanceOf(address(this)); uint balance1 = IERC20(token1).balanceOf(address(this)); uint amount0 = balance0.sub(_reserve0); uint amount1 = balance1.sub(_reserve1); bool feeOn = _mintFee(_reserve0, _reserve1); uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee

Lấy số dư trước khi add liquidity của 2 token trong pool Lấy số dư sau khi add liquidity của 2 token trong pool Gọi hàm _mintFee để mint ra lượng LP token tương đương lượng phí 0,03% chuyển vào vào địa chỉ treasury của Pancakeswap chính là địa chỉ feeTo đã set trước đó (Phí pancakeswap đang tính là 0.25% khối lượng giao dịch trong đó 0,17% phân phối cho các liquidity provider, 0,05% pancakeswap sẽ mua lại và burn,0,03% sẽ đi vào quỹ treasury để phát triển nền tảng). Để tiết kiệm gas thì phí này chỉ tính khi liquidity provider add hoặc remove liquidity if (_totalSupply == 0) { liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY); _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens } else { liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1); } Tính lượng LP token: Nếu là lần đầu add liquidity của cặp token thì tính số lượng LP token như công thức Lượng LP token tối thiểu được mint rồi khóa vĩnh viễn ở địa chỉ address(0) để tránh phép chia cho 0 Nếu cặp token đã được add liquidity trước đó thì số lượng LP token sẽ lấy theo số nhỏ hơn như là sự trừng phạt dành cho liquidity provider nếu cố tình add liquidity theo tỷ lệ không giống như tỷ lệ sẵn có trong pool require(liquidity > 0, 'Pancake: INSUFFICIENT_LIQUIDITY_MINTED'); _mint(to, liquidity);

 _update(balance0, balance1, _reserve0, _reserve1); if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date 

if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date Kiểm tra điều kiện LP token được tính ra ra phải >0 nếu không báo lỗi mint không thành công Gọi hàm _mint để mint LP token theo số lượng đã tính ở trên và chuyển về địa chỉ ví to Update số dư của 2 token trong pool Update k

REMOVE LIQUIDITY

I.Luồng thực hiện function RemoveLiquidity

Các bước để remove liquidity : Approve số lượng token tự tạo và LP token cho phép router sử dụng . Có thể approve trên testnet.bscscan hoặc remix. Các coin như ETH,BTC,DAI… thì không cần approve. Approve trên testnet.bscscan thì cần verify contract trước.

Gọi hàm RemoveLiquidity

1.pairFor: lấy địa chỉ LP token của cặp token 2.transferFrom:chuyển từ địa chỉ ví của người gọi hàm lượng LP token tới địa chỉ LP token vừa tìm được ở trên 3.burn: đốt lượng LP token và nhận về lượng 2 token tương ứng của cặp token 4.sortTokens:sắp xếp token

STT Input Nội dung Input 1 address tokenA Địa chỉ token A 2 address tokenB Địa chỉ token B 3 uint liquidity Số lượng LP token A muốn burn 4 uint amountAMin Số lượng token A tối thiểu được trả về ví 5 uint amountBMin Số lượng token B tối thiểu được trả về ví 6 address to Địa chỉ nhận liquidity token trả về 7 uint deadline Thời gian tối đa thực hiện function STT Output Nội dung Output 1 uint amountA Số lượng token A trả về ví 2 uint amountB Số lượng token B trả về ví

, II.Nội dung function RemoveLiquidity: Nội dung function: address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB); IPancakePair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair (uint amount0, uint amount1) = IPancakePair(pair).burn(to); (address token0,) = PancakeLibrary.sortTokens(tokenA, tokenB); (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0); require(amountA >= amountAMin, 'PancakeRouter: INSUFFICIENT_A_AMOUNT'); require(amountB >= amountBMin, 'PancakeRouter: INSUFFICIENT_B_AMOUNT');

Lấy địa chỉ LP token của cặp token Chuyển từ địa chỉ ví của người gọi hàm lượng LP token tới địa chỉ LP token vừa tìm được ở trên Đốt lượng LP token và nhận về lượng 2 token tương ứng của cặp token Sắp xếp 2 token Sắp xếp thứ tự của số lượng token trả về tương ứng với thứ tự token sau khi sắp xếp Kiểm tra yêu cầu cả 2 lượng token trả về phải lớn hơn số tối thiểu đã nhập vào nếu không sẽ revert và báo lỗi

III.Nội dung chi tiết các hàm liên quan: PancakeLibrary pairFor: ở trên

PancakePair TransferFrom: chuyển token STT Input Nội dung Input 1 address from Địa chỉ chuyển token 2 address to Địa chỉ nhận token 3 uint256 value Số lượng token chuyển STT Output Nội dung Output 1 bool trả về giá trị true nếu chuyển thành công

Nội dung function: function transferFrom(address from, address to, uint value) external returns (bool) { if (allowance[from][msg.sender] != uint(-1)) { allowance[from][msg.sender] = allowance[from][msg.sender].sub(value); } _transfer(from, to, value); return true; -kiểm tra nếu allowance(số token được sử dụng tối đa) chưa đạt giá trị tối đa thì update lại allowance sau khi trừ đi số token muốn chuyển -chuyển token trả về giá trị true nếu chuyển thành công Burn: trả về địa chỉ to 2 token sau khi burn LP token STT Input Nội dung Input 1 address to Địa chỉ nhận token trả về STT Output Nội dung Output 1 uint amountA Số lượng token A trả về ví 2 uint amountB Số lượng token B trả về ví

Nội dung function: (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings address _token0 = token0; // gas savings address _token1 = token1; // gas savings uint balance0 = IERC20(_token0).balanceOf(address(this)); uint balance1 = IERC20(_token1).balanceOf(address(this)); uint liquidity = balanceOf[address(this)];

 bool feeOn = _mintFee(_reserve0, _reserve1);

Lấy số dư trước khi remove liquidity của 2 token trong pool Lấy số dư sau khi remove liquidity của 2 token trong pool Lấu số lượng LP token trong contract Gọi hàm _mintFee để mint ra lượng LP token tương đương lượng phí 0,03% chuyển vào vào địa chỉ treasury của Pancakeswap chính là địa chỉ feeTo đã set trước đó uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution require(amount0 > 0 && amount1 > 0, 'Pancake: INSUFFICIENT_LIQUIDITY_BURNED'); Tính số lượng 2 token sẽ trả về ví Kiểm tra yêu cầu 2 số tính ra phải >0 nếu không báo lỗi burn không thành công _burn(address(this), liquidity); _safeTransfer(_token0, to, amount0); _safeTransfer(_token1, to, amount1); Gọi hàm _burn để update số dư và tổng cung LP token trong contract sau khi trừ đi lượng LP token cần burn Chuyển 2 token về địa chỉ ví to theo số lượng đã tính ở trên balance0 = IERC20(_token0).balanceOf(address(this)); balance1 = IERC20(_token1).balanceOf(address(this));

 _update(balance0, balance1, _reserve0, _reserve1); if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date

update lại số dư 2 token trong contract, update k PancakeLibrary 3.1 sortTokens: ở trên

Bình luận

Bài viết tương tự

- vừa được xem lúc

[Blockchain] Road to Bitcoin

. Chắc mọi người hẳn đã không còn xa lạ gì với anh chàng tỷ phú đã ném vỡ cửa kính ô tô nhà mình cùng với siêu năng lực điều khiển vật giá chỉ bằng lời nói, người đã đẩy định giá Bitcoin trên thị trường vượt ngưỡng 50K dolar/coin với những bài twitter để đời . .

0 0 44

- vừa được xem lúc

Khi Ethereum có chi phí giao dịch quá đắt đỏ - Tương lai cho layer2 ?

Với sự phát triển như vũ bão của Blockchain, ETH dường như đang quá tải và hệ quả là chi phí Gas đã lên đến 1000Gwei, phí để tạo những transaction phức tạp đã xấp xỉ 500$ . Và một giải pháp cứu cánh cho các sản phẩm Defi trên ETH chính là Layer2, và trong nhiệm vụ lần này Matic đang thể hiện khả năn

0 0 73

- vừa được xem lúc

Blockchain với Java - Tại sao không?

Cuộc cách mạng công nghiệp 4.0 ra đời kéo theo nhiều sự thay đổi và xu hướng mới được hình thành. Riêng đối với lĩnh vực CNTT cũng không nằm ngoài vùng ảnh hưởng mạnh mẽ. Chính làn sóng 4.

0 0 78

- vừa được xem lúc

Phân loại và tầm quan trọng của các node trong mạng blockchain

Trước khi đi vào phân loại và nêu rõ được tầm quan trọng của các node trọng mạng blockchain thì mình xin được trích dẫn khái niệm về blockchain từ Wikipedia như sau:. .

0 1 46

- vừa được xem lúc

Code Smart Contract bằng Assembly ?

Introduction. Hồi còn học trong ghế nhà trường bộ môn lập trình tốn nhiều não nhất của mình là code assembly. Nôm na thì bất cứ ngôn ngữ bậc cao nào như C , Go, Java,... được sinh ra để người dễ hiểu và dễ code , tuy nhiên chúng đều sẽ được compiled down xuống assembly một ngôn ngữ bậc thấp để máy h

0 0 43

- vừa được xem lúc

Dextool - Công cụ phân tích Decentralized Exchange tuyệt vời

. Trend Defi mặc dù đã bớt nhiệt nhưng những sản phẩm nổi bật của làn sóng này mang lại thì vẫn rất được người dùng ưa chuộng. Đặc biệt là các nền tảng Decentralized Exchange, tiêu biểu là Uniswap, SushiSwap, 1inch Exchange, FalconSwap,... Nhưng khi đã sử dụng các nền tảng DEx này mà không biết đến

0 0 92