Skip to content

Commit

Permalink
Merge branch 'main' into test/more
Browse files Browse the repository at this point in the history
  • Loading branch information
clemlak authored Jul 12, 2024
2 parents a5e38a5 + d89b753 commit 2eeb0e4
Show file tree
Hide file tree
Showing 18 changed files with 6,300 additions and 2 deletions.
49 changes: 49 additions & 0 deletions broadcast/DeployFactory.s.sol/1/run-1718649905.json

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions broadcast/DeployFactory.s.sol/1/run-1718649919.json

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions broadcast/DeployFactory.s.sol/1/run-1718649926.json

Large diffs are not rendered by default.

84 changes: 84 additions & 0 deletions broadcast/DeployFactory.s.sol/1/run-1718650179.json

Large diffs are not rendered by default.

84 changes: 84 additions & 0 deletions broadcast/DeployFactory.s.sol/1/run-latest.json

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions broadcast/DeployFactory.s.sol/753712/run-1718650463.json

Large diffs are not rendered by default.

84 changes: 84 additions & 0 deletions broadcast/DeployFactory.s.sol/753712/run-1718650520.json

Large diffs are not rendered by default.

84 changes: 84 additions & 0 deletions broadcast/DeployFactory.s.sol/753712/run-latest.json

Large diffs are not rendered by default.

1,002 changes: 1,002 additions & 0 deletions broadcast/DeployPool.s.sol/753712/run-1718650594.json

Large diffs are not rendered by default.

1,080 changes: 1,080 additions & 0 deletions broadcast/DeployPool.s.sol/753712/run-1718650742.json

Large diffs are not rendered by default.

1,034 changes: 1,034 additions & 0 deletions broadcast/DeployPool.s.sol/753712/run-1718650883.json

Large diffs are not rendered by default.

1,112 changes: 1,112 additions & 0 deletions broadcast/DeployPool.s.sol/753712/run-1718651002.json

Large diffs are not rendered by default.

1,112 changes: 1,112 additions & 0 deletions broadcast/DeployPool.s.sol/753712/run-latest.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ mainnet = "${MAINNET_RPC_URL}"
op_sepolia = "${OP_SEPOLIA_RPC_URL}"
testnet = "${TESTNET_RPC_URL}"

unknown_chain = { key = "", chain = 753712, url = "https://virtual.mainnet.rpc.tenderly.co/ab7a4b34-a4da-4803-8130-01cf2230dbe6" }
[etherscan]
unknown_chain = { key = "${TENDERLY_ACCESS_KEY}", chain = 753712, url = "https://virtual.mainnet.rpc.tenderly.co/ab7a4b34-a4da-4803-8130-01cf2230dbe6" }
3 changes: 3 additions & 0 deletions script/DeployFactory.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.13;

import {Script, console2} from "forge-std/Script.sol";
import {RMM} from "../src/RMM.sol";
import {LiquidityManager} from "../src/LiquidityManager.sol";
import {Factory} from "../src/Factory.sol";

address constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
Expand All @@ -20,7 +21,9 @@ contract DeployFactory is Script {
address sender = vm.addr(pk);
console2.log("Deploying RMM from", sender);
Factory factory = new Factory(WETH_ADDRESS);
LiquidityManager liquidityManager = new LiquidityManager();
console2.log("Factory deployed at", address(factory));
console2.log("LiquidityManager deployed at", address(liquidityManager));

vm.stopBroadcast();
}
Expand Down
2 changes: 1 addition & 1 deletion script/DeployPool.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ contract DeployPool is Script {
address public constant PT_ADDRESS = address(0);
uint256 public constant fee = 0.0002 ether;
address public constant curator = address(0);
Factory FACTORY = Factory(0x6755436568792bC8E69020d8d77230fADCC4C9ef);
Factory FACTORY = Factory(0xA61D6761ce83F1A2E3B128B7a5033e99BcdAa7d5);
IPMarket market = IPMarket(0xC374f7eC85F8C7DE3207a10bB1978bA104bdA3B2);
IPAllActionV3 router = IPAllActionV3(0x00000000005BBB0EF59571E58418F9a4357b68A0);
address wstETH = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; //real wsteth
Expand Down
182 changes: 182 additions & 0 deletions src/LiquidityManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.13;

import {IStandardizedYield} from "pendle/interfaces/IStandardizedYield.sol";
import {PYIndexLib, PYIndex} from "pendle/core/StandardizedYield/PYIndex.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {SafeTransferLib, ERC20} from "solmate/utils/SafeTransferLib.sol";

import {RMM, IPYieldToken} from "./RMM.sol";
import {InvalidTokenIn, InsufficientSYMinted} from "./lib/RmmErrors.sol";

contract LiquidityManager {
using PYIndexLib for PYIndex;
using PYIndexLib for IPYieldToken;
using FixedPointMathLib for uint256;
using SafeTransferLib for ERC20;

function mintSY(address SY, address receiver, address tokenIn, uint256 amountTokenToDeposit, uint256 minSharesOut)
public
payable
returns (uint256 amountOut)
{
IStandardizedYield sy = IStandardizedYield(SY);
if (!sy.isValidTokenIn(tokenIn)) revert InvalidTokenIn(tokenIn);

if (msg.value > 0 && sy.isValidTokenIn(address(0))) {
// SY minted check is done in this function instead of relying on the SY contract's deposit().
amountOut += sy.deposit{value: msg.value}(address(this), address(0), msg.value, 0);
}

if (tokenIn != address(0)) {
ERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountTokenToDeposit);
amountOut += sy.deposit(receiver, tokenIn, amountTokenToDeposit, 0);
}

if (amountOut < minSharesOut) {
revert InsufficientSYMinted(amountOut, minSharesOut);
}
}

struct AllocateArgs {
address rmm;
uint256 amountIn;
uint256 minOut;
uint256 minLiquidityDelta;
uint256 initialGuess;
uint256 epsilon;
}

function allocateFromSy(AllocateArgs calldata args) external returns (uint256 liquidity) {
RMM rmm = RMM(payable(args.rmm));

ERC20 sy = ERC20(address(rmm.SY()));
ERC20 pt = ERC20(address(rmm.PT()));

PYIndex index = IPYieldToken(rmm.YT()).newIndex();
uint256 rX = rmm.reserveX();
uint256 rY = rmm.reserveY();

// validate swap approximation
(uint256 syToSwap,) = computeSyToPtToAddLiquidity(
ComputeArgs({
rmm: args.rmm,
rX: rX,
rY: rY,
index: index,
maxIn: args.amountIn,
blockTime: block.timestamp,
initialGuess: args.initialGuess,
epsilon: args.epsilon
})
);

// transfer all sy in
sy.safeTransferFrom(msg.sender, address(this), args.amountIn);
sy.approve(address(args.rmm), args.amountIn);

// swap syToSwap for pt
rmm.swapExactSyForPt(syToSwap, args.minOut, address(this));
uint256 syBal = sy.balanceOf(address(this));
uint256 ptBal = pt.balanceOf(address(this));

pt.approve(address(args.rmm), ptBal);
liquidity = rmm.allocate(syBal, ptBal, args.minLiquidityDelta, msg.sender);
}

function allocateFromPt(AllocateArgs calldata args) external returns (uint256 liquidity) {
RMM rmm = RMM(payable(args.rmm));
ERC20 sy = ERC20(address(rmm.SY()));
ERC20 pt = ERC20(address(rmm.PT()));

PYIndex index = IPYieldToken(rmm.YT()).newIndex();
uint256 rX = rmm.reserveX();
uint256 rY = rmm.reserveY();

// validate swap approximation
(uint256 ptToSwap,) = computePtToSyToAddLiquidity(
ComputeArgs({
rmm: args.rmm,
rX: rX,
rY: rY,
index: index,
maxIn: args.amountIn,
blockTime: block.timestamp,
initialGuess: args.initialGuess,
epsilon: args.epsilon
})
);

// transfer all pt in
pt.safeTransferFrom(msg.sender, address(this), args.amountIn);
pt.approve(address(rmm), args.amountIn);

// swap ptToSwap for sy
rmm.swapExactPtForSy(ptToSwap, args.minOut, address(this));
uint256 syBal = sy.balanceOf(address(this));
uint256 ptBal = pt.balanceOf(address(this));

sy.approve(address(rmm), syBal);
liquidity = rmm.allocate(syBal, ptBal, args.minLiquidityDelta, msg.sender);
}

struct ComputeArgs {
address rmm;
uint256 rX;
uint256 rY;
PYIndex index;
uint256 maxIn;
uint256 blockTime;
uint256 initialGuess;
uint256 epsilon;
}

function computePtToSyToAddLiquidity(ComputeArgs memory args) public view returns (uint256 guess, uint256 syOut) {
uint256 min = 0;
uint256 max = args.maxIn - 1;
for (uint256 iter = 0; iter < 256; ++iter) {
guess = args.initialGuess > 0 && iter == 0 ? args.initialGuess : (min + max) / 2;
(,, syOut,,) = RMM(payable(args.rmm)).prepareSwapPtIn(guess, args.blockTime, args.index);

uint256 syNumerator = syOut * (args.rX - syOut);
uint256 ptNumerator = (args.maxIn - guess) * (args.rY + guess);

if (isAApproxB(syNumerator, ptNumerator, args.epsilon)) {
return (guess, syOut);
}

if (syNumerator <= ptNumerator) {
min = guess + 1;
} else {
max = guess - 1;
}
}
}

function computeSyToPtToAddLiquidity(ComputeArgs memory args) public view returns (uint256 guess, uint256 ptOut) {
RMM rmm = RMM(payable(args.rmm));
uint256 min = 0;
uint256 max = args.maxIn - 1;
for (uint256 iter = 0; iter < 256; ++iter) {
guess = args.initialGuess > 0 && iter == 0 ? args.initialGuess : (min + max) / 2;
(,, ptOut,,) = rmm.prepareSwapSyIn(guess, args.blockTime, args.index);

uint256 syNumerator = (args.maxIn - guess) * (args.rX + guess);
uint256 ptNumerator = ptOut * (args.rY - ptOut);

if (isAApproxB(syNumerator, ptNumerator, args.epsilon)) {
return (guess, ptOut);
}

if (ptNumerator <= syNumerator) {
min = guess + 1;
} else {
max = guess - 1;
}
}
}

function isAApproxB(uint256 a, uint256 b, uint256 eps) internal pure returns (bool) {
return b.mulWadDown(1 ether - eps) <= a && a <= b.mulWadDown(1 ether + eps);
}
}
Loading

0 comments on commit 2eeb0e4

Please sign in to comment.