Skip to content

Commit

Permalink
Merge pull request #2 from saucepoint/create-liquidity
Browse files Browse the repository at this point in the history
Snippets for liquidity creation
  • Loading branch information
saucepoint authored Oct 18, 2023
2 parents c02e9ab + bfc7f36 commit 71f6bed
Show file tree
Hide file tree
Showing 9 changed files with 254 additions and 2 deletions.
6 changes: 6 additions & 0 deletions src/keywords.json
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,12 @@
"memory",
"calldata"
],
"/create-liquidity": [
"liquidity",
"LP",
"provision",
"supply"
],
"/constructor": [
"constructor",
"constructors",
Expand Down
4 changes: 4 additions & 0 deletions src/nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export const SOL_ROUTES: Route[] = [
path: "initialize",
title: "Pool Initialize"
},
{
path: "create-liquidity",
title: "Create Liquidity"
},
{
path: "hello-world",
title: "Hello World",
Expand Down
26 changes: 26 additions & 0 deletions src/pages/create-liquidity/CreateLiquidity.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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 {PoolModifyPositionTest} from "@uniswap/v4-core/contracts/test/PoolModifyPositionTest.sol";

contract CreateLiquidity {
// set the router address
PoolModifyPositionTest lpRouter = PoolModifyPositionTest(0x01);

function createLiquidity(
PoolKey memory poolKey,
int24 tickLower,
int24 tickUpper,
int256 liquidity,
bytes calldata hookData
) external {
// if 0 < liquidity: add liquidity -- otherwise remove liquidity
lpRouter.modifyPosition(
poolKey,
IPoolManager.ModifyPositionParams({tickLower: tickLower, tickUpper: tickUpper, liquidityDelta: liquidity}),
hookData
);
}
}
43 changes: 43 additions & 0 deletions src/pages/create-liquidity/CreateLiquidityExampleInputs.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// 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(token0),
currency1: Currency(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)
);
}
}
104 changes: 104 additions & 0 deletions src/pages/create-liquidity/index.html.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// metadata
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",
"provision",
"supply",
]

