Uniswap V2: Bản Đồ Kiến Trúc Cốt Lõi Trước Những Giao Dịch Swap

05 tháng 4, 2026·9 phút đọc

Bài viết này phân tích kiến trúc của Uniswap V2, làm rõ sự khác biệt giữa các hợp đồng Core và Periphery, cũng như vai trò của Factory, Pair và Router. Đây là bản thiết kế cần thiết để hiểu cách thức vận hành của giao thức DeFi này trước khi đi sâu vào các quy trình cụ thể.

Uniswap V2: Bản Đồ Kiến Trúc Cốt Lõi Trước Những Giao Dịch Swap

Gần đây, tôi đã có một bài đăng blog nơi chúng ta cùng mổ xẻ nhanh về AMM là gì, đặc biệt là Uniswap, và xây dựng sự hiểu biết cơ bản về cách mọi thứ hoạt động bên dưới lớp vỏ. Ban đầu, nó chỉ được định vị là một lời giới thiệu ngắn gọn, nhưng sau đó lại trở nên khá mang tính kỹ thuật. Chúng ta đã đề cập đến công thức Constant Product (Hằng số sản phẩm), nguồn gốc của nó, và cách nó trở thành nền tảng của toàn bộ không gian DeFi thực thụ.

Đây là bài đăng thứ hai trong chuỗi series này. Nhưng trước khi chúng ta đi sâu vào các luồng hoạt động thực tế — cách swap diễn ra, cách thanh khoản được thêm vào, và tất cả những thứ khác — đáng lẽ ra chúng ta nên dành năm phút để hiểu cách Uniswap V2 được bố trí. Không phải là chi tiết từng hợp đồng, chúng ta sẽ đến phần đó từng cái một trong các bài sau. Mà ở đây là về cấu trúc tổng thể. Hãy coi nó như bản thiết kế của một tòa nhà mà bạn chưa từng bước vào. Bạn không cần biết mọi căn phòng ở đâu, chỉ cần biết cửa chính ở đâu và cầu thang nào dẫn đến đâu.

Nếu một số thuật ngữ hoặc khái niệm ở đây có vẻ xa lạ, đừng lo lắng. Đến khi chúng ta hoàn thành chuỗi bài này, mọi thứ sẽ tự động khớp vào vị trí của nó. Bài đăng này chỉ cung cấp bối cảnh — một bản đồ mà bạn có thể tham khảo bất cứ khi nào cần định hướng trong quá trình theo dõi.

Hai kho lưu trữ (repo), một giao thức

Điều đầu tiên khiến nhiều người bối rối khi mở GitHub của Uniswap V2 là có hai repository: v2-corev2-periphery. Rất dễ dàng để giả định rằng đây chỉ là một lựa chọn tổ chức (ít nhất là tôi từng nghĩ vậy), nghĩa là ai đó quyết định chia mã thành hai thư mục và đặt cho chúng những cái tên nghe cho có vẻ "hoành tráng". Thực tế, đây là một quyết định kiến trúc có tính toán kỹ lưỡng, và việc hiểu tại sao nó lại được chia như vậy sẽ giúp bạn dễ dàng hình dung toàn bộ hệ thống hơn.

Core (Lõi) chứa các hợp đồng thực sự nắm giữ tiền của bạn. Đó là lý do tại sao nó được gọi là lõi. Không có gì cầu kỳ, không có gì thừa thãi. Vì các hợp đồng này lưu ký tiền thật, chúng được thiết kế tối giản và hoàn toàn bất biến (immutable) sau khi triển khai. Không có khóa quản trị (admin key), không có cơ chế nâng cấp, không có cách nào vá lỗi sau khi đã ra mắt. Nếu tìm thấy lỗi trong Core, lựa chọn duy nhất là triển khai một phiên bản hoàn toàn mới. Nghe có vẻ đáng sợ lúc đầu, nhưng hãy nhìn theo hướng khác: điều này cũng có nghĩa là không ai có thể thay đổi các hợp đồng này để làm điều gì đó bất ngờ với số tiền của bạn. Mãi mãi.

