Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SY Covered Call #135

Open
wants to merge 14 commits into
base: feat/v0.3.0
Choose a base branch
from
15 changes: 14 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,17 @@

[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
url = https://github.com/foundry-rs/forge-std

[submodule "lib/pendle-core-v2-public"]
path = lib/pendle-core-v2-public
url = https://github.com/pendle-finance/pendle-core-v2-public

[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
branch = v4.9.3

[submodule "lib/openzeppelin-contracts-upgradeable"]
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
2 changes: 2 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
remappings = [
"solmate/=lib/solstat/lib/solmate/src/",
"solstat/=lib/solstat/src/",
"pendle/=lib/pendle-core-v2-public/contracts/"
]
solc_version = "0.8.22"

Expand All @@ -23,6 +24,7 @@ number_underscore = "thousands"
[rpc_endpoints]
local = "http://localhost:8545"
optimism_sepolia = "${OPTIMISM_SEPOLIA_RPC_URL}"
mainnet = "${MAINNET_RPC_URL}"

[etherscan]
optimism_sepolia = { key = "${ETHERSCAN_API_KEY}" }
1 change: 1 addition & 0 deletions lib/openzeppelin-contracts
Submodule openzeppelin-contracts added at dbb610
1 change: 1 addition & 0 deletions lib/openzeppelin-contracts-upgradeable
1 change: 1 addition & 0 deletions lib/pendle-core-v2-public
Submodule pendle-core-v2-public added at bc27b1
2 changes: 1 addition & 1 deletion src/ConstantSum/ConstantSumSolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ contract ConstantSumSolver {
swapData = abi.encode(1, 0, amountIn, amountOut);
}

(bool valid,,,,,,) = IStrategy(strategy).validateSwap(
(bool valid,,,,,,,) = IStrategy(strategy).validateSwap(
address(this), poolId, pool, swapData
);
return (valid, amountOut, swapData);
Expand Down
32 changes: 24 additions & 8 deletions src/CoveredCall/CoveredCall.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
decodeControllerUpdate
} from "src/CoveredCall/CoveredCallUtils.sol";
import { EPSILON } from "src/lib/StrategyLib.sol";
import "forge-std/console2.sol";
import { IStandardizedYield } from "pendle/interfaces/IStandardizedYield.sol";

enum UpdateCode {
Invalid,
Expand All @@ -33,6 +33,7 @@ struct InternalParams {
uint256 maturity;
uint256 swapFee;
address controller;
uint256 lastTimestamp;
}

/// @dev Parameterization of the Log Normal curve.
Expand All @@ -42,7 +43,7 @@ struct CoveredCallParams {
uint256 maturity;
uint256 swapFee;
address controller;
uint256 timestamp;
uint256 lastTimestamp;
}

/// @dev Thrown when the mean parameter is not within the allowed bounds.
Expand Down Expand Up @@ -98,7 +99,7 @@ contract CoveredCall is PairStrategy {
(reserves, totalLiquidity, params) =
abi.decode(data, (uint256[], uint256, CoveredCallParams));

params.timestamp = block.timestamp;
params.lastTimestamp = block.timestamp;

if (params.mean < MIN_WIDTH || params.mean > MAX_MEAN) {
revert InvalidMean();
Expand Down Expand Up @@ -158,7 +159,7 @@ contract CoveredCall is PairStrategy {
params.mean = internalParams[poolId].mean;
params.swapFee = internalParams[poolId].swapFee;
params.maturity = internalParams[poolId].maturity;
params.timestamp = IDFMM(dfmm).pools(poolId).lastSwapTimestamp;
params.lastTimestamp = internalParams[poolId].lastTimestamp;

return abi.encode(params);
}
Expand All @@ -180,19 +181,25 @@ contract CoveredCall is PairStrategy {
uint256 tokenOutIndex,
uint256 amountIn,
uint256 amountOut,
uint256 deltaLiquidity
uint256 deltaLiquidity,
bytes memory params
)
{
bytes memory params = getPoolParams(poolId);
params = getPoolParams(poolId);

CoveredCallParams memory ccParams =
abi.decode(params, (CoveredCallParams));
ccParams.lastTimestamp = block.timestamp;

params = abi.encode(ccParams);

uint256 computedL;
(tokenInIndex, tokenOutIndex, amountIn, amountOut, computedL) =
abi.decode(data, (uint256, uint256, uint256, uint256, uint256));

int256 computedInvariant =
tradingFunction(pool.reserves, computedL, params);

console2.log("Computed Invariant: {}", computedInvariant);

if (computedInvariant < 0 || computedInvariant > EPSILON) {
revert InvalidComputedLiquidity(computedInvariant);
}
Expand All @@ -211,6 +218,15 @@ contract CoveredCall is PairStrategy {
//valid = invariant >= 0 && invariant <= EPSILON;
}

function postSwapHook(
address,
uint256 poolId,
Pool calldata pool,
bytes calldata
) external override onlyDFMM {
internalParams[poolId].lastTimestamp = block.timestamp;
}

/// @inheritdoc IStrategy
function tradingFunction(
uint256[] memory reserves,
Expand Down
4 changes: 2 additions & 2 deletions src/CoveredCall/CoveredCallMath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ function computeTradingFunction(
}

function computeTau(CoveredCallParams memory params) pure returns (uint256) {
if (params.timestamp >= params.maturity) {
if (params.lastTimestamp >= params.maturity) {
return 0;
} else {
return ONE * (params.maturity - params.timestamp) / YEAR;
return ONE * (params.maturity - params.lastTimestamp) / YEAR;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/CoveredCall/CoveredCallSolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ contract CoveredCallSolver {
uint256 timestamp
) public view returns (CoveredCallParams memory) {
CoveredCallParams memory params = getPoolParams(poolId);
params.timestamp = timestamp;
params.lastTimestamp = timestamp;
return params;
}

Expand Down Expand Up @@ -305,7 +305,7 @@ contract CoveredCallSolver {
}

uint256 poolId = poolId;
(bool valid,,,,,,) = IStrategy(strategy).validateSwap(
(bool valid,,,,,,,) = IStrategy(strategy).validateSwap(
address(this), poolId, pool, swapData
);

Expand Down
26 changes: 15 additions & 11 deletions src/DFMM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
downscaleUp
} from "./lib/ScalingLib.sol";
import { LPToken } from "./LPToken.sol";
import "forge-std/console2.sol";

/**
* @title DFMM
Expand Down Expand Up @@ -81,8 +82,7 @@ contract DFMM is IDFMM {
totalLiquidity: 0,
liquidityToken: address(liquidityToken),
feeCollector: params.feeCollector,
controllerFee: params.controllerFee,
lastSwapTimestamp: block.timestamp
controllerFee: params.controllerFee
});

(
Expand Down Expand Up @@ -216,9 +216,9 @@ contract DFMM is IDFMM {
uint256 amountIn;
uint256 amountOut;
uint256 deltaLiquidity;
bytes postSwapHookData;
}

/// @inheritdoc IDFMM
function swap(
uint256 poolId,
address recipient,
Expand All @@ -227,20 +227,21 @@ contract DFMM is IDFMM {
) external payable lock returns (address, address, uint256, uint256) {
SwapState memory state;

_pools[poolId].lastSwapTimestamp = block.timestamp;

(
state.valid,
state.invariant,
state.tokenInIndex,
state.tokenOutIndex,
state.amountIn,
state.amountOut,
state.deltaLiquidity
state.deltaLiquidity,
state.postSwapHookData
) = IStrategy(_pools[poolId].strategy).validateSwap(
msg.sender, poolId, _pools[poolId], data
);

uint256 poolId = poolId;

if (!state.valid) revert InvalidInvariant(state.invariant);

if (_pools[poolId].controllerFee > 0) {
Expand All @@ -259,16 +260,19 @@ contract DFMM is IDFMM {
state.tokenIn = _pools[poolId].tokens[state.tokenInIndex];
state.tokenOut = _pools[poolId].tokens[state.tokenOutIndex];

address[] memory tokens = new address[](1);
tokens[0] = state.tokenIn;
uint256[] memory amounts = new uint256[](1);
amounts[0] = state.amountIn;

// Optimistically transfer the output tokens to the recipient.
_transfer(state.tokenOut, recipient, state.amountOut);

IStrategy(_pools[poolId].strategy).postSwapHook(
msg.sender, poolId, _pools[poolId], state.postSwapHookData
);

// If the callbackData is empty, do a regular `_transferFrom()` call, as in the other operations.
if (callbackData.length == 0) {
address[] memory tokens = new address[](1);
tokens[0] = state.tokenIn;
uint256[] memory amounts = new uint256[](1);
amounts[0] = state.amountIn;
_transferFrom(tokens, amounts);
} else {
// Otherwise, execute the callback and assert the input amount has been paid
Expand Down
2 changes: 1 addition & 1 deletion src/GeometricMean/GeometricMeanSolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ contract GeometricMeanSolver {
bytes memory swapData =
abi.encode(tokenInIndex, tokenOutIndex, amountIn, state.amountOut);

(bool valid,,,,,,) = IStrategy(strategy).validateSwap(
(bool valid,,,,,,,) = IStrategy(strategy).validateSwap(
address(this), poolId, pool, swapData
);

Expand Down
2 changes: 1 addition & 1 deletion src/LogNormal/LogNormalSolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ contract LogNormalSolver {
}

uint256 poolId = poolId;
(bool valid,,,,,,) = IStrategy(strategy).validateSwap(
(bool valid,,,,,,,) = IStrategy(strategy).validateSwap(
address(this), poolId, pool, swapData
);
return (
Expand Down
2 changes: 1 addition & 1 deletion src/NTokenGeometricMean/NTokenGeometricMeanSolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ contract NTokenGeometricMeanSolver {
bytes memory swapData =
abi.encode(tokenInIndex, tokenOutIndex, amountIn, state.amountOut);

(bool valid,,,,,,) = IStrategy(strategy).validateSwap(
(bool valid,,,,,,,) = IStrategy(strategy).validateSwap(
address(this), poolId, pool, swapData
);

Expand Down
12 changes: 10 additions & 2 deletions src/NTokenStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,11 @@ abstract contract NTokenStrategy is IStrategy {
uint256 tokenOutIndex,
uint256 amountIn,
uint256 amountOut,
uint256 deltaLiquidity
uint256 deltaLiquidity,
bytes memory params
)
{
bytes memory params = getPoolParams(poolId);
params = getPoolParams(poolId);

(tokenInIndex, tokenOutIndex, amountIn, amountOut) =
abi.decode(data, (uint256, uint256, uint256, uint256));
Expand All @@ -150,6 +151,13 @@ abstract contract NTokenStrategy is IStrategy {
valid = invariant >= 0;
}

function postSwapHook(
address,
uint256,
Pool memory,
bytes memory
) external { }

/// @inheritdoc IStrategy
function getPoolParams(uint256 poolId)
public
Expand Down
12 changes: 10 additions & 2 deletions src/PairStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,11 @@ abstract contract PairStrategy is IStrategy {
uint256 tokenOutIndex,
uint256 amountIn,
uint256 amountOut,
uint256 deltaLiquidity
uint256 deltaLiquidity,
bytes memory params
)
{
bytes memory params = getPoolParams(poolId);
params = getPoolParams(poolId);

(tokenInIndex, tokenOutIndex, amountIn, amountOut) =
abi.decode(data, (uint256, uint256, uint256, uint256));
Expand All @@ -156,6 +157,13 @@ abstract contract PairStrategy is IStrategy {
valid = invariant >= 0;
}

function postSwapHook(
address,
uint256,
Pool memory,
bytes calldata
) external virtual onlyDFMM { }

/// @inheritdoc IStrategy
function getPoolParams(uint256 poolId)
public
Expand Down
Loading
Loading