Skip to content

Commit

Permalink
feat: add direct RFQT fill suport to ZeroExApiAdapter [SIM-230] (#241)
Browse files Browse the repository at this point in the history
  • Loading branch information
dorothy-zbornak authored Apr 11, 2022
1 parent 361728a commit f4b976e
Show file tree
Hide file tree
Showing 4 changed files with 384 additions and 161 deletions.
59 changes: 29 additions & 30 deletions contracts/mocks/external/ZeroExMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,24 @@ contract ZeroExMock {
bytes data;
}

struct BatchFillData {
address inputToken;
address outputToken;
uint256 sellAmount;
WrappedBatchCall[] calls;
}

struct WrappedBatchCall {
bytes4 selector;
uint256 sellAmount;
bytes data;
}

struct MultiHopFillData {
address[] tokens;
uint256 sellAmount;
WrappedMultiHopCall[] calls;
}

struct WrappedMultiHopCall {
bytes4 selector;
bytes data;
struct RfqOrder {
address makerToken;
address takerToken;
uint128 makerAmount;
uint128 takerAmount;
address maker;
address taker;
address txOrigin;
bytes32 pool;
uint64 expiry;
uint256 salt;
}

struct Signature {
uint8 signatureType;
uint8 v;
bytes32 r;
bytes32 s;
}

struct BatchSellSubcall {
Expand Down Expand Up @@ -145,24 +141,27 @@ contract ZeroExMock {
_transferTokens();
}

function batchFill(
BatchFillData memory /* fillData */,
uint256 /* minBuyAmount */
function fillRfqOrder(
RfqOrder memory /* order */,
Signature memory /* signature */,
uint128 /* takerTokenFillAmount */
)
external
payable
returns (uint256)
returns (uint128, uint128)
{
_transferTokens();
}

function multiHopFill(
MultiHopFillData memory /* fillData */,
uint256 /* minBuyAmount */
function batchFillRfqOrders(
RfqOrder[] memory /* order */,
Signature[] memory /* signature */,
uint128[] memory /* takerTokenFillAmount */,
bool /* revertIfIncomplete */
)
external
payable
returns (uint256)
returns (uint128[] memory, uint128[] memory)
{
_transferTokens();
}
Expand Down
89 changes: 52 additions & 37 deletions contracts/protocol/integration/exchange/ZeroExApiAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,24 @@ pragma experimental "ABIEncoderV2";

contract ZeroExApiAdapter {

struct BatchFillData {
address inputToken;
address outputToken;
uint256 sellAmount;
WrappedBatchCall[] calls;
}

struct WrappedBatchCall {
bytes4 selector;
uint256 sellAmount;
bytes data;
struct RfqOrder {
address makerToken;
address takerToken;
uint128 makerAmount;
uint128 takerAmount;
address maker;
address taker;
address txOrigin;
bytes32 pool;
uint64 expiry;
uint256 salt;
}

struct MultiHopFillData {
address[] tokens;
uint256 sellAmount;
WrappedMultiHopCall[] calls;
}

struct WrappedMultiHopCall {
bytes4 selector;
bytes data;
struct Signature {
uint8 signatureType;
uint8 v;
bytes32 r;
bytes32 s;
}

/* ============ State Variables ============ */
Expand Down Expand Up @@ -149,23 +145,31 @@ contract ZeroExApiAdapter {
require(path.length > 1, "Uniswap token path too short");
inputToken = path[0];
outputToken = path[path.length - 1];
} else if (selector == 0xafc6728e) {
// batchFill()
BatchFillData memory fillData;
(fillData, minOutputTokenAmount) =
abi.decode(_data[4:], (BatchFillData, uint256));
inputToken = fillData.inputToken;
outputToken = fillData.outputToken;
inputTokenAmount = fillData.sellAmount;
} else if (selector == 0x21c184b6) {
// multiHopFill()
MultiHopFillData memory fillData;
(fillData, minOutputTokenAmount) =
abi.decode(_data[4:], (MultiHopFillData, uint256));
require(fillData.tokens.length > 1, "Multihop token path too short");
inputToken = fillData.tokens[0];
outputToken = fillData.tokens[fillData.tokens.length - 1];
inputTokenAmount = fillData.sellAmount;
} else if (selector == 0xaa77476c) {
// fillRfqOrder()
RfqOrder memory order;
uint128 takerTokenFillAmount;
(order, , takerTokenFillAmount) =
abi.decode(_data[4:], (RfqOrder, Signature, uint128));
inputTokenAmount = uint256(takerTokenFillAmount);
inputToken = order.takerToken;
outputToken = order.makerToken;
minOutputTokenAmount = getRfqOrderMakerFillAmount(order, inputTokenAmount);
} else if (selector == 0x75103cb9) {
// batchFillRfqOrders()
RfqOrder[] memory orders;
uint128[] memory takerTokenFillAmounts;
bool revertIfIncomplete;
(orders, , takerTokenFillAmounts, revertIfIncomplete) =
abi.decode(_data[4:], (RfqOrder[], uint256, uint128[], bool));
require(orders.length > 0, "Empty RFQ orders");
require(revertIfIncomplete, "batchFillRfqOrder must be all or nothing");
inputToken = orders[0].takerToken;
outputToken = orders[0].makerToken;
for (uint256 i = 0; i < orders.length; ++i) {
inputTokenAmount += uint256(takerTokenFillAmounts[i]);
minOutputTokenAmount += getRfqOrderMakerFillAmount(orders[i], takerTokenFillAmounts[i]);
}
} else if (selector == 0x6af479b2) {
// sellTokenForTokenToUniswapV3()
bytes memory encodedPath;
Expand Down Expand Up @@ -208,6 +212,17 @@ contract ZeroExApiAdapter {
);
}

function getRfqOrderMakerFillAmount(RfqOrder memory order, uint256 takerTokenFillAmount)
private
pure
returns (uint256 makerTokenFillAmount)
{
if (order.takerAmount == 0 || order.makerAmount == 0 || takerTokenFillAmount == 0) {
return 0;
}
return uint256(order.makerAmount * takerTokenFillAmount / order.takerAmount);
}

// Decode input and output tokens from an arbitrary length encoded Uniswap V3 path
function _decodeTokensFromUniswapV3EncodedPath(bytes memory encodedPath)
private
Expand Down
2 changes: 1 addition & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,4 @@ function checkForkedProviderEnvironment() {
}
}

export default config;
export default config;
Loading

0 comments on commit f4b976e

Please sign in to comment.