Detect Bridge orders and fill direct

This commit is contained in:
Jacob Evans
2020-06-19 17:03:06 +10:00
parent f14b6f2ba2
commit 56529180e9
7 changed files with 590 additions and 19 deletions

View File

@@ -0,0 +1,436 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
import "../errors/LibTransformERC20RichErrors.sol";
import "../vendor/v3/IExchange.sol";
import "./Transformer.sol";
import "./LibERC20Transformer.sol";
/// @dev A transformer that fills an ERC20 market sell/buy quote.
contract FillOrdersTransformer is
Transformer
{
using LibERC20TokenV06 for IERC20TokenV06;
using LibERC20Transformer for IERC20TokenV06;
using LibSafeMathV06 for uint256;
using LibRichErrorsV06 for bytes;
/// @dev Whether we are performing a market sell or buy.
enum Side {
Sell,
Buy
}
/// @dev Transform data to ABI-encode and pass into `transform()`.
struct TransformData {
// Whether we aer performing a market sell or buy.
Side side;
// The token being sold.
// This should be an actual token, not the ETH pseudo-token.
IERC20TokenV06 sellToken;
// The token being bought.
// This should be an actual token, not the ETH pseudo-token.
IERC20TokenV06 buyToken;
// The orders to fill.
IExchange.Order[] orders;
// Signatures for each respective order in `orders`.
bytes[] signatures;
// Maximum fill amount for each order. This may be shorter than the
// number of orders, where missing entries will be treated as `uint256(-1)`.
// For sells, this will be the maximum sell amount (taker asset).
// For buys, this will be the maximum buy amount (maker asset).
uint256[] maxOrderFillAmounts;
// Amount of `sellToken` to sell or `buyToken` to buy.
// For sells, this may be `uint256(-1)` to sell the entire balance of
// `sellToken`.
uint256 fillAmount;
}
/// @dev Results of a call to `_fillOrder()`.
struct FillOrderResults {
// The amount of taker tokens sold, according to balance checks.
uint256 takerTokenSoldAmount;
// The amount of maker tokens sold, according to balance checks.
uint256 makerTokenBoughtAmount;
// The amount of protocol fee paid.
uint256 protocolFeePaid;
}
/// @dev The Exchange ERC20Proxy ID.
bytes4 private constant ERC20_ASSET_PROXY_ID = 0xf47261b0;
/// @dev Maximum uint256 value.
uint256 private constant MAX_UINT256 = uint256(-1);
/// @dev The Exchange contract.
IExchange public immutable exchange;
/// @dev The ERC20Proxy address.
address public immutable erc20Proxy;
/// @dev Create this contract.
/// @param exchange_ The Exchange V3 instance.
constructor(IExchange exchange_)
public
Transformer()
{
exchange = exchange_;
erc20Proxy = exchange_.getAssetProxy(ERC20_ASSET_PROXY_ID);
}
/// @dev Sell this contract's entire balance of of `sellToken` in exchange
/// for `buyToken` by filling `orders`. Protocol fees should be attached
/// to this call. `buyToken` and excess ETH will be transferred back to the caller.
/// @param data_ ABI-encoded `TransformData`.
/// @return success The success bytes (`LibERC20Transformer.TRANSFORMER_SUCCESS`).
function transform(
bytes32, // callDataHash,
address payable, // taker,
bytes calldata data_
)
external
override
returns (bytes4 success)
{
TransformData memory data = abi.decode(data_, (TransformData));
// Validate data fields.
if (data.sellToken.isTokenETH() || data.buyToken.isTokenETH()) {
LibTransformERC20RichErrors.InvalidTransformDataError(
LibTransformERC20RichErrors.InvalidTransformDataErrorCode.INVALID_TOKENS,
data_
).rrevert();
}
if (data.orders.length != data.signatures.length) {
LibTransformERC20RichErrors.InvalidTransformDataError(
LibTransformERC20RichErrors.InvalidTransformDataErrorCode.INVALID_ARRAY_LENGTH,
data_
).rrevert();
}
if (data.side == Side.Sell && data.fillAmount == MAX_UINT256) {
// If `sellAmount == -1 then we are selling
// the entire balance of `sellToken`. This is useful in cases where
// the exact sell amount is not exactly known in advance, like when
// unwrapping Chai/cUSDC/cDAI.
data.fillAmount = data.sellToken.getTokenBalanceOf(address(this));
}
// Approve the ERC20 proxy to spend `sellToken`.
data.sellToken.approveIfBelow(erc20Proxy, data.fillAmount);
// Fill the orders.
uint256 singleProtocolFee = exchange.protocolFeeMultiplier().safeMul(tx.gasprice);
uint256 ethRemaining = address(this).balance;
uint256 boughtAmount = 0;
uint256 soldAmount = 0;
for (uint256 i = 0; i < data.orders.length; ++i) {
// Check if we've hit our targets.
if (data.side == Side.Sell) {
// Market sell check.
if (soldAmount >= data.fillAmount) {
break;
}
} else {
// Market buy check.
if (boughtAmount >= data.fillAmount) {
break;
}
}
// Ensure we have enough ETH to cover the protocol fee.
if (ethRemaining < singleProtocolFee) {
LibTransformERC20RichErrors
.InsufficientProtocolFeeError(ethRemaining, singleProtocolFee)
.rrevert();
}
// Fill the order.
FillOrderResults memory results;
if (data.side == Side.Sell) {
// Market sell.
results = _sellToOrder(
data.buyToken,
data.sellToken,
data.orders[i],
data.signatures[i],
data.fillAmount.safeSub(soldAmount).min256(
data.maxOrderFillAmounts.length > i
? data.maxOrderFillAmounts[i]
: MAX_UINT256
),
singleProtocolFee
);
} else {
// Market buy.
results = _buyFromOrder(
data.buyToken,
data.sellToken,
data.orders[i],
data.signatures[i],
data.fillAmount.safeSub(boughtAmount).min256(
data.maxOrderFillAmounts.length > i
? data.maxOrderFillAmounts[i]
: MAX_UINT256
),
singleProtocolFee
);
}
// Accumulate totals.
soldAmount = soldAmount.safeAdd(results.takerTokenSoldAmount);
boughtAmount = boughtAmount.safeAdd(results.makerTokenBoughtAmount);
ethRemaining = ethRemaining.safeSub(results.protocolFeePaid);
}
// Ensure we hit our targets.
if (data.side == Side.Sell) {
// Market sell check.
if (soldAmount < data.fillAmount) {
LibTransformERC20RichErrors
.IncompleteFillSellQuoteError(
address(data.sellToken),
soldAmount,
data.fillAmount
).rrevert();
}
} else {
// Market buy check.
if (boughtAmount < data.fillAmount) {
LibTransformERC20RichErrors
.IncompleteFillBuyQuoteError(
address(data.buyToken),
boughtAmount,
data.fillAmount
).rrevert();
}
}
return LibERC20Transformer.TRANSFORMER_SUCCESS;
}
/// @dev Try to sell up to `sellAmount` from an order.
/// @param makerToken The maker/buy token.
/// @param takerToken The taker/sell token.
/// @param order The order to fill.
/// @param signature The signature for `order`.
/// @param sellAmount Amount of taker token to sell.
/// @param protocolFee The protocol fee needed to fill `order`.
function _sellToOrder(
IERC20TokenV06 makerToken,
IERC20TokenV06 takerToken,
IExchange.Order memory order,
bytes memory signature,
uint256 sellAmount,
uint256 protocolFee
)
private
returns (FillOrderResults memory results)
{
IERC20TokenV06 takerFeeToken =
_getTokenFromERC20AssetData(order.takerFeeAssetData);
uint256 takerTokenFillAmount = sellAmount;
if (order.takerFee != 0) {
if (takerFeeToken == makerToken) {
// Taker fee is payable in the maker token, so we need to
// approve the proxy to spend the maker token.
// It isn't worth computing the actual taker fee
// since `approveIfBelow()` will set the allowance to infinite. We
// just need a reasonable upper bound to avoid unnecessarily re-approving.
takerFeeToken.approveIfBelow(erc20Proxy, order.takerFee);
} else if (takerFeeToken == takerToken){
// Taker fee is payable in the taker token, so we need to
// reduce the fill amount to cover the fee.
// takerTokenFillAmount' =
// (takerTokenFillAmount * order.takerAssetAmount) /
// (order.takerAssetAmount + order.takerFee)
takerTokenFillAmount = LibMathV06.getPartialAmountCeil(
order.takerAssetAmount,
order.takerAssetAmount.safeAdd(order.takerFee),
sellAmount
);
} else {
// Only support taker or maker asset denominated taker fees.
LibTransformERC20RichErrors.InvalidTakerFeeTokenError(
address(takerFeeToken)
).rrevert();
}
}
// Clamp fill amount to order size.
takerTokenFillAmount = LibSafeMathV06.min256(
takerTokenFillAmount,
order.takerAssetAmount
);
// Perform the fill.
return _fillOrder(
order,
signature,
takerTokenFillAmount,
protocolFee,
makerToken,
takerFeeToken == takerToken
);
}
/// @dev Try to buy up to `buyAmount` from an order.
/// @param makerToken The maker/buy token.
/// @param takerToken The taker/sell token.
/// @param order The order to fill.
/// @param signature The signature for `order`.
/// @param buyAmount Amount of maker token to buy.
/// @param protocolFee The protocol fee needed to fill `order`.
function _buyFromOrder(
IERC20TokenV06 makerToken,
IERC20TokenV06 takerToken,
IExchange.Order memory order,
bytes memory signature,
uint256 buyAmount,
uint256 protocolFee
)
private
returns (FillOrderResults memory results)
{
IERC20TokenV06 takerFeeToken =
_getTokenFromERC20AssetData(order.takerFeeAssetData);
// Compute the default taker token fill amount.
uint256 takerTokenFillAmount = LibMathV06.getPartialAmountCeil(
buyAmount,
order.makerAssetAmount,
order.takerAssetAmount
);
if (order.takerFee != 0) {
if (takerFeeToken == makerToken) {
// Taker fee is payable in the maker token.
// Adjust the taker token fill amount to account for maker
// tokens being lost to the taker fee.
// takerTokenFillAmount' =
// (order.takerAssetAmount * buyAmount) /
// (order.makerAssetAmount - order.takerFee)
takerTokenFillAmount = LibMathV06.getPartialAmountCeil(
buyAmount,
order.makerAssetAmount.safeSub(order.takerFee),
order.takerAssetAmount
);
// Approve the proxy to spend the maker token.
// It isn't worth computing the actual taker fee
// since `approveIfBelow()` will set the allowance to infinite. We
// just need a reasonable upper bound to avoid unnecessarily re-approving.
takerFeeToken.approveIfBelow(erc20Proxy, order.takerFee);
} else if (takerFeeToken != takerToken) {
// Only support taker or maker asset denominated taker fees.
LibTransformERC20RichErrors.InvalidTakerFeeTokenError(
address(takerFeeToken)
).rrevert();
}
}
// Clamp to order size.
takerTokenFillAmount = LibSafeMathV06.min256(
order.takerAssetAmount,
takerTokenFillAmount
);
// Perform the fill.
return _fillOrder(
order,
signature,
takerTokenFillAmount,
protocolFee,
makerToken,
takerFeeToken == takerToken
);
}
/// @dev Attempt to fill an order. If the fill reverts, the revert will be
/// swallowed and `results` will be zeroed out.
/// @param order The order to fill.
/// @param signature The order signature.
/// @param takerAssetFillAmount How much taker asset to fill.
/// @param protocolFee The protocol fee needed to fill this order.
/// @param makerToken The maker token.
/// @param isTakerFeeInTakerToken Whether the taker fee token is the same as the
/// taker token.
function _fillOrder(
IExchange.Order memory order,
bytes memory signature,
uint256 takerAssetFillAmount,
uint256 protocolFee,
IERC20TokenV06 makerToken,
bool isTakerFeeInTakerToken
)
private
returns (FillOrderResults memory results)
{
// Track changes in the maker token balance.
uint256 initialMakerTokenBalance = makerToken.balanceOf(address(this));
try
exchange.fillOrder
{value: protocolFee}
(order, takerAssetFillAmount, signature)
returns (IExchange.FillResults memory fillResults)
{
// Update maker quantity based on changes in token balances.
results.makerTokenBoughtAmount = makerToken.balanceOf(address(this))
.safeSub(initialMakerTokenBalance);
// We can trust the other fill result quantities.
results.protocolFeePaid = fillResults.protocolFeePaid;
results.takerTokenSoldAmount = fillResults.takerAssetFilledAmount;
// If the taker fee is payable in the taker asset, include the
// taker fee in the total amount sold.
if (isTakerFeeInTakerToken) {
results.takerTokenSoldAmount =
results.takerTokenSoldAmount.safeAdd(fillResults.takerFeePaid);
}
} catch (bytes memory) {
// Swallow failures, leaving all results as zero.
}
}
/// @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.
function _getTokenFromERC20AssetData(bytes memory assetData)
private
pure
returns (IERC20TokenV06 token)
{
if (assetData.length == 0) {
return IERC20TokenV06(address(0));
}
if (assetData.length != 36 ||
LibBytesV06.readBytes4(assetData, 0) != ERC20_ASSET_PROXY_ID)
{
LibTransformERC20RichErrors
.InvalidERC20AssetDataError(assetData)
.rrevert();
}
return IERC20TokenV06(LibBytesV06.readAddress(assetData, 16));
}
}

