@0x/contracts-zero-ex
: Address review feedback.
This commit is contained in:
@@ -130,7 +130,13 @@ library LibTransformERC20RichErrors {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum InvalidTransformDataErrorCode {
|
||||||
|
INVALID_TOKENS,
|
||||||
|
INVALID_ARRAY_LENGTH
|
||||||
|
}
|
||||||
|
|
||||||
function InvalidTransformDataError(
|
function InvalidTransformDataError(
|
||||||
|
InvalidTransformDataErrorCode errorCode,
|
||||||
bytes memory transformData
|
bytes memory transformData
|
||||||
)
|
)
|
||||||
internal
|
internal
|
||||||
@@ -138,7 +144,8 @@ library LibTransformERC20RichErrors {
|
|||||||
returns (bytes memory)
|
returns (bytes memory)
|
||||||
{
|
{
|
||||||
return abi.encodeWithSelector(
|
return abi.encodeWithSelector(
|
||||||
bytes4(keccak256("InvalidTransformDataError(bytes)")),
|
bytes4(keccak256("InvalidTransformDataError(uint8,bytes)")),
|
||||||
|
errorCode,
|
||||||
transformData
|
transformData
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -35,8 +35,16 @@ import "./LibERC20Transformer.sol";
|
|||||||
contract FillQuoteTransformer is
|
contract FillQuoteTransformer is
|
||||||
Transformer
|
Transformer
|
||||||
{
|
{
|
||||||
|
/// @dev Whether we are performing a market sell or buy.
|
||||||
|
enum Side {
|
||||||
|
Sell,
|
||||||
|
Buy
|
||||||
|
}
|
||||||
|
|
||||||
/// @dev Transform data to ABI-encode and pass into `transform()`.
|
/// @dev Transform data to ABI-encode and pass into `transform()`.
|
||||||
struct TransformData {
|
struct TransformData {
|
||||||
|
// Whether we aer performing a market sell or buy.
|
||||||
|
Side side;
|
||||||
// The token being sold.
|
// The token being sold.
|
||||||
// This should be an actual token, not the ETH pseudo-token.
|
// This should be an actual token, not the ETH pseudo-token.
|
||||||
IERC20TokenV06 sellToken;
|
IERC20TokenV06 sellToken;
|
||||||
@@ -52,11 +60,10 @@ contract FillQuoteTransformer is
|
|||||||
// For sells, this will be the maximum sell amount (taker asset).
|
// For sells, this will be the maximum sell amount (taker asset).
|
||||||
// For buys, this will be the maximum buy amount (maker asset).
|
// For buys, this will be the maximum buy amount (maker asset).
|
||||||
uint256[] maxOrderFillAmounts;
|
uint256[] maxOrderFillAmounts;
|
||||||
// Amount of `sellToken` to sell. May be `uint256(-1)` to sell entire
|
// Amount of `sellToken` to sell or `buyToken` to buy.
|
||||||
// amount of `sellToken` received. Zero if performing a market buy.
|
// For sells, this may be `uint256(-1)` to sell the entire balance of
|
||||||
uint256 sellAmount;
|
// `sellToken`.
|
||||||
// Amount of `buyToken` to buy. Zero if performing a market sell.
|
uint256 fillAmount;
|
||||||
uint256 buyAmount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Results of a call to `_fillOrder()`.
|
/// @dev Results of a call to `_fillOrder()`.
|
||||||
@@ -96,7 +103,6 @@ contract FillQuoteTransformer is
|
|||||||
/// @dev Sell this contract's entire balance of of `sellToken` in exchange
|
/// @dev Sell this contract's entire balance of of `sellToken` in exchange
|
||||||
/// for `buyToken` by filling `orders`. Protocol fees should be attached
|
/// for `buyToken` by filling `orders`. Protocol fees should be attached
|
||||||
/// to this call. `buyToken` and excess ETH will be transferred back to the caller.
|
/// to this call. `buyToken` and excess ETH will be transferred back to the caller.
|
||||||
/// This function cannot be re-entered.
|
|
||||||
/// @param data_ ABI-encoded `TransformData`.
|
/// @param data_ ABI-encoded `TransformData`.
|
||||||
/// @return rlpDeploymentNonce RLP-encoded deployment nonce of the deployer
|
/// @return rlpDeploymentNonce RLP-encoded deployment nonce of the deployer
|
||||||
/// when this transformer was deployed. This is used to verify that
|
/// when this transformer was deployed. This is used to verify that
|
||||||
@@ -113,23 +119,29 @@ contract FillQuoteTransformer is
|
|||||||
TransformData memory data = abi.decode(data_, (TransformData));
|
TransformData memory data = abi.decode(data_, (TransformData));
|
||||||
|
|
||||||
// Validate data fields.
|
// Validate data fields.
|
||||||
if (data.sellToken.isTokenETH() ||
|
if (data.sellToken.isTokenETH() || data.buyToken.isTokenETH()) {
|
||||||
data.buyToken.isTokenETH() ||
|
LibTransformERC20RichErrors.InvalidTransformDataError(
|
||||||
data.orders.length != data.signatures.length)
|
LibTransformERC20RichErrors.InvalidTransformDataErrorCode.INVALID_TOKENS,
|
||||||
{
|
data_
|
||||||
LibTransformERC20RichErrors.InvalidTransformDataError(data_).rrevert();
|
).rrevert();
|
||||||
|
}
|
||||||
|
if (data.orders.length != data.signatures.length) {
|
||||||
|
LibTransformERC20RichErrors.InvalidTransformDataError(
|
||||||
|
LibTransformERC20RichErrors.InvalidTransformDataErrorCode.INVALID_ARRAY_LENGTH,
|
||||||
|
data_
|
||||||
|
).rrevert();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If `sellAmount == -1` and `buyAmount == 0` then we are selling
|
if (data.side == Side.Sell && data.fillAmount == uint256(-1)) {
|
||||||
// the entire balance of `sellToken`. This is useful in cases where
|
// If `sellAmount == -1 then we are selling
|
||||||
// the exact sell amount is not exactly known in advance, like when
|
// the entire balance of `sellToken`. This is useful in cases where
|
||||||
// unwrapping Chai/cUSDC/cDAI.
|
// the exact sell amount is not exactly known in advance, like when
|
||||||
if (data.sellAmount == uint256(-1) && data.buyAmount == 0) {
|
// unwrapping Chai/cUSDC/cDAI.
|
||||||
data.sellAmount = data.sellToken.getTokenBalanceOf(address(this));
|
data.fillAmount = data.sellToken.getTokenBalanceOf(address(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Approve the ERC20 proxy to spend `sellToken`.
|
// Approve the ERC20 proxy to spend `sellToken`.
|
||||||
data.sellToken.approveIfBelow(erc20Proxy, data.sellAmount);
|
data.sellToken.approveIfBelow(erc20Proxy, data.fillAmount);
|
||||||
|
|
||||||
// Fill the orders.
|
// Fill the orders.
|
||||||
uint256 singleProtocolFee = exchange.protocolFeeMultiplier().safeMul(tx.gasprice);
|
uint256 singleProtocolFee = exchange.protocolFeeMultiplier().safeMul(tx.gasprice);
|
||||||
@@ -138,14 +150,14 @@ contract FillQuoteTransformer is
|
|||||||
uint256 soldAmount = 0;
|
uint256 soldAmount = 0;
|
||||||
for (uint256 i = 0; i < data.orders.length; ++i) {
|
for (uint256 i = 0; i < data.orders.length; ++i) {
|
||||||
// Check if we've hit our targets.
|
// Check if we've hit our targets.
|
||||||
if (data.buyAmount == 0) {
|
if (data.side == Side.Sell) {
|
||||||
// Market sell check.
|
// Market sell check.
|
||||||
if (soldAmount >= data.sellAmount) {
|
if (soldAmount >= data.fillAmount) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Market buy check.
|
// Market buy check.
|
||||||
if (boughtAmount >= data.buyAmount) {
|
if (boughtAmount >= data.fillAmount) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,14 +171,14 @@ contract FillQuoteTransformer is
|
|||||||
|
|
||||||
// Fill the order.
|
// Fill the order.
|
||||||
FillOrderResults memory results;
|
FillOrderResults memory results;
|
||||||
if (data.buyAmount == 0) {
|
if (data.side == Side.Sell) {
|
||||||
// Market sell.
|
// Market sell.
|
||||||
results = _sellToOrder(
|
results = _sellToOrder(
|
||||||
data.buyToken,
|
data.buyToken,
|
||||||
data.sellToken,
|
data.sellToken,
|
||||||
data.orders[i],
|
data.orders[i],
|
||||||
data.signatures[i],
|
data.signatures[i],
|
||||||
data.sellAmount.safeSub(soldAmount).min256(
|
data.fillAmount.safeSub(soldAmount).min256(
|
||||||
data.maxOrderFillAmounts.length > i
|
data.maxOrderFillAmounts.length > i
|
||||||
? data.maxOrderFillAmounts[i]
|
? data.maxOrderFillAmounts[i]
|
||||||
: uint256(-1)
|
: uint256(-1)
|
||||||
@@ -180,7 +192,7 @@ contract FillQuoteTransformer is
|
|||||||
data.sellToken,
|
data.sellToken,
|
||||||
data.orders[i],
|
data.orders[i],
|
||||||
data.signatures[i],
|
data.signatures[i],
|
||||||
data.buyAmount.safeSub(boughtAmount).min256(
|
data.fillAmount.safeSub(boughtAmount).min256(
|
||||||
data.maxOrderFillAmounts.length > i
|
data.maxOrderFillAmounts.length > i
|
||||||
? data.maxOrderFillAmounts[i]
|
? data.maxOrderFillAmounts[i]
|
||||||
: uint256(-1)
|
: uint256(-1)
|
||||||
@@ -196,24 +208,24 @@ contract FillQuoteTransformer is
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we hit our targets.
|
// Ensure we hit our targets.
|
||||||
if (data.buyAmount == 0) {
|
if (data.side == Side.Sell) {
|
||||||
// Market sell check.
|
// Market sell check.
|
||||||
if (soldAmount < data.sellAmount) {
|
if (soldAmount < data.fillAmount) {
|
||||||
LibTransformERC20RichErrors
|
LibTransformERC20RichErrors
|
||||||
.IncompleteFillSellQuoteError(
|
.IncompleteFillSellQuoteError(
|
||||||
address(data.sellToken),
|
address(data.sellToken),
|
||||||
soldAmount,
|
soldAmount,
|
||||||
data.sellAmount
|
data.fillAmount
|
||||||
).rrevert();
|
).rrevert();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Market buy check.
|
// Market buy check.
|
||||||
if (boughtAmount < data.buyAmount) {
|
if (boughtAmount < data.fillAmount) {
|
||||||
LibTransformERC20RichErrors
|
LibTransformERC20RichErrors
|
||||||
.IncompleteFillBuyQuoteError(
|
.IncompleteFillBuyQuoteError(
|
||||||
address(data.buyToken),
|
address(data.buyToken),
|
||||||
boughtAmount,
|
boughtAmount,
|
||||||
data.buyAmount
|
data.fillAmount
|
||||||
).rrevert();
|
).rrevert();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,9 +250,8 @@ contract FillQuoteTransformer is
|
|||||||
private
|
private
|
||||||
returns (FillOrderResults memory results)
|
returns (FillOrderResults memory results)
|
||||||
{
|
{
|
||||||
IERC20TokenV06 takerFeeToken = order.takerFeeAssetData.length == 0
|
IERC20TokenV06 takerFeeToken =
|
||||||
? IERC20TokenV06(address(0))
|
_getTokenFromERC20AssetData(order.takerFeeAssetData);
|
||||||
: _getTokenFromERC20AssetData(order.takerFeeAssetData);
|
|
||||||
|
|
||||||
uint256 takerTokenFillAmount = sellAmount;
|
uint256 takerTokenFillAmount = sellAmount;
|
||||||
|
|
||||||
@@ -261,7 +272,7 @@ contract FillQuoteTransformer is
|
|||||||
takerTokenFillAmount = LibMathV06.getPartialAmountCeil(
|
takerTokenFillAmount = LibMathV06.getPartialAmountCeil(
|
||||||
order.takerAssetAmount,
|
order.takerAssetAmount,
|
||||||
order.takerAssetAmount.safeAdd(order.takerFee),
|
order.takerAssetAmount.safeAdd(order.takerFee),
|
||||||
takerTokenFillAmount
|
sellAmount
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Only support taker or maker asset denominated taker fees.
|
// Only support taker or maker asset denominated taker fees.
|
||||||
@@ -306,24 +317,27 @@ contract FillQuoteTransformer is
|
|||||||
private
|
private
|
||||||
returns (FillOrderResults memory results)
|
returns (FillOrderResults memory results)
|
||||||
{
|
{
|
||||||
IERC20TokenV06 takerFeeToken = order.takerFeeAssetData.length == 0
|
IERC20TokenV06 takerFeeToken =
|
||||||
? IERC20TokenV06(address(0))
|
_getTokenFromERC20AssetData(order.takerFeeAssetData);
|
||||||
: _getTokenFromERC20AssetData(order.takerFeeAssetData);
|
// Compute the default taker token fill amount.
|
||||||
|
uint256 takerTokenFillAmount = LibMathV06.getPartialAmountCeil(
|
||||||
uint256 makerTokenFillAmount = buyAmount;
|
buyAmount,
|
||||||
|
order.makerAssetAmount,
|
||||||
|
order.takerAssetAmount
|
||||||
|
);
|
||||||
|
|
||||||
if (order.takerFee != 0) {
|
if (order.takerFee != 0) {
|
||||||
if (takerFeeToken == makerToken) {
|
if (takerFeeToken == makerToken) {
|
||||||
// Taker fee is payable in the maker token.
|
// Taker fee is payable in the maker token.
|
||||||
// Increase the fill amount to account for maker tokens being
|
// Adjust the taker token fill amount to account for maker
|
||||||
// lost to the taker fee.
|
// tokens being lost to the taker fee.
|
||||||
// makerTokenFillAmount' =
|
// takerTokenFillAmount' =
|
||||||
// (order.makerAssetAmount * makerTokenFillAmount) /
|
// (order.takerAssetAmount * buyAmount) /
|
||||||
// (order.makerAssetAmount - order.takerFee)
|
// (order.makerAssetAmount - order.takerFee)
|
||||||
makerTokenFillAmount = LibMathV06.getPartialAmountCeil(
|
takerTokenFillAmount = LibMathV06.getPartialAmountCeil(
|
||||||
order.makerAssetAmount,
|
buyAmount,
|
||||||
order.makerAssetAmount.safeSub(order.takerFee),
|
order.makerAssetAmount.safeSub(order.takerFee),
|
||||||
makerTokenFillAmount
|
order.takerAssetAmount
|
||||||
);
|
);
|
||||||
// Approve the proxy to spend the maker token.
|
// Approve the proxy to spend the maker token.
|
||||||
// It isn't worth computing the actual taker fee
|
// It isn't worth computing the actual taker fee
|
||||||
@@ -338,14 +352,10 @@ contract FillQuoteTransformer is
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert maker fill amount to taker fill amount.
|
// Clamp to order size.
|
||||||
uint256 takerTokenFillAmount = LibSafeMathV06.min256(
|
takerTokenFillAmount = LibSafeMathV06.min256(
|
||||||
order.takerAssetAmount,
|
order.takerAssetAmount,
|
||||||
LibMathV06.getPartialAmountCeil(
|
takerTokenFillAmount
|
||||||
makerTokenFillAmount,
|
|
||||||
order.makerAssetAmount,
|
|
||||||
order.takerAssetAmount
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Perform the fill.
|
// Perform the fill.
|
||||||
@@ -380,7 +390,7 @@ contract FillQuoteTransformer is
|
|||||||
returns (FillOrderResults memory results)
|
returns (FillOrderResults memory results)
|
||||||
{
|
{
|
||||||
// Track changes in the maker token balance.
|
// Track changes in the maker token balance.
|
||||||
results.makerTokenBoughtAmount = makerToken.balanceOf(address(this));
|
uint256 initialMakerTokenBalance = makerToken.balanceOf(address(this));
|
||||||
try
|
try
|
||||||
exchange.fillOrder
|
exchange.fillOrder
|
||||||
{value: protocolFee}
|
{value: protocolFee}
|
||||||
@@ -389,7 +399,7 @@ contract FillQuoteTransformer is
|
|||||||
{
|
{
|
||||||
// Update maker quantity based on changes in token balances.
|
// Update maker quantity based on changes in token balances.
|
||||||
results.makerTokenBoughtAmount = makerToken.balanceOf(address(this))
|
results.makerTokenBoughtAmount = makerToken.balanceOf(address(this))
|
||||||
.safeSub(results.makerTokenBoughtAmount);
|
.safeSub(initialMakerTokenBalance);
|
||||||
// We can trust the other fill result quantities.
|
// We can trust the other fill result quantities.
|
||||||
results.protocolFeePaid = fillResults.protocolFeePaid;
|
results.protocolFeePaid = fillResults.protocolFeePaid;
|
||||||
results.takerTokenSoldAmount = fillResults.takerAssetFilledAmount;
|
results.takerTokenSoldAmount = fillResults.takerAssetFilledAmount;
|
||||||
@@ -400,18 +410,21 @@ contract FillQuoteTransformer is
|
|||||||
results.takerTokenSoldAmount.safeAdd(fillResults.takerFeePaid);
|
results.takerTokenSoldAmount.safeAdd(fillResults.takerFeePaid);
|
||||||
}
|
}
|
||||||
} catch (bytes memory) {
|
} catch (bytes memory) {
|
||||||
// If the fill fails, zero out fill quantities.
|
// Swallow failures, leaving all results as zero.
|
||||||
results.makerTokenBoughtAmount = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Extract the token from plain ERC20 asset data.
|
/// @dev Extract the token from plain ERC20 asset data.
|
||||||
|
/// If the asset-data is empty, a zero token address will be returned.
|
||||||
/// @param assetData The order asset data.
|
/// @param assetData The order asset data.
|
||||||
function _getTokenFromERC20AssetData(bytes memory assetData)
|
function _getTokenFromERC20AssetData(bytes memory assetData)
|
||||||
private
|
private
|
||||||
pure
|
pure
|
||||||
returns (IERC20TokenV06 token)
|
returns (IERC20TokenV06 token)
|
||||||
{
|
{
|
||||||
|
if (assetData.length == 0) {
|
||||||
|
return IERC20TokenV06(address(0));
|
||||||
|
}
|
||||||
if (assetData.length != 36 ||
|
if (assetData.length != 36 ||
|
||||||
LibBytesV06.readBytes4(assetData, 0) != ERC20_ASSET_PROXY_ID)
|
LibBytesV06.readBytes4(assetData, 0) != ERC20_ASSET_PROXY_ID)
|
||||||
{
|
{
|
||||||
|
@@ -49,7 +49,6 @@ contract PayTakerTransformer is
|
|||||||
|
|
||||||
/// @dev Create this contract.
|
/// @dev Create this contract.
|
||||||
/// @param deploymentNonce_ The nonce of the deployer when deploying this contract.
|
/// @param deploymentNonce_ The nonce of the deployer when deploying this contract.
|
||||||
/// @dev Construct the transformer and store the WETH address in an immutable.
|
|
||||||
constructor(uint256 deploymentNonce_)
|
constructor(uint256 deploymentNonce_)
|
||||||
public
|
public
|
||||||
Transformer(deploymentNonce_)
|
Transformer(deploymentNonce_)
|
||||||
|
@@ -47,10 +47,9 @@ contract WethTransformer is
|
|||||||
using LibSafeMathV06 for uint256;
|
using LibSafeMathV06 for uint256;
|
||||||
using LibERC20Transformer for IERC20TokenV06;
|
using LibERC20Transformer for IERC20TokenV06;
|
||||||
|
|
||||||
/// @dev Create this contract.
|
/// @dev Construct the transformer and store the WETH address in an immutable.
|
||||||
/// @param weth_ The weth token.
|
/// @param weth_ The weth token.
|
||||||
/// @param deploymentNonce_ The nonce of the deployer when deploying this contract.
|
/// @param deploymentNonce_ The nonce of the deployer when deploying this contract.
|
||||||
/// @dev Construct the transformer and store the WETH address in an immutable.
|
|
||||||
constructor(IEtherTokenV06 weth_, uint256 deploymentNonce_)
|
constructor(IEtherTokenV06 weth_, uint256 deploymentNonce_)
|
||||||
public
|
public
|
||||||
Transformer(deploymentNonce_)
|
Transformer(deploymentNonce_)
|
||||||
@@ -74,7 +73,10 @@ contract WethTransformer is
|
|||||||
{
|
{
|
||||||
TransformData memory data = abi.decode(data_, (TransformData));
|
TransformData memory data = abi.decode(data_, (TransformData));
|
||||||
if (!data.token.isTokenETH() && data.token != weth) {
|
if (!data.token.isTokenETH() && data.token != weth) {
|
||||||
LibTransformERC20RichErrors.InvalidTransformDataError(data_).rrevert();
|
LibTransformERC20RichErrors.InvalidTransformDataError(
|
||||||
|
LibTransformERC20RichErrors.InvalidTransformDataErrorCode.INVALID_TOKENS,
|
||||||
|
data_
|
||||||
|
).rrevert();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 amount = data.amount;
|
uint256 amount = data.amount;
|
||||||
|
@@ -20,7 +20,6 @@ pragma solidity ^0.6.5;
|
|||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
contract TestDelegateCaller {
|
contract TestDelegateCaller {
|
||||||
function executeDelegateCall(
|
function executeDelegateCall(
|
||||||
address target,
|
address target,
|
||||||
|
@@ -26,6 +26,7 @@ export const fillQuoteTransformerDataEncoder = AbiEncoder.create([
|
|||||||
name: 'data',
|
name: 'data',
|
||||||
type: 'tuple',
|
type: 'tuple',
|
||||||
components: [
|
components: [
|
||||||
|
{ name: 'side', type: 'uint8' },
|
||||||
{ name: 'sellToken', type: 'address' },
|
{ name: 'sellToken', type: 'address' },
|
||||||
{ name: 'buyToken', type: 'address' },
|
{ name: 'buyToken', type: 'address' },
|
||||||
{
|
{
|
||||||
@@ -35,23 +36,30 @@ export const fillQuoteTransformerDataEncoder = AbiEncoder.create([
|
|||||||
},
|
},
|
||||||
{ name: 'signatures', type: 'bytes[]' },
|
{ name: 'signatures', type: 'bytes[]' },
|
||||||
{ name: 'maxOrderFillAmounts', type: 'uint256[]' },
|
{ name: 'maxOrderFillAmounts', type: 'uint256[]' },
|
||||||
{ name: 'sellAmount', type: 'uint256' },
|
{ name: 'fillAmount', type: 'uint256' },
|
||||||
{ name: 'buyAmount', type: 'uint256' },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Market operation for `FillQuoteTransformerData`.
|
||||||
|
*/
|
||||||
|
export enum FillQuoteTransformerSide {
|
||||||
|
Sell,
|
||||||
|
Buy,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `FillQuoteTransformer.TransformData`
|
* `FillQuoteTransformer.TransformData`
|
||||||
*/
|
*/
|
||||||
export interface FillQuoteTransformerData {
|
export interface FillQuoteTransformerData {
|
||||||
|
side: FillQuoteTransformerSide;
|
||||||
sellToken: string;
|
sellToken: string;
|
||||||
buyToken: string;
|
buyToken: string;
|
||||||
orders: Array<Exclude<Order, ['signature', 'exchangeAddress', 'chainId']>>;
|
orders: Array<Exclude<Order, ['signature', 'exchangeAddress', 'chainId']>>;
|
||||||
signatures: string[];
|
signatures: string[];
|
||||||
maxOrderFillAmounts: BigNumber[];
|
maxOrderFillAmounts: BigNumber[];
|
||||||
sellAmount: BigNumber;
|
fillAmount: BigNumber;
|
||||||
buyAmount: BigNumber;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -13,7 +13,11 @@ import { BigNumber, hexUtils, ZeroExRevertErrors } from '@0x/utils';
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { rlpEncodeNonce } from '../../src/nonce_utils';
|
import { rlpEncodeNonce } from '../../src/nonce_utils';
|
||||||
import { encodeFillQuoteTransformerData, FillQuoteTransformerData } from '../../src/transformer_data_encoders';
|
import {
|
||||||
|
encodeFillQuoteTransformerData,
|
||||||
|
FillQuoteTransformerData,
|
||||||
|
FillQuoteTransformerSide,
|
||||||
|
} from '../../src/transformer_data_encoders';
|
||||||
import { artifacts } from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
import {
|
import {
|
||||||
FillQuoteTransformerContract,
|
FillQuoteTransformerContract,
|
||||||
@@ -217,13 +221,13 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
|
|
||||||
function encodeTransformData(fields: Partial<FillQuoteTransformerData> = {}): string {
|
function encodeTransformData(fields: Partial<FillQuoteTransformerData> = {}): string {
|
||||||
return encodeFillQuoteTransformerData({
|
return encodeFillQuoteTransformerData({
|
||||||
|
side: FillQuoteTransformerSide.Sell,
|
||||||
sellToken: takerToken.address,
|
sellToken: takerToken.address,
|
||||||
buyToken: makerToken.address,
|
buyToken: makerToken.address,
|
||||||
orders: [],
|
orders: [],
|
||||||
signatures: [],
|
signatures: [],
|
||||||
maxOrderFillAmounts: [],
|
maxOrderFillAmounts: [],
|
||||||
sellAmount: MAX_UINT256,
|
fillAmount: MAX_UINT256,
|
||||||
buyAmount: ZERO_AMOUNT,
|
|
||||||
...fields,
|
...fields,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -455,7 +459,7 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
sellAmount: qfr.takerAssetSpent,
|
fillAmount: qfr.takerAssetSpent,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
||||||
@@ -479,7 +483,7 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
sellAmount: qfr.takerAssetSpent,
|
fillAmount: qfr.takerAssetSpent,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
||||||
@@ -614,7 +618,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
buyAmount: qfr.makerAssetBought,
|
side: FillQuoteTransformerSide.Buy,
|
||||||
|
fillAmount: qfr.makerAssetBought,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
||||||
@@ -636,7 +641,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
buyAmount: qfr.makerAssetBought,
|
side: FillQuoteTransformerSide.Buy,
|
||||||
|
fillAmount: qfr.makerAssetBought,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
||||||
@@ -661,7 +667,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
buyAmount: qfr.makerAssetBought,
|
side: FillQuoteTransformerSide.Buy,
|
||||||
|
fillAmount: qfr.makerAssetBought,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
||||||
@@ -684,7 +691,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
buyAmount: qfr.makerAssetBought,
|
side: FillQuoteTransformerSide.Buy,
|
||||||
|
fillAmount: qfr.makerAssetBought,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ value: maxProtocolFees });
|
.awaitTransactionSuccessAsync({ value: maxProtocolFees });
|
||||||
@@ -709,7 +717,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
buyAmount: qfr.makerAssetBought,
|
side: FillQuoteTransformerSide.Buy,
|
||||||
|
fillAmount: qfr.makerAssetBought,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
||||||
@@ -736,7 +745,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
buyAmount: qfr.makerAssetBought,
|
side: FillQuoteTransformerSide.Buy,
|
||||||
|
fillAmount: qfr.makerAssetBought,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
||||||
@@ -760,7 +770,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
buyAmount: qfr.makerAssetBought.plus(1),
|
side: FillQuoteTransformerSide.Buy,
|
||||||
|
fillAmount: qfr.makerAssetBought.plus(1),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
||||||
@@ -789,7 +800,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
buyAmount: qfr.makerAssetBought,
|
side: FillQuoteTransformerSide.Buy,
|
||||||
|
fillAmount: qfr.makerAssetBought,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
||||||
@@ -812,7 +824,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
buyAmount: qfr.makerAssetBought,
|
side: FillQuoteTransformerSide.Buy,
|
||||||
|
fillAmount: qfr.makerAssetBought,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
||||||
@@ -835,7 +848,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
buyAmount: qfr.makerAssetBought,
|
side: FillQuoteTransformerSide.Buy,
|
||||||
|
fillAmount: qfr.makerAssetBought,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
.awaitTransactionSuccessAsync({ value: qfr.protocolFeePaid });
|
||||||
@@ -855,7 +869,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
buyAmount: qfr.makerAssetBought,
|
side: FillQuoteTransformerSide.Buy,
|
||||||
|
fillAmount: qfr.makerAssetBought,
|
||||||
// Skip the first order.
|
// Skip the first order.
|
||||||
maxOrderFillAmounts: [ZERO_AMOUNT],
|
maxOrderFillAmounts: [ZERO_AMOUNT],
|
||||||
}),
|
}),
|
||||||
@@ -879,6 +894,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
|||||||
encodeTransformData({
|
encodeTransformData({
|
||||||
orders,
|
orders,
|
||||||
signatures,
|
signatures,
|
||||||
|
side: FillQuoteTransformerSide.Buy,
|
||||||
|
fillAmount: qfr.makerAssetBought,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.callAsync({ value: qfr.protocolFeePaid });
|
.callAsync({ value: qfr.protocolFeePaid });
|
||||||
|
@@ -61,7 +61,12 @@ blockchainTests.resets('WethTransformer', env => {
|
|||||||
const tx = host
|
const tx = host
|
||||||
.executeTransform(amount, transformer.address, data)
|
.executeTransform(amount, transformer.address, data)
|
||||||
.awaitTransactionSuccessAsync({ value: amount });
|
.awaitTransactionSuccessAsync({ value: amount });
|
||||||
return expect(tx).to.revertWith(new ZeroExRevertErrors.TransformERC20.InvalidTransformDataError(data));
|
return expect(tx).to.revertWith(
|
||||||
|
new ZeroExRevertErrors.TransformERC20.InvalidTransformDataError(
|
||||||
|
ZeroExRevertErrors.TransformERC20.InvalidTransformDataErrorCode.InvalidTokens,
|
||||||
|
data,
|
||||||
|
),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can unwrap WETH', async () => {
|
it('can unwrap WETH', async () => {
|
||||||
|
Reference in New Issue
Block a user