diff --git a/scripts/md-to-react.ts b/scripts/md-to-react.ts index 64eb9b36a..95b23e46c 100644 --- a/scripts/md-to-react.ts +++ b/scripts/md-to-react.ts @@ -38,7 +38,7 @@ hljs.registerLanguage("solidity", solidity) async function findSolidityFiles(dir: string): Promise { const files = await readdir(dir) - return files.filter((file) => file.split(".").pop() == "sol") + return files.filter((file) => file.split(".").pop() == "sol" || file.split(".").pop() == "solsnippet") } async function mdToHtml(filePath: string) { diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index e0b74d4ae..c6ab047d4 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -5,17 +5,13 @@ import youTube from "./youtube.png" import telegram from "./telegram.png" import discord from "./discord.png" -// Khan Academy -const ADDRESS = "0x95a647B3d8a3F11176BAdB799b9499C671fa243a" - function Footer() { return (
- {/* smart contract engineer */} - 👽  - - saucepoint + 🦄  + + Uniswap Foundation
{/*
@@ -42,36 +38,23 @@ function Footer() {
*/}
- Donate - 🙂 - - {ADDRESS.slice(0, 6)}...{ADDRESS.slice(-6, -1)} - - to - - Khan Academy - -
- {/*
- - contact@solidity-by-example.org - -
*/} -
- + source
|
license
+
+ (fork of  + + solidity-by-example) + +
) } diff --git a/src/components/SideNav.tsx b/src/components/SideNav.tsx index ffc09304d..5c9fabdc1 100644 --- a/src/components/SideNav.tsx +++ b/src/components/SideNav.tsx @@ -17,7 +17,7 @@ const SideNav: React.FC = ({ onClick }) => { return ( <> -

Basic

+

Lifecycle

{ROUTES_BY_CATEGORY.map(({ routes, title }, i) => (
{title &&

{title}

} diff --git a/src/keywords.json b/src/keywords.json index a7c012213..6e67db626 100644 --- a/src/keywords.json +++ b/src/keywords.json @@ -1,23 +1,5 @@ { - "/swap": [ - "swap", - "trade", - "swapping" - ], - "/initialize": [ - "pool", - "initialize", - "init", - "create", - "pair", - "factory" - ], - "/create-liquidity": [ - "liquidity", - "LP", - "lp", - "provide", - "provision", - "supply" - ] -} \ No newline at end of file + "/swap": ["swap", "trade", "swapping"], + "/initialize": ["pool", "initialize", "init", "create", "pair", "factory"], + "/create-liquidity": ["liquidity", "LP", "lp", "provide", "provision", "supply"] +} diff --git a/src/nav.ts b/src/nav.ts index 947a376f8..94ce3f706 100644 --- a/src/nav.ts +++ b/src/nav.ts @@ -8,36 +8,30 @@ export interface Translation { url: string } -export const TRANSLATIONS: Translation[] = [ - -] +export const TRANSLATIONS: Translation[] = [] export const SOL_ROUTES: Route[] = [ { path: "initialize", - title: "Initialize Pool" + title: "Initialize Pool", }, { path: "create-liquidity", - title: "Create Liquidity" + title: "Create Liquidity", }, { path: "swap", - title: "Swap" + title: "Swap", }, ] -export const APP_ROUTES: Route[] = [ -] +export const APP_ROUTES: Route[] = [] -const HACK_ROUTES: Route[] = [ -] +const HACK_ROUTES: Route[] = [] -export const TEST_ROUTES: Route[] = [ -] +export const TEST_ROUTES: Route[] = [] -export const DEFI_ROUTES = [ -] +export const DEFI_ROUTES = [] export const ROUTES_BY_CATEGORY = [ { diff --git a/src/pages/create-liquidity/CreateLiquidityExampleInputs.sol b/src/pages/create-liquidity/CreateLiquidityExampleInputs.sol deleted file mode 100644 index cacf7a95b..000000000 --- a/src/pages/create-liquidity/CreateLiquidityExampleInputs.sol +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {IERC20} from "forge-std/interfaces/IERC20.sol"; -import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol"; -import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol"; -import {PoolModifyPositionTest} from "@uniswap/v4-core/contracts/test/PoolModifyPositionTest.sol"; -import {CurrencyLibrary, Currency} from "@uniswap/v4-core/contracts/types/Currency.sol"; - -contract CreateLiquidityExampleInputs { - using CurrencyLibrary for Currency; - - // set the router address - PoolModifyPositionTest lpRouter = PoolModifyPositionTest(0x01); - - function exampleA() external { - address token0 = address(0x11); - address token1 = address(0x22); - - // Using a hookless pool - PoolKey memory pool = PoolKey({ - currency0: Currency.wrap(token0), - currency1: Currency.wrap(token1), - fee: 3000, - tickSpacing: 60, - hooks: IHooks(address(0x0)) - }); - - // approve tokens to the LP Router - IERC20(token0).approve(address(lpRouter), type(uint256).max); - IERC20(token1).approve(address(lpRouter), type(uint256).max); - - // Provide 10e18 worth of liquidity on the range of [-600, 600] - int24 tickLower = -600; - int24 tickUpper = 600; - int256 liquidity = 10e18; - lpRouter.modifyPosition( - poolKey, - IPoolManager.ModifyPositionParams({tickLower: tickLower, tickUpper: tickUpper, liquidityDelta: liquidity}), - new bytes(0) - ); - } -} diff --git a/src/pages/create-liquidity/CreateLiquidityExampleInputs.solsnippet b/src/pages/create-liquidity/CreateLiquidityExampleInputs.solsnippet new file mode 100644 index 000000000..3366c871f --- /dev/null +++ b/src/pages/create-liquidity/CreateLiquidityExampleInputs.solsnippet @@ -0,0 +1,29 @@ +import {PoolModifyPositionTest} from "@uniswap/v4-core/contracts/test/PoolModifyPositionTest.sol"; + +PoolModifyPositionTest lpRouter = PoolModifyPositionTest(0x01); +address token0 = address(0x11); +address token1 = address(0x22); +address hookAddress = address(0x80); + +// Pool that will receieve liquidity +PoolKey memory pool = PoolKey({ + currency0: Currency.wrap(token0), + currency1: Currency.wrap(token1), + fee: 3000, + tickSpacing: 60, + hooks: IHooks(hookAddress) +}); + +// approve tokens to the LP Router +IERC20(token0).approve(address(lpRouter), type(uint256).max); +IERC20(token1).approve(address(lpRouter), type(uint256).max); + +// Provide 10e18 worth of liquidity on the range of [-600, 600] +int24 tickLower = -600; +int24 tickUpper = 600; +int256 liquidity = 10e18; +lpRouter.modifyPosition( + poolKey, + IPoolManager.ModifyPositionParams({tickLower: tickLower, tickUpper: tickUpper, liquidityDelta: liquidity}), + new bytes(0) +); diff --git a/src/pages/create-liquidity/index.html.ts b/src/pages/create-liquidity/index.html.ts index 5c861734b..aa84ffe3a 100644 --- a/src/pages/create-liquidity/index.html.ts +++ b/src/pages/create-liquidity/index.html.ts @@ -3,35 +3,30 @@ export const version = "0.8.20" export const title = "Create Liquidity" export const description = "Providing Liquidity to a Uniswap V4 Pool" -export const keywords = [ - "liquidity", - "LP", - "lp", - "provide", - "provision", - "supply", -] +export const keywords = ["liquidity", "LP", "lp", "provide", "provision", "supply"] export const codes = [ - { - fileName: "CreateLiquidity.sol", - code: "Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCB7SVBvb2xNYW5hZ2VyfSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy9pbnRlcmZhY2VzL0lQb29sTWFuYWdlci5zb2wiOwppbXBvcnQge1Bvb2xLZXl9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL3R5cGVzL1Bvb2xLZXkuc29sIjsKaW1wb3J0IHtQb29sTW9kaWZ5UG9zaXRpb25UZXN0fSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy90ZXN0L1Bvb2xNb2RpZnlQb3NpdGlvblRlc3Quc29sIjsKCmNvbnRyYWN0IENyZWF0ZUxpcXVpZGl0eSB7CiAgICAvLyBzZXQgdGhlIHJvdXRlciBhZGRyZXNzCiAgICBQb29sTW9kaWZ5UG9zaXRpb25UZXN0IGxwUm91dGVyID0gUG9vbE1vZGlmeVBvc2l0aW9uVGVzdCgweDAxKTsKCiAgICBmdW5jdGlvbiBjcmVhdGVMaXF1aWRpdHkoCiAgICAgICAgUG9vbEtleSBtZW1vcnkgcG9vbEtleSwKICAgICAgICBpbnQyNCB0aWNrTG93ZXIsCiAgICAgICAgaW50MjQgdGlja1VwcGVyLAogICAgICAgIGludDI1NiBsaXF1aWRpdHksCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgaG9va0RhdGEKICAgICkgZXh0ZXJuYWwgewogICAgICAgIC8vIGlmIDAgPCBsaXF1aWRpdHk6IGFkZCBsaXF1aWRpdHkgLS0gb3RoZXJ3aXNlIHJlbW92ZSBsaXF1aWRpdHkKICAgICAgICBscFJvdXRlci5tb2RpZnlQb3NpdGlvbigKICAgICAgICAgICAgcG9vbEtleSwKICAgICAgICAgICAgSVBvb2xNYW5hZ2VyLk1vZGlmeVBvc2l0aW9uUGFyYW1zKHt0aWNrTG93ZXI6IHRpY2tMb3dlciwgdGlja1VwcGVyOiB0aWNrVXBwZXIsIGxpcXVpZGl0eURlbHRhOiBsaXF1aWRpdHl9KSwKICAgICAgICAgICAgaG9va0RhdGEKICAgICAgICApOwogICAgfQp9Cg==", - }, - { - fileName: "CreateLiquidityExampleInputs.sol", - code: "Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCB7SUVSQzIwfSBmcm9tICJmb3JnZS1zdGQvaW50ZXJmYWNlcy9JRVJDMjAuc29sIjsKaW1wb3J0IHtJUG9vbE1hbmFnZXJ9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL2ludGVyZmFjZXMvSVBvb2xNYW5hZ2VyLnNvbCI7CmltcG9ydCB7UG9vbEtleX0gZnJvbSAiQHVuaXN3YXAvdjQtY29yZS9jb250cmFjdHMvdHlwZXMvUG9vbEtleS5zb2wiOwppbXBvcnQge1Bvb2xNb2RpZnlQb3NpdGlvblRlc3R9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL3Rlc3QvUG9vbE1vZGlmeVBvc2l0aW9uVGVzdC5zb2wiOwppbXBvcnQge0N1cnJlbmN5TGlicmFyeSwgQ3VycmVuY3l9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL3R5cGVzL0N1cnJlbmN5LnNvbCI7Cgpjb250cmFjdCBDcmVhdGVMaXF1aWRpdHlFeGFtcGxlSW5wdXRzIHsKICAgIHVzaW5nIEN1cnJlbmN5TGlicmFyeSBmb3IgQ3VycmVuY3k7CgogICAgLy8gc2V0IHRoZSByb3V0ZXIgYWRkcmVzcwogICAgUG9vbE1vZGlmeVBvc2l0aW9uVGVzdCBscFJvdXRlciA9IFBvb2xNb2RpZnlQb3NpdGlvblRlc3QoMHgwMSk7CgogICAgZnVuY3Rpb24gZXhhbXBsZUEoKSBleHRlcm5hbCB7CiAgICAgICAgYWRkcmVzcyB0b2tlbjAgPSBhZGRyZXNzKDB4MTEpOwogICAgICAgIGFkZHJlc3MgdG9rZW4xID0gYWRkcmVzcygweDIyKTsKCiAgICAgICAgLy8gVXNpbmcgYSBob29rbGVzcyBwb29sCiAgICAgICAgUG9vbEtleSBtZW1vcnkgcG9vbCA9IFBvb2xLZXkoewogICAgICAgICAgICBjdXJyZW5jeTA6IEN1cnJlbmN5LndyYXAodG9rZW4wKSwKICAgICAgICAgICAgY3VycmVuY3kxOiBDdXJyZW5jeS53cmFwKHRva2VuMSksCiAgICAgICAgICAgIGZlZTogMzAwMCwKICAgICAgICAgICAgdGlja1NwYWNpbmc6IDYwLAogICAgICAgICAgICBob29rczogSUhvb2tzKGFkZHJlc3MoMHgwKSkKICAgICAgICB9KTsKCiAgICAgICAgLy8gYXBwcm92ZSB0b2tlbnMgdG8gdGhlIExQIFJvdXRlcgogICAgICAgIElFUkMyMCh0b2tlbjApLmFwcHJvdmUoYWRkcmVzcyhscFJvdXRlciksIHR5cGUodWludDI1NikubWF4KTsKICAgICAgICBJRVJDMjAodG9rZW4xKS5hcHByb3ZlKGFkZHJlc3MobHBSb3V0ZXIpLCB0eXBlKHVpbnQyNTYpLm1heCk7CgogICAgICAgIC8vIFByb3ZpZGUgMTBlMTggd29ydGggb2YgbGlxdWlkaXR5IG9uIHRoZSByYW5nZSBvZiBbLTYwMCwgNjAwXQogICAgICAgIGludDI0IHRpY2tMb3dlciA9IC02MDA7CiAgICAgICAgaW50MjQgdGlja1VwcGVyID0gNjAwOwogICAgICAgIGludDI1NiBsaXF1aWRpdHkgPSAxMGUxODsKICAgICAgICBscFJvdXRlci5tb2RpZnlQb3NpdGlvbigKICAgICAgICAgICAgcG9vbEtleSwKICAgICAgICAgICAgSVBvb2xNYW5hZ2VyLk1vZGlmeVBvc2l0aW9uUGFyYW1zKHt0aWNrTG93ZXI6IHRpY2tMb3dlciwgdGlja1VwcGVyOiB0aWNrVXBwZXIsIGxpcXVpZGl0eURlbHRhOiBsaXF1aWRpdHl9KSwKICAgICAgICAgICAgbmV3IGJ5dGVzKDApCiAgICAgICAgKTsKICAgIH0KfQo=", - }, + { + fileName: "CreateLiquidity.sol", + code: "Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCB7SVBvb2xNYW5hZ2VyfSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy9pbnRlcmZhY2VzL0lQb29sTWFuYWdlci5zb2wiOwppbXBvcnQge1Bvb2xLZXl9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL3R5cGVzL1Bvb2xLZXkuc29sIjsKaW1wb3J0IHtQb29sTW9kaWZ5UG9zaXRpb25UZXN0fSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy90ZXN0L1Bvb2xNb2RpZnlQb3NpdGlvblRlc3Quc29sIjsKCmNvbnRyYWN0IENyZWF0ZUxpcXVpZGl0eSB7CiAgICAvLyBzZXQgdGhlIHJvdXRlciBhZGRyZXNzCiAgICBQb29sTW9kaWZ5UG9zaXRpb25UZXN0IGxwUm91dGVyID0gUG9vbE1vZGlmeVBvc2l0aW9uVGVzdCgweDAxKTsKCiAgICBmdW5jdGlvbiBjcmVhdGVMaXF1aWRpdHkoCiAgICAgICAgUG9vbEtleSBtZW1vcnkgcG9vbEtleSwKICAgICAgICBpbnQyNCB0aWNrTG93ZXIsCiAgICAgICAgaW50MjQgdGlja1VwcGVyLAogICAgICAgIGludDI1NiBsaXF1aWRpdHksCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgaG9va0RhdGEKICAgICkgZXh0ZXJuYWwgewogICAgICAgIC8vIGlmIDAgPCBsaXF1aWRpdHk6IGFkZCBsaXF1aWRpdHkgLS0gb3RoZXJ3aXNlIHJlbW92ZSBsaXF1aWRpdHkKICAgICAgICBscFJvdXRlci5tb2RpZnlQb3NpdGlvbigKICAgICAgICAgICAgcG9vbEtleSwKICAgICAgICAgICAgSVBvb2xNYW5hZ2VyLk1vZGlmeVBvc2l0aW9uUGFyYW1zKHt0aWNrTG93ZXI6IHRpY2tMb3dlciwgdGlja1VwcGVyOiB0aWNrVXBwZXIsIGxpcXVpZGl0eURlbHRhOiBsaXF1aWRpdHl9KSwKICAgICAgICAgICAgaG9va0RhdGEKICAgICAgICApOwogICAgfQp9Cg==", + }, + { + fileName: "CreateLiquidityExampleInputs.sol", + code: "aW1wb3J0IHtQb29sTW9kaWZ5UG9zaXRpb25UZXN0fSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy90ZXN0L1Bvb2xNb2RpZnlQb3NpdGlvblRlc3Quc29sIjsKClBvb2xNb2RpZnlQb3NpdGlvblRlc3QgbHBSb3V0ZXIgPSBQb29sTW9kaWZ5UG9zaXRpb25UZXN0KDB4MDEpOwphZGRyZXNzIHRva2VuMCA9IGFkZHJlc3MoMHgxMSk7CmFkZHJlc3MgdG9rZW4xID0gYWRkcmVzcygweDIyKTsKYWRkcmVzcyBob29rQWRkcmVzcyA9IGFkZHJlc3MoMHg4MCk7CgovLyBQb29sIHRoYXQgd2lsbCByZWNlaWV2ZSBsaXF1aWRpdHkKUG9vbEtleSBtZW1vcnkgcG9vbCA9IFBvb2xLZXkoewogICAgY3VycmVuY3kwOiBDdXJyZW5jeS53cmFwKHRva2VuMCksCiAgICBjdXJyZW5jeTE6IEN1cnJlbmN5LndyYXAodG9rZW4xKSwKICAgIGZlZTogMzAwMCwKICAgIHRpY2tTcGFjaW5nOiA2MCwKICAgIGhvb2tzOiBJSG9va3MoaG9va0FkZHJlc3MpCn0pOwoKLy8gYXBwcm92ZSB0b2tlbnMgdG8gdGhlIExQIFJvdXRlcgpJRVJDMjAodG9rZW4wKS5hcHByb3ZlKGFkZHJlc3MobHBSb3V0ZXIpLCB0eXBlKHVpbnQyNTYpLm1heCk7CklFUkMyMCh0b2tlbjEpLmFwcHJvdmUoYWRkcmVzcyhscFJvdXRlciksIHR5cGUodWludDI1NikubWF4KTsKCi8vIFByb3ZpZGUgMTBlMTggd29ydGggb2YgbGlxdWlkaXR5IG9uIHRoZSByYW5nZSBvZiBbLTYwMCwgNjAwXQppbnQyNCB0aWNrTG93ZXIgPSAtNjAwOwppbnQyNCB0aWNrVXBwZXIgPSA2MDA7CmludDI1NiBsaXF1aWRpdHkgPSAxMGUxODsKbHBSb3V0ZXIubW9kaWZ5UG9zaXRpb24oCiAgICBwb29sS2V5LAogICAgSVBvb2xNYW5hZ2VyLk1vZGlmeVBvc2l0aW9uUGFyYW1zKHt0aWNrTG93ZXI6IHRpY2tMb3dlciwgdGlja1VwcGVyOiB0aWNrVXBwZXIsIGxpcXVpZGl0eURlbHRhOiBsaXF1aWRpdHl9KSwKICAgIG5ldyBieXRlcygwKQopOwo=", + }, ] const html = `
  • Provide Liquidity to a Uniswap v4 Pool
-

⚠️ Using the test router in production will lead to a loss of funds ⚠️

-

Using the v4-core provided test router, we can provide liquidity to a pool. These snippets should only be used for non-production, testing purposes

Creating liquidity involves using periphery contracts. It is not recommended to directly provide liquidity with poolManager.modifyPosition

+
+

Using the provided test router, we can provide liquidity to a pool. These snippets should only be used for non-production, testing purposes

+

(⚠️ Using the test router in production will lead to a loss of funds ⚠️ )

+

Providing liquidity involves 3 primary arguments:

    -
  • Which pool to swap on
  • +
  • Which pool to LP on
  • The range of the the liquidity, i.e. the upper and lower bounds
  • A liquidity value that determines input token amounts
@@ -64,49 +59,35 @@ const html = `
    } }

    Examples of Providing Liquidity to a V4 Pool

    -
    // SPDX-License-Identifier: MIT
    -pragma solidity ^0.8.20;
    +
    import {PoolModifyPositionTest} from "@uniswap/v4-core/contracts/test/PoolModifyPositionTest.sol";
     
    -import {IERC20} from "forge-std/interfaces/IERC20.sol";
    -import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol";
    -import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol";
    -import {PoolModifyPositionTest} from "@uniswap/v4-core/contracts/test/PoolModifyPositionTest.sol";
    -import {CurrencyLibrary, Currency} from "@uniswap/v4-core/contracts/types/Currency.sol";
    -
    -contract CreateLiquidityExampleInputs {
    -    using CurrencyLibrary for Currency;
    +PoolModifyPositionTest lpRouter = PoolModifyPositionTest(0x01);
    +address token0 = address(0x11);
    +address token1 = address(0x22);
    +address hookAddress = address(0x80);
     
    -    // set the router address
    -    PoolModifyPositionTest lpRouter = PoolModifyPositionTest(0x01);
    +// Pool that will receieve liquidity
    +PoolKey memory pool = PoolKey({
    +    currency0: Currency.wrap(token0),
    +    currency1: Currency.wrap(token1),
    +    fee: 3000,
    +    tickSpacing: 60,
    +    hooks: IHooks(hookAddress)
    +});
     
    -    function exampleA() external {
    -        address token0 = address(0x11);
    -        address token1 = address(0x22);
    +// approve tokens to the LP Router
    +IERC20(token0).approve(address(lpRouter), type(uint256).max);
    +IERC20(token1).approve(address(lpRouter), type(uint256).max);
     
    -        // Using a hookless pool
    -        PoolKey memory pool = PoolKey({
    -            currency0: Currency.wrap(token0),
    -            currency1: Currency.wrap(token1),
    -            fee: 3000,
    -            tickSpacing: 60,
    -            hooks: IHooks(address(0x0))
    -        });
    -
    -        // approve tokens to the LP Router
    -        IERC20(token0).approve(address(lpRouter), type(uint256).max);
    -        IERC20(token1).approve(address(lpRouter), type(uint256).max);
    -
    -        // Provide 10e18 worth of liquidity on the range of [-600, 600]
    -        int24 tickLower = -600;
    -        int24 tickUpper = 600;
    -        int256 liquidity = 10e18;
    -        lpRouter.modifyPosition(
    -            poolKey,
    -            IPoolManager.ModifyPositionParams({tickLower: tickLower, tickUpper: tickUpper, liquidityDelta: liquidity}),
    -            new bytes(0)
    -        );
    -    }
    -}
    +// Provide 10e18 worth of liquidity on the range of [-600, 600]
    +int24 tickLower = -600;
    +int24 tickUpper = 600;
    +int256 liquidity = 10e18;
    +lpRouter.modifyPosition(
    +    poolKey,
    +    IPoolManager.ModifyPositionParams({tickLower: tickLower, tickUpper: tickUpper, liquidityDelta: liquidity}),
    +    new bytes(0)
    +);
     
    ` export default html diff --git a/src/pages/create-liquidity/index.md b/src/pages/create-liquidity/index.md index 5cd0b1e15..153b849c2 100644 --- a/src/pages/create-liquidity/index.md +++ b/src/pages/create-liquidity/index.md @@ -5,23 +5,28 @@ description: Providing Liquidity to a Uniswap V4 Pool keywords: [liquidity, LP, lp, provide, provision, supply] --- -* Provide Liquidity to a Uniswap v4 Pool +- Provide Liquidity to a Uniswap v4 Pool -⚠️ Using the test router in production **will lead to a loss of funds** ⚠️ +Creating liquidity involves using periphery contracts. It is **not** recommended to directly provide liquidity with `poolManager.modifyPosition` + +--- -Using the `v4-core` provided *test* router, we can provide liquidity to a pool. These snippets should only be used for non-production, testing purposes +Using the provided _test_ router, we can provide liquidity to a pool. These snippets should only be used for non-production, testing purposes -Creating liquidity involves using periphery contracts. It is **not** recommended to directly provide liquidity with `poolManager.modifyPosition` +(⚠️ Using the test router in production **will lead to a loss of funds** ⚠️ ) + +--- Providing liquidity involves 3 primary arguments: -* Which pool to swap on -* The range of the the liquidity, i.e. the upper and lower bounds -* A `liquidity` value that determines input token amounts +- Which pool to LP on +- The range of the the liquidity, i.e. the upper and lower bounds +- A `liquidity` value that determines input token amounts Please see [LiquidityAmounts](https://github.com/Uniswap/v4-periphery/blob/main/contracts/libraries/LiquidityAmounts.sol) for calculating the `liquidity` value #### Expect Uniswap Labs to release an official contract around launch + ```solidity {{{CreateLiquidity}}} ``` diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 5969c7389..102b2d72c 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -8,9 +8,7 @@ import styles from "./index.module.css" import youTube from "../components/youtube.png" import { ROUTES, ROUTES_BY_CATEGORY, TRANSLATIONS } from "../nav" -const UPDATES = [ - "2023/10/18 - Initial V4 Snippets", -] +const UPDATES = ["2023/11/13 - Make snippets concise", "2023/10/18 - Initial V4 Snippets"] export default function HomePage() { const [query, setQuery] = useState("") @@ -111,17 +109,18 @@ export default function HomePage() { return (

    Uniswap v4 by Example

    -
    v 0.8.20
    +
    v0.8.22

    - an introduction to integrating and using Uniswap v4 with - simple examples + An introduction to integrating and using{" "} + Uniswap v4 through simple + examples

    diff --git a/src/pages/initialize/HookDataInit.solsnippet b/src/pages/initialize/HookDataInit.solsnippet new file mode 100644 index 000000000..7d6376c60 --- /dev/null +++ b/src/pages/initialize/HookDataInit.solsnippet @@ -0,0 +1,22 @@ +IPoolManager manager = IPoolManager(0x01); + +address hook = address(0x80); // prefix indicates the hook only has a beforeInitialize() function +address token0 = address(0x11); +address token1 = address(0x22); +uint24 swapFee = 3000; // 0.30% fee tier +int24 tickSpacing = 60; + +// floor(sqrt(1) * 2^96) +uint160 startingPrice = 79228162514264337593543950336; + +// Assume the custom hook requires a timestamp when initializing it +bytes memory hookData = abi.encode(block.timestamp); + +PoolKey memory pool = PoolKey({ + currency0: Currency.wrap(token0), + currency1: Currency.wrap(token1), + fee: swapFee, + tickSpacing: tickSpacing, + hooks: IHooks(hook) +}); +manager.initialize(pool, startingPrice, hookData); \ No newline at end of file diff --git a/src/pages/initialize/Hookless.solsnippet b/src/pages/initialize/Hookless.solsnippet new file mode 100644 index 000000000..747d8c340 --- /dev/null +++ b/src/pages/initialize/Hookless.solsnippet @@ -0,0 +1,21 @@ +IPoolManager manager = IPoolManager(0x01); + +address token0 = address(0x11); +address token1 = address(0x22); +uint24 swapFee = 500; // 0.05% fee tier +int24 tickSpacing = 10; + +// floor(sqrt(1) * 2^96) +uint160 startingPrice = 79228162514264337593543950336; + +// hookless pool doesnt expect any initialization data +bytes memory hookData = new bytes(0); + +PoolKey memory pool = PoolKey({ + currency0: Currency.wrap(token0), + currency1: Currency.wrap(token1), + fee: swapFee, + tickSpacing: tickSpacing, + hooks: IHooks(address(0x0)) // !!! Hookless pool is address(0x0) +}); +manager.initialize(pool, startingPrice, hookData); \ No newline at end of file diff --git a/src/pages/initialize/PoolInitializeExampleInputs.sol b/src/pages/initialize/PoolInitializeExampleInputs.sol deleted file mode 100644 index 83c443e10..000000000 --- a/src/pages/initialize/PoolInitializeExampleInputs.sol +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol"; -import {IHooks} from "@uniswap/v4-core/contracts/interfaces/IHooks.sol"; -import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol"; -import {CurrencyLibrary, Currency} from "@uniswap/v4-core/contracts/types/Currency.sol"; - -contract PoolInitializeExampleInputs { - using CurrencyLibrary for Currency; - - // set the pool manager address - IPoolManager manager = IPoolManager(0x01); - - /// @notice Initialize a hookless pool: - /// 0.05% swap fee - /// tick spacing of 10 - /// starting price of 1:1 - function exampleA() external { - address token0 = address(0x11); - address token1 = address(0x22); - uint24 swapFee = 500; - int24 tickSpacing = 10; - - // floor(sqrt(1) * 2^96) - uint160 startingPrice = 79228162514264337593543950336; - - // hookless pool doesnt expect any initialization data - bytes memory hookData = new bytes(0); - - PoolKey memory pool = PoolKey({ - currency0: Currency.wrap(token0), - currency1: Currency.wrap(token1), - fee: swapFee, - tickSpacing: tickSpacing, - hooks: IHooks(address(0x0)) - }); - manager.initialize(pool, startingPrice, hookData); - } - - /// @notice Initialize a pool with a custom hook: - /// 0.30% swap fee - /// tick spacing of 60 - /// starting price of 1:1 - /// hook's beforeInitialize() requires providing a timestamp - function exampleB() external { - address hook = address(0x80); // prefix indicates the hook only has a beforeInitialize() function - address token0 = address(0x11); - address token1 = address(0x22); - uint24 swapFee = 3000; - int24 tickSpacing = 60; - - // floor(sqrt(1) * 2^96) - uint160 startingPrice = 79228162514264337593543950336; - - // Assume the custom hook requires a timestamp when initializing it - bytes memory hookData = abi.encode(block.timestamp); - - PoolKey memory pool = PoolKey({ - currency0: Currency.wrap(token0), - currency1: Currency.wrap(token1), - fee: swapFee, - tickSpacing: tickSpacing, - hooks: IHooks(hook) - }); - manager.initialize(pool, startingPrice, hookData); - } -} diff --git a/src/pages/initialize/index.html.ts b/src/pages/initialize/index.html.ts index de8ac1b4b..8bb00760d 100644 --- a/src/pages/initialize/index.html.ts +++ b/src/pages/initialize/index.html.ts @@ -3,31 +3,28 @@ export const version = "0.8.20" export const title = "Initialize a Pool" export const description = "Initializing a pool in Uniswap v4" -export const keywords = [ - "pool", - "initialize", - "init", - "create", - "pair", - "factory", -] +export const keywords = ["pool", "initialize", "init", "create", "pair", "factory"] export const codes = [ - { - fileName: "PoolInitialize.sol", - code: "Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCB7SVBvb2xNYW5hZ2VyfSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy9pbnRlcmZhY2VzL0lQb29sTWFuYWdlci5zb2wiOwppbXBvcnQge0lIb29rc30gZnJvbSAiQHVuaXN3YXAvdjQtY29yZS9jb250cmFjdHMvaW50ZXJmYWNlcy9JSG9va3Muc29sIjsKaW1wb3J0IHtQb29sS2V5fSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy90eXBlcy9Qb29sS2V5LnNvbCI7CmltcG9ydCB7Q3VycmVuY3lMaWJyYXJ5LCBDdXJyZW5jeX0gZnJvbSAiQHVuaXN3YXAvdjQtY29yZS9jb250cmFjdHMvdHlwZXMvQ3VycmVuY3kuc29sIjsKCmNvbnRyYWN0IFBvb2xJbml0aWFsaXplIHsKICAgIHVzaW5nIEN1cnJlbmN5TGlicmFyeSBmb3IgQ3VycmVuY3k7CgogICAgLy8gc2V0IHRoZSBwb29sIG1hbmFnZXIgYWRkcmVzcwogICAgSVBvb2xNYW5hZ2VyIG1hbmFnZXIgPSBJUG9vbE1hbmFnZXIoMHgwMSk7CgogICAgZnVuY3Rpb24gaW5pdCgKICAgICAgICBhZGRyZXNzIHRva2VuMCwKICAgICAgICBhZGRyZXNzIHRva2VuMSwKICAgICAgICB1aW50MjQgc3dhcEZlZSwKICAgICAgICBpbnQyNCB0aWNrU3BhY2luZywKICAgICAgICBhZGRyZXNzIGhvb2ssCiAgICAgICAgdWludDE2MCBzcXJ0UHJpY2VYOTYsCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgaG9va0RhdGEKICAgICkgZXh0ZXJuYWwgewogICAgICAgIC8vIHNvcnQgeW91ciB0b2tlbnMhIHY0IHJlcXVpcmVzIHRva2VuMCA8IHRva2VuMQogICAgICAgIGlmICh0b2tlbjAgPiB0b2tlbjEpIHsKICAgICAgICAgICAgKHRva2VuMCwgdG9rZW4xKSA9ICh0b2tlbjEsIHRva2VuMCk7CiAgICAgICAgfQoKICAgICAgICBQb29sS2V5IG1lbW9yeSBwb29sID0gUG9vbEtleSh7CiAgICAgICAgICAgIGN1cnJlbmN5MDogQ3VycmVuY3kud3JhcCh0b2tlbjApLAogICAgICAgICAgICBjdXJyZW5jeTE6IEN1cnJlbmN5LndyYXAodG9rZW4xKSwKICAgICAgICAgICAgZmVlOiBzd2FwRmVlLAogICAgICAgICAgICB0aWNrU3BhY2luZzogdGlja1NwYWNpbmcsCiAgICAgICAgICAgIGhvb2tzOiBJSG9va3MoaG9vaykKICAgICAgICB9KTsKICAgICAgICBtYW5hZ2VyLmluaXRpYWxpemUocG9vbCwgc3FydFByaWNlWDk2LCBob29rRGF0YSk7CiAgICB9Cn0K", - }, - { - fileName: "PoolInitializeExampleInputs.sol", - code: "Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCB7SVBvb2xNYW5hZ2VyfSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy9pbnRlcmZhY2VzL0lQb29sTWFuYWdlci5zb2wiOwppbXBvcnQge0lIb29rc30gZnJvbSAiQHVuaXN3YXAvdjQtY29yZS9jb250cmFjdHMvaW50ZXJmYWNlcy9JSG9va3Muc29sIjsKaW1wb3J0IHtQb29sS2V5fSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy90eXBlcy9Qb29sS2V5LnNvbCI7CmltcG9ydCB7Q3VycmVuY3lMaWJyYXJ5LCBDdXJyZW5jeX0gZnJvbSAiQHVuaXN3YXAvdjQtY29yZS9jb250cmFjdHMvdHlwZXMvQ3VycmVuY3kuc29sIjsKCmNvbnRyYWN0IFBvb2xJbml0aWFsaXplRXhhbXBsZUlucHV0cyB7CiAgICB1c2luZyBDdXJyZW5jeUxpYnJhcnkgZm9yIEN1cnJlbmN5OwoKICAgIC8vIHNldCB0aGUgcG9vbCBtYW5hZ2VyIGFkZHJlc3MKICAgIElQb29sTWFuYWdlciBtYW5hZ2VyID0gSVBvb2xNYW5hZ2VyKDB4MDEpOwoKICAgIC8vLyBAbm90aWNlIEluaXRpYWxpemUgYSBob29rbGVzcyBwb29sOgogICAgLy8vICAgICAwLjA1JSBzd2FwIGZlZQogICAgLy8vICAgICB0aWNrIHNwYWNpbmcgb2YgMTAKICAgIC8vLyAgICAgc3RhcnRpbmcgcHJpY2Ugb2YgMToxCiAgICBmdW5jdGlvbiBleGFtcGxlQSgpIGV4dGVybmFsIHsKICAgICAgICBhZGRyZXNzIHRva2VuMCA9IGFkZHJlc3MoMHgxMSk7CiAgICAgICAgYWRkcmVzcyB0b2tlbjEgPSBhZGRyZXNzKDB4MjIpOwogICAgICAgIHVpbnQyNCBzd2FwRmVlID0gNTAwOwogICAgICAgIGludDI0IHRpY2tTcGFjaW5nID0gMTA7CgogICAgICAgIC8vIGZsb29yKHNxcnQoMSkgKiAyXjk2KQogICAgICAgIHVpbnQxNjAgc3RhcnRpbmdQcmljZSA9IDc5MjI4MTYyNTE0MjY0MzM3NTkzNTQzOTUwMzM2OwoKICAgICAgICAvLyBob29rbGVzcyBwb29sIGRvZXNudCBleHBlY3QgYW55IGluaXRpYWxpemF0aW9uIGRhdGEKICAgICAgICBieXRlcyBtZW1vcnkgaG9va0RhdGEgPSBuZXcgYnl0ZXMoMCk7CgogICAgICAgIFBvb2xLZXkgbWVtb3J5IHBvb2wgPSBQb29sS2V5KHsKICAgICAgICAgICAgY3VycmVuY3kwOiBDdXJyZW5jeS53cmFwKHRva2VuMCksCiAgICAgICAgICAgIGN1cnJlbmN5MTogQ3VycmVuY3kud3JhcCh0b2tlbjEpLAogICAgICAgICAgICBmZWU6IHN3YXBGZWUsCiAgICAgICAgICAgIHRpY2tTcGFjaW5nOiB0aWNrU3BhY2luZywKICAgICAgICAgICAgaG9va3M6IElIb29rcyhhZGRyZXNzKDB4MCkpCiAgICAgICAgfSk7CiAgICAgICAgbWFuYWdlci5pbml0aWFsaXplKHBvb2wsIHN0YXJ0aW5nUHJpY2UsIGhvb2tEYXRhKTsKICAgIH0KCiAgICAvLy8gQG5vdGljZSBJbml0aWFsaXplIGEgcG9vbCB3aXRoIGEgY3VzdG9tIGhvb2s6CiAgICAvLy8gICAgIDAuMzAlIHN3YXAgZmVlCiAgICAvLy8gICAgIHRpY2sgc3BhY2luZyBvZiA2MAogICAgLy8vICAgICBzdGFydGluZyBwcmljZSBvZiAxOjEKICAgIC8vLyAgICAgaG9vaydzIGJlZm9yZUluaXRpYWxpemUoKSByZXF1aXJlcyBwcm92aWRpbmcgYSB0aW1lc3RhbXAKICAgIGZ1bmN0aW9uIGV4YW1wbGVCKCkgZXh0ZXJuYWwgewogICAgICAgIGFkZHJlc3MgaG9vayA9IGFkZHJlc3MoMHg4MCk7IC8vIHByZWZpeCBpbmRpY2F0ZXMgdGhlIGhvb2sgb25seSBoYXMgYSBiZWZvcmVJbml0aWFsaXplKCkgZnVuY3Rpb24KICAgICAgICBhZGRyZXNzIHRva2VuMCA9IGFkZHJlc3MoMHgxMSk7CiAgICAgICAgYWRkcmVzcyB0b2tlbjEgPSBhZGRyZXNzKDB4MjIpOwogICAgICAgIHVpbnQyNCBzd2FwRmVlID0gMzAwMDsKICAgICAgICBpbnQyNCB0aWNrU3BhY2luZyA9IDYwOwoKICAgICAgICAvLyBmbG9vcihzcXJ0KDEpICogMl45NikKICAgICAgICB1aW50MTYwIHN0YXJ0aW5nUHJpY2UgPSA3OTIyODE2MjUxNDI2NDMzNzU5MzU0Mzk1MDMzNjsKCiAgICAgICAgLy8gQXNzdW1lIHRoZSBjdXN0b20gaG9vayByZXF1aXJlcyBhIHRpbWVzdGFtcCB3aGVuIGluaXRpYWxpemluZyBpdAogICAgICAgIGJ5dGVzIG1lbW9yeSBob29rRGF0YSA9IGFiaS5lbmNvZGUoYmxvY2sudGltZXN0YW1wKTsKCiAgICAgICAgUG9vbEtleSBtZW1vcnkgcG9vbCA9IFBvb2xLZXkoewogICAgICAgICAgICBjdXJyZW5jeTA6IEN1cnJlbmN5LndyYXAodG9rZW4wKSwKICAgICAgICAgICAgY3VycmVuY3kxOiBDdXJyZW5jeS53cmFwKHRva2VuMSksCiAgICAgICAgICAgIGZlZTogc3dhcEZlZSwKICAgICAgICAgICAgdGlja1NwYWNpbmc6IHRpY2tTcGFjaW5nLAogICAgICAgICAgICBob29rczogSUhvb2tzKGhvb2spCiAgICAgICAgfSk7CiAgICAgICAgbWFuYWdlci5pbml0aWFsaXplKHBvb2wsIHN0YXJ0aW5nUHJpY2UsIGhvb2tEYXRhKTsKICAgIH0KfQo=", - }, + { + fileName: "HookDataInit.sol", + code: "SVBvb2xNYW5hZ2VyIG1hbmFnZXIgPSBJUG9vbE1hbmFnZXIoMHgwMSk7CgphZGRyZXNzIGhvb2sgPSBhZGRyZXNzKDB4ODApOyAvLyBwcmVmaXggaW5kaWNhdGVzIHRoZSBob29rIG9ubHkgaGFzIGEgYmVmb3JlSW5pdGlhbGl6ZSgpIGZ1bmN0aW9uCmFkZHJlc3MgdG9rZW4wID0gYWRkcmVzcygweDExKTsKYWRkcmVzcyB0b2tlbjEgPSBhZGRyZXNzKDB4MjIpOwp1aW50MjQgc3dhcEZlZSA9IDMwMDA7IC8vIDAuMDUlIGZlZSB0aWVyCmludDI0IHRpY2tTcGFjaW5nID0gNjA7CgovLyBmbG9vcihzcXJ0KDEpICogMl45NikKdWludDE2MCBzdGFydGluZ1ByaWNlID0gNzkyMjgxNjI1MTQyNjQzMzc1OTM1NDM5NTAzMzY7CgovLyBBc3N1bWUgdGhlIGN1c3RvbSBob29rIHJlcXVpcmVzIGEgdGltZXN0YW1wIHdoZW4gaW5pdGlhbGl6aW5nIGl0CmJ5dGVzIG1lbW9yeSBob29rRGF0YSA9IGFiaS5lbmNvZGUoYmxvY2sudGltZXN0YW1wKTsKClBvb2xLZXkgbWVtb3J5IHBvb2wgPSBQb29sS2V5KHsKICAgIGN1cnJlbmN5MDogQ3VycmVuY3kud3JhcCh0b2tlbjApLAogICAgY3VycmVuY3kxOiBDdXJyZW5jeS53cmFwKHRva2VuMSksCiAgICBmZWU6IHN3YXBGZWUsCiAgICB0aWNrU3BhY2luZzogdGlja1NwYWNpbmcsCiAgICBob29rczogSUhvb2tzKGhvb2spCn0pOwptYW5hZ2VyLmluaXRpYWxpemUocG9vbCwgc3RhcnRpbmdQcmljZSwgaG9va0RhdGEpOw==", + }, + { + fileName: "Hookless.sol", + code: "SVBvb2xNYW5hZ2VyIG1hbmFnZXIgPSBJUG9vbE1hbmFnZXIoMHgwMSk7CgphZGRyZXNzIHRva2VuMCA9IGFkZHJlc3MoMHgxMSk7CmFkZHJlc3MgdG9rZW4xID0gYWRkcmVzcygweDIyKTsKdWludDI0IHN3YXBGZWUgPSA1MDA7IC8vIDAuMDUlIGZlZSB0aWVyCmludDI0IHRpY2tTcGFjaW5nID0gMTA7CgovLyBmbG9vcihzcXJ0KDEpICogMl45NikKdWludDE2MCBzdGFydGluZ1ByaWNlID0gNzkyMjgxNjI1MTQyNjQzMzc1OTM1NDM5NTAzMzY7CgovLyBob29rbGVzcyBwb29sIGRvZXNudCBleHBlY3QgYW55IGluaXRpYWxpemF0aW9uIGRhdGEKYnl0ZXMgbWVtb3J5IGhvb2tEYXRhID0gbmV3IGJ5dGVzKDApOwoKUG9vbEtleSBtZW1vcnkgcG9vbCA9IFBvb2xLZXkoewogICAgY3VycmVuY3kwOiBDdXJyZW5jeS53cmFwKHRva2VuMCksCiAgICBjdXJyZW5jeTE6IEN1cnJlbmN5LndyYXAodG9rZW4xKSwKICAgIGZlZTogc3dhcEZlZSwKICAgIHRpY2tTcGFjaW5nOiB0aWNrU3BhY2luZywKICAgIGhvb2tzOiBJSG9va3MoYWRkcmVzcygweDApKSAvLyAhISEgSG9va2xlc3MgcG9vbCBpcyBhZGRyZXNzKDB4MCkKfSk7Cm1hbmFnZXIuaW5pdGlhbGl6ZShwb29sLCBzdGFydGluZ1ByaWNlLCBob29rRGF0YSk7", + }, + { + fileName: "PoolInitialize.sol", + code: "Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCB7SVBvb2xNYW5hZ2VyfSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy9pbnRlcmZhY2VzL0lQb29sTWFuYWdlci5zb2wiOwppbXBvcnQge0lIb29rc30gZnJvbSAiQHVuaXN3YXAvdjQtY29yZS9jb250cmFjdHMvaW50ZXJmYWNlcy9JSG9va3Muc29sIjsKaW1wb3J0IHtQb29sS2V5fSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy90eXBlcy9Qb29sS2V5LnNvbCI7CmltcG9ydCB7Q3VycmVuY3lMaWJyYXJ5LCBDdXJyZW5jeX0gZnJvbSAiQHVuaXN3YXAvdjQtY29yZS9jb250cmFjdHMvdHlwZXMvQ3VycmVuY3kuc29sIjsKCmNvbnRyYWN0IFBvb2xJbml0aWFsaXplIHsKICAgIHVzaW5nIEN1cnJlbmN5TGlicmFyeSBmb3IgQ3VycmVuY3k7CgogICAgLy8gc2V0IHRoZSBwb29sIG1hbmFnZXIgYWRkcmVzcwogICAgSVBvb2xNYW5hZ2VyIG1hbmFnZXIgPSBJUG9vbE1hbmFnZXIoMHgwMSk7CgogICAgZnVuY3Rpb24gaW5pdCgKICAgICAgICBhZGRyZXNzIHRva2VuMCwKICAgICAgICBhZGRyZXNzIHRva2VuMSwKICAgICAgICB1aW50MjQgc3dhcEZlZSwKICAgICAgICBpbnQyNCB0aWNrU3BhY2luZywKICAgICAgICBhZGRyZXNzIGhvb2ssCiAgICAgICAgdWludDE2MCBzcXJ0UHJpY2VYOTYsCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgaG9va0RhdGEKICAgICkgZXh0ZXJuYWwgewogICAgICAgIC8vIHNvcnQgeW91ciB0b2tlbnMhIHY0IHJlcXVpcmVzIHRva2VuMCA8IHRva2VuMQogICAgICAgIGlmICh0b2tlbjAgPiB0b2tlbjEpIHsKICAgICAgICAgICAgKHRva2VuMCwgdG9rZW4xKSA9ICh0b2tlbjEsIHRva2VuMCk7CiAgICAgICAgfQoKICAgICAgICBQb29sS2V5IG1lbW9yeSBwb29sID0gUG9vbEtleSh7CiAgICAgICAgICAgIGN1cnJlbmN5MDogQ3VycmVuY3kud3JhcCh0b2tlbjApLAogICAgICAgICAgICBjdXJyZW5jeTE6IEN1cnJlbmN5LndyYXAodG9rZW4xKSwKICAgICAgICAgICAgZmVlOiBzd2FwRmVlLAogICAgICAgICAgICB0aWNrU3BhY2luZzogdGlja1NwYWNpbmcsCiAgICAgICAgICAgIGhvb2tzOiBJSG9va3MoaG9vaykKICAgICAgICB9KTsKICAgICAgICBtYW5hZ2VyLmluaXRpYWxpemUocG9vbCwgc3FydFByaWNlWDk2LCBob29rRGF0YSk7CiAgICB9Cn0K", + }, ] const html = `
    • Create a Uniswap v4 Pool
    -

    A single trading pair (ETH/USDC), can exist as an infinite number of pools in v4. Uniswap v4 does not restrict fee tiers to 1%, 0.30%, or 0.05%. The same trading pair can also have an infinite number of hooks.

    -

    Initializing a V3 Pair involved deploying a contract via the factory. In V4, pools are initialized and managed by a single contract: PoolManager

    +

    A single trading pair (ETH/USDC), can exist as an infinite number of pools in v4. Uniswap v4 does not restrict fee tiers to 1%, 0.30%, or 0.05%. A trading pair exists as many pools, but one pool has one hook contract

    +

    In V4, pools are initialized and managed by a single contract: PoolManager

    Think of a PoolKey as the unique identifier for a pool, i.e. like a v3 pair's contract address

    Creating a Pool is determined by 5 primary arguments:

      @@ -77,74 +74,50 @@ const html = `
        }

    Examples of Initializing a V4 Pool

    Hooks are not mandatory, you can create a pool without a hook

    -
    // SPDX-License-Identifier: MIT
    -pragma solidity ^0.8.20;
    -
    -import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol";
    -import {IHooks} from "@uniswap/v4-core/contracts/interfaces/IHooks.sol";
    -import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol";
    -import {CurrencyLibrary, Currency} from "@uniswap/v4-core/contracts/types/Currency.sol";
    -
    -contract PoolInitializeExampleInputs {
    -    using CurrencyLibrary for Currency;
    -
    -    // set the pool manager address
    -    IPoolManager manager = IPoolManager(0x01);
    -
    -    /// @notice Initialize a hookless pool:
    -    ///     0.05% swap fee
    -    ///     tick spacing of 10
    -    ///     starting price of 1:1
    -    function exampleA() external {
    -        address token0 = address(0x11);
    -        address token1 = address(0x22);
    -        uint24 swapFee = 500;
    -        int24 tickSpacing = 10;
    -
    -        // floor(sqrt(1) * 2^96)
    -        uint160 startingPrice = 79228162514264337593543950336;
    -
    -        // hookless pool doesnt expect any initialization data
    -        bytes memory hookData = new bytes(0);
    -
    -        PoolKey memory pool = PoolKey({
    -            currency0: Currency.wrap(token0),
    -            currency1: Currency.wrap(token1),
    -            fee: swapFee,
    -            tickSpacing: tickSpacing,
    -            hooks: IHooks(address(0x0))
    -        });
    -        manager.initialize(pool, startingPrice, hookData);
    -    }
    -
    -    /// @notice Initialize a pool with a custom hook:
    -    ///     0.30% swap fee
    -    ///     tick spacing of 60
    -    ///     starting price of 1:1
    -    ///     hook's beforeInitialize() requires providing a timestamp
    -    function exampleB() external {
    -        address hook = address(0x80); // prefix indicates the hook only has a beforeInitialize() function
    -        address token0 = address(0x11);
    -        address token1 = address(0x22);
    -        uint24 swapFee = 3000;
    -        int24 tickSpacing = 60;
    -
    -        // floor(sqrt(1) * 2^96)
    -        uint160 startingPrice = 79228162514264337593543950336;
    -
    -        // Assume the custom hook requires a timestamp when initializing it
    -        bytes memory hookData = abi.encode(block.timestamp);
    -
    -        PoolKey memory pool = PoolKey({
    -            currency0: Currency.wrap(token0),
    -            currency1: Currency.wrap(token1),
    -            fee: swapFee,
    -            tickSpacing: tickSpacing,
    -            hooks: IHooks(hook)
    -        });
    -        manager.initialize(pool, startingPrice, hookData);
    -    }
    -}
    +
    IPoolManager manager = IPoolManager(0x01);
    +
    +address token0 = address(0x11);
    +address token1 = address(0x22);
    +uint24 swapFee = 500; // 0.05% fee tier
    +int24 tickSpacing = 10;
    +
    +// floor(sqrt(1) * 2^96)
    +uint160 startingPrice = 79228162514264337593543950336;
    +
    +// hookless pool doesnt expect any initialization data
    +bytes memory hookData = new bytes(0);
    +
    +PoolKey memory pool = PoolKey({
    +    currency0: Currency.wrap(token0),
    +    currency1: Currency.wrap(token1),
    +    fee: swapFee,
    +    tickSpacing: tickSpacing,
    +    hooks: IHooks(address(0x0)) // !!! Hookless pool is address(0x0)
    +});
    +manager.initialize(pool, startingPrice, hookData);
    +

    Some hooks may require initialization data, i.e. block.timestamp

    +
    IPoolManager manager = IPoolManager(0x01);
    +
    +address hook = address(0x80); // prefix indicates the hook only has a beforeInitialize() function
    +address token0 = address(0x11);
    +address token1 = address(0x22);
    +uint24 swapFee = 3000; // 0.05% fee tier
    +int24 tickSpacing = 60;
    +
    +// floor(sqrt(1) * 2^96)
    +uint160 startingPrice = 79228162514264337593543950336;
    +
    +// Assume the custom hook requires a timestamp when initializing it
    +bytes memory hookData = abi.encode(block.timestamp);
    +
    +PoolKey memory pool = PoolKey({
    +    currency0: Currency.wrap(token0),
    +    currency1: Currency.wrap(token1),
    +    fee: swapFee,
    +    tickSpacing: tickSpacing,
    +    hooks: IHooks(hook)
    +});
    +manager.initialize(pool, startingPrice, hookData);
     
    ` export default html diff --git a/src/pages/initialize/index.md b/src/pages/initialize/index.md index 79053779f..aa786de04 100644 --- a/src/pages/initialize/index.md +++ b/src/pages/initialize/index.md @@ -5,21 +5,21 @@ description: Initializing a pool in Uniswap v4 keywords: [pool, initialize, init, create, pair, factory] --- -* Create a Uniswap v4 Pool +- Create a Uniswap v4 Pool -A single trading pair (*ETH/USDC*), can exist as an infinite number of pools in v4. Uniswap v4 does **not** restrict fee tiers to 1%, 0.30%, or 0.05%. The same trading pair can also have an infinite number of hooks. +A single trading pair (_ETH/USDC_), can exist as an infinite number of pools in v4. Uniswap v4 does **not** restrict fee tiers to 1%, 0.30%, or 0.05%. A trading pair exists as many pools, but one _pool_ has one _hook contract_ -Initializing a V3 Pair involved deploying a contract via the factory. In V4, pools are initialized and managed by a single contract: `PoolManager` +In V4, pools are initialized and managed by a single contract: `PoolManager` -*Think of a `PoolKey` as the unique identifier for a pool, i.e. like a v3 pair's contract address* +_Think of a `PoolKey` as the unique identifier for a pool, i.e. like a v3 pair's contract address_ Creating a Pool is determined by 5 primary arguments: -* Trading pair *currency0, currency1* -* Fee tier -* Tick spacing -* Hook -* Starting Price +- Trading pair _currency0, currency1_ +- Fee tier +- Tick spacing +- Hook +- Starting Price ```solidity {{{PoolInitialize}}} @@ -27,8 +27,14 @@ Creating a Pool is determined by 5 primary arguments: ### Examples of Initializing a V4 Pool -*Hooks are not mandatory, you can create a pool without a hook* +_Hooks are not mandatory, you can create a pool without a hook_ ```solidity -{{{PoolInitializeExampleInputs}}} +{{{Hookless}}} +``` + +_Some hooks may require initialization data, i.e. `block.timestamp`_ + +```solidity +{{{HookDataInit}}} ``` diff --git a/src/pages/swap/SwapExampleInputs.sol b/src/pages/swap/SwapExampleInputs.sol deleted file mode 100644 index cba894462..000000000 --- a/src/pages/swap/SwapExampleInputs.sol +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol"; -import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol"; -import {PoolSwapTest} from "@uniswap/v4-core/contracts/test/PoolSwapTest.sol"; -import {TickMath} from "@uniswap/v4-core/contracts/libraries/TickMath.sol"; - -contract SwapExampleInputs { - // set the router address - PoolSwapTest swapRouter = PoolSwapTest(0x01); - - // slippage tolerance to allow for unlimited price impact - uint160 public constant MIN_PRICE_LIMIT = TickMath.MIN_SQRT_RATIO + 1; - uint160 public constant MAX_PRICE_LIMIT = TickMath.MAX_SQRT_RATIO - 1; - - function exampleA() internal { - address token0 = address(0x11); - address token1 = address(0x22); - - // Using a hookless pool - PoolKey memory pool = PoolKey({ - currency0: Currency.wrap(token0), - currency1: Currency.wrap(token1), - fee: 3000, - tickSpacing: 60, - hooks: IHooks(address(0x0)) - }); - - // approve tokens to the swap router - IERC20(token0).approve(address(swapRouter), type(uint256).max); - IERC20(token1).approve(address(swapRouter), type(uint256).max); - - // ---------------------------- // - // Swap 1e18 token0 into token1 - // ---------------------------- // - bool zeroForOne = true; - IPoolManager.SwapParams memory params = IPoolManager.SwapParams({ - zeroForOne: zeroForOne, - amountSpecified: 1e18, - sqrtPriceLimitX96: zeroForOne ? MIN_PRICE_LIMIT : MAX_PRICE_LIMIT // unlimited impact - }); - - // in v4, users have the option to receieve native ERC20s or wrapped ERC1155 tokens - // here, we'll take the ERC20s - PoolSwapTest.TestSettings memory testSettings = - PoolSwapTest.TestSettings({withdrawTokens: true, settleUsingTransfer: true}); - - bytes memory hookData = new bytes(0); // no hook data on the hookless pool - swapRouter.swap(key, params, testSettings, hookData); - } -} diff --git a/src/pages/swap/SwapExampleInputs.solsnippet b/src/pages/swap/SwapExampleInputs.solsnippet new file mode 100644 index 000000000..3e9a0b546 --- /dev/null +++ b/src/pages/swap/SwapExampleInputs.solsnippet @@ -0,0 +1,39 @@ +PoolSwapTest swapRouter = PoolSwapTest(0x01); + +// slippage tolerance to allow for unlimited price impact +uint160 public constant MIN_PRICE_LIMIT = TickMath.MIN_SQRT_RATIO + 1; +uint160 public constant MAX_PRICE_LIMIT = TickMath.MAX_SQRT_RATIO - 1; + +address token0 = address(0x11); +address token1 = address(0x22); +address hookAddr = address(0x33); + +PoolKey memory pool = PoolKey({ + currency0: Currency.wrap(token0), + currency1: Currency.wrap(token1), + fee: 3000, + tickSpacing: 60, + hooks: IHooks(hookAddr) +}); + +// approve tokens to the swap router +IERC20(token0).approve(address(swapRouter), type(uint256).max); +IERC20(token1).approve(address(swapRouter), type(uint256).max); + +// ---------------------------- // +// Swap 1e18 token0 into token1 +// ---------------------------- // +bool zeroForOne = true; +IPoolManager.SwapParams memory params = IPoolManager.SwapParams({ + zeroForOne: zeroForOne, + amountSpecified: 1e18, + sqrtPriceLimitX96: zeroForOne ? MIN_PRICE_LIMIT : MAX_PRICE_LIMIT // unlimited impact +}); + +// in v4, users have the option to receieve native ERC20s or wrapped ERC1155 tokens +// here, we'll take the ERC20s +PoolSwapTest.TestSettings memory testSettings = + PoolSwapTest.TestSettings({withdrawTokens: true, settleUsingTransfer: true}); + +bytes memory hookData = new bytes(0); // no hook data on the hookless pool +swapRouter.swap(key, params, testSettings, hookData); diff --git a/src/pages/swap/index.html.ts b/src/pages/swap/index.html.ts index fe341323c..4a1de3b13 100644 --- a/src/pages/swap/index.html.ts +++ b/src/pages/swap/index.html.ts @@ -3,28 +3,26 @@ export const version = "0.8.20" export const title = "Single Swap" export const description = "Swapping on a single pool" -export const keywords = [ - "swap", - "trade", - "swapping", -] +export const keywords = ["swap", "trade", "swapping"] export const codes = [ - { - fileName: "Swap.sol", - code: "Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCB7SVBvb2xNYW5hZ2VyfSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy9pbnRlcmZhY2VzL0lQb29sTWFuYWdlci5zb2wiOwppbXBvcnQge1Bvb2xLZXl9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL3R5cGVzL1Bvb2xLZXkuc29sIjsKaW1wb3J0IHtQb29sU3dhcFRlc3R9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL3Rlc3QvUG9vbFN3YXBUZXN0LnNvbCI7CmltcG9ydCB7VGlja01hdGh9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL2xpYnJhcmllcy9UaWNrTWF0aC5zb2wiOwoKY29udHJhY3QgU3dhcCB7CiAgICAvLyBzZXQgdGhlIHJvdXRlciBhZGRyZXNzCiAgICBQb29sU3dhcFRlc3Qgc3dhcFJvdXRlciA9IFBvb2xTd2FwVGVzdCgweDAxKTsKCiAgICAvLyBzbGlwcGFnZSB0b2xlcmFuY2UgdG8gYWxsb3cgZm9yIHVubGltaXRlZCBwcmljZSBpbXBhY3QKICAgIHVpbnQxNjAgcHVibGljIGNvbnN0YW50IE1JTl9QUklDRV9MSU1JVCA9IFRpY2tNYXRoLk1JTl9TUVJUX1JBVElPICsgMTsKICAgIHVpbnQxNjAgcHVibGljIGNvbnN0YW50IE1BWF9QUklDRV9MSU1JVCA9IFRpY2tNYXRoLk1BWF9TUVJUX1JBVElPIC0gMTsKCiAgICAvLy8gQG5vdGljZSBTd2FwIHRva2VucwogICAgLy8vIEBwYXJhbSBrZXkgdGhlIHBvb2wgd2hlcmUgdGhlIHN3YXAgaXMgaGFwcGVuaW5nCiAgICAvLy8gQHBhcmFtIGFtb3VudFNwZWNpZmllZCB0aGUgYW1vdW50IG9mIHRva2VucyB0byBzd2FwCiAgICAvLy8gQHBhcmFtIHplcm9Gb3JPbmUgd2hldGhlciB0aGUgc3dhcCBpcyB0b2tlbjAgLT4gdG9rZW4xIG9yIHRva2VuMSAtPiB0b2tlbjAKICAgIC8vLyBAcGFyYW0gaG9va0RhdGEgYW55IGRhdGEgdG8gYmUgcGFzc2VkIHRvIHRoZSBwb29sJ3MgaG9vawogICAgZnVuY3Rpb24gc3dhcChQb29sS2V5IG1lbW9yeSBrZXksIGludDI1NiBhbW91bnRTcGVjaWZpZWQsIGJvb2wgemVyb0Zvck9uZSwgYnl0ZXMgbWVtb3J5IGhvb2tEYXRhKSBpbnRlcm5hbCB7CiAgICAgICAgSVBvb2xNYW5hZ2VyLlN3YXBQYXJhbXMgbWVtb3J5IHBhcmFtcyA9IElQb29sTWFuYWdlci5Td2FwUGFyYW1zKHsKICAgICAgICAgICAgemVyb0Zvck9uZTogemVyb0Zvck9uZSwKICAgICAgICAgICAgYW1vdW50U3BlY2lmaWVkOiBhbW91bnRTcGVjaWZpZWQsCiAgICAgICAgICAgIHNxcnRQcmljZUxpbWl0WDk2OiB6ZXJvRm9yT25lID8gTUlOX1BSSUNFX0xJTUlUIDogTUFYX1BSSUNFX0xJTUlUIC8vIHVubGltaXRlZCBpbXBhY3QKICAgICAgICB9KTsKCiAgICAgICAgLy8gaW4gdjQsIHVzZXJzIGhhdmUgdGhlIG9wdGlvbiB0byByZWNlaWV2ZSBuYXRpdmUgRVJDMjBzIG9yIHdyYXBwZWQgRVJDMTE1NSB0b2tlbnMKICAgICAgICAvLyBoZXJlLCB3ZSdsbCB0YWtlIHRoZSBFUkMyMHMKICAgICAgICBQb29sU3dhcFRlc3QuVGVzdFNldHRpbmdzIG1lbW9yeSB0ZXN0U2V0dGluZ3MgPQogICAgICAgICAgICBQb29sU3dhcFRlc3QuVGVzdFNldHRpbmdzKHt3aXRoZHJhd1Rva2VuczogdHJ1ZSwgc2V0dGxlVXNpbmdUcmFuc2ZlcjogdHJ1ZX0pOwoKICAgICAgICBzd2FwUm91dGVyLnN3YXAoa2V5LCBwYXJhbXMsIHRlc3RTZXR0aW5ncywgaG9va0RhdGEpOwogICAgfQp9Cg==", - }, - { - fileName: "SwapExampleInputs.sol", - code: "Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCB7SVBvb2xNYW5hZ2VyfSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy9pbnRlcmZhY2VzL0lQb29sTWFuYWdlci5zb2wiOwppbXBvcnQge1Bvb2xLZXl9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL3R5cGVzL1Bvb2xLZXkuc29sIjsKaW1wb3J0IHtQb29sU3dhcFRlc3R9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL3Rlc3QvUG9vbFN3YXBUZXN0LnNvbCI7CmltcG9ydCB7VGlja01hdGh9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL2xpYnJhcmllcy9UaWNrTWF0aC5zb2wiOwoKY29udHJhY3QgU3dhcEV4YW1wbGVJbnB1dHMgewogICAgLy8gc2V0IHRoZSByb3V0ZXIgYWRkcmVzcwogICAgUG9vbFN3YXBUZXN0IHN3YXBSb3V0ZXIgPSBQb29sU3dhcFRlc3QoMHgwMSk7CgogICAgLy8gc2xpcHBhZ2UgdG9sZXJhbmNlIHRvIGFsbG93IGZvciB1bmxpbWl0ZWQgcHJpY2UgaW1wYWN0CiAgICB1aW50MTYwIHB1YmxpYyBjb25zdGFudCBNSU5fUFJJQ0VfTElNSVQgPSBUaWNrTWF0aC5NSU5fU1FSVF9SQVRJTyArIDE7CiAgICB1aW50MTYwIHB1YmxpYyBjb25zdGFudCBNQVhfUFJJQ0VfTElNSVQgPSBUaWNrTWF0aC5NQVhfU1FSVF9SQVRJTyAtIDE7CgogICAgZnVuY3Rpb24gZXhhbXBsZUEoKSBpbnRlcm5hbCB7CiAgICAgICAgYWRkcmVzcyB0b2tlbjAgPSBhZGRyZXNzKDB4MTEpOwogICAgICAgIGFkZHJlc3MgdG9rZW4xID0gYWRkcmVzcygweDIyKTsKCiAgICAgICAgLy8gVXNpbmcgYSBob29rbGVzcyBwb29sCiAgICAgICAgUG9vbEtleSBtZW1vcnkgcG9vbCA9IFBvb2xLZXkoewogICAgICAgICAgICBjdXJyZW5jeTA6IEN1cnJlbmN5LndyYXAodG9rZW4wKSwKICAgICAgICAgICAgY3VycmVuY3kxOiBDdXJyZW5jeS53cmFwKHRva2VuMSksCiAgICAgICAgICAgIGZlZTogMzAwMCwKICAgICAgICAgICAgdGlja1NwYWNpbmc6IDYwLAogICAgICAgICAgICBob29rczogSUhvb2tzKGFkZHJlc3MoMHgwKSkKICAgICAgICB9KTsKCiAgICAgICAgLy8gYXBwcm92ZSB0b2tlbnMgdG8gdGhlIHN3YXAgcm91dGVyCiAgICAgICAgSUVSQzIwKHRva2VuMCkuYXBwcm92ZShhZGRyZXNzKHN3YXBSb3V0ZXIpLCB0eXBlKHVpbnQyNTYpLm1heCk7CiAgICAgICAgSUVSQzIwKHRva2VuMSkuYXBwcm92ZShhZGRyZXNzKHN3YXBSb3V0ZXIpLCB0eXBlKHVpbnQyNTYpLm1heCk7CgogICAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gLy8KICAgICAgICAvLyBTd2FwIDFlMTggdG9rZW4wIGludG8gdG9rZW4xCiAgICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAvLwogICAgICAgIGJvb2wgemVyb0Zvck9uZSA9IHRydWU7CiAgICAgICAgSVBvb2xNYW5hZ2VyLlN3YXBQYXJhbXMgbWVtb3J5IHBhcmFtcyA9IElQb29sTWFuYWdlci5Td2FwUGFyYW1zKHsKICAgICAgICAgICAgemVyb0Zvck9uZTogemVyb0Zvck9uZSwKICAgICAgICAgICAgYW1vdW50U3BlY2lmaWVkOiAxZTE4LAogICAgICAgICAgICBzcXJ0UHJpY2VMaW1pdFg5NjogemVyb0Zvck9uZSA/IE1JTl9QUklDRV9MSU1JVCA6IE1BWF9QUklDRV9MSU1JVCAvLyB1bmxpbWl0ZWQgaW1wYWN0CiAgICAgICAgfSk7CgogICAgICAgIC8vIGluIHY0LCB1c2VycyBoYXZlIHRoZSBvcHRpb24gdG8gcmVjZWlldmUgbmF0aXZlIEVSQzIwcyBvciB3cmFwcGVkIEVSQzExNTUgdG9rZW5zCiAgICAgICAgLy8gaGVyZSwgd2UnbGwgdGFrZSB0aGUgRVJDMjBzCiAgICAgICAgUG9vbFN3YXBUZXN0LlRlc3RTZXR0aW5ncyBtZW1vcnkgdGVzdFNldHRpbmdzID0KICAgICAgICAgICAgUG9vbFN3YXBUZXN0LlRlc3RTZXR0aW5ncyh7d2l0aGRyYXdUb2tlbnM6IHRydWUsIHNldHRsZVVzaW5nVHJhbnNmZXI6IHRydWV9KTsKCiAgICAgICAgYnl0ZXMgbWVtb3J5IGhvb2tEYXRhID0gbmV3IGJ5dGVzKDApOyAvLyBubyBob29rIGRhdGEgb24gdGhlIGhvb2tsZXNzIHBvb2wKICAgICAgICBzd2FwUm91dGVyLnN3YXAoa2V5LCBwYXJhbXMsIHRlc3RTZXR0aW5ncywgaG9va0RhdGEpOwogICAgfQp9Cg==", - }, + { + fileName: "Swap.sol", + code: "Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCB7SVBvb2xNYW5hZ2VyfSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy9pbnRlcmZhY2VzL0lQb29sTWFuYWdlci5zb2wiOwppbXBvcnQge1Bvb2xLZXl9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL3R5cGVzL1Bvb2xLZXkuc29sIjsKaW1wb3J0IHtQb29sU3dhcFRlc3R9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL3Rlc3QvUG9vbFN3YXBUZXN0LnNvbCI7CmltcG9ydCB7VGlja01hdGh9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL2xpYnJhcmllcy9UaWNrTWF0aC5zb2wiOwoKY29udHJhY3QgU3dhcCB7CiAgICAvLyBzZXQgdGhlIHJvdXRlciBhZGRyZXNzCiAgICBQb29sU3dhcFRlc3Qgc3dhcFJvdXRlciA9IFBvb2xTd2FwVGVzdCgweDAxKTsKCiAgICAvLyBzbGlwcGFnZSB0b2xlcmFuY2UgdG8gYWxsb3cgZm9yIHVubGltaXRlZCBwcmljZSBpbXBhY3QKICAgIHVpbnQxNjAgcHVibGljIGNvbnN0YW50IE1JTl9QUklDRV9MSU1JVCA9IFRpY2tNYXRoLk1JTl9TUVJUX1JBVElPICsgMTsKICAgIHVpbnQxNjAgcHVibGljIGNvbnN0YW50IE1BWF9QUklDRV9MSU1JVCA9IFRpY2tNYXRoLk1BWF9TUVJUX1JBVElPIC0gMTsKCiAgICAvLy8gQG5vdGljZSBTd2FwIHRva2VucwogICAgLy8vIEBwYXJhbSBrZXkgdGhlIHBvb2wgd2hlcmUgdGhlIHN3YXAgaXMgaGFwcGVuaW5nCiAgICAvLy8gQHBhcmFtIGFtb3VudFNwZWNpZmllZCB0aGUgYW1vdW50IG9mIHRva2VucyB0byBzd2FwCiAgICAvLy8gQHBhcmFtIHplcm9Gb3JPbmUgd2hldGhlciB0aGUgc3dhcCBpcyB0b2tlbjAgLT4gdG9rZW4xIG9yIHRva2VuMSAtPiB0b2tlbjAKICAgIC8vLyBAcGFyYW0gaG9va0RhdGEgYW55IGRhdGEgdG8gYmUgcGFzc2VkIHRvIHRoZSBwb29sJ3MgaG9vawogICAgZnVuY3Rpb24gc3dhcChQb29sS2V5IG1lbW9yeSBrZXksIGludDI1NiBhbW91bnRTcGVjaWZpZWQsIGJvb2wgemVyb0Zvck9uZSwgYnl0ZXMgbWVtb3J5IGhvb2tEYXRhKSBpbnRlcm5hbCB7CiAgICAgICAgSVBvb2xNYW5hZ2VyLlN3YXBQYXJhbXMgbWVtb3J5IHBhcmFtcyA9IElQb29sTWFuYWdlci5Td2FwUGFyYW1zKHsKICAgICAgICAgICAgemVyb0Zvck9uZTogemVyb0Zvck9uZSwKICAgICAgICAgICAgYW1vdW50U3BlY2lmaWVkOiBhbW91bnRTcGVjaWZpZWQsCiAgICAgICAgICAgIHNxcnRQcmljZUxpbWl0WDk2OiB6ZXJvRm9yT25lID8gTUlOX1BSSUNFX0xJTUlUIDogTUFYX1BSSUNFX0xJTUlUIC8vIHVubGltaXRlZCBpbXBhY3QKICAgICAgICB9KTsKCiAgICAgICAgLy8gaW4gdjQsIHVzZXJzIGhhdmUgdGhlIG9wdGlvbiB0byByZWNlaWV2ZSBuYXRpdmUgRVJDMjBzIG9yIHdyYXBwZWQgRVJDMTE1NSB0b2tlbnMKICAgICAgICAvLyBoZXJlLCB3ZSdsbCB0YWtlIHRoZSBFUkMyMHMKICAgICAgICBQb29sU3dhcFRlc3QuVGVzdFNldHRpbmdzIG1lbW9yeSB0ZXN0U2V0dGluZ3MgPQogICAgICAgICAgICBQb29sU3dhcFRlc3QuVGVzdFNldHRpbmdzKHt3aXRoZHJhd1Rva2VuczogdHJ1ZSwgc2V0dGxlVXNpbmdUcmFuc2ZlcjogdHJ1ZX0pOwoKICAgICAgICBzd2FwUm91dGVyLnN3YXAoa2V5LCBwYXJhbXMsIHRlc3RTZXR0aW5ncywgaG9va0RhdGEpOwogICAgfQp9Cg==", + }, + { + fileName: "SwapExampleInputs.sol", + code: "UG9vbFN3YXBUZXN0IHN3YXBSb3V0ZXIgPSBQb29sU3dhcFRlc3QoMHgwMSk7CgovLyBzbGlwcGFnZSB0b2xlcmFuY2UgdG8gYWxsb3cgZm9yIHVubGltaXRlZCBwcmljZSBpbXBhY3QKdWludDE2MCBwdWJsaWMgY29uc3RhbnQgTUlOX1BSSUNFX0xJTUlUID0gVGlja01hdGguTUlOX1NRUlRfUkFUSU8gKyAxOwp1aW50MTYwIHB1YmxpYyBjb25zdGFudCBNQVhfUFJJQ0VfTElNSVQgPSBUaWNrTWF0aC5NQVhfU1FSVF9SQVRJTyAtIDE7CgphZGRyZXNzIHRva2VuMCA9IGFkZHJlc3MoMHgxMSk7CmFkZHJlc3MgdG9rZW4xID0gYWRkcmVzcygweDIyKTsKYWRkcmVzcyBob29rQWRkciA9IGFkZHJlc3MoMHgzMyk7CgovLyBVc2luZyBhIGhvb2tsZXNzIHBvb2wKUG9vbEtleSBtZW1vcnkgcG9vbCA9IFBvb2xLZXkoewogICAgY3VycmVuY3kwOiBDdXJyZW5jeS53cmFwKHRva2VuMCksCiAgICBjdXJyZW5jeTE6IEN1cnJlbmN5LndyYXAodG9rZW4xKSwKICAgIGZlZTogMzAwMCwKICAgIHRpY2tTcGFjaW5nOiA2MCwKICAgIGhvb2tzOiBJSG9va3MoaG9va0FkZHIpCn0pOwoKLy8gYXBwcm92ZSB0b2tlbnMgdG8gdGhlIHN3YXAgcm91dGVyCklFUkMyMCh0b2tlbjApLmFwcHJvdmUoYWRkcmVzcyhzd2FwUm91dGVyKSwgdHlwZSh1aW50MjU2KS5tYXgpOwpJRVJDMjAodG9rZW4xKS5hcHByb3ZlKGFkZHJlc3Moc3dhcFJvdXRlciksIHR5cGUodWludDI1NikubWF4KTsKCi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gLy8KLy8gU3dhcCAxZTE4IHRva2VuMCBpbnRvIHRva2VuMQovLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC8vCmJvb2wgemVyb0Zvck9uZSA9IHRydWU7CklQb29sTWFuYWdlci5Td2FwUGFyYW1zIG1lbW9yeSBwYXJhbXMgPSBJUG9vbE1hbmFnZXIuU3dhcFBhcmFtcyh7CiAgICB6ZXJvRm9yT25lOiB6ZXJvRm9yT25lLAogICAgYW1vdW50U3BlY2lmaWVkOiAxZTE4LAogICAgc3FydFByaWNlTGltaXRYOTY6IHplcm9Gb3JPbmUgPyBNSU5fUFJJQ0VfTElNSVQgOiBNQVhfUFJJQ0VfTElNSVQgLy8gdW5saW1pdGVkIGltcGFjdAp9KTsKCi8vIGluIHY0LCB1c2VycyBoYXZlIHRoZSBvcHRpb24gdG8gcmVjZWlldmUgbmF0aXZlIEVSQzIwcyBvciB3cmFwcGVkIEVSQzExNTUgdG9rZW5zCi8vIGhlcmUsIHdlJ2xsIHRha2UgdGhlIEVSQzIwcwpQb29sU3dhcFRlc3QuVGVzdFNldHRpbmdzIG1lbW9yeSB0ZXN0U2V0dGluZ3MgPQogICAgUG9vbFN3YXBUZXN0LlRlc3RTZXR0aW5ncyh7d2l0aGRyYXdUb2tlbnM6IHRydWUsIHNldHRsZVVzaW5nVHJhbnNmZXI6IHRydWV9KTsKCmJ5dGVzIG1lbW9yeSBob29rRGF0YSA9IG5ldyBieXRlcygwKTsgLy8gbm8gaG9vayBkYXRhIG9uIHRoZSBob29rbGVzcyBwb29sCnN3YXBSb3V0ZXIuc3dhcChrZXksIHBhcmFtcywgdGVzdFNldHRpbmdzLCBob29rRGF0YSk7Cg==", + }, ] const html = `
    • Swap between tokens on a single pool
    -

    Using the v4-core provided test router, we can swap on a single pool. These snippets should only be used for non-production, testing purposes

    Swapping will typically make use of a periphery contract. It is not recommended to directly swap with poolManager.swap

    +
    +

    Using the v4-core provided test router, we can swap on a single pool. These snippets should only be used for non-production, testing purposes

    +

    Swapping involves 3 primary arguments:

    • Which pool to swap on
    • @@ -70,58 +68,46 @@ const html = `
        } }

    Examples of Swapping on a V4 Pool

    -
    // SPDX-License-Identifier: MIT
    -pragma solidity ^0.8.20;
    -
    -import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol";
    -import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol";
    -import {PoolSwapTest} from "@uniswap/v4-core/contracts/test/PoolSwapTest.sol";
    -import {TickMath} from "@uniswap/v4-core/contracts/libraries/TickMath.sol";
    -
    -contract SwapExampleInputs {
    -    // set the router address
    -    PoolSwapTest swapRouter = PoolSwapTest(0x01);
    -
    -    // slippage tolerance to allow for unlimited price impact
    -    uint160 public constant MIN_PRICE_LIMIT = TickMath.MIN_SQRT_RATIO + 1;
    -    uint160 public constant MAX_PRICE_LIMIT = TickMath.MAX_SQRT_RATIO - 1;
    -
    -    function exampleA() internal {
    -        address token0 = address(0x11);
    -        address token1 = address(0x22);
    -
    -        // Using a hookless pool
    -        PoolKey memory pool = PoolKey({
    -            currency0: Currency.wrap(token0),
    -            currency1: Currency.wrap(token1),
    -            fee: 3000,
    -            tickSpacing: 60,
    -            hooks: IHooks(address(0x0))
    -        });
    -
    -        // approve tokens to the swap router
    -        IERC20(token0).approve(address(swapRouter), type(uint256).max);
    -        IERC20(token1).approve(address(swapRouter), type(uint256).max);
    -
    -        // ---------------------------- //
    -        // Swap 1e18 token0 into token1
    -        // ---------------------------- //
    -        bool zeroForOne = true;
    -        IPoolManager.SwapParams memory params = IPoolManager.SwapParams({
    -            zeroForOne: zeroForOne,
    -            amountSpecified: 1e18,
    -            sqrtPriceLimitX96: zeroForOne ? MIN_PRICE_LIMIT : MAX_PRICE_LIMIT // unlimited impact
    -        });
    -
    -        // in v4, users have the option to receieve native ERC20s or wrapped ERC1155 tokens
    -        // here, we'll take the ERC20s
    -        PoolSwapTest.TestSettings memory testSettings =
    -            PoolSwapTest.TestSettings({withdrawTokens: true, settleUsingTransfer: true});
    -
    -        bytes memory hookData = new bytes(0); // no hook data on the hookless pool
    -        swapRouter.swap(key, params, testSettings, hookData);
    -    }
    -}
    +
    PoolSwapTest swapRouter = PoolSwapTest(0x01);
    +
    +// slippage tolerance to allow for unlimited price impact
    +uint160 public constant MIN_PRICE_LIMIT = TickMath.MIN_SQRT_RATIO + 1;
    +uint160 public constant MAX_PRICE_LIMIT = TickMath.MAX_SQRT_RATIO - 1;
    +
    +address token0 = address(0x11);
    +address token1 = address(0x22);
    +address hookAddr = address(0x33);
    +
    +// Using a hookless pool
    +PoolKey memory pool = PoolKey({
    +    currency0: Currency.wrap(token0),
    +    currency1: Currency.wrap(token1),
    +    fee: 3000,
    +    tickSpacing: 60,
    +    hooks: IHooks(hookAddr)
    +});
    +
    +// approve tokens to the swap router
    +IERC20(token0).approve(address(swapRouter), type(uint256).max);
    +IERC20(token1).approve(address(swapRouter), type(uint256).max);
    +
    +// ---------------------------- //
    +// Swap 1e18 token0 into token1
    +// ---------------------------- //
    +bool zeroForOne = true;
    +IPoolManager.SwapParams memory params = IPoolManager.SwapParams({
    +    zeroForOne: zeroForOne,
    +    amountSpecified: 1e18,
    +    sqrtPriceLimitX96: zeroForOne ? MIN_PRICE_LIMIT : MAX_PRICE_LIMIT // unlimited impact
    +});
    +
    +// in v4, users have the option to receieve native ERC20s or wrapped ERC1155 tokens
    +// here, we'll take the ERC20s
    +PoolSwapTest.TestSettings memory testSettings =
    +    PoolSwapTest.TestSettings({withdrawTokens: true, settleUsingTransfer: true});
    +
    +bytes memory hookData = new bytes(0); // no hook data on the hookless pool
    +swapRouter.swap(key, params, testSettings, hookData);
     
    ` export default html diff --git a/src/pages/swap/index.md b/src/pages/swap/index.md index 28316b0c8..4cb520cc4 100644 --- a/src/pages/swap/index.md +++ b/src/pages/swap/index.md @@ -5,21 +5,26 @@ description: Swapping on a single pool keywords: [swap, trade, swapping] --- -* Swap between tokens on a single pool - -Using the `v4-core` provided *test* router, we can swap on a single pool. These snippets should only be used for non-production, testing purposes +- Swap between tokens on a single pool Swapping will typically make use of a periphery contract. It is **not** recommended to directly swap with `poolManager.swap` +--- + +Using the `v4-core` provided _test_ router, we can swap on a single pool. These snippets should only be used for non-production, testing purposes + +--- + Swapping involves 3 primary arguments: -* Which pool to swap on -* The direction of the swap, `token0 -> token1` or `token1 -> token0` -* The input token amount +- Which pool to swap on +- The direction of the swap, `token0 -> token1` or `token1 -> token0` +- The input token amount (Note: A quoter contract is unavailable at this time) #### Expect Uniswap Labs to release an official contract around launch + ```solidity {{{Swap}}} ``` diff --git a/src/routes.tsx b/src/routes.tsx index 112241229..22c148760 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -20,22 +20,22 @@ interface Route { } const routes: Route[] = [ - { - path: "/create-liquidity", - component: component_create_liquidity - }, - { - path: "/initialize", - component: component_initialize - }, - { - path: "/swap", - component: component_swap - }, - { - path: "", - component: component_ - }, + { + path: "/create-liquidity", + component: component_create_liquidity, + }, + { + path: "/initialize", + component: component_initialize, + }, + { + path: "/swap", + component: component_swap, + }, + { + path: "", + component: component_, + }, ] -export default routes \ No newline at end of file +export default routes diff --git a/src/search.json b/src/search.json index 5a0b7cf6c..3745822af 100644 --- a/src/search.json +++ b/src/search.json @@ -1,47 +1,17 @@ { - "swap": [ - "/swap" - ], - "trade": [ - "/swap" - ], - "swapping": [ - "/swap" - ], - "pool": [ - "/initialize" - ], - "initialize": [ - "/initialize" - ], - "init": [ - "/initialize" - ], - "create": [ - "/initialize" - ], - "pair": [ - "/initialize" - ], - "factory": [ - "/initialize" - ], - "liquidity": [ - "/create-liquidity" - ], - "LP": [ - "/create-liquidity" - ], - "lp": [ - "/create-liquidity" - ], - "provide": [ - "/create-liquidity" - ], - "provision": [ - "/create-liquidity" - ], - "supply": [ - "/create-liquidity" - ] -} \ No newline at end of file + "swap": ["/swap"], + "trade": ["/swap"], + "swapping": ["/swap"], + "pool": ["/initialize"], + "initialize": ["/initialize"], + "init": ["/initialize"], + "create": ["/initialize"], + "pair": ["/initialize"], + "factory": ["/initialize"], + "liquidity": ["/create-liquidity"], + "LP": ["/create-liquidity"], + "lp": ["/create-liquidity"], + "provide": ["/create-liquidity"], + "provision": ["/create-liquidity"], + "supply": ["/create-liquidity"] +}