export const codes = [
{
fileName: "CreateLiquidity.sol",
code: "Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCB7SVBvb2xNYW5hZ2VyfSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy9pbnRlcmZhY2VzL0lQb29sTWFuYWdlci5zb2wiOwppbXBvcnQge1Bvb2xLZXl9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL3R5cGVzL1Bvb2xLZXkuc29sIjsKaW1wb3J0IHtQb29sTW9kaWZ5UG9zaXRpb25UZXN0fSBmcm9tICJAdW5pc3dhcC92NC1jb3JlL2NvbnRyYWN0cy90ZXN0L1Bvb2xNb2RpZnlQb3NpdGlvblRlc3Quc29sIjsKCmNvbnRyYWN0IENyZWF0ZUxpcXVpZGl0eSB7CiAgICAvLyBzZXQgdGhlIHJvdXRlciBhZGRyZXNzCiAgICBQb29sTW9kaWZ5UG9zaXRpb25UZXN0IGxwUm91dGVyID0gUG9vbE1vZGlmeVBvc2l0aW9uVGVzdCgweDAxKTsKCiAgICBmdW5jdGlvbiBjcmVhdGVMaXF1aWRpdHkoCiAgICAgICAgUG9vbEtleSBtZW1vcnkgcG9vbEtleSwKICAgICAgICBpbnQyNCB0aWNrTG93ZXIsCiAgICAgICAgaW50MjQgdGlja1VwcGVyLAogICAgICAgIGludDI1NiBsaXF1aWRpdHksCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgaG9va0RhdGEKICAgICkgZXh0ZXJuYWwgewogICAgICAgIC8vIGlmIDAgPCBsaXF1aWRpdHk6IGFkZCBsaXF1aWRpdHkgLS0gb3RoZXJ3aXNlIHJlbW92ZSBsaXF1aWRpdHkKICAgICAgICBscFJvdXRlci5tb2RpZnlQb3NpdGlvbigKICAgICAgICAgICAgcG9vbEtleSwKICAgICAgICAgICAgSVBvb2xNYW5hZ2VyLk1vZGlmeVBvc2l0aW9uUGFyYW1zKHt0aWNrTG93ZXI6IHRpY2tMb3dlciwgdGlja1VwcGVyOiB0aWNrVXBwZXIsIGxpcXVpZGl0eURlbHRhOiBsaXF1aWRpdHl9KSwKICAgICAgICAgICAgaG9va0RhdGEKICAgICAgICApOwogICAgfQp9Cg==",
},
{
fileName: "CreateLiquidityExampleInputs.sol",
code: "Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCB7SUVSQzIwfSBmcm9tICJmb3JnZS1zdGQvaW50ZXJmYWNlcy9JRVJDMjAuc29sIjsKaW1wb3J0IHtJUG9vbE1hbmFnZXJ9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL2ludGVyZmFjZXMvSVBvb2xNYW5hZ2VyLnNvbCI7CmltcG9ydCB7UG9vbEtleX0gZnJvbSAiQHVuaXN3YXAvdjQtY29yZS9jb250cmFjdHMvdHlwZXMvUG9vbEtleS5zb2wiOwppbXBvcnQge1Bvb2xNb2RpZnlQb3NpdGlvblRlc3R9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL3Rlc3QvUG9vbE1vZGlmeVBvc2l0aW9uVGVzdC5zb2wiOwppbXBvcnQge0N1cnJlbmN5TGlicmFyeSwgQ3VycmVuY3l9IGZyb20gIkB1bmlzd2FwL3Y0LWNvcmUvY29udHJhY3RzL3R5cGVzL0N1cnJlbmN5LnNvbCI7Cgpjb250cmFjdCBDcmVhdGVMaXF1aWRpdHlFeGFtcGxlSW5wdXRzIHsKICAgIHVzaW5nIEN1cnJlbmN5TGlicmFyeSBmb3IgQ3VycmVuY3k7CgogICAgLy8gc2V0IHRoZSByb3V0ZXIgYWRkcmVzcwogICAgUG9vbE1vZGlmeVBvc2l0aW9uVGVzdCBscFJvdXRlciA9IFBvb2xNb2RpZnlQb3NpdGlvblRlc3QoMHgwMSk7CgogICAgZnVuY3Rpb24gZXhhbXBsZUEoKSBleHRlcm5hbCB7CiAgICAgICAgYWRkcmVzcyB0b2tlbjAgPSBhZGRyZXNzKDB4MTEpOwogICAgICAgIGFkZHJlc3MgdG9rZW4xID0gYWRkcmVzcygweDIyKTsKCiAgICAgICAgLy8gVXNpbmcgYSBob29rbGVzcyBwb29sCiAgICAgICAgUG9vbEtleSBtZW1vcnkgcG9vbCA9IFBvb2xLZXkoewogICAgICAgICAgICBjdXJyZW5jeTA6IEN1cnJlbmN5KHRva2VuMCksCiAgICAgICAgICAgIGN1cnJlbmN5MTogQ3VycmVuY3kodG9rZW4xKSwKICAgICAgICAgICAgZmVlOiAzMDAwLAogICAgICAgICAgICB0aWNrU3BhY2luZzogNjAsCiAgICAgICAgICAgIGhvb2tzOiBJSG9va3MoYWRkcmVzcygweDApKQogICAgICAgIH0pOwoKICAgICAgICAvLyBhcHByb3ZlIHRva2VucyB0byB0aGUgTFAgUm91dGVyCiAgICAgICAgSUVSQzIwKHRva2VuMCkuYXBwcm92ZShhZGRyZXNzKGxwUm91dGVyKSwgdHlwZSh1aW50MjU2KS5tYXgpOwogICAgICAgIElFUkMyMCh0b2tlbjEpLmFwcHJvdmUoYWRkcmVzcyhscFJvdXRlciksIHR5cGUodWludDI1NikubWF4KTsKCiAgICAgICAgLy8gUHJvdmlkZSAxMGUxOCB3b3J0aCBvZiBsaXF1aWRpdHkgb24gdGhlIHJhbmdlIG9mIFstNjAwLCA2MDBdCiAgICAgICAgaW50MjQgdGlja0xvd2VyID0gLTYwMDsKICAgICAgICBpbnQyNCB0aWNrVXBwZXIgPSA2MDA7CiAgICAgICAgaW50MjU2IGxpcXVpZGl0eSA9IDEwZTE4OwogICAgICAgIGxwUm91dGVyLm1vZGlmeVBvc2l0aW9uKAogICAgICAgICAgICBwb29sS2V5LAogICAgICAgICAgICBJUG9vbE1hbmFnZXIuTW9kaWZ5UG9zaXRpb25QYXJhbXMoe3RpY2tMb3dlcjogdGlja0xvd2VyLCB0aWNrVXBwZXI6IHRpY2tVcHBlciwgbGlxdWlkaXR5RGVsdGE6IGxpcXVpZGl0eX0pLAogICAgICAgICAgICBuZXcgYnl0ZXMoMCkKICAgICAgICApOwogICAgfQp9Cg==",
},
]

