start
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
cache/
|
||||
out/
|
||||
.idea/
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "lib/forge-std"]
|
||||
path = lib/forge-std
|
||||
url = https://github.com/foundry-rs/forge-std
|
||||
41
docs/order_types.md
Normal file
41
docs/order_types.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Order Types
|
||||
## TWAP
|
||||
* time-to-expiry is required
|
||||
* number of tranches > 1
|
||||
* optional lower and upper price bounds
|
||||
|
||||
## DCA
|
||||
* similar to a TWAP, but the tranches are divided by value instead of quantity
|
||||
|
||||
## Timed Entry
|
||||
* specific time when an order is triggered
|
||||
* can be market/limit TWAP, whatever
|
||||
|
||||
## Limit
|
||||
|
||||
## Stop
|
||||
* enabled on a price condition instead of at a specific time
|
||||
* how to enforce this in the contract? would need a price history of when the stop was touched. perhaps this is a use case for a "chain" order where one set of constraints doesn't invoke a trade but instead creates a subsequent order
|
||||
|
||||
## Ladder
|
||||
* split into many traches across a range of prices
|
||||
* required number of tranches
|
||||
* required upper and lower bounds of the ladder
|
||||
|
||||
|
||||
# Conditions
|
||||
|
||||
* current price above/below
|
||||
* historical price touched above/below (e.g. trailing stop): keep an updated data structure of swing highs & lows. this structure must only be updated once before the relevant observation rolls off the back of the window. "management gas"
|
||||
* volume above/below
|
||||
* historical volume touched above/below: this could work like historical price swing high/lows if we first bucket the volumes into sizes <= the pool observation window
|
||||
* per-swap slippage constraint
|
||||
|
||||
|
||||
# Gas
|
||||
|
||||
* an amount for gas is reserved ahead of time
|
||||
* excess gas is kept
|
||||
* Dexible has a gas refund delay, saying:
|
||||
> `get/setLockoutBlocks` Retrieves or sets the number of blocks a trader must wait before withdrawing their gas deposit. This is to prevent traders from front-running a relay that submitted an order in order to circumvent paying for the execution or forcing a failed txn.
|
||||
|
||||
9
foundry.toml
Normal file
9
foundry.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[profile.default]
|
||||
libs = ['lib']
|
||||
remappings = [
|
||||
'@openzeppelin/contracts/=lib/openzeppelin/contracts/',
|
||||
'@uniswap/v3-core/=lib/uniswap/v3-core/',
|
||||
'@uniswap/v3-periphery/=lib/uniswap/v3-periphery/',
|
||||
]
|
||||
optimizer=true
|
||||
optimizer_runs=999999999
|
||||
1
lib/forge-std
Submodule
1
lib/forge-std
Submodule
Submodule lib/forge-std added at 74cfb77e30
22
src/IERC20Metadata.sol
Normal file
22
src/IERC20Metadata.sol
Normal file
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.7.6;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
|
||||
// the version of OpenZeppelin required by Uniswap v3 doesn't have IERC20Metadata yet, so we copy it here.
|
||||
interface IERC20Metadata is IERC20 {
|
||||
/**
|
||||
* @dev Returns the name of the token.
|
||||
*/
|
||||
function name() external view returns (string memory);
|
||||
|
||||
/**
|
||||
* @dev Returns the symbol of the token.
|
||||
*/
|
||||
function symbol() external view returns (string memory);
|
||||
|
||||
/**
|
||||
* @dev Returns the decimals places of the token.
|
||||
*/
|
||||
function decimals() external view returns (uint8);
|
||||
}
|
||||
17
src/MockERC20.sol
Normal file
17
src/MockERC20.sol
Normal file
@@ -0,0 +1,17 @@
|
||||
import "openzeppelin/contracts/token/ERC20/ERC20.sol";
|
||||
import "./IERC20Metadata.sol";
|
||||
|
||||
|
||||
contract MockERC20 is ERC20, IERC20Metadata {
|
||||
|
||||
constructor(string name, string symbol, uint8 decimals)
|
||||
ERC20(name, symbol)
|
||||
{
|
||||
_setupDecimals(decimals);
|
||||
}
|
||||
|
||||
|
||||
function mint(address account, uint256 amount) external {
|
||||
_mint(account, amount);
|
||||
}
|
||||
}
|
||||
71
test/TestSinglePool.sol
Normal file
71
test/TestSinglePool.sol
Normal file
@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity =0.7.6;
|
||||
|
||||
import "forge-std/console2.sol";
|
||||
import "../src/MockERC20.sol";
|
||||
import "uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol";
|
||||
import "uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
|
||||
import "uniswap/v3-core/contracts/libraries/TickMath.sol";
|
||||
import "uniswap/v3-periphery/contracts/interfaces/INonfungiblePositionManager.sol";
|
||||
import "uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
|
||||
import "uniswap/v3-periphery/contracts/libraries/LiquidityAmounts.sol";
|
||||
|
||||
|
||||
contract TestSinglePool {
|
||||
|
||||
IUniswapV3Factory public factory = IUniswapV3Factory(0x1F98431c8aD98523631AE4a59f267346ea31F984);
|
||||
INonfungiblePositionManager public nfpm = INonfungiblePositionManager(0xC36442b4a4522E871399CD717aBDD847Ab11FE88);
|
||||
ISwapRouter public swapper = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);
|
||||
IUniswapV3Pool public immutable pool;
|
||||
uint24 public fee;
|
||||
MockERC20 public WETH;
|
||||
MockERC20 public USDC;
|
||||
MockERC20 public token0; // either WETH or USDC depending on the order in the pool
|
||||
MockERC20 public token1;
|
||||
|
||||
function setUp() public {
|
||||
MockERC20 weth = MockERC20('Mock Wrapped Ethereum', 'WETH', 18);
|
||||
MockERC20 usdc = MockERC20('Mock USD Coin', 'USDC', 6);
|
||||
uint24 fee_ = 500;
|
||||
fee = fee_;
|
||||
WETH = weth;
|
||||
USDC = usdc;
|
||||
IUniswapV3Pool pool_ = UniswapV3Pool(factory.createPool(address(weth), address(usdc), fee_));
|
||||
pool = pool_;
|
||||
token0 = pool_.token0();
|
||||
token1 = pool_.token1();
|
||||
}
|
||||
|
||||
// struct MintParams {
|
||||
// address token0;
|
||||
// address token1;
|
||||
// uint24 fee;
|
||||
// int24 tickLower;
|
||||
// int24 tickUpper;
|
||||
// uint256 amount0Desired;
|
||||
// uint256 amount1Desired;
|
||||
// uint256 amount0Min;
|
||||
// uint256 amount1Min;
|
||||
// address recipient;
|
||||
// uint256 deadline;
|
||||
// }
|
||||
|
||||
function stake(uint160 liquidity, uint24 lower, uint24 upper) public {
|
||||
uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(lower);
|
||||
uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(upper);
|
||||
(uint160 sqrtPriceX96, , , , , , ) = pool.slot0();
|
||||
(uint256 amount0, uint256 amount1) = LiquidityAmounts.getAmountsForLiquidity(liquidity, sqrtPriceX96, sqrtRatioAX96, sqrtRatioBX96);
|
||||
token0.mint(amount0);
|
||||
token1.mint(amount1);
|
||||
INonfungiblePositionManager.MintParams memory params = INonfungiblePositionManager.MintParams(
|
||||
address(token0), address(token1), fee, lower, upper, amount0, amount1, 0, 0, msg.sender, block.timestamp
|
||||
);
|
||||
nfpm.mint(params);
|
||||
}
|
||||
|
||||
|
||||
function swap() public {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user