Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add direct RFQT fill suport to ZeroExApiAdapter [SIM-230] #241

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
4 changes: 2 additions & 2 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const config: HardhatUserConfig = {
contractSizer: {
runOnCompile: false,
},

mocha: mochaConfig,

// These are external artifacts we don't compile but would like to improve
Expand Down Expand Up @@ -106,4 +106,4 @@ function checkForkedProviderEnvironment() {
}
}

export default config;
export default config;
Loading