View File

@@ -27,11 +27,13 @@ import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
import "../errors/LibTransformERC20RichErrors.sol";
import "../vendor/v3/IExchange.sol";
import "../vendor/v3/IERC20Bridge.sol";
import "./Transformer.sol";
import "./LibERC20Transformer.sol";
/// @dev A transformer that fills an ERC20 market sell/buy quote.
/// This transformer shortcuts bridge orders and fills them directly
contract FillQuoteTransformer is
Transformer
{
@@ -83,6 +85,8 @@ contract FillQuoteTransformer is
/// @dev The Exchange ERC20Proxy ID.
bytes4 private constant ERC20_ASSET_PROXY_ID = 0xf47261b0;
/// @dev The Exchange ERC20BridgeProxy ID.
bytes4 private constant ERC20_BRIDGE_PROXY_ID = 0xdc1600f3;
/// @dev Maximum uint256 value.
uint256 private constant MAX_UINT256 = uint256(-1);
@@ -387,28 +391,95 @@ contract FillQuoteTransformer is
)
private
returns (FillOrderResults memory results)
{
bytes4 makerAssetProxyId = LibBytesV06.readBytes4(order.makerAssetData, 0);
// If it is a Bridge order we fill this directly
// rather than filling via 0x Exchange
if (makerAssetProxyId == ERC20_BRIDGE_PROXY_ID) {
return _fillBridgeOrder(order,
signature,
takerAssetFillAmount,
makerToken,
isTakerFeeInTakerToken);
} else {
// Track changes in the maker token balance.
uint256 initialMakerTokenBalance = makerToken.balanceOf(address(this));
try
exchange.fillOrder
{value: protocolFee}
(order, takerAssetFillAmount, signature)
returns (IExchange.FillResults memory fillResults)
{
// Update maker quantity based on changes in token balances.
results.makerTokenBoughtAmount = makerToken.balanceOf(address(this))
.safeSub(initialMakerTokenBalance);
// We can trust the other fill result quantities.
results.protocolFeePaid = fillResults.protocolFeePaid;
results.takerTokenSoldAmount = fillResults.takerAssetFilledAmount;
// If the taker fee is payable in the taker asset, include the
// taker fee in the total amount sold.
if (isTakerFeeInTakerToken) {
results.takerTokenSoldAmount =
results.takerTokenSoldAmount.safeAdd(fillResults.takerFeePaid);
}
} catch (bytes memory) {
// Swallow failures, leaving all results as zero.
}
}
}
/// @dev Attempt to fill a ERC20 Bridge order. If the fill reverts,
/// the revert will be swallowed and `results` will be zeroed out.
/// @param order The bridge order to fill.
/// @param signature The order signature.
/// @param takerAssetFillAmount How much taker asset to fill.
/// @param makerToken The maker token.
/// @param isTakerFeeInTakerToken Whether the taker fee token is the same as the
/// taker token.
function _fillBridgeOrder(
IExchange.Order memory order,
bytes memory signature,
uint256 takerAssetFillAmount,
IERC20TokenV06 makerToken,
bool isTakerFeeInTakerToken
)
private
returns (FillOrderResults memory results)
{
// Track changes in the maker token balance.
uint256 initialMakerTokenBalance = makerToken.balanceOf(address(this));
(
address tokenAddress,
address bridgeAddress,
bytes memory bridgeData
) = abi.decode(
LibBytesV06.sliceDestructive(
order.makerAssetData,
4,
order.makerAssetData.length),
(address, address, bytes)
);
uint256 outputTokenAmount = LibMathV06.getPartialAmountFloor(
takerAssetFillAmount,
order.takerAssetAmount,
order.makerAssetAmount
);
try
exchange.fillOrder
{value: protocolFee}
(order, takerAssetFillAmount, signature)
returns (IExchange.FillResults memory fillResults)
IERC20Bridge(bridgeAddress).bridgeTransferFrom(
tokenAddress,
order.makerAddress,
address(this),
takerAssetFillAmount,
bridgeData
)
returns (bytes4 success)
{
// Update maker quantity based on changes in token balances.
results.makerTokenBoughtAmount = makerToken.balanceOf(address(this))
.safeSub(initialMakerTokenBalance);
// We can trust the other fill result quantities.
results.protocolFeePaid = fillResults.protocolFeePaid;
results.takerTokenSoldAmount = fillResults.takerAssetFilledAmount;
// If the taker fee is payable in the taker asset, include the
// taker fee in the total amount sold.
if (isTakerFeeInTakerToken) {
results.takerTokenSoldAmount =
results.takerTokenSoldAmount.safeAdd(fillResults.takerFeePaid);
}
} catch (bytes memory) {
results.makerTokenBoughtAmount = afterMakerTokenBalance.safeSub(
makerToken.balanceOf(address(this))
);
results.takerTokenSoldAmount = takerAssetFillAmount;
// protocol fee paid remains 0
} catch (bytes memory) {
// Swallow failures, leaving all results as zero.
}
}