Periphery (Ngoại vi), đúng như tên gọi, nằm ở bên ngoài logic cốt lõi. Nó chứa mọi thứ làm cho Core trở nên khả dụng. Logic định tuyến (routing), kiểm tra độ trượt (slippage), tính toán số lượng tối ưu, giải quyết đường đi đa nhảy (multi-hop path), tất cả đều nằm ở đây. Và quan trọng là, Periphery có thể được thay thế. Nếu một router tốt hơn được triển khai ngày mai, người dùng có thể chuyển sang sử dụng nó mà các pool (hồ thanh khoản) bên dưới hoàn toàn không đổi. Các pool không quan tâm ai là người gọi chúng.

Sự chia tách này là ranh giới của niềm tin. Core là thứ bạn phải tin tưởng. Periphery chỉ là sự tiện lợi.

Nội dung thực sự trong từng repo

Core có ba hợp đồng quan trọng: UniswapV2Factory, UniswapV2Pair, và UniswapV2ERC20.

Factory là sổ đăng ký. Nó triển khai các hợp đồng pool mới và giữ bản ghi của mọi pool đang tồn tại — một ánh xạ từ cặp token đến địa chỉ pool. Khi bạn muốn tìm hoặc tạo một pool cho hai token, Factory là nơi bạn đến. Một chi tiết thú vị: nó sử dụng phương pháp triển khai xác định (CREATE2), điều này có nghĩa là địa chỉ của bất kỳ pool nào đều có thể được tính toán ngoại tuyến (off-chain) chỉ từ địa chỉ factory và hai địa chỉ token, mà không cần truy vấn chuỗi. Về mặt kỹ thuật, CREATE2 chỉ là băm của nhiều tham số, trong đó có salt (muối). Điều này có nghĩa là cùng một tham số sẽ tạo ra cùng một kết quả (địa chỉ hợp đồng) mỗi lần.

Pair chính là pool. Mỗi hợp đồng pair đã triển khai chứa chính xác hai token và xử lý mọi thứ: đúc (mint) token LP khi thanh khoản được thêm vào, đốt (burn) chúng khi bị loại bỏ, thực hiện swap, vay nhanh (flash loans), tất tần tật. Nó cũng lưu trữ bộ tích lũy giá (price accumulators) giúp tạo điều kiện cho oracle TWAP tích hợp sẵn của Uniswap. Một điều đáng chú ý: UniswapV2Pair bản thân nó là một ERC-20. Các token LP chính là token của hợp đồng pair đó. Nắm giữ token LP của một pool nghĩa là nắm giữ cổ phần của hợp đồng đó.

UniswapV2ERC20 chỉ là cơ sở ERC-20 mà Pair kế thừa, bao gồm chức năng token tiêu chuẩn cộng với hỗ trợ EIP-2612 permit, cho phép bạn phê duyệt và thực hiện hành động trong một giao dịch duy nhất thay vì hai.

Core cũng có một vài thư viện tiện ích — Math.sol cho căn bậc hai số nguyên được sử dụng trong tính toán token LP ban đầu, và UQ112x112.sol cho số học dấu phẩy tĩnh được sử dụng trong tích lũy giá. Bạn không cần nghĩ quá nhiều về chúng lúc này.

Periphery được neo giữ bởi UniswapV2Router02 — hợp đồng mà người dùng thực sự tương tác. Mọi hàm mà bạn gọi khi sử dụng giao diện DEX, hoặc bất kỳ bên tích hợp nào, đều nằm ở đây. Nó xử lý cả bốn thao tác, bọc và mở gói ETH cho các swap liên quan đến ETH, thực thi thời hạn chót (deadlines), và tính toán số lượng tối ưu trước khi bất cứ thứ gì chạm vào Core. Cũng có một Router01 trong repo, nhưng về cơ bản nó đã bị loại bỏ. Router02 thay thế nó với hỗ trợ tốt hơn cho phạm vi token rộng hơn.

