TRANCHE EXECUTION WORKS

This commit is contained in:
Tim Olson
2023-10-29 16:53:07 -04:00
parent e1eecad898
commit fd18cba58f
8 changed files with 124 additions and 78 deletions

View File

@@ -1,5 +1,11 @@
| Code | Name | Description | | Code | Name | Description |
|-------|--------------------|------------------------------------------------------------------------| |------|---------------------------|------------------------------------------------------------------------|
| UC | Unknown Constraint | The constraint specification did not have a recognized Constraint Mode | | OCOM | Invalid OCO Mode | The OCO mode provided to placeOrder() is invalid. |
| OCOM | Invalid OCO Mode | The OCO mode provided to placeOrder() is invalid. | | UR | Unknown Route | The specified order route is invalid. |
| UR | Unknown Route | The specified order route is invalid. | | NO | Not Open | Order status state is not OPEN |
| UC | Unknown Constraint | The constraint specification did not have a recognized Constraint Mode |
| TE | Too Early | Time constraint window hasn't opened yet |
| TL | Too Late | Time constraint has expired the tranche |
| L | Limit | Price limit constraint violation |
| IIA | Insufficient Input Amount | Not enough input coin available in the vault (from Uniswap) |
| TF | Tranche Filled | The tranche has no remaining amount available to execute. |

View File

@@ -17,7 +17,7 @@ contract Deploy is Script {
Factory deployer = new Factory(); // hardhat often breaks on the CREATE2 above :( Factory deployer = new Factory(); // hardhat often breaks on the CREATE2 above :(
QueryHelper query = new QueryHelper(); QueryHelper query = new QueryHelper();
Dexorder dexorder = new Dexorder(); Dexorder dexorder = new Dexorder();
MockEnv mock = new MockEnv(); // MockEnv mock = new MockEnv();
vm.stopBroadcast(); vm.stopBroadcast();
console2.log('Factory'); console2.log('Factory');
console2.log(address(deployer)); console2.log(address(deployer));
@@ -25,7 +25,7 @@ contract Deploy is Script {
console2.log(address(query)); console2.log(address(query));
console2.log('Dexorder'); console2.log('Dexorder');
console2.log(address(dexorder)); console2.log(address(dexorder));
console2.log('MockEnv'); // todo no mock in production deployment // console2.log('MockEnv'); // todo no mock in production deployment
console2.log(address(mock)); // console2.log(address(mock));
} }
} }

View File