const html = `<blockquote>
<p>Expect Uniswap Labs to release an official contract around launch</p>
</blockquote>
<blockquote>
<p>⚠️ Using the test router in production will lead to a loss of funds ⚠️ </p>
</blockquote>
<p>Using the <code>v4-core</code> provided <em>test</em> router, we can provide liquidity to a pool. This should only be used for non-production testing purposes</p>
<p>Creating liquidity involves using periphery contracts. It is <strong>not</strong> recommended to directly provide liquidity with <code>poolManager.modifyPosition</code></p>
<pre><code class="language-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>
<span class="hljs-keyword">import</span> {<span class="hljs-title">IPoolManager</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@uniswap/v4-core/contracts/interfaces/IPoolManager.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">PoolKey</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@uniswap/v4-core/contracts/types/PoolKey.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">PoolModifyPositionTest</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@uniswap/v4-core/contracts/test/PoolModifyPositionTest.sol"</span>;
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">CreateLiquidity</span> </span>{
<span class="hljs-comment">// set the router address</span>
PoolModifyPositionTest lpRouter <span class="hljs-operator">=</span> PoolModifyPositionTest(<span class="hljs-number">0x01</span>);
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createLiquidity</span>(<span class="hljs-params">
PoolKey <span class="hljs-keyword">memory</span> poolKey,
<span class="hljs-keyword">int24</span> tickLower,
<span class="hljs-keyword">int24</span> tickUpper,
<span class="hljs-keyword">int256</span> liquidity,
<span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> hookData
</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
<span class="hljs-comment">// if 0 &lt; liquidity: add liquidity -- otherwise remove liquidity</span>
lpRouter.modifyPosition(
poolKey,
IPoolManager.ModifyPositionParams({tickLower: tickLower, tickUpper: tickUpper, liquidityDelta: liquidity}),
hookData
);
}
}
</code></pre><h3>Examples of Providing Liquidity to a V4 Pool</h3>
<pre><code class="language-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>
<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/interfaces/IERC20.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">IPoolManager</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@uniswap/v4-core/contracts/interfaces/IPoolManager.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">PoolKey</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@uniswap/v4-core/contracts/types/PoolKey.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">PoolModifyPositionTest</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@uniswap/v4-core/contracts/test/PoolModifyPositionTest.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">CurrencyLibrary</span>, <span class="hljs-title">Currency</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@uniswap/v4-core/contracts/types/Currency.sol"</span>;
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">CreateLiquidityExampleInputs</span> </span>{
<span class="hljs-keyword">using</span> <span class="hljs-title">CurrencyLibrary</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title">Currency</span>;
<span class="hljs-comment">// set the router address</span>
PoolModifyPositionTest lpRouter <span class="hljs-operator">=</span> PoolModifyPositionTest(<span class="hljs-number">0x01</span>);
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">exampleA</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
<span class="hljs-keyword">address</span> token0 <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0x11</span>);
<span class="hljs-keyword">address</span> token1 <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0x22</span>);
<span class="hljs-comment">// Using a hookless pool</span>
PoolKey <span class="hljs-keyword">memory</span> pool <span class="hljs-operator">=</span> PoolKey({
currency0: Currency(token0),
currency1: Currency(token1),
fee: <span class="hljs-number">3000</span>,
tickSpacing: <span class="hljs-number">60</span>,
hooks: IHooks(<span class="hljs-keyword">address</span>(<span class="hljs-number">0x0</span>))
});
<span class="hljs-comment">// approve tokens to the LP Router</span>
IERC20(token0).approve(<span class="hljs-keyword">address</span>(lpRouter), <span class="hljs-keyword">type</span>(<span class="hljs-keyword">uint256</span>).<span class="hljs-built_in">max</span>);
IERC20(token1).approve(<span class="hljs-keyword">address</span>(lpRouter), <span class="hljs-keyword">type</span>(<span class="hljs-keyword">uint256</span>).<span class="hljs-built_in">max</span>);
<span class="hljs-comment">// Provide 10e18 worth of liquidity on the range of [-600, 600]</span>
<span class="hljs-keyword">int24</span> tickLower <span class="hljs-operator">=</span> <span class="hljs-number">-600</span>;
<span class="hljs-keyword">int24</span> tickUpper <span class="hljs-operator">=</span> <span class="hljs-number">600</span>;
<span class="hljs-keyword">int256</span> liquidity <span class="hljs-operator">=</span> <span class="hljs-number">10e18</span>;
lpRouter.modifyPosition(
poolKey,
IPoolManager.ModifyPositionParams({tickLower: tickLower, tickUpper: tickUpper, liquidityDelta: liquidity}),
<span class="hljs-keyword">new</span> <span class="hljs-keyword">bytes</span>(<span class="hljs-number">0</span>)
);
}
}
</code></pre>`

