Skip to content

Commit

Permalink
finish donate with a basic test case
Browse files Browse the repository at this point in the history
  • Loading branch information
pysel committed Nov 25, 2024
1 parent c5df211 commit a37fb4a
Show file tree
Hide file tree
Showing 9 changed files with 377 additions and 197 deletions.
4 changes: 4 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
src = "src"
out = "out"
libs = ["lib"]
ffi = true
fs_permissions = [{ access = "read-write", path = ".forge-snapshots/"}]
solc_version = "0.8.26"
evm_version = "cancun"

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
remappings = [
Expand Down
57 changes: 0 additions & 57 deletions src/ClvrExecutor.sol

This file was deleted.

160 changes: 110 additions & 50 deletions src/ClvrHook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,32 @@ 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 {BalanceDelta, BalanceDeltaLibrary} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {BeforeSwapDelta, BeforeSwapDeltaLibrary, toBeforeSwapDelta } 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 {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol";
import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";
import {CurrencySettler} from "@uniswap/v4-core/test/utils/CurrencySettler.sol";


import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import { ClvrIntentPool } from "./ClvrIntentPool.sol";
import { ClvrModel } from "./ClvrModel.sol";
import {PoolSwapTest} from "@uniswap/v4-core/src/test/PoolSwapTest.sol";
import {console} from "forge-std/console.sol";


contract ClvrHook is BaseHook {
using SafeCast for *;
using StateLibrary for IPoolManager;
using BalanceDeltaLibrary for BalanceDelta;
using TransientStateLibrary for IPoolManager;
using CurrencySettler for Currency;

struct SwapParamsExtended {
address sender;
address recepient;
IPoolManager.SwapParams params;
}
Expand All @@ -33,8 +42,12 @@ contract ClvrHook is BaseHook {
mapping(PoolId => SwapParamsExtended[]) public swapParams;

ClvrModel private model;
PoolSwapTest swapRouter;

constructor(IPoolManager _manager) BaseHook(_manager) {}
constructor(IPoolManager _manager, PoolSwapTest _swapRouter) BaseHook(_manager) {
model = new ClvrModel(0, 0);
swapRouter = _swapRouter;
}

function getHookPermissions()
public
Expand All @@ -43,87 +56,134 @@ contract ClvrHook is BaseHook {
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
});
return
Hooks.Permissions({
beforeInitialize: false,
afterInitialize: false,
beforeAddLiquidity: false,
afterAddLiquidity: false,
beforeRemoveLiquidity: false,
afterRemoveLiquidity: false,
beforeSwap: true,
afterSwap: false,
beforeDonate: true,
afterDonate: false,
beforeSwapReturnDelta: true,
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");
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);
address recepient = abi.decode(data, (address));

if (recepient == BATCH) { // TODO: make sure this can't easily be called
if (recepient == BATCH) {
// TODO: make sure this can't easily be called
// perform the swap right away
return (BaseHook.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA, 0);
return (
BaseHook.beforeSwap.selector,
BeforeSwapDeltaLibrary.ZERO_DELTA,
0
);
}

// the hook takes the exact amount of the input currency to itself
Currency input = params.zeroForOne ? key.currency0 : key.currency1;
uint256 amountTaken = uint256(params.amountSpecified);
uint256 amountTaken = uint256(-params.amountSpecified);
poolManager.mint(address(this), input.toId(), amountTaken);

SwapParamsExtended memory paramsE = SwapParamsExtended({
sender: tx.origin,
recepient: recepient,
params: params
});

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

return (BaseHook.beforeSwap.selector, toBeforeSwapDelta(amountTaken.toInt128(), 0), 0);
return (
BaseHook.beforeSwap.selector,
toBeforeSwapDelta(amountTaken.toInt128(), 0),
0
);
}

function beforeDonate(address, PoolKey calldata key, uint256, uint256, bytes calldata)
external
override
returns (bytes4)
{
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;
}

(uint160 sqrtPriceX96, , ,) = poolManager.getSlot0(poolId);
uint256 decimals = 10 ** ERC20(Currency.unwrap(key.currency1)).decimals();
uint256 sqrtPrice = (sqrtPriceX96 * decimals) / 2 ** 96; // get sqrtPrice with decimals of token
uint256 currentPrice = sqrtPrice ** 2 / decimals;

params = model.clvrReorder(currentPrice, params, currentPrice * 1e18, 1e18/currentPrice); // currentPrice hack to simulate token amounts

for (uint256 i = 0; i < params.length; i++) {
poolManager.swap(
key,
params[i].params,
abi.encode(BATCH)
);
uint256 currentPrice = getCurrentPrice(key);

params = model.clvrReorder(
currentPrice,
params,
currentPrice * 1e18,
1e18 / currentPrice
); // currentPrice hack to simulate token amounts

for (uint256 i = 1; i < params.length; i++) {
// PoolSwapTest.TestSettings memory testSettings =
// PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false});
// swapRouter.swap(key, params[i].params, testSettings, abi.encode(BATCH));
poolManager.swap(key, params[i].params, abi.encode(BATCH));

int256 delta0 = poolManager.currencyDelta(address(this), key.currency0);
int256 delta1 = poolManager.currencyDelta(address(this), key.currency1);

// console.log(delta0);
// console.log(delta1);

if (delta0 < 0) {
key.currency0.settle(poolManager, address(this), uint256(-delta0), true);
}

if (delta1 < 0) {
key.currency1.settle(poolManager, address(this), uint256(-delta1), true);
}

if (delta0 > 0) {
key.currency0.take(poolManager, params[i].recepient, uint256(delta0), false);
}

if (delta1 > 0) {
key.currency1.take(poolManager, params[i].recepient, uint256(delta1), false);
}
}

return BaseHook.beforeDonate.selector;
}

// function sqrtPriceX96ToPrice(uint160 sqrtPriceX96) internal pure returns (uint256) {
// uint256 priceX96 = uint256(sqrtPriceX96).mul(uint256(sqrtPriceX96)).mul(1e18) >> (96 * 2);
// return priceX96;
// }
function getCurrentPrice(PoolKey calldata key) view internal returns (uint256) {
(uint160 sqrtPriceX96, , , ) = poolManager.getSlot0(key.toId());
uint256 decimals = 10 **
ERC20(Currency.unwrap(key.currency1)).decimals();
uint256 sqrtPrice = (sqrtPriceX96 * decimals) / 2 ** 96; // get sqrtPrice with decimals of token
return sqrtPrice ** 2 / decimals;
}

function _unlockCallback(
bytes calldata data
) internal override returns (bytes memory) {}
}
19 changes: 19 additions & 0 deletions src/ClvrModel.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol";

import { ClvrLn } from "./ClvrLn.sol";
import { ClvrHook } from "./ClvrHook.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";


import { console } from "forge-std/console.sol";

Expand Down Expand Up @@ -33,16 +35,21 @@ contract ClvrModel {
uint256 reserve_x,
uint256 reserve_y
) public returns (ClvrHook.SwapParamsExtended[] memory) {
o = addMockTrade(o);

// console.log("ENTERED FUNCTION");
set_reserve_x(reserve_x);
set_reserve_y(reserve_y);

int128 lnP0 = p0.lnU256().toInt128();
for (uint256 i = 1; i < o.length; i++) {
// console.log("ENTERED LOOP");
uint256 candidateIndex = i;
int128 unsquaredCandidateValue = lnP0 - P(o, i).lnU256().toInt128();
int256 candidateValue = unsquaredCandidateValue ** 2 / 1e18;

for (uint256 j = i + 1; j < o.length; j++) {
// console.log("ENTERED INNER LOOP");
swap(o, i, j);

int256 unsquaredValue = lnP0 - P(o, i).lnU256().toInt128();
Expand All @@ -64,6 +71,18 @@ contract ClvrModel {
return o;
}

// adds a mock trade as a first entry of th array
function addMockTrade(ClvrHook.SwapParamsExtended[] memory o) internal pure returns(ClvrHook.SwapParamsExtended[] memory) {
ClvrHook.SwapParamsExtended memory mock = ClvrHook.SwapParamsExtended(address(0), address(0), IPoolManager.SwapParams(false, 0, 0));
ClvrHook.SwapParamsExtended[] memory newO = new ClvrHook.SwapParamsExtended[](o.length + 1);
for (uint256 i = 0; i < o.length; i++) {
newO[i] = o[i];
}
newO[o.length] = o[0];
newO[0] = mock;
return newO;
}

function swap(ClvrHook.SwapParamsExtended[] memory o, uint256 i1, uint256 i2) internal pure {
ClvrHook.SwapParamsExtended memory temp = o[i1];
o[i1] = o[i2];
Expand Down
Loading

0 comments on commit a37fb4a

Please sign in to comment.