@@ -192,7 +192,7 @@ library OrderLib {
// TE current time is too early for this tranche // TE current time is too early for this tranche
// TL current time is too late for this tranche // TL current time is too late for this tranche
// //
function execute(OrdersInfo storage self, address owner, uint64 orderIndex, uint8 trancheIndex, PriceProof memory proof) internal { function execute(OrdersInfo storage self, address owner, uint64 orderIndex, uint8 trancheIndex, PriceProof memory ) internal {
console2.log('execute'); console2.log('execute');
console2.log(address(this)); console2.log(address(this));
console2.log(uint(orderIndex)); console2.log(uint(orderIndex));
@@ -205,67 +205,86 @@ library OrderLib {
uint160 sqrtPriceLimitX96 = 0; // 0 means "not set yet" and 1 is the minimum value uint160 sqrtPriceLimitX96 = 0; // 0 means "not set yet" and 1 is the minimum value
// todo other routes // todo other routes
address pool = Constants.uniswapV3Factory.getPool(status.order.tokenIn, status.order.tokenOut, status.order.route.fee); address pool = Constants.uniswapV3Factory.getPool(status.order.tokenIn, status.order.tokenOut, status.order.route.fee);
// for (uint8 c = 0; c < tranche.constraints.length; c++) { for (uint8 c = 0; c < tranche.constraints.length; c++) {
// Constraint storage constraint = tranche.constraints[c]; Constraint storage constraint = tranche.constraints[c];
// if (constraint.mode == ConstraintMode.Time) { if (constraint.mode == ConstraintMode.Time) {
// TimeConstraint memory tc = abi.decode(constraint.constraint, (TimeConstraint)); console2.log('time constraint');
// uint32 time = tc.earliest.mode == TimeMode.Timestamp ? tc.earliest.time : status.start + tc.earliest.time; TimeConstraint memory tc = abi.decode(constraint.constraint, (TimeConstraint));
// if (time > block.timestamp) uint32 time = tc.earliest.mode == TimeMode.Timestamp ? tc.earliest.time : status.start + tc.earliest.time;
// revert('TE'); // time early if (time > block.timestamp)
// time = tc.latest.mode == TimeMode.Timestamp ? tc.latest.time : status.start + tc.latest.time; revert('TE'); // time early
// if (time < block.timestamp) time = tc.latest.mode == TimeMode.Timestamp ? tc.latest.time : status.start + tc.latest.time;
// revert('TL'); // time late if (time < block.timestamp)
// } revert('TL'); // time late
// else if (constraint.mode == ConstraintMode.Limit) { }
// if( sqrtPriceX96 == 0 ) { else if (constraint.mode == ConstraintMode.Limit) {
// (sqrtPriceX96,,,,,,) = IUniswapV3Pool(pool).slot0(); console2.log('limit constraint');
// } if( sqrtPriceX96 == 0 ) {
// PriceConstraint memory pc = abi.decode(constraint.constraint, (PriceConstraint)); (sqrtPriceX96,,,,,,) = IUniswapV3Pool(pool).slot0();
// uint256 price = sqrtPriceX96; }
// if( pc.isRatio ) PriceConstraint memory pc = abi.decode(constraint.constraint, (PriceConstraint));
// pc.valueSqrtX96 = uint160(price * pc.valueSqrtX96 / 2**96); // todo overflow check! uint256 price = sqrtPriceX96;
// if( pc.isAbove && price < pc.valueSqrtX96 || !pc.isAbove && price > pc.valueSqrtX96 ) if( pc.isRatio )
// revert('L'); pc.valueSqrtX96 = uint160(price * pc.valueSqrtX96 / 2**96); // todo overflow check!
// if( sqrtPriceLimitX96 == 0 || if( pc.isAbove && price < pc.valueSqrtX96 || !pc.isAbove && price > pc.valueSqrtX96 )
// pc.isAbove && pc.valueSqrtX96 < sqrtPriceLimitX96 || revert('L');
// !pc.isAbove && pc.valueSqrtX96 > sqrtPriceLimitX96 if( sqrtPriceLimitX96 == 0 ||
// ) pc.isAbove && pc.valueSqrtX96 < sqrtPriceLimitX96 ||
// sqrtPriceLimitX96 = pc.valueSqrtX96; !pc.isAbove && pc.valueSqrtX96 > sqrtPriceLimitX96
// } )
// else if (constraint.mode == ConstraintMode.Barrier) { sqrtPriceLimitX96 = pc.valueSqrtX96;
// revert('NI'); // not implemented }
// } else if (constraint.mode == ConstraintMode.Barrier) {
// else if (constraint.mode == ConstraintMode.Trailing) { console2.log('barrier constraint');
// revert('NI'); // not implemented revert('NI'); // not implemented
// } }
// else if (constraint.mode == ConstraintMode.Line) { else if (constraint.mode == ConstraintMode.Trailing) {
// revert('NI'); // not implemented console2.log('trailing constraint');
// } revert('NI'); // not implemented
// else // unknown constraint }
// revert('NI'); // not implemented else if (constraint.mode == ConstraintMode.Line) {
// } console2.log('line constraint');
revert('NI'); // not implemented
}
else // unknown constraint
revert('UC'); // not implemented
}
console2.log('computing amount');
console2.log(status.order.amount);
console2.log(tranche.fraction);
console2.log(status.order.amountIsInput);
console2.log(status.filledIn);
console2.log(status.filledOut);
console2.log(status.trancheFilledIn[trancheIndex]);
console2.log(status.trancheFilledOut[trancheIndex]);
uint256 amount = status.order.amount * tranche.fraction / type(uint16).max // the most this tranche could do uint256 amount = status.order.amount * tranche.fraction / type(uint16).max // the most this tranche could do
- (status.order.amountIsInput ? status.trancheFilledIn[trancheIndex] : status.trancheFilledOut[trancheIndex]); // minus tranche fills - (status.order.amountIsInput ? status.trancheFilledIn[trancheIndex] : status.trancheFilledOut[trancheIndex]); // minus tranche fills
console2.log('amount');
console2.log(amount);
// order amount remaining // order amount remaining
require( (status.order.amountIsInput ? status.filledIn : status.filledOut) <= status.order.amount, 'OVERFILL' );
uint256 remaining = status.order.amount - (status.order.amountIsInput ? status.filledIn : status.filledOut); uint256 remaining = status.order.amount - (status.order.amountIsInput ? status.filledIn : status.filledOut);
console2.log('remaining');
console2.log(remaining);
if (amount > remaining) // not more than the order's overall remaining amount if (amount > remaining) // not more than the order's overall remaining amount
amount = remaining; amount = remaining;
require( amount > 0, 'TF' );
console2.log(amount); console2.log(amount);
address recipient = status.order.outputDirectlyToOwner ? owner : address(this); address recipient = status.order.outputDirectlyToOwner ? owner : address(this);
console2.log(recipient); console2.log(recipient);
uint256 amountIn; uint256 amountIn;
uint256 amountOut; 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); (amountIn, amountOut) = _do_execute_univ3(recipient, status.order, pool, amount, sqrtPriceLimitX96);
// todo other routes // todo other routes
// else else
// revert('UR'); // unknown route revert('UR'); // unknown route
// status.filledIn += amountIn; status.filledIn += amountIn;
// status.filledOut += amountOut; status.filledOut += amountOut;
// status.trancheFilledIn[trancheIndex] += amountIn; status.trancheFilledIn[trancheIndex] += amountIn;
// status.trancheFilledOut[trancheIndex] += amountOut; status.trancheFilledOut[trancheIndex] += amountOut;
// emit DexorderSwapFilled(orderIndex, trancheIndex, amountIn, amountOut); emit DexorderSwapFilled(orderIndex, trancheIndex, amountIn, amountOut);
// _checkCompleted(self, orderIndex, status); _checkCompleted(self, orderIndex, status);
} }
@@ -276,13 +295,11 @@ library OrderLib {
console2.log('price limit'); console2.log('price limit');
console2.log(uint(sqrtPriceLimitX96)); console2.log(uint(sqrtPriceLimitX96));
if (order.amountIsInput) { if (order.amountIsInput) {
amountIn = amount; (amountIn, amountOut) = UniswapSwapper.swapExactInput(UniswapSwapper.SwapParams(
amountOut = UniswapSwapper.swapExactInput(UniswapSwapper.SwapParams(
pool, order.tokenIn, order.tokenOut, recipient, order.route.fee, amount, sqrtPriceLimitX96)); pool, order.tokenIn, order.tokenOut, recipient, order.route.fee, amount, sqrtPriceLimitX96));
} }
else { else {
amountOut = amount; (amountIn, amountOut) = UniswapSwapper.swapExactOutput(UniswapSwapper.SwapParams(
amountIn = UniswapSwapper.swapExactOutput(UniswapSwapper.SwapParams(
pool, order.tokenIn, order.tokenOut, recipient, order.route.fee, amount, sqrtPriceLimitX96)); pool, order.tokenIn, order.tokenOut, recipient, order.route.fee, amount, sqrtPriceLimitX96));
} }
} }

