Skip to content

Commit

Permalink
clvr model
Browse files Browse the repository at this point in the history
  • Loading branch information
pysel committed Nov 23, 2024
1 parent 481d7ac commit 75228ae
Show file tree
Hide file tree
Showing 12 changed files with 388 additions and 96 deletions.
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@
[submodule "lib/prb-math"]
path = lib/prb-math
url = https://github.com/paulrberg/prb-math
[submodule "lib/v4-core"]
path = lib/v4-core
url = https://github.com/Uniswap/v4-core
[submodule "lib/v4-periphery"]
path = lib/v4-periphery
url = https://github.com/Uniswap/v4-periphery
2 changes: 2 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ remappings = [
"@uniswap/v3-periphery/=lib/v3-periphery/",
"@uniswap/v3-core/=lib/v3-core/",
"@prb-math/=lib/prb-math/src/",
"@uniswap/v4-core/=lib/v4-core/",
"@uniswap/v4-periphery/=lib/v4-periphery/",
]
1 change: 1 addition & 0 deletions lib/v4-core
Submodule v4-core added at b619b6
1 change: 1 addition & 0 deletions lib/v4-periphery
Submodule v4-periphery added at 1394ff
114 changes: 57 additions & 57 deletions src/ClvrExecutor.sol
Original file line number Diff line number Diff line change
@@ -1,57 +1,57 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import { ISwapRouter } from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import { ClvrIntentPool } from "./ClvrIntentPool.sol";
import { ClvrLibrary } from "./ClvrLibrary.sol";

contract ClvrExecutor {
ClvrIntentPool private intentPool;
ISwapRouter private swapRouter;

constructor(address intentPool_, address swapRouter_) {
intentPool = ClvrIntentPool(intentPool_);
swapRouter = ISwapRouter(swapRouter_);
}

/**
* @notice Execute a batch of intents
* @param statusQuoPrice The starting price TODO: get this in contract
* @param poolKey The identifier for the pool through which the intents are being executed
* @param intents The intents to execute
*/
function executeBatch(uint256 statusQuoPrice, bytes32 poolKey, ClvrLibrary.CLVRIntent[] memory intents) public {
// uint256[] memory volumes = new uint256[](intents.length);
for (uint256 i = 0; i < intents.length; i++) {
bytes32 intentHash = keccak256(abi.encode(intents[i]));

bytes4 verification = intentPool.intentExists(poolKey, intentHash);

if (verification != ClvrLibrary.MAGICVALUE) {
revert("Invalid Intent Passed to Executor");
}
}
}

function executeIntent(ClvrLibrary.CLVRIntent memory intent) private {
IERC20(intent.tokenIn).transferFrom(intent.creator, address(this), intent.amountIn);
IERC20(intent.tokenIn).approve(address(swapRouter), intent.amountIn);

uint256 amountOut = swapRouter.exactInputSingle(ISwapRouter.ExactInputSingleParams({
tokenIn: intent.tokenIn,
tokenOut: intent.tokenOut,
fee: intent.fee,
recipient: intent.recipient,
deadline: block.timestamp,
amountIn: intent.amountIn,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
}));

IERC20(intent.tokenOut).transfer(intent.recipient, amountOut);

// emit IntentExecuted(intent.creator, intent.tokenIn, intent.tokenOut, intent.recipient, intent.fee, intent.amountIn, amountOut);
}
}
// // SPDX-License-Identifier: MIT
// pragma solidity ^0.8.24;

// import { ISwapRouter } from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
// import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

// import { ClvrIntentPool } from "./ClvrIntentPool.sol";
// import { ClvrLibrary } from "./ClvrLibrary.sol";

// contract ClvrExecutor {
// ClvrIntentPool private intentPool;
// ISwapRouter private swapRouter;

// constructor(address intentPool_, address swapRouter_) {
// intentPool = ClvrIntentPool(intentPool_);
// swapRouter = ISwapRouter(swapRouter_);
// }

