Skip to content

Commit

Permalink
feat: update init contract
Browse files Browse the repository at this point in the history
  • Loading branch information
yutingzhao1991 committed Aug 5, 2024
1 parent c49fc43 commit 86de20d
Show file tree
Hide file tree
Showing 11 changed files with 318 additions and 423 deletions.
31 changes: 27 additions & 4 deletions P102_InitContracts/code/Factory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,45 @@ pragma solidity ^0.8.24;
import "./interfaces/IFactory.sol";

contract Factory is IFactory {
mapping(address => mapping(address => address[])) public pools;

// parameters 是用于 Pool 创建时回调获取参数用
// 不是用构造函数是为了避免构造函数变化,那样会导致 Pool 合约地址不能按照参数计算出来
// 具体参考 https://docs.openzeppelin.com/cli/2.8/deploying-with-create2
// new_address = hash(0xFF, sender, salt, bytecode)
function parameters()
external
view
override
returns (address factory, address token0, address token1, uint24 fee)
returns (
address factory,
address token0,
address token1,
int24 tickLower,
int24 tickUpper,
uint24 fee
)
{}

function getPool(
address token0,
address token1,
uint24 fee
) external view override returns (address pool) {}
uint32 index
) external view override returns (address) {
return pools[token0][token1][index];
}

function createPool(
address token0,
address token1,
int24 tickLower,
int24 tickUpper,
uint24 fee
) external override returns (address pool) {}
) external override returns (address pool) {
// 先调用 getPools 获取当前 token0 token1 的所有 pool
// 然后判断是否已经存在 tickLower tickUpper fee 相同的 pool
// 如果存在就直接返回
// 如果不存在就创建一个新的 pool
// 然后记录到 pools 中
}
}
83 changes: 61 additions & 22 deletions P102_InitContracts/code/Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,84 @@
pragma solidity ^0.8.24;

import "./interfaces/IPool.sol";
import "./interfaces/IFactory.sol";

contract Pool is IPool {
function factory() external view override returns (address) {}
/// @inheritdoc IPool
address public immutable override factory;
/// @inheritdoc IPool
address public immutable override token0;
/// @inheritdoc IPool
address public immutable override token1;
/// @inheritdoc IPool
uint24 public immutable override fee;
/// @inheritdoc IPool
int24 public immutable override tickLower;
/// @inheritdoc IPool
int24 public immutable override tickUpper;

function token0() external view override returns (address) {}
/// @inheritdoc IPool
uint160 public override sqrtPriceX96;
/// @inheritdoc IPool
int24 public override tick;
/// @inheritdoc IPool
uint128 public override liquidity;

function token1() external view override returns (address) {}
// 用一个 mapping 来存放所有 Position 的信息
mapping(address => Position) public positions;

function fee() external view override returns (uint24) {}
constructor() {
// constructor 中初始化 immutable 的常量
// Factory 创建 Pool 时会通 new Pool{salt: salt}() 的方式创建 Pool 合约,通过 salt 指定 Pool 的地址,这样其他地方也可以推算出 Pool 的地址
// 参数通过读取 Factory 合约的 parameters 获取
// 不通过构造函数传入,因为 CREATE2 会根据 initcode 计算出新地址(new_address = hash(0xFF, sender, salt, bytecode)),带上参数就不能计算出稳定的地址了
(factory, token0, token1, tickLower, tickUpper, fee) = IFactory(
msg.sender
).parameters();
}

function tickLower() external view override returns (int24) {}

function tickUpper() external view override returns (int24) {}

function sqrtPriceX96() external view override returns (uint160) {}

function tick() external view override returns (int24) {}

function liquidity() external view override returns (uint128) {}

function initialize(
uint160 sqrtPriceX96_,
int24 tickLower_,
int24 tickUpper_
) external override {}
function initialize(uint160 sqrtPriceX96_) external override {
// 初始化 Pool 的 sqrtPriceX96
sqrtPriceX96 = sqrtPriceX96_;
}

function mint(
address recipient,
uint128 amount,
bytes calldata data
) external override returns (uint256 amount0, uint256 amount1) {}
) external override returns (uint256 amount0, uint256 amount1) {
// 基于 amount 计算出当前需要多少 amount0 和 amount1
// TODO 当前先写个假的
(amount0, amount1) = (amount / 2, amount / 2);
// 把流动性记录到对应的 position 中
positions[recipient].liquidity += amount;
// 回调 mintCallback
IMintCallback(recipient).mintCallback(amount0, amount1, data);
// TODO 检查钱到位了没有,如果到位了对应修改相关信息
}

function collect(
address recipient
) external override returns (uint128 amount0, uint128 amount1) {}
) external override returns (uint128 amount0, uint128 amount1) {
// 获取当前用户的 position,TODO recipient 应该改为 msg.sender
Position storage position = positions[recipient];
// TODO 把钱退给用户 recipient
// 修改 position 中的信息
position.tokensOwed0 -= amount0;
position.tokensOwed1 -= amount1;
}

function burn(
uint128 amount
) external override returns (uint256 amount0, uint256 amount1) {}
) external override returns (uint256 amount0, uint256 amount1) {
// 修改 positions 中的信息
positions[msg.sender].liquidity -= amount;
// 获取燃烧后的 amount0 和 amount1
// TODO 当前先写个假的
(amount0, amount1) = (amount / 2, amount / 2);
positions[msg.sender].tokensOwed0 += amount0;
positions[msg.sender].tokensOwed1 += amount1;
}