View File

@@ -50,8 +50,8 @@ contract QueryHelper {
// here we find the highest liquidity pool for v2 and for v3 // here we find the highest liquidity pool for v2 and for v3
uint24[4] memory fees = [uint24(100),500,3000,10000]; uint24[4] memory fees = [uint24(100),500,3000,10000];
uint24 uniswapV2Fee = 0; uint24 uniswapV2Fee = 0;
uint128 uniswapV2Liquidity = 0; // uint128 uniswapV2Liquidity = 0;
address uniswapV2Pool = address(0); // address uniswapV2Pool = address(0);
uint24 uniswapV3Fee = 0; uint24 uniswapV3Fee = 0;
uint128 uniswapV3Liquidity = 0; uint128 uniswapV3Liquidity = 0;
address uniswapV3Pool = address(0); address uniswapV3Pool = address(0);

View File

@@ -22,7 +22,7 @@ library UniswapSwapper {
uint160 sqrtPriceLimitX96; uint160 sqrtPriceLimitX96;
} }
function swapExactInput(SwapParams memory params) internal returns (uint256 amountOut) function swapExactInput(SwapParams memory params) internal returns (uint256 amountIn, uint256 amountOut)
{ {
// struct ExactInputSingleParams { // struct ExactInputSingleParams {
// address tokenIn; // address tokenIn;
@@ -44,23 +44,30 @@ library UniswapSwapper {
console2.log(uint(params.sqrtPriceLimitX96)); console2.log(uint(params.sqrtPriceLimitX96));
console2.log(address(Constants.uniswapV3SwapRouter)); console2.log(address(Constants.uniswapV3SwapRouter));
TransferHelper.safeApprove(params.tokenIn, address(Constants.uniswapV3SwapRouter), params.amount); amountIn = params.amount;
uint256 balance = IERC20(params.tokenIn).balanceOf(address(this));
if( balance == 0 ) {
// todo dust?
revert('IIA');
}
if( balance < amountIn )
amountIn = balance;
TransferHelper.safeApprove(params.tokenIn, address(Constants.uniswapV3SwapRouter), amountIn);
// if (params.sqrtPriceLimitX96 == 0) // if (params.sqrtPriceLimitX96 == 0)
// params.sqrtPriceLimitX96 = params.tokenIn < params.tokenOut ? TickMath.MIN_SQRT_RATIO+1 : TickMath.MAX_SQRT_RATIO-1; // params.sqrtPriceLimitX96 = params.tokenIn < params.tokenOut ? TickMath.MIN_SQRT_RATIO+1 : TickMath.MAX_SQRT_RATIO-1;
console2.log('splx96'); console2.log('swapping...');
console2.log(uint(params.sqrtPriceLimitX96));
amountOut = Constants.uniswapV3SwapRouter.exactInputSingle(ISwapRouter.ExactInputSingleParams({ amountOut = Constants.uniswapV3SwapRouter.exactInputSingle(ISwapRouter.ExactInputSingleParams({
tokenIn: params.tokenIn, tokenOut: params.tokenOut, fee: params.fee, recipient: params.recipient, tokenIn: params.tokenIn, tokenOut: params.tokenOut, fee: params.fee, recipient: params.recipient,
deadline: block.timestamp, amountIn: params.amount, amountOutMinimum: 1, sqrtPriceLimitX96: params.sqrtPriceLimitX96 deadline: block.timestamp, amountIn: amountIn, amountOutMinimum: 1, sqrtPriceLimitX96: params.sqrtPriceLimitX96
})); }));
console2.log('swapped'); console2.log('swapped');
console2.log(amountOut); console2.log(amountOut);
TransferHelper.safeApprove(params.tokenIn, address(Constants.uniswapV3SwapRouter), 0); TransferHelper.safeApprove(params.tokenIn, address(Constants.uniswapV3SwapRouter), 0);
} }
function swapExactOutput(SwapParams memory params) internal returns (uint256 amountIn) function swapExactOutput(SwapParams memory params) internal returns (uint256 amountIn, uint256 amountOut)
{ {
// TODO copy changes over from swapExactInput // TODO copy changes over from swapExactInput
@@ -74,8 +81,7 @@ library UniswapSwapper {
// uint256 amountInMaximum; // uint256 amountInMaximum;
// uint160 sqrtPriceLimitX96; // uint160 sqrtPriceLimitX96;
// } // }
address t = address(this); uint256 balance = IERC20(params.tokenIn).balanceOf(address(this));
uint256 balance = IERC20(params.tokenIn).balanceOf(t);
if( balance == 0 ) { if( balance == 0 ) {
// todo dust? // todo dust?
revert('IIA'); revert('IIA');
@@ -99,14 +105,33 @@ library UniswapSwapper {
// if (params.sqrtPriceLimitX96 == 0) // if (params.sqrtPriceLimitX96 == 0)
// params.sqrtPriceLimitX96 = params.tokenIn < params.tokenOut ? TickMath.MIN_SQRT_RATIO+1 : TickMath.MAX_SQRT_RATIO-1; // params.sqrtPriceLimitX96 = params.tokenIn < params.tokenOut ? TickMath.MIN_SQRT_RATIO+1 : TickMath.MAX_SQRT_RATIO-1;
amountIn = Constants.uniswapV3SwapRouter.exactOutputSingle(ISwapRouter.ExactOutputSingleParams({ console2.log('swapping...');
try Constants.uniswapV3SwapRouter.exactOutputSingle(ISwapRouter.ExactOutputSingleParams({
tokenIn: params.tokenIn, tokenOut: params.tokenOut, fee: params.fee, recipient: params.recipient, tokenIn: params.tokenIn, tokenOut: params.tokenOut, fee: params.fee, recipient: params.recipient,
deadline: block.timestamp, amountOut: params.amount, amountInMaximum: maxAmountIn, deadline: block.timestamp, amountOut: params.amount, amountInMaximum: maxAmountIn,
sqrtPriceLimitX96: params.sqrtPriceLimitX96 sqrtPriceLimitX96: params.sqrtPriceLimitX96
})); })) returns (uint256 amtIn) {
amountIn = amtIn;
amountOut = params.amount;
}
catch Error( string memory reason ) {
// todo check reason before trying exactinput
// if the input amount was insufficient, use exactInputSingle to spend whatever remains.
try Constants.uniswapV3SwapRouter.exactInputSingle(ISwapRouter.ExactInputSingleParams({
tokenIn: params.tokenIn, tokenOut: params.tokenOut, fee: params.fee, recipient: params.recipient,
deadline: block.timestamp, amountIn: maxAmountIn, amountOutMinimum: 1, sqrtPriceLimitX96: params.sqrtPriceLimitX96
})) returns (uint256 amtOut) {
amountIn = maxAmountIn;
amountOut = amtOut;
}
catch Error( string memory ) {
revert(reason); // revert on the original reason
}
}
console2.log('swapped'); console2.log('swapped');
console2.log(amountIn); console2.log(amountIn);
console2.log(amountOut);
TransferHelper.safeApprove(params.tokenIn, address(Constants.uniswapV3SwapRouter), 0); TransferHelper.safeApprove(params.tokenIn, address(Constants.uniswapV3SwapRouter), 0);
} }

View File

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

View File

@@ -63,7 +63,6 @@ contract TestOrder is MockEnv, Test {
vault.placeOrder(order); vault.placeOrder(order);
console2.log('placed order'); console2.log('placed order');
console2.log(uint(orderIndex)); console2.log(uint(orderIndex));
string memory result;
vault.execute(orderIndex, 0, OrderLib.PriceProof(0)); vault.execute(orderIndex, 0, OrderLib.PriceProof(0));
console2.log('executed'); console2.log('executed');
} }
@@ -85,7 +84,6 @@ contract TestOrder is MockEnv, Test {
vault.placeOrder(order); vault.placeOrder(order);
console2.log('placed order'); console2.log('placed order');
console2.log(uint(orderIndex)); console2.log(uint(orderIndex));
string memory result;
vault.execute(orderIndex, 0, OrderLib.PriceProof(0)); vault.execute(orderIndex, 0, OrderLib.PriceProof(0));
console2.log('executed'); console2.log('executed');
} }

View File

@@ -22,7 +22,7 @@ contract TestVault is Test {
console2.log(address(vault)); console2.log(address(vault));
} }
function testDeterministicAddress() public { function testDeterministicAddress() public view {
console2.log(address(vault)); console2.log(address(vault));
address d = VaultAddress.computeAddress(address(factory), address(this)); address d = VaultAddress.computeAddress(address(factory), address(this));
console2.log(d); console2.log(d);