// /**
// * @notice Execute a batch of intents
// * @param statusQuoPrice The starting price TODO: get this in contract
// * @param poolKey The identifier for the pool through which the intents are being executed
// * @param intents The intents to execute
// */
// function executeBatch(uint256 statusQuoPrice, bytes32 poolKey, ClvrLibrary.CLVRIntent[] memory intents) public {
// // uint256[] memory volumes = new uint256[](intents.length);
// for (uint256 i = 0; i < intents.length; i++) {
// bytes32 intentHash = keccak256(abi.encode(intents[i]));

// bytes4 verification = intentPool.intentExists(poolKey, intentHash);

// if (verification != ClvrLibrary.MAGICVALUE) {
// revert("Invalid Intent Passed to Executor");
// }
// }
// }

// function executeIntent(ClvrLibrary.CLVRIntent memory intent) private {
// IERC20(intent.tokenIn).transferFrom(intent.creator, address(this), intent.amountIn);
// IERC20(intent.tokenIn).approve(address(swapRouter), intent.amountIn);

// uint256 amountOut = swapRouter.exactInputSingle(ISwapRouter.ExactInputSingleParams({
// tokenIn: intent.tokenIn,
// tokenOut: intent.tokenOut,
// fee: intent.fee,
// recipient: intent.recipient,
// deadline: block.timestamp,
// amountIn: intent.amountIn,
// amountOutMinimum: 0,
// sqrtPriceLimitX96: 0
// }));

// IERC20(intent.tokenOut).transfer(intent.recipient, amountOut);

// // emit IntentExecuted(intent.creator, intent.tokenIn, intent.tokenOut, intent.recipient, intent.fee, intent.amountIn, amountOut);
// }
// }
121 changes: 121 additions & 0 deletions src/ClvrHook.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {BaseHook} from "@uniswap/v4-periphery/src/base/hooks/BaseHook.sol";

import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol";
import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {BeforeSwapDelta, BeforeSwapDeltaLibrary} from "@uniswap/v4-core/src/types/BeforeSwapDelta.sol";
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol";

import { ClvrIntentPool } from "./ClvrIntentPool.sol";
import { ClvrModel } from "./ClvrModel.sol";


contract ClvrHook is BaseHook {
using SafeCast for *;

struct SwapParamsExtended {
address recepient;
IPoolManager.SwapParams params;
}

mapping(PoolId => SwapParamsExtended[]) public swapParams;
ClvrModel private model;

constructor(IPoolManager _manager) BaseHook(_manager) {}

function getHookPermissions()
public
pure
virtual
override
returns (Hooks.Permissions memory)
{
return Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: true,
afterSwap: false,
beforeDonate: true,
afterDonate: false,
beforeSwapReturnDelta: false,
afterSwapReturnDelta: false,
afterAddLiquidityReturnDelta: false,
afterRemoveLiquidityReturnDelta: false
});
}

function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata params, bytes calldata data)
external
override
returns (bytes4, BeforeSwapDelta, uint24)
{
require(params.amountSpecified < 0, "Clvr Pools only work with exact input swaps");

PoolId poolId = PoolIdLibrary.toId(key);

Currency input = params.zeroForOne ? key.currency0 : key.currency1;
uint256 amountTaken = uint256(params.amountSpecified);
poolManager.mint(address(this), input.toId(), amountTaken);

address recepient = abi.decode(data, (address));

SwapParamsExtended memory paramsE = SwapParamsExtended({
recepient: recepient,
params: params
});

// Store the swap params
swapParams[poolId].push(paramsE);

return (BaseHook.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA, 0);
}

function beforeDonate(address, PoolKey calldata key, uint256, uint256, bytes calldata)
external
override
returns (bytes4)
{
PoolId poolId = key.toId();

SwapParamsExtended[] memory params = swapParams[poolId];
if (params.length == 0) {
return BaseHook.beforeDonate.selector;
}

// ClvrModel.TradeMinimal[] memory trades = swapParamsToTradeMinimalArrays(params);


}

// function swapParamsToTradeMinimalArrays(SwapParamsExtended[] memory params) internal view returns (ClvrModel.TradeMinimal[] memory) {
// ClvrModel.TradeMinimal[] memory tradeMinimals = new ClvrModel.TradeMinimal[](params.length);

// // append null trade at the beginning
// tradeMinimals[0] = ClvrModel.TradeMinimal({
// direction: ClvrModel.Direction.NULL,
// amountIn: 0
// });