function swap(
address recipient,
Expand Down
44 changes: 23 additions & 21 deletions P102_InitContracts/code/PoolManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,35 @@ pragma solidity ^0.8.24;
pragma abicoder v2;

import "./interfaces/IPoolManager.sol";
import "./Factory.sol";

contract PoolManager is IPoolManager {
function getPools()
external
view
override
returns (PoolKey[] memory pools)
{}
contract PoolManager is Factory, IPoolManager {
Pair[] public pairs;

function getTokens()
function getPairs() external view override returns (Pair[] memory) {
// 返回有哪些交易对,DApp 和 getAllPools 会用到
return pairs;
}

function getAllPools()
external
view
override
returns (address[] memory tokens)
{}

function getTokenPools(
address token
) external view override returns (PoolKey[] memory pools) {}

function getPoolInfo(
address token0,
address token1,
uint24 fee
) external view override returns (PoolInfo memory poolInfo) {}
returns (PoolInfo[] memory poolsInfo)
{
// 遍历 pairs,获取当前有的所有的交易对
// 然后调用 Factory 的 getPools 获取每个交易对的所有 pool
// 然后获取每个 pool 的信息
// 然后返回
// 先 mock
poolsInfo = new PoolInfo[](pairs.length);
return poolsInfo;
}

function createAndInitializePoolIfNecessary(
CreateAndInitializeParams calldata params
) external payable override returns (address pool) {}
) external payable override returns (address pool) {
// 如果没有对应的 Pool 就创建一个 Pool
// 创建成功后记录到 pairs 中
}
}
86 changes: 79 additions & 7 deletions P102_InitContracts/code/PositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,24 @@
pragma solidity ^0.8.24;
pragma abicoder v2;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "./interfaces/IPositionManager.sol";
import "./interfaces/IPool.sol";
import "./interfaces/IPoolManager.sol";

contract PositionManager is IPositionManager {
function getPositions(
address owner
) external view override returns (uint256[] memory positionIds) {}
contract PositionManager is IPositionManager, ERC721 {
// 保存 PoolManager 合约地址
IPoolManager public poolManager;

constructor(address _poolManger) ERC721("WTFSwapPosition", "WTFP") {
poolManager = IPoolManager(_poolManger);
}

// 用一个 mapping 来存放所有 Position 的信息
mapping(uint256 => PositionInfo) public positions;

// 通过 positionId 获取 Position 信息,positionId 就是 NFT 的 tokenId
// 如果要获得某个用户的所有的 Position 信息,需要自己遍历所有的 tokenId,可以通过 ZAN 的节点服务来获取
function getPositionInfo(
uint256 positionId
) external view override returns (PositionInfo memory positionInfo) {}
Expand All @@ -25,14 +36,75 @@ contract PositionManager is IPositionManager {
uint256 amount0,
uint256 amount1
)
{}
{
// mint 一个 NFT 作为 position 发给 LP
// NFT 的 tokenId 就是 positionId
// 通过 MintParams 里面的 token0 和 token1 以及 index 获取对应的 Pool
// 调用 poolManager 的 getPool 方法获取 Pool 地址
address _pool = poolManager.getPool(
params.token0,
params.token1,
params.index
);
IPool pool = IPool(_pool);
// 通过获取 pool 相关信息,结合 params.amount0Desired 和 params.amount1Desired 计算这次要注入的流动性
// TODO: 计算 _liquidity,这里只是随便写的
uint128 _liquidity = uint128(
params.amount0Desired * params.amount1Desired
);
// data 是 mint 后回调 PositionManager 会额外带的数据
// 需要 PoistionManger 实现回调,在回调中给 Pool 打钱
bytes memory data = abi.encode("todo");
(amount0, amount1) = pool.mint(params.recipient, _liquidity, data);
positionId = 1;
liquidity = _liquidity;
// TODO 以 NFT 的形式把 Position 的所有权发给 LP
}

function burn(
uint256 positionId
) external override returns (uint256 amount0, uint256 amount1) {}
) external override returns (uint256 amount0, uint256 amount1) {
// TODO 检查 positionId 是否属于 msg.sender
// 移除流动性,但是 token 还是保留在 pool 中,需要再调用 collect 方法才能取回 token
// 通过 positionId 获取对应 LP 的流动性
uint128 _liquidity = positions[positionId].liquidity;
// 调用 Pool 的方法给 LP 退流动性
address _pool = poolManager.getPool(
positions[positionId].token0,
positions[positionId].token1,
positions[positionId].index
);
IPool pool = IPool(_pool);
(amount0, amount1) = pool.burn(_liquidity);
// 修改 positionInfo 中的信息
positions[positionId].liquidity = 0;
positions[positionId].tokensOwed0 = amount0;
positions[positionId].tokensOwed1 = amount1;
}

function collect(
uint256 positionId,
address recipient
) external override returns (uint256 amount0, uint256 amount1) {}
) external override returns (uint256 amount0, uint256 amount1) {
// TODO 检查 positionId 是否属于 msg.sender
// 调用 Pool 的方法给 LP 退流动性
address _pool = poolManager.getPool(
positions[positionId].token0,
positions[positionId].token1,
positions[positionId].index
);
IPool pool = IPool(_pool);
(amount0, amount1) = pool.collect(recipient);
// 修改 positionInfo 中的信息
positions[positionId].tokensOwed0 = 0;
positions[positionId].tokensOwed1 = 0;
}

function mintCallback(
uint256 amount0,
uint256 amount1,
bytes calldata data
) external override {
// 在这里给 Pool 打钱,需要用户先 approve 足够的金额,这里才会成功
}
}
Loading

0 comments on commit 86de20d

Please sign in to comment.