export default html
27 changes: 27 additions & 0 deletions src/pages/create-liquidity/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
title: Create Liquidity
version: 0.8.20
description: Providing Liquidity to a Uniswap V4 Pool
keywords: [liquidity, LP, provision, supply]
---

> Expect Uniswap Labs to release an official contract around launch
> ⚠️ 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. This 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`

```solidity
{{{CreateLiquidity}}}
```

### Examples of Providing Liquidity to a V4 Pool

```solidity
{{{CreateLiquidityExampleInputs}}}
```
29 changes: 29 additions & 0 deletions src/pages/create-liquidity/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react"
import Example from "../../components/Example"
import html, { version, title, description, codes } from "./index.html"

interface Path {
path: string
title: string
}

interface Props {
prev: Path | null
next: Path | null
}

const ExamplePage: React.FC<Props> = ({ prev, next }) => {
return (
<Example
version={version}
title={title}
description={description}
html={html}
prev={prev}
next={next}
codes={codes}
/>
)
}

export default ExamplePage
5 changes: 5 additions & 0 deletions src/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import component_call from "./pages/call"
import component_calling_contract from "./pages/calling-contract"
import component_constants from "./pages/constants"
import component_constructor from "./pages/constructor"
import component_create_liquidity from "./pages/create-liquidity"
import component_data_locations from "./pages/data-locations"
import component_defi_chainlink_price_oracle from "./pages/defi/chainlink-price-oracle"
import component_defi_constant_product_amm from "./pages/defi/constant-product-amm"
Expand Down Expand Up @@ -266,6 +267,10 @@ const routes: Route[] = [
path: "/constructor",
component: component_constructor
},
{
path: "/create-liquidity",
component: component_create_liquidity
},
{
path: "/data-locations",
component: component_data_locations
Expand Down
12 changes: 10 additions & 2 deletions src/search.json
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,8 @@
],
"liquidity": [
"/defi/uniswap-v3-liquidity",
"/defi/uniswap-v2-add-remove-liquidity"
"/defi/uniswap-v2-add-remove-liquidity",
"/create-liquidity"
],
"arbitrage": [
"/defi/uniswap-v3-flash-swap"
Expand Down Expand Up @@ -774,7 +775,8 @@
"/defi/uniswap-v2-optimal-one-sided-supply"
],
"supply": [
"/defi/uniswap-v2-optimal-one-sided-supply"
"/defi/uniswap-v2-optimal-one-sided-supply",
"/create-liquidity"
],
"add": [
"/defi/uniswap-v2-add-remove-liquidity",
Expand Down Expand Up @@ -834,6 +836,12 @@
"calldata": [
"/data-locations"
],
"LP": [
"/create-liquidity"
],
"provision": [
"/create-liquidity"
],
"constructor": [
"/constructor"
],
Expand Down

0 comments on commit 71f6bed

Please sign in to comment.