Hỗ trợ cho Router là UniswapV2Library, một thư viện tiện ích không trạng thái xử lý tất cả công việc tính toán: tra cứu địa chỉ pair, tìm nạp dự trữ (reserves), tính toán đầu ra swap, duyệt qua đường đi đa nhảy. Không cần phải chạm đến trạng thái nên nó được biên dịch nội tuyến (inline) thay vì được triển khai như một hợp đồng độc lập. Và có UniswapV2OracleLibrary, cung cấp các trình trợ giúp để xây dựng oracle TWAP dựa trên bộ tích lũy giá của pair — nếu bạn từng thắc mắc các giao thức lấy nguồn cấp giá dữ liệu trên chuỗi chống lại sự thao túng như thế nào, đây là một phần của câu chuyện đó.

Các trình trợ giúp không nằm trong repo nào

Hai gói tiện ích bên ngoài được đưa vào V2 đáng để biết đến, chủ yếu vì bạn sẽ thấy chúng được nhập trong các hợp đồng khi bạn theo dõi.

Thứ nhất là TransferHelper từ @uniswap/solidity-lib. Vấn đề nó giải quyết là rất thực tế: hàm transfer() của ERC-20 nên trả về một giá trị boolean chỉ thị thành công, nhưng một số lượng đáng kinh ngạc các token, với USDT là nổi tiếng nhất, không trả về bất cứ thứ gì cả. Một lệnh require(token.transfer(...)) ngây thơ sẽ chỉ bị đảo ngược (revert) trên các token này ngay cả khi việc chuyển tiền diễn ra tốt đẹp. TransferHelper bọc các lệnh chuyển tiền trong một cuộc gọi ở mức thấp (low-level call) xử lý trơn tru cả hai trường hợp. Đó là một điều nhỏ, nhưng如果没有 nó, Router sẽ âm thầm thất bại trên một lớp lớn các token mà mọi người thực sự sử dụng.

Thứ hai là FixedPoint từ @uniswap/lib, cung cấp các kiểu số dấu phẩy tĩnh cho thư viện oracle. Solidity không có dấu phẩy động (floating-point) bản địa, do đó các giá trị giá tích lũy cần một cách để tích lũy các tỷ lệ phân số theo thời gian mà không mất độ chính xác. Đó là điều mà nó xử lý.

Luồng gọi hàm trong một dòng

Đối với mọi thao tác, đường đi là:

Người dùng → Router → Pair → Người dùng

Factory đứng ở một bên, được Router tham khảo để tìm hoặc triển khai địa chỉ pair khi cần, nhưng không nằm trên đường dẫn quan trọng của mọi giao dịch. Các thư viện là cơ sở hạ tầng thầm lặng, được biên dịch vào Router và không bao giờ được gọi trực tiếp.

Đó là bản đồ. Hãy giữ nó ở đâu đó trong góc tâm trí khi chúng ta đi vào các luồng hoạt động. Bất cứ khi nào bạn thấy Router gọi thứ gì đó trên Pair, hoặc Pair kiểm tra thứ gì đó thông qua Library, bạn sẽ biết chính xác mình đang ở đâu.

Dưới đây là tất cả các hợp đồng và repo được tham chiếu trong bài đăng này, nếu bạn muốn tự khám phá, mặc dù bạn chắc chắn không cần phải làm điều đó ngay bây giờ.

Tiếp theo: thêm thanh khoản vào một pool. Đây là nơi công thức hằng số sản phẩm ngừng là lý thuyết và bắt đầu thực hành "làm bẩn tay".

Trong trường hợp bạn lỡ bỏ qua phần giới thiệu: x * y = k, và những thứ khác tôi lẽ ra nên học sớm hơn.

Bài viết được tổng hợp và biên soạn bằng AI từ các nguồn tin tức công nghệ. Nội dung mang tính tham khảo. Xem bài gốc ↗