// for (uint256 i = 0; i < params.length; i++) {
// tradeMinimals[i + 1] = swapParamsToTradeMinimal(params[i]);
// }
// return tradeMinimals;
// }

// function swapParamsToTradeMinimal(SwapParamsExtended memory params) internal view returns (ClvrModel.TradeMinimal memory) {
// return ClvrModel.TradeMinimal({
// direction: params.params.zeroForOne ? ClvrModel.Direction.Buy : ClvrModel.Direction.Sell,
// amountIn: uint256(-params.params.amountSpecified)
// });
// }
}
33 changes: 25 additions & 8 deletions src/ClvrIntentPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,25 @@ pragma solidity ^0.8.24;
import "@openzeppelin/contracts/interfaces/IERC1271.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import { ClvrLibrary } from "./ClvrLibrary.sol";


contract ClvrIntentPool {
struct CLVRIntent {
address creator;
address tokenIn;
address tokenOut;
address recipient;
uint24 fee;
uint256 amountIn;
uint256 deadline;
}

// Mapping from PoolKey to Intents for a pool
mapping(bytes32 => mapping(bytes32 => ClvrLibrary.CLVRIntent)) public intents;
mapping(bytes32 => mapping(bytes32 => CLVRIntent)) public intents;

address internal constant EMPTY_ADDRESS = address(0);
bytes4 internal constant MAGICVALUE = 0x1626ba7e;
bytes4 internal constant INVALID_SIGNATURE = ~MAGICVALUE;

constructor() {}

Expand All @@ -20,7 +33,7 @@ contract ClvrIntentPool {
* @param r The r component of the signature
* @param s The s component of the signature
*/
function submitIntent(ClvrLibrary.CLVRIntent memory intent, uint8 v, bytes32 r, bytes32 s) public {
function submitIntent(CLVRIntent memory intent, uint8 v, bytes32 r, bytes32 s) public {
bytes32 digest = keccak256(abi.encode(intent));

// Ensure the intent is valid
Expand All @@ -29,22 +42,26 @@ contract ClvrIntentPool {
revert("Invalid signature");
}

bytes32 poolKey = ClvrLibrary.getPoolKey(intent.tokenIn, intent.tokenOut, intent.fee);
bytes32 poolKey = getPoolKey(intent.tokenIn, intent.tokenOut, intent.fee);

// Store the intent
// Note: if the intent exists in the mapping, it has been signed already
intents[poolKey][digest] = intent;
}

function getPoolKey(address tokenIn, address tokenOut, uint24 fee) internal pure returns (bytes32) {
return keccak256(abi.encode(tokenIn, tokenOut, fee));
}

function intentExists(
bytes32 poolKey,
bytes32 intentHash
) external view returns (bytes4 magicValue) {
ClvrLibrary.CLVRIntent memory intent = intents[poolKey][intentHash];
if (intent.creator == ClvrLibrary.EMPTY_ADDRESS) {
return ClvrLibrary.INVALID_SIGNATURE;
CLVRIntent memory intent = intents[poolKey][intentHash];
if (intent.creator == EMPTY_ADDRESS) {
return INVALID_SIGNATURE;
}

return ClvrLibrary.MAGICVALUE;
return MAGICVALUE;
}
}
25 changes: 0 additions & 25 deletions src/ClvrLibrary.sol

This file was deleted.

20 changes: 20 additions & 0 deletions src/ClvrLn.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import { ln } from "@prb-math/ud60x18/Math.sol";
import { UD60x18, ud } from "@prb-math/UD60x18.sol";
import { console } from "forge-std/console.sol";

import { ClvrIntentPool } from "./ClvrIntentPool.sol";

// NOT AN ACTUAL NATURAL LOG
library ClvrLn {
// ln only takes >1e18 uints, hence use property:
// ln(a) = ln(a * 1e18 / 1e18) = ln(a * 1e18) - ln(1e18)
function lnU256(uint256 x) public pure returns (uint256) {
uint256 appendedX = x * 1e18;
uint256 natlog1e18 = ln(ud(appendedX)).unwrap();
return natlog1e18;
}
}

Loading

0 comments on commit 75228ae

Please sign in to comment.