reworked to optionally use Hardhat in mock; chain id 31337; refactored TransactionJob management; execute() mostly commented out for minimalism

This commit is contained in:
Tim Olson
2023-10-26 16:56:08 -04:00
parent 904549f564
commit f775f86960
10 changed files with 119 additions and 67 deletions

View File

@@ -8,7 +8,6 @@ pragma abicoder v2;
contract Factory is VaultDeployer {
address public admin;
constructor() {
admin = msg.sender;
}

View File

@@ -191,69 +191,80 @@ library OrderLib {
// TE current time is too early for this tranche
// TL current time is too late for this tranche
//
function execute(OrdersInfo storage self, address owner, uint64 orderIndex, uint8 tranche_index, PriceProof memory proof) internal {
function execute(OrdersInfo storage self, address owner, uint64 orderIndex, uint8 trancheIndex, PriceProof memory proof) internal {
console2.log('execute');
console2.log(address(this));
console2.log(uint(orderIndex));
console2.log(uint(trancheIndex));
SwapOrderStatus storage status = self.orders[orderIndex];
if (status.state != SwapOrderState.Open)
revert('NO'); // Not Open
Tranche storage tranche = status.order.tranches[tranche_index];
Tranche storage tranche = status.order.tranches[trancheIndex];
uint160 sqrtPriceX96 = 0;
uint160 sqrtPriceLimitX96 = 0;
uint160 sqrtPriceLimitX96 = 0; // 0 means "not set yet" and 1 is the minimum value
// todo other routes
address pool = Constants.uniswapV3Factory.getPool(status.order.tokenIn, status.order.tokenOut, status.order.route.fee);
for (uint8 c = 0; c < tranche.constraints.length; c++) {
Constraint storage constraint = tranche.constraints[c];
if (constraint.mode == ConstraintMode.Time) {
TimeConstraint memory tc = abi.decode(constraint.constraint, (TimeConstraint));
uint32 time = tc.earliest.mode == TimeMode.Timestamp ? tc.earliest.time : status.start + tc.earliest.time;
if (time > block.timestamp)
revert('TE'); // time early
time = tc.latest.mode == TimeMode.Timestamp ? tc.latest.time : status.start + tc.latest.time;
if (time < block.timestamp)
revert('TL'); // time late
}
else if (constraint.mode == ConstraintMode.Limit) {
if( sqrtPriceX96 == 0 ) {
(sqrtPriceX96,,,,,,) = IUniswapV3Pool(pool).slot0();
}
PriceConstraint memory pc = abi.decode(constraint.constraint, (PriceConstraint));
uint256 price = sqrtPriceX96;
if( pc.isRatio )
pc.valueSqrtX96 = uint160(price * pc.valueSqrtX96 / 2**96); // todo overflow check!
if( pc.isAbove && price < pc.valueSqrtX96 || !pc.isAbove && price > pc.valueSqrtX96 )
revert('L');
}
else if (constraint.mode == ConstraintMode.Barrier) {
revert('NI'); // not implemented
}
else if (constraint.mode == ConstraintMode.Trailing) {
revert('NI'); // not implemented
}
else if (constraint.mode == ConstraintMode.Line) {
revert('NI'); // not implemented
}
else // unknown constraint
revert('NI'); // not implemented
}
// for (uint8 c = 0; c < tranche.constraints.length; c++) {
// Constraint storage constraint = tranche.constraints[c];
// if (constraint.mode == ConstraintMode.Time) {
// TimeConstraint memory tc = abi.decode(constraint.constraint, (TimeConstraint));
// uint32 time = tc.earliest.mode == TimeMode.Timestamp ? tc.earliest.time : status.start + tc.earliest.time;
// if (time > block.timestamp)
// revert('TE'); // time early
// time = tc.latest.mode == TimeMode.Timestamp ? tc.latest.time : status.start + tc.latest.time;
// if (time < block.timestamp)
// revert('TL'); // time late
// }
// else if (constraint.mode == ConstraintMode.Limit) {
// if( sqrtPriceX96 == 0 ) {
// (sqrtPriceX96,,,,,,) = IUniswapV3Pool(pool).slot0();
// }
// PriceConstraint memory pc = abi.decode(constraint.constraint, (PriceConstraint));
// uint256 price = sqrtPriceX96;
// if( pc.isRatio )
// pc.valueSqrtX96 = uint160(price * pc.valueSqrtX96 / 2**96); // todo overflow check!
// if( pc.isAbove && price < pc.valueSqrtX96 || !pc.isAbove && price > pc.valueSqrtX96 )
// revert('L');
// if( sqrtPriceLimitX96 == 0 ||
// pc.isAbove && pc.valueSqrtX96 < sqrtPriceLimitX96 ||
// !pc.isAbove && pc.valueSqrtX96 > sqrtPriceLimitX96
// )
// sqrtPriceLimitX96 = pc.valueSqrtX96;
// }
// else if (constraint.mode == ConstraintMode.Barrier) {
// revert('NI'); // not implemented
// }
// else if (constraint.mode == ConstraintMode.Trailing) {
// revert('NI'); // not implemented
// }
// else if (constraint.mode == ConstraintMode.Line) {
// revert('NI'); // not implemented
// }
// else // unknown constraint
// revert('NI'); // not implemented
// }
uint256 amount = status.order.amount * tranche.fraction / type(uint16).max // the most this tranche could do
- (status.order.amountIsInput ? status.trancheFilledIn[tranche_index] : status.trancheFilledOut[tranche_index]); // minus tranche fills
- (status.order.amountIsInput ? status.trancheFilledIn[trancheIndex] : status.trancheFilledOut[trancheIndex]); // minus tranche fills
// order amount remaining
uint256 remaining = status.order.amount - (status.order.amountIsInput ? status.filledIn : status.filledOut);
if (amount > remaining) // not more than the order's overall remaining amount
amount = remaining;
console2.log(amount);
address recipient = status.order.outputDirectlyToOwner ? owner : address(this);
console2.log(recipient);
uint256 amountIn;
uint256 amountOut;
if( status.order.route.exchange == Exchange.UniswapV3 )
// if( status.order.route.exchange == Exchange.UniswapV3 )
(amountIn, amountOut) = _do_execute_univ3(recipient, status.order, pool, amount, sqrtPriceLimitX96);
// todo other routes
else
revert('UR'); // unknown route
status.filledIn += amountIn;
status.filledOut += amountOut;
status.trancheFilledIn[tranche_index] += amountIn;
status.trancheFilledOut[tranche_index] += amountOut;
emit DexorderSwapFilled(orderIndex, tranche_index, amountIn, amountOut);
_checkCompleted(self, orderIndex, status);
// else
// revert('UR'); // unknown route
// status.filledIn += amountIn;
// status.filledOut += amountOut;
// status.trancheFilledIn[trancheIndex] += amountIn;
// status.trancheFilledOut[trancheIndex] += amountOut;
// emit DexorderSwapFilled(orderIndex, trancheIndex, amountIn, amountOut);
// _checkCompleted(self, orderIndex, status);
}
@@ -261,9 +272,8 @@ library OrderLib {
returns (uint256 amountIn, uint256 amountOut)
{
// todo refactor this signature to be more low-level, taking only the in/out amounts and limit prices. doesnt need self/status/index
if (sqrtPriceLimitX96 == 0)
// check pool inversion to see if the price should be high or low
sqrtPriceLimitX96 = order.tokenIn < order.tokenOut ? 0 : type(uint160).max;
console2.log('price limit');
console2.log(uint(sqrtPriceLimitX96));
if (order.amountIsInput) {
amountIn = amount;
amountOut = UniswapSwapper.swapExactInput(UniswapSwapper.SwapParams(

View File

@@ -5,6 +5,7 @@ pragma abicoder v2;
import "./Constants.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "v3-periphery/libraries/TransferHelper.sol";
import "v3-core/contracts/libraries/TickMath.sol";
import "forge-std/console2.sol";
@@ -33,12 +34,20 @@ library UniswapSwapper {
// uint160 sqrtPriceLimitX96;
// }
console2.log('swapExactInput approve...');
TransferHelper.safeApprove(params.tokenIn, address(Constants.uniswapV3SwapRouter), params.amount);
console2.log(address(this));
console2.log(params.tokenIn);
console2.log(params.tokenOut);
console2.log(uint(params.fee));
console2.log(address(Constants.uniswapV3SwapRouter));
console2.log(address(params.recipient));
console2.log(params.amount);
console2.log(uint(params.sqrtPriceLimitX96));
console2.log(address(Constants.uniswapV3SwapRouter));
if (params.sqrtPriceLimitX96 == 0)
params.sqrtPriceLimitX96 = params.tokenIn < params.tokenOut ? TickMath.MIN_SQRT_RATIO+1 : TickMath.MAX_SQRT_RATIO-1;
TransferHelper.safeApprove(params.tokenIn, address(Constants.uniswapV3SwapRouter), params.amount);
console2.log('splx96');
console2.log(uint(params.sqrtPriceLimitX96));
amountOut = Constants.uniswapV3SwapRouter.exactInputSingle(ISwapRouter.ExactInputSingleParams({
tokenIn: params.tokenIn, tokenOut: params.tokenOut, fee: params.fee, recipient: params.recipient,
deadline: block.timestamp, amountIn: params.amount, amountOutMinimum: 0, sqrtPriceLimitX96: params.sqrtPriceLimitX96
@@ -50,6 +59,8 @@ library UniswapSwapper {
function swapExactOutput(SwapParams memory params) internal returns (uint256 amountIn)
{
// TODO copy changes over from swapExactInput
// struct ExactOutputSingleParams {
// address tokenIn;
// address tokenOut;

View File

@@ -16,7 +16,7 @@ contract Vault {
uint8 public immutable version;
address public immutable owner;
OrderLib.OrdersInfo public orderList;
OrderLib.OrdersInfo public ordersInfo;
constructor()
{
@@ -54,23 +54,26 @@ contract Vault {
token.transfer(recipient, amount);
}
function numSwapOrders() external view returns (uint64 num) {
return uint64(ordersInfo.orders.length);
}
function placeOrder(OrderLib.SwapOrder memory order) public onlyOwner {
console2.log('Vault.placeOrder()');
orderList._placeOrder(order);
ordersInfo._placeOrder(order);
}
function placeOrders(OrderLib.SwapOrder[] memory orders, OrderLib.OcoMode ocoMode) public onlyOwner {
orderList._placeOrders(orders, ocoMode);
ordersInfo._placeOrders(orders, ocoMode);
}
function swapOrderStatus(uint64 orderIndex) public view returns (OrderLib.SwapOrderStatus memory status) {
return orderList.orders[orderIndex];
function swapOrderStatus(uint64 orderIndex) external view returns (OrderLib.SwapOrderStatus memory status) {
return ordersInfo.orders[orderIndex];
}
function execute(uint64 orderIndex, uint8 tranche_index, OrderLib.PriceProof memory proof) public
{
orderList.execute(owner, orderIndex, tranche_index, proof);
ordersInfo.execute(owner, orderIndex, tranche_index, proof);
}
modifier onlyOwner() {

View File

@@ -10,7 +10,7 @@ library VaultAddress {
// keccak-256 hash of the Vault's bytecode (not the deployed bytecode but the initialization bytecode)
// can paste into:
// https://emn178.github.io/online-tools/keccak_256.html
bytes32 internal constant VAULT_INIT_CODE_HASH = 0x72f8226a3666abba278cd472062b776a74be697e53a365b69f0e9bfbcfabc1b9;
bytes32 public constant VAULT_INIT_CODE_HASH = 0xaa3457854b70ea8d66f3b73269f0cf34c7e2212e4b4bd8176e8388ff223a2bd0;
// the contract being constructed must not have any constructor arguments or the determinism will be broken. instead, use a callback to
// get construction arguments