View File

@@ -0,0 +1,55 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
interface IERC20Bridge {
/// @dev Emitted when a trade occurs.
/// @param inputToken The token the bridge is converting from.
/// @param outputToken The token the bridge is converting to.
/// @param inputTokenAmount Amount of input token.
/// @param outputTokenAmount Amount of output token.
/// @param from The `from` address in `bridgeTransferFrom()`
/// @param to The `to` address in `bridgeTransferFrom()`
event ERC20BridgeTransfer(
address inputToken,
address outputToken,
uint256 inputTokenAmount,
uint256 outputTokenAmount,
address from,
address to
);
/// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
/// @param tokenAddress The address of the ERC20 token to transfer.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer.
/// @param bridgeData Arbitrary asset data needed by the bridge contract.
/// @return success The magic bytes `0xdc1600f3` if successful.
function bridgeTransferFrom(
address tokenAddress,
address from,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success);
}

View File

@@ -35,12 +35,13 @@
"lint-contracts": "#solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
"compile:truffle": "truffle compile",
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES",
"publish:private": "yarn build && gitpkg publish"
},
"config": {
"publicInterfaceContracts": "ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnable,ISimpleFunctionRegistry,ITokenSpender,ITransformERC20,FillQuoteTransformer,PayTakerTransformer,WethTransformer",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|Bootstrap|FillQuoteTransformer|FixinCommon|FlashWallet|FullMigration|IAllowanceTarget|IBootstrap|IERC20Transformer|IExchange|IFeature|IFlashWallet|IOwnable|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|ITokenSpender|ITransformERC20|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibMigrate|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|Ownable|PayTakerTransformer|SimpleFunctionRegistry|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpender|TransformERC20|Transformer|TransformerDeployer|WethTransformer|ZeroEx).json"
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|Bootstrap|FillOrdersTransformer|FillQuoteTransformer|FixinCommon|FlashWallet|FullMigration|IAllowanceTarget|IBootstrap|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IOwnable|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|ITokenSpender|ITransformERC20|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibMigrate|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|Ownable|PayTakerTransformer|SimpleFunctionRegistry|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpender|TransformERC20|Transformer|TransformerDeployer|WethTransformer|ZeroEx).json"
},
"repository": {
"type": "git",

View File

@@ -8,12 +8,14 @@ import { ContractArtifact } from 'ethereum-types';
import * as AffiliateFeeTransformer from '../test/generated-artifacts/AffiliateFeeTransformer.json';
import * as AllowanceTarget from '../test/generated-artifacts/AllowanceTarget.json';
import * as Bootstrap from '../test/generated-artifacts/Bootstrap.json';
import * as FillOrdersTransformer from '../test/generated-artifacts/FillOrdersTransformer.json';
import * as FillQuoteTransformer from '../test/generated-artifacts/FillQuoteTransformer.json';
import * as FixinCommon from '../test/generated-artifacts/FixinCommon.json';
import * as FlashWallet from '../test/generated-artifacts/FlashWallet.json';
import * as FullMigration from '../test/generated-artifacts/FullMigration.json';
import * as IAllowanceTarget from '../test/generated-artifacts/IAllowanceTarget.json';
import * as IBootstrap from '../test/generated-artifacts/IBootstrap.json';
import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
import * as IERC20Transformer from '../test/generated-artifacts/IERC20Transformer.json';
import * as IExchange from '../test/generated-artifacts/IExchange.json';
import * as IFeature from '../test/generated-artifacts/IFeature.json';
@@ -106,12 +108,14 @@ export const artifacts = {
LibTokenSpenderStorage: LibTokenSpenderStorage as ContractArtifact,
LibTransformERC20Storage: LibTransformERC20Storage as ContractArtifact,
AffiliateFeeTransformer: AffiliateFeeTransformer as ContractArtifact,
FillOrdersTransformer: FillOrdersTransformer as ContractArtifact,
FillQuoteTransformer: FillQuoteTransformer as ContractArtifact,
IERC20Transformer: IERC20Transformer as ContractArtifact,
LibERC20Transformer: LibERC20Transformer as ContractArtifact,
PayTakerTransformer: PayTakerTransformer as ContractArtifact,
Transformer: Transformer as ContractArtifact,
WethTransformer: WethTransformer as ContractArtifact,
IERC20Bridge: IERC20Bridge as ContractArtifact,
IExchange: IExchange as ContractArtifact,
ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact,
TestCallTarget: TestCallTarget as ContractArtifact,

View File

@@ -6,12 +6,14 @@
export * from '../test/generated-wrappers/affiliate_fee_transformer';
export * from '../test/generated-wrappers/allowance_target';
export * from '../test/generated-wrappers/bootstrap';
export * from '../test/generated-wrappers/fill_orders_transformer';
export * from '../test/generated-wrappers/fill_quote_transformer';
export * from '../test/generated-wrappers/fixin_common';
export * from '../test/generated-wrappers/flash_wallet';
export * from '../test/generated-wrappers/full_migration';
export * from '../test/generated-wrappers/i_allowance_target';
export * from '../test/generated-wrappers/i_bootstrap';
export * from '../test/generated-wrappers/i_erc20_bridge';
export * from '../test/generated-wrappers/i_erc20_transformer';
export * from '../test/generated-wrappers/i_exchange';
export * from '../test/generated-wrappers/i_feature';

View File

@@ -19,12 +19,14 @@
"test/generated-artifacts/AffiliateFeeTransformer.json",
"test/generated-artifacts/AllowanceTarget.json",
"test/generated-artifacts/Bootstrap.json",
"test/generated-artifacts/FillOrdersTransformer.json",
"test/generated-artifacts/FillQuoteTransformer.json",
"test/generated-artifacts/FixinCommon.json",
"test/generated-artifacts/FlashWallet.json",
"test/generated-artifacts/FullMigration.json",
"test/generated-artifacts/IAllowanceTarget.json",
"test/generated-artifacts/IBootstrap.json",
"test/generated-artifacts/IERC20Bridge.json",
"test/generated-artifacts/IERC20Transformer.json",
"test/generated-artifacts/IExchange.json",
"test/generated-artifacts/IFeature.json",