Cherry pick DevUtils refactor code from #2456

This commit is contained in:
Lawrence Forman 2020-01-31 15:56:08 -05:00
parent 8635849977
commit 4016808fa4
42 changed files with 1490 additions and 1041 deletions

View File

@ -1,4 +1,17 @@
[
{
"version": "1.1.0",
"changes": [
{
"note": "Refactor mixins into public libraries.",
"pr": 2464
},
{
"note": "Remove `LibTransactionDecoder` export",
"pr": 2464
}
]
},
{
"timestamp": 1580988106,
"version": "1.0.6",

View File

@ -0,0 +1,51 @@
/*
Copyright 2019 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.5.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
// solhint-disable no-empty-blocks
contract Addresses is
DeploymentConstants
{
address public exchangeAddress;
address public erc20ProxyAddress;
address public erc721ProxyAddress;
address public erc1155ProxyAddress;
address public staticCallProxyAddress;
address public chaiBridgeAddress;
constructor (
address exchange_,
address chaiBridge_
)
public
{
exchangeAddress = exchange_;
chaiBridgeAddress = chaiBridge_;
erc20ProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).ERC20Token.selector);
erc721ProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).ERC721Token.selector);
erc1155ProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
staticCallProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).StaticCall.selector);
}
}

View File

@ -0,0 +1,374 @@
/*
Copyright 2019 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.5.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IChai.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "./Addresses.sol";
import "./LibAssetData.sol";
contract AssetBalance is
Addresses
{
// 2^256 - 1
uint256 constant internal _MAX_UINT256 = uint256(-1);
using LibBytes for bytes;
/// @dev Returns the owner's balance of the assets(s) specified in
/// assetData. When the asset data contains multiple assets (eg in
/// ERC1155 or Multi-Asset), the return value indicates how many
/// complete "baskets" of those assets are owned by owner.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
/// @return Number of assets (or asset baskets) held by owner.
function getBalance(address ownerAddress, bytes memory assetData)
public
returns (uint256 balance)
{
// Get id of AssetProxy contract
bytes4 assetProxyId = assetData.readBytes4(0);
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
// Get ERC20 token address
address tokenAddress = assetData.readAddress(16);
balance = LibERC20Token.balanceOf(tokenAddress, ownerAddress);
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
// Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = LibAssetData.decodeERC721AssetData(assetData);
// Check if id is owned by ownerAddress
bytes memory ownerOfCalldata = abi.encodeWithSelector(
IERC721Token(address(0)).ownerOf.selector,
tokenId
);
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
balance = currentOwnerAddress == ownerAddress ? 1 : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address, array of ids, and array of values
(, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = LibAssetData.decodeERC1155AssetData(assetData);
uint256 length = tokenIds.length;
for (uint256 i = 0; i != length; i++) {
// Skip over the token if the corresponding value is 0.
if (tokenValues[i] == 0) {
continue;
}
// Encode data for `balanceOf(ownerAddress, tokenIds[i])
bytes memory balanceOfData = abi.encodeWithSelector(
IERC1155(address(0)).balanceOf.selector,
ownerAddress,
tokenIds[i]
);
// Query balance
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
uint256 totalBalance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
// Scale total balance down by corresponding value in assetData
uint256 scaledBalance = totalBalance / tokenValues[i];
if (scaledBalance == 0) {
return 0;
}
if (scaledBalance < balance || balance == 0) {
balance = scaledBalance;
}
}
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// Encode data for `staticCallProxy.transferFrom(assetData,...)`
bytes memory transferFromData = abi.encodeWithSelector(
IAssetProxy(address(0)).transferFrom.selector,
assetData,
address(0), // `from` address is not used
address(0), // `to` address is not used
0 // `amount` is not used
);
// Check if staticcall would be successful
(bool success,) = staticCallProxyAddress.staticcall(transferFromData);
// Success means that the staticcall can be made an unlimited amount of times
balance = success ? _MAX_UINT256 : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
// Get address of ERC20 token and bridge contract
(, address tokenAddress, address bridgeAddress, ) = LibAssetData.decodeERC20BridgeAssetData(assetData);
if (tokenAddress == _getDaiAddress() && bridgeAddress == chaiBridgeAddress) {
uint256 chaiBalance = LibERC20Token.balanceOf(_getChaiAddress(), ownerAddress);
// Calculate Dai balance
balance = _convertChaiToDaiAmount(chaiBalance);
}
// Balance will be 0 if bridge is not supported
} else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
// Get array of values and array of assetDatas
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = LibAssetData.decodeMultiAssetData(assetData);
uint256 length = nestedAssetData.length;
for (uint256 i = 0; i != length; i++) {
// Skip over the asset if the corresponding amount is 0.
if (assetAmounts[i] == 0) {
continue;
}
// Query balance of individual assetData
uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]);
// Scale total balance down by corresponding value in assetData
uint256 scaledBalance = totalBalance / assetAmounts[i];
if (scaledBalance == 0) {
return 0;
}
if (scaledBalance < balance || balance == 0) {
balance = scaledBalance;
}
}
}
// Balance will be 0 if assetProxyId is unknown
return balance;
}
/// @dev Calls getBalance() for each element of assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
/// @return Array of asset balances from getBalance(), with each element
/// corresponding to the same-indexed element in the assetData input.
function getBatchBalances(address ownerAddress, bytes[] memory assetData)
public
returns (uint256[] memory balances)
{
uint256 length = assetData.length;
balances = new uint256[](length);
for (uint256 i = 0; i != length; i++) {
balances[i] = getBalance(ownerAddress, assetData[i]);
}
return balances;
}
/// @dev Returns the number of asset(s) (described by assetData) that
/// the corresponding AssetProxy contract is authorized to spend. When the asset data contains
/// multiple assets (eg for Multi-Asset), the return value indicates
/// how many complete "baskets" of those assets may be spent by all of the corresponding
/// AssetProxy contracts.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
/// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getAssetProxyAllowance(address ownerAddress, bytes memory assetData)
public
returns (uint256 allowance)
{
// Get id of AssetProxy contract
bytes4 assetProxyId = assetData.readBytes4(0);
if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
// Get array of values and array of assetDatas
(, uint256[] memory amounts, bytes[] memory nestedAssetData) = LibAssetData.decodeMultiAssetData(assetData);
uint256 length = nestedAssetData.length;
for (uint256 i = 0; i != length; i++) {
// Skip over the asset if the corresponding amount is 0.
if (amounts[i] == 0) {
continue;
}
// Query allowance of individual assetData
uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]);
// Scale total allowance down by corresponding value in assetData
uint256 scaledAllowance = totalAllowance / amounts[i];
if (scaledAllowance == 0) {
return 0;
}
if (scaledAllowance < allowance || allowance == 0) {
allowance = scaledAllowance;
}
}
return allowance;
}
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
// Get ERC20 token address
address tokenAddress = assetData.readAddress(16);
allowance = LibERC20Token.allowance(tokenAddress, ownerAddress, erc20ProxyAddress);
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
// Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = LibAssetData.decodeERC721AssetData(assetData);
// Encode data for `isApprovedForAll(ownerAddress, erc721ProxyAddress)`
bytes memory isApprovedForAllData = abi.encodeWithSelector(
IERC721Token(address(0)).isApprovedForAll.selector,
ownerAddress,
erc721ProxyAddress
);
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
// If not approved for all, call `getApproved(tokenId)`
if (!success || returnData.length != 32 || returnData.readUint256(0) != 1) {
// Encode data for `getApproved(tokenId)`
bytes memory getApprovedData = abi.encodeWithSelector(IERC721Token(address(0)).getApproved.selector, tokenId);
(success, returnData) = tokenAddress.staticcall(getApprovedData);
// Allowance is 1 if successful and the approved address is the ERC721Proxy
allowance = success && returnData.length == 32 && returnData.readAddress(12) == erc721ProxyAddress ? 1 : 0;
} else {
// Allowance is 2^256 - 1 if `isApprovedForAll` returned true
allowance = _MAX_UINT256;
}
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address
(, address tokenAddress, , , ) = LibAssetData.decodeERC1155AssetData(assetData);
// Encode data for `isApprovedForAll(ownerAddress, erc1155ProxyAddress)`
bytes memory isApprovedForAllData = abi.encodeWithSelector(
IERC1155(address(0)).isApprovedForAll.selector,
ownerAddress,
erc1155ProxyAddress
);
// Query allowance
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// The StaticCallProxy does not require any approvals
allowance = _MAX_UINT256;
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
// Get address of ERC20 token and bridge contract
(, address tokenAddress, address bridgeAddress,) = LibAssetData.decodeERC20BridgeAssetData(assetData);
if (tokenAddress == _getDaiAddress() && bridgeAddress == chaiBridgeAddress) {
uint256 chaiAllowance = LibERC20Token.allowance(_getChaiAddress(), ownerAddress, chaiBridgeAddress);
// Dai allowance is unlimited if Chai allowance is unlimited
allowance = chaiAllowance == _MAX_UINT256 ? _MAX_UINT256 : _convertChaiToDaiAmount(chaiAllowance);
}
// Allowance will be 0 if bridge is not supported
}
// Allowance will be 0 if the assetProxyId is unknown
return allowance;
}
/// @dev Calls getAssetProxyAllowance() for each element of assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
/// @return An array of asset allowances from getAllowance(), with each
/// element corresponding to the same-indexed element in the assetData input.
function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
public
returns (uint256[] memory allowances)
{
uint256 length = assetData.length;
allowances = new uint256[](length);
for (uint256 i = 0; i != length; i++) {
allowances[i] = getAssetProxyAllowance(ownerAddress, assetData[i]);
}
return allowances;
}
/// @dev Calls getBalance() and getAllowance() for assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
/// @return Number of assets (or asset baskets) held by owner, and number
/// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getBalanceAndAssetProxyAllowance(
address ownerAddress,
bytes memory assetData
)
public
returns (uint256 balance, uint256 allowance)
{
balance = getBalance(ownerAddress, assetData);
allowance = getAssetProxyAllowance(ownerAddress, assetData);
return (balance, allowance);
}
/// @dev Calls getBatchBalances() and getBatchAllowances() for each element of assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
/// @return An array of asset balances from getBalance(), and an array of
/// asset allowances from getAllowance(), with each element
/// corresponding to the same-indexed element in the assetData input.
function getBatchBalancesAndAssetProxyAllowances(
address ownerAddress,
bytes[] memory assetData
)
public
returns (uint256[] memory balances, uint256[] memory allowances)
{
balances = getBatchBalances(ownerAddress, assetData);
allowances = getBatchAssetProxyAllowances(ownerAddress, assetData);
return (balances, allowances);
}
/// @dev Converts an amount of Chai into its equivalent Dai amount.
/// Also accumulates Dai from DSR if called after the last time it was collected.
/// @param chaiAmount Amount of Chai to converts.
function _convertChaiToDaiAmount(uint256 chaiAmount)
internal
returns (uint256 daiAmount)
{
PotLike pot = IChai(_getChaiAddress()).pot();
// Accumulate savings if called after last time savings were collected
// solhint-disable-next-line not-rely-on-time
uint256 chiMultiplier = (now > pot.rho())
? pot.drip()
: pot.chi();
daiAmount = LibMath.getPartialAmountFloor(chiMultiplier, 10**27, chaiAmount);
return daiAmount;
}
/// @dev Returns an order MAKER's balance of the assets(s) specified in
/// makerAssetData. Unlike `getBalanceAndAssetProxyAllowance()`, this
/// can handle maker asset types that depend on taker tokens being
/// transferred to the maker first.
/// @param order The order.
/// @return balance Quantity of assets transferrable from maker to taker.
function _getConvertibleMakerBalanceAndAssetProxyAllowance(
LibOrder.Order memory order
)
internal
returns (uint256 balance, uint256 allowance)
{
if (order.makerAssetData.length < 4) {
return (0, 0);
}
return (
getBalance(order.makerAddress, order.makerAssetData),
getAssetProxyAllowance(order.makerAddress, order.makerAssetData)
);
}
}

View File

@ -16,7 +16,7 @@
*/
pragma solidity ^0.5.5;
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol";
@ -24,27 +24,29 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
import "@0x/contracts-utils/contracts/src/LibEIP712.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "./Addresses.sol";
import "./OrderValidationUtils.sol";
import "./OrderTransferSimulationUtils.sol";
import "./EthBalanceChecker.sol";
import "./ExternalFunctions.sol";
// solhint-disable no-empty-blocks
contract DevUtils is
Addresses,
OrderValidationUtils,
LibEIP712ExchangeDomain,
EthBalanceChecker
EthBalanceChecker,
ExternalFunctions
{
constructor (
address _exchange,
address _chaiBridge
address exchange_,
address chaiBridge_
)
public
OrderValidationUtils(
_exchange,
_chaiBridge
Addresses(
exchange_,
chaiBridge_
)
OrderTransferSimulationUtils(_exchange)
LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants
{}

View File

@ -16,7 +16,7 @@
*/
pragma solidity ^0.5.5;
pragma solidity ^0.5.16;
contract EthBalanceChecker {

View File

@ -0,0 +1,322 @@
/*
Copyright 2019 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.5.16;
pragma experimental ABIEncoderV2;
import "./Addresses.sol";
import "./LibAssetData.sol";
import "./LibTransactionDecoder.sol";
import "./LibOrderTransferSimulation.sol";
contract ExternalFunctions is
Addresses
{
/// @dev Decodes the call data for an Exchange contract method call.
/// @param transactionData ABI-encoded calldata for an Exchange
/// contract method call.
/// @return The name of the function called, and the parameters it was
/// given. For single-order fills and cancels, the arrays will have
/// just one element.
function decodeZeroExTransactionData(bytes memory transactionData)
public
pure
returns(
string memory functionName,
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
bytes[] memory signatures
)
{
return LibTransactionDecoder.decodeZeroExTransactionData(transactionData);
}
/// @dev Decode AssetProxy identifier
/// @param assetData AssetProxy-compliant asset data describing an ERC-20, ERC-721, ERC1155, or MultiAsset asset.
/// @return The AssetProxy identifier
function decodeAssetProxyId(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId
)
{
return LibAssetData.decodeAssetProxyId(assetData);
}
/// @dev Encode ERC-20 asset data into the format described in the AssetProxy contract specification.
/// @param tokenAddress The address of the ERC-20 contract hosting the asset to be traded.
/// @return AssetProxy-compliant data describing the asset.
function encodeERC20AssetData(address tokenAddress)
public
pure
returns (bytes memory assetData)
{
return LibAssetData.encodeERC20AssetData(tokenAddress);
}
/// @dev Decode ERC-20 asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC-20 asset.
/// @return The AssetProxy identifier, and the address of the ERC-20
/// contract hosting this asset.
function decodeERC20AssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
address tokenAddress
)
{
return LibAssetData.decodeERC20AssetData(assetData);
}
/// @dev Encode ERC-721 asset data into the format described in the AssetProxy specification.
/// @param tokenAddress The address of the ERC-721 contract hosting the asset to be traded.
/// @param tokenId The identifier of the specific asset to be traded.
/// @return AssetProxy-compliant asset data describing the asset.
function encodeERC721AssetData(address tokenAddress, uint256 tokenId)
public
pure
returns (bytes memory assetData)
{
return LibAssetData.encodeERC721AssetData(tokenAddress, tokenId);
}
/// @dev Decode ERC-721 asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC-721 asset.
/// @return The ERC-721 AssetProxy identifier, the address of the ERC-721
/// contract hosting this asset, and the identifier of the specific
/// asset to be traded.
function decodeERC721AssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
address tokenAddress,
uint256 tokenId
)
{
return LibAssetData.decodeERC721AssetData(assetData);
}
/// @dev Encode ERC-1155 asset data into the format described in the AssetProxy contract specification.
/// @param tokenAddress The address of the ERC-1155 contract hosting the asset(s) to be traded.
/// @param tokenIds The identifiers of the specific assets to be traded.
/// @param tokenValues The amounts of each asset to be traded.
/// @param callbackData Data to be passed to receiving contracts when a transfer is performed.
/// @return AssetProxy-compliant asset data describing the set of assets.
function encodeERC1155AssetData(
address tokenAddress,
uint256[] memory tokenIds,
uint256[] memory tokenValues,
bytes memory callbackData
)
public
pure
returns (bytes memory assetData)
{
return LibAssetData.encodeERC1155AssetData(
tokenAddress,
tokenIds,
tokenValues,
callbackData
);
}
/// @dev Decode ERC-1155 asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC-1155 set of assets.
/// @return The ERC-1155 AssetProxy identifier, the address of the ERC-1155
/// contract hosting the assets, an array of the identifiers of the
/// assets to be traded, an array of asset amounts to be traded, and
/// callback data. Each element of the arrays corresponds to the
/// same-indexed element of the other array. Return values specified as
/// `memory` are returned as pointers to locations within the memory of
/// the input parameter `assetData`.
function decodeERC1155AssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
address tokenAddress,
uint256[] memory tokenIds,
uint256[] memory tokenValues,
bytes memory callbackData
)
{
return LibAssetData.decodeERC1155AssetData(assetData);
}
/// @dev Encode data for multiple assets, per the AssetProxy contract specification.
/// @param amounts The amounts of each asset to be traded.
/// @param nestedAssetData AssetProxy-compliant data describing each asset to be traded.
/// @return AssetProxy-compliant data describing the set of assets.
function encodeMultiAssetData(uint256[] memory amounts, bytes[] memory nestedAssetData)
public
pure
returns (bytes memory assetData)
{
return LibAssetData.encodeMultiAssetData(amounts, nestedAssetData);
}
/// @dev Decode multi-asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant data describing a multi-asset basket.
/// @return The Multi-Asset AssetProxy identifier, an array of the amounts
/// of the assets to be traded, and an array of the
/// AssetProxy-compliant data describing each asset to be traded. Each
/// element of the arrays corresponds to the same-indexed element of the other array.
function decodeMultiAssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
uint256[] memory amounts,
bytes[] memory nestedAssetData
)
{
return LibAssetData.decodeMultiAssetData(assetData);
}
/// @dev Encode StaticCall asset data into the format described in the AssetProxy contract specification.
/// @param staticCallTargetAddress Target address of StaticCall.
/// @param staticCallData Data that will be passed to staticCallTargetAddress in the StaticCall.
/// @param expectedReturnDataHash Expected Keccak-256 hash of the StaticCall return data.
/// @return AssetProxy-compliant asset data describing the set of assets.
function encodeStaticCallAssetData(
address staticCallTargetAddress,
bytes memory staticCallData,
bytes32 expectedReturnDataHash
)
public
pure
returns (bytes memory assetData)
{
return LibAssetData.encodeStaticCallAssetData(
staticCallTargetAddress,
staticCallData,
expectedReturnDataHash
);
}
/// @dev Decode StaticCall asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing a StaticCall asset
/// @return The StaticCall AssetProxy identifier, the target address of the StaticCAll, the data to be
/// passed to the target address, and the expected Keccak-256 hash of the static call return data.
function decodeStaticCallAssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
address staticCallTargetAddress,
bytes memory staticCallData,
bytes32 expectedReturnDataHash
)
{
return LibAssetData.decodeStaticCallAssetData(assetData);
}
/// @dev Decode ERC20Bridge asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC20Bridge asset
/// @return The ERC20BridgeProxy identifier, the address of the ERC20 token to transfer, the address
/// of the bridge contract, and extra data to be passed to the bridge contract.
function decodeERC20BridgeAssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
address tokenAddress,
address bridgeAddress,
bytes memory bridgeData
)
{
return LibAssetData.decodeERC20BridgeAssetData(assetData);
}
/// @dev Reverts if assetData is not of a valid format for its given proxy id.
/// @param assetData AssetProxy compliant asset data.
function revertIfInvalidAssetData(bytes memory assetData)
public
pure
{
return LibAssetData.revertIfInvalidAssetData(assetData);
}
/// @dev Simulates the maker transfers within an order and returns the index of the first failed transfer.
/// @param order The order to simulate transfers for.
/// @param takerAddress The address of the taker that will fill the order.
/// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill.
/// @return The index of the first failed transfer (or 4 if all transfers are successful).
function getSimulatedOrderMakerTransferResults(
LibOrder.Order memory order,
address takerAddress,
uint256 takerAssetFillAmount
)
public
returns (LibOrderTransferSimulation.OrderTransferResults orderTransferResults)
{
return LibOrderTransferSimulation.getSimulatedOrderMakerTransferResults(
exchangeAddress,
order,
takerAddress,
takerAssetFillAmount
);
}
/// @dev Simulates all of the transfers within an order and returns the index of the first failed transfer.
/// @param order The order to simulate transfers for.
/// @param takerAddress The address of the taker that will fill the order.
/// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill.
/// @return The index of the first failed transfer (or 4 if all transfers are successful).
function getSimulatedOrderTransferResults(
LibOrder.Order memory order,
address takerAddress,
uint256 takerAssetFillAmount
)
public
returns (LibOrderTransferSimulation.OrderTransferResults orderTransferResults)
{
return LibOrderTransferSimulation.getSimulatedOrderTransferResults(
exchangeAddress,
order,
takerAddress,
takerAssetFillAmount
);
}
/// @dev Simulates all of the transfers for each given order and returns the indices of each first failed transfer.
/// @param orders Array of orders to individually simulate transfers for.
/// @param takerAddresses Array of addresses of takers that will fill each order.
/// @param takerAssetFillAmounts Array of amounts of takerAsset that will be filled for each order.
/// @return The indices of the first failed transfer (or 4 if all transfers are successful) for each order.
function getSimulatedOrdersTransferResults(
LibOrder.Order[] memory orders,
address[] memory takerAddresses,
uint256[] memory takerAssetFillAmounts
)
public
returns (LibOrderTransferSimulation.OrderTransferResults[] memory orderTransferResults)
{
return LibOrderTransferSimulation.getSimulatedOrdersTransferResults(
exchangeAddress,
orders,
takerAddresses,
takerAssetFillAmounts
);
}
}

View File

@ -16,357 +16,17 @@
*/
pragma solidity ^0.5.5;
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IChai.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
contract LibAssetData is
DeploymentConstants
{
// 2^256 - 1
uint256 constant internal _MAX_UINT256 = uint256(-1);
library LibAssetData {
using LibBytes for bytes;
// solhint-disable var-name-mixedcase
IExchange internal _EXCHANGE;
address internal _ERC20_PROXY_ADDRESS;
address internal _ERC721_PROXY_ADDRESS;
address internal _ERC1155_PROXY_ADDRESS;
address internal _STATIC_CALL_PROXY_ADDRESS;
address internal _CHAI_BRIDGE_ADDRESS;
// solhint-enable var-name-mixedcase
constructor (
address _exchange,
address _chaiBridge
)
public
{
_EXCHANGE = IExchange(_exchange);
_ERC20_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC20Token.selector);
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector);
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
_STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).StaticCall.selector);
_CHAI_BRIDGE_ADDRESS = _chaiBridge;
}
/// @dev Returns the owner's balance of the assets(s) specified in
/// assetData. When the asset data contains multiple assets (eg in
/// ERC1155 or Multi-Asset), the return value indicates how many
/// complete "baskets" of those assets are owned by owner.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
/// @return Number of assets (or asset baskets) held by owner.
function getBalance(address ownerAddress, bytes memory assetData)
public
returns (uint256 balance)
{
// Get id of AssetProxy contract
bytes4 assetProxyId = assetData.readBytes4(0);
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
// Get ERC20 token address
address tokenAddress = assetData.readAddress(16);
balance = _erc20BalanceOf(tokenAddress, ownerAddress);
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
// Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
// Check if id is owned by ownerAddress
bytes memory ownerOfCalldata = abi.encodeWithSelector(
IERC721Token(address(0)).ownerOf.selector,
tokenId
);
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
balance = currentOwnerAddress == ownerAddress ? 1 : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address, array of ids, and array of values
(, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData);
uint256 length = tokenIds.length;
for (uint256 i = 0; i != length; i++) {
// Skip over the token if the corresponding value is 0.
if (tokenValues[i] == 0) {
continue;
}
// Encode data for `balanceOf(ownerAddress, tokenIds[i])
bytes memory balanceOfData = abi.encodeWithSelector(
IERC1155(address(0)).balanceOf.selector,
ownerAddress,
tokenIds[i]
);
// Query balance
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
uint256 totalBalance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
// Scale total balance down by corresponding value in assetData
uint256 scaledBalance = totalBalance / tokenValues[i];
if (scaledBalance == 0) {
return 0;
}
if (scaledBalance < balance || balance == 0) {
balance = scaledBalance;
}
}
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// Encode data for `staticCallProxy.transferFrom(assetData,...)`
bytes memory transferFromData = abi.encodeWithSelector(
IAssetProxy(address(0)).transferFrom.selector,
assetData,
address(0), // `from` address is not used
address(0), // `to` address is not used
0 // `amount` is not used
);
// Check if staticcall would be successful
(bool success,) = _STATIC_CALL_PROXY_ADDRESS.staticcall(transferFromData);
// Success means that the staticcall can be made an unlimited amount of times
balance = success ? _MAX_UINT256 : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
// Get address of ERC20 token and bridge contract
(, address tokenAddress, address bridgeAddress,) = decodeERC20BridgeAssetData(assetData);
if (tokenAddress == _getDaiAddress() && bridgeAddress == _CHAI_BRIDGE_ADDRESS) {
uint256 chaiBalance = _erc20BalanceOf(_getChaiAddress(), ownerAddress);
// Calculate Dai balance
balance = _convertChaiToDaiAmount(chaiBalance);
}
// Balance will be 0 if bridge is not supported
} else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
// Get array of values and array of assetDatas
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
uint256 length = nestedAssetData.length;
for (uint256 i = 0; i != length; i++) {
// Skip over the asset if the corresponding amount is 0.
if (assetAmounts[i] == 0) {
continue;
}
// Query balance of individual assetData
uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]);
// Scale total balance down by corresponding value in assetData
uint256 scaledBalance = totalBalance / assetAmounts[i];
if (scaledBalance == 0) {
return 0;
}
if (scaledBalance < balance || balance == 0) {
balance = scaledBalance;
}
}
}
// Balance will be 0 if assetProxyId is unknown
return balance;
}
/// @dev Calls getBalance() for each element of assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
/// @return Array of asset balances from getBalance(), with each element
/// corresponding to the same-indexed element in the assetData input.
function getBatchBalances(address ownerAddress, bytes[] memory assetData)
public
returns (uint256[] memory balances)
{
uint256 length = assetData.length;
balances = new uint256[](length);
for (uint256 i = 0; i != length; i++) {
balances[i] = getBalance(ownerAddress, assetData[i]);
}
return balances;
}
/// @dev Returns the number of asset(s) (described by assetData) that
/// the corresponding AssetProxy contract is authorized to spend. When the asset data contains
/// multiple assets (eg for Multi-Asset), the return value indicates
/// how many complete "baskets" of those assets may be spent by all of the corresponding
/// AssetProxy contracts.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
/// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getAssetProxyAllowance(address ownerAddress, bytes memory assetData)
public
returns (uint256 allowance)
{
// Get id of AssetProxy contract
bytes4 assetProxyId = assetData.readBytes4(0);
if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
// Get array of values and array of assetDatas
(, uint256[] memory amounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
uint256 length = nestedAssetData.length;
for (uint256 i = 0; i != length; i++) {
// Skip over the asset if the corresponding amount is 0.
if (amounts[i] == 0) {
continue;
}
// Query allowance of individual assetData
uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]);
// Scale total allowance down by corresponding value in assetData
uint256 scaledAllowance = totalAllowance / amounts[i];
if (scaledAllowance == 0) {
return 0;
}
if (scaledAllowance < allowance || allowance == 0) {
allowance = scaledAllowance;
}
}
return allowance;
}
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
// Get ERC20 token address
address tokenAddress = assetData.readAddress(16);
// Encode data for `allowance(ownerAddress, _ERC20_PROXY_ADDRESS)`
bytes memory allowanceData = abi.encodeWithSelector(
IERC20Token(address(0)).allowance.selector,
ownerAddress,
_ERC20_PROXY_ADDRESS
);
// Query allowance
(bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData);
allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
// Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
// Encode data for `isApprovedForAll(ownerAddress, _ERC721_PROXY_ADDRESS)`
bytes memory isApprovedForAllData = abi.encodeWithSelector(
IERC721Token(address(0)).isApprovedForAll.selector,
ownerAddress,
_ERC721_PROXY_ADDRESS
);
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
// If not approved for all, call `getApproved(tokenId)`
if (!success || returnData.length != 32 || returnData.readUint256(0) != 1) {
// Encode data for `getApproved(tokenId)`
bytes memory getApprovedData = abi.encodeWithSelector(IERC721Token(address(0)).getApproved.selector, tokenId);
(success, returnData) = tokenAddress.staticcall(getApprovedData);
// Allowance is 1 if successful and the approved address is the ERC721Proxy
allowance = success && returnData.length == 32 && returnData.readAddress(12) == _ERC721_PROXY_ADDRESS ? 1 : 0;
} else {
// Allowance is 2^256 - 1 if `isApprovedForAll` returned true
allowance = _MAX_UINT256;
}
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address
(, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
// Encode data for `isApprovedForAll(ownerAddress, _ERC1155_PROXY_ADDRESS)`
bytes memory isApprovedForAllData = abi.encodeWithSelector(
IERC1155(address(0)).isApprovedForAll.selector,
ownerAddress,
_ERC1155_PROXY_ADDRESS
);
// Query allowance
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// The StaticCallProxy does not require any approvals
allowance = _MAX_UINT256;
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
// Get address of ERC20 token and bridge contract
(, address tokenAddress, address bridgeAddress,) = decodeERC20BridgeAssetData(assetData);
if (tokenAddress == _getDaiAddress() && bridgeAddress == _CHAI_BRIDGE_ADDRESS) {
bytes memory allowanceData = abi.encodeWithSelector(
IERC20Token(address(0)).allowance.selector,
ownerAddress,
_CHAI_BRIDGE_ADDRESS
);
(bool success, bytes memory returnData) = _getChaiAddress().staticcall(allowanceData);
uint256 chaiAllowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
// Dai allowance is unlimited if Chai allowance is unlimited
allowance = chaiAllowance == _MAX_UINT256 ? _MAX_UINT256 : _convertChaiToDaiAmount(chaiAllowance);
}
// Allowance will be 0 if bridge is not supported
}
// Allowance will be 0 if the assetProxyId is unknown
return allowance;
}
/// @dev Calls getAssetProxyAllowance() for each element of assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
/// @return An array of asset allowances from getAllowance(), with each
/// element corresponding to the same-indexed element in the assetData input.
function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
public
returns (uint256[] memory allowances)
{
uint256 length = assetData.length;
allowances = new uint256[](length);
for (uint256 i = 0; i != length; i++) {
allowances[i] = getAssetProxyAllowance(ownerAddress, assetData[i]);
}
return allowances;
}
/// @dev Calls getBalance() and getAllowance() for assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
/// @return Number of assets (or asset baskets) held by owner, and number
/// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData)
public
returns (uint256 balance, uint256 allowance)
{
balance = getBalance(ownerAddress, assetData);
allowance = getAssetProxyAllowance(ownerAddress, assetData);
return (balance, allowance);
}
/// @dev Calls getBatchBalances() and getBatchAllowances() for each element of assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
/// @return An array of asset balances from getBalance(), and an array of
/// asset allowances from getAllowance(), with each element
/// corresponding to the same-indexed element in the assetData input.
function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
public
returns (uint256[] memory balances, uint256[] memory allowances)
{
balances = getBatchBalances(ownerAddress, assetData);
allowances = getBatchAssetProxyAllowances(ownerAddress, assetData);
return (balances, allowances);
}
/// @dev Decode AssetProxy identifier
/// @param assetData AssetProxy-compliant asset data describing an ERC-20, ERC-721, ERC1155, or MultiAsset asset.
/// @return The AssetProxy identifier
@ -691,44 +351,4 @@ contract LibAssetData is
revert("WRONG_PROXY_ID");
}
}
/// @dev Queries balance of an ERC20 token. Returns 0 if call was unsuccessful.
/// @param tokenAddress Address of ERC20 token.
/// @param ownerAddress Address of owner of ERC20 token.
/// @return balance ERC20 token balance of owner.
function _erc20BalanceOf(
address tokenAddress,
address ownerAddress
)
internal
view
returns (uint256 balance)
{
// Encode data for `balanceOf(ownerAddress)`
bytes memory balanceOfData = abi.encodeWithSelector(
IERC20Token(address(0)).balanceOf.selector,
ownerAddress
);
// Query balance
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
return balance;
}
/// @dev Converts an amount of Chai into its equivalent Dai amount.
/// Also accumulates Dai from DSR if called after the last time it was collected.
/// @param chaiAmount Amount of Chai to converts.
function _convertChaiToDaiAmount(uint256 chaiAmount)
internal
returns (uint256 daiAmount)
{
PotLike pot = IChai(_getChaiAddress()).pot();
// Accumulate savings if called after last time savings were collected
uint256 chiMultiplier = (now > pot.rho())
? pot.drip()
: pot.chi();
daiAmount = LibMath.getPartialAmountFloor(chiMultiplier, 10**27, chaiAmount);
return daiAmount;
}
}

View File

@ -0,0 +1,227 @@
/*
Copyright 2019 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.5.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-exchange/contracts/src/libs/LibExchangeRichErrorDecoder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
library LibOrderTransferSimulation {
using LibBytes for bytes;
enum OrderTransferResults {
TakerAssetDataFailed, // Transfer of takerAsset failed
MakerAssetDataFailed, // Transfer of makerAsset failed
TakerFeeAssetDataFailed, // Transfer of takerFeeAsset failed
MakerFeeAssetDataFailed, // Transfer of makerFeeAsset failed
TransfersSuccessful // All transfers in the order were successful
}
// NOTE(jalextowle): This is a random address that we use to avoid issues that addresses like `address(1)`
// may cause later.
address constant internal UNUSED_ADDRESS = address(0x377f698C4c287018D09b516F415317aEC5919332);
// keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL"));
bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0;
/// @dev Simulates the maker transfers within an order and returns the index of the first failed transfer.
/// @param order The order to simulate transfers for.
/// @param takerAddress The address of the taker that will fill the order.
/// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill.
/// @return The index of the first failed transfer (or 4 if all transfers are successful).
function getSimulatedOrderMakerTransferResults(
address exchange,
LibOrder.Order memory order,
address takerAddress,
uint256 takerAssetFillAmount
)
public
returns (OrderTransferResults orderTransferResults)
{
LibFillResults.FillResults memory fillResults = LibFillResults.calculateFillResults(
order,
takerAssetFillAmount,
IExchange(exchange).protocolFeeMultiplier(),
tx.gasprice
);
bytes[] memory assetData = new bytes[](2);
address[] memory fromAddresses = new address[](2);
address[] memory toAddresses = new address[](2);
uint256[] memory amounts = new uint256[](2);
// Transfer `makerAsset` from maker to taker
assetData[0] = order.makerAssetData;
fromAddresses[0] = order.makerAddress;
toAddresses[0] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress;
amounts[0] = fillResults.makerAssetFilledAmount;
// Transfer `makerFeeAsset` from maker to feeRecipient
assetData[1] = order.makerFeeAssetData;
fromAddresses[1] = order.makerAddress;
toAddresses[1] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[1] = fillResults.makerFeePaid;
return _simulateTransferFromCalls(
exchange,
assetData,
fromAddresses,
toAddresses,
amounts
);
}
/// @dev Simulates all of the transfers within an order and returns the index of the first failed transfer.
/// @param order The order to simulate transfers for.
/// @param takerAddress The address of the taker that will fill the order.
/// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill.
/// @return The index of the first failed transfer (or 4 if all transfers are successful).
function getSimulatedOrderTransferResults(
address exchange,
LibOrder.Order memory order,
address takerAddress,
uint256 takerAssetFillAmount
)
public
returns (OrderTransferResults orderTransferResults)
{
LibFillResults.FillResults memory fillResults = LibFillResults.calculateFillResults(
order,
takerAssetFillAmount,
IExchange(exchange).protocolFeeMultiplier(),
tx.gasprice
);
// Create input arrays
bytes[] memory assetData = new bytes[](4);
address[] memory fromAddresses = new address[](4);
address[] memory toAddresses = new address[](4);
uint256[] memory amounts = new uint256[](4);
// Transfer `takerAsset` from taker to maker
assetData[0] = order.takerAssetData;
fromAddresses[0] = takerAddress;
toAddresses[0] = order.makerAddress;
amounts[0] = takerAssetFillAmount;
// Transfer `makerAsset` from maker to taker
assetData[1] = order.makerAssetData;
fromAddresses[1] = order.makerAddress;
toAddresses[1] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress;
amounts[1] = fillResults.makerAssetFilledAmount;
// Transfer `takerFeeAsset` from taker to feeRecipient
assetData[2] = order.takerFeeAssetData;
fromAddresses[2] = takerAddress;
toAddresses[2] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[2] = fillResults.takerFeePaid;
// Transfer `makerFeeAsset` from maker to feeRecipient
assetData[3] = order.makerFeeAssetData;
fromAddresses[3] = order.makerAddress;
toAddresses[3] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[3] = fillResults.makerFeePaid;
return _simulateTransferFromCalls(
exchange,
assetData,
fromAddresses,
toAddresses,
amounts
);
}
/// @dev Simulates all of the transfers for each given order and returns the indices of each first failed transfer.
/// @param orders Array of orders to individually simulate transfers for.
/// @param takerAddresses Array of addresses of takers that will fill each order.
/// @param takerAssetFillAmounts Array of amounts of takerAsset that will be filled for each order.
/// @return The indices of the first failed transfer (or 4 if all transfers are successful) for each order.
function getSimulatedOrdersTransferResults(
address exchange,
LibOrder.Order[] memory orders,
address[] memory takerAddresses,
uint256[] memory takerAssetFillAmounts
)
public
returns (OrderTransferResults[] memory orderTransferResults)
{
uint256 length = orders.length;
orderTransferResults = new OrderTransferResults[](length);
for (uint256 i = 0; i != length; i++) {
orderTransferResults[i] = getSimulatedOrderTransferResults(
exchange,
orders[i],
takerAddresses[i],
takerAssetFillAmounts[i]
);
}
return orderTransferResults;
}
/// @dev Makes the simulation call with information about the transfers and processes
/// the returndata.
/// @param assetData The assetdata to use to make transfers.
/// @param fromAddresses The addresses to transfer funds.
/// @param toAddresses The addresses that will receive funds
/// @param amounts The amounts involved in the transfer.
function _simulateTransferFromCalls(
address exchange,
bytes[] memory assetData,
address[] memory fromAddresses,
address[] memory toAddresses,
uint256[] memory amounts
)
private
returns (OrderTransferResults orderTransferResults)
{
// Encode data for `simulateDispatchTransferFromCalls(assetData, fromAddresses, toAddresses, amounts)`
bytes memory simulateDispatchTransferFromCallsData = abi.encodeWithSelector(
IExchange(address(0)).simulateDispatchTransferFromCalls.selector,
assetData,
fromAddresses,
toAddresses,
amounts
);
// Perform call and catch revert
(, bytes memory returnData) = address(exchange).call(simulateDispatchTransferFromCallsData);
bytes4 selector = returnData.readBytes4(0);
if (selector == LibExchangeRichErrors.AssetProxyDispatchErrorSelector()) {
// Decode AssetProxyDispatchError and return index of failed transfer
(, bytes32 failedTransferIndex,) = LibExchangeRichErrorDecoder.decodeAssetProxyDispatchError(returnData);
return OrderTransferResults(uint8(uint256(failedTransferIndex)));
} else if (selector == LibExchangeRichErrors.AssetProxyTransferErrorSelector()) {
// Decode AssetProxyTransferError and return index of failed transfer
(bytes32 failedTransferIndex, ,) = LibExchangeRichErrorDecoder.decodeAssetProxyTransferError(returnData);
return OrderTransferResults(uint8(uint256(failedTransferIndex)));
} else if (keccak256(returnData) == _TRANSFERS_SUCCESSFUL_RESULT_HASH) {
// All transfers were successful
return OrderTransferResults.TransfersSuccessful;
} else {
revert("UNKNOWN_RETURN_DATA");
}
}
}

View File

@ -16,7 +16,7 @@
*/
pragma solidity ^0.5.5;
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
@ -24,7 +24,7 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
contract LibTransactionDecoder {
library LibTransactionDecoder {
using LibBytes for bytes;

View File

@ -16,36 +16,26 @@
*/
pragma solidity ^0.5.9;
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "./Addresses.sol";
import "./AssetBalance.sol";
import "./LibAssetData.sol";
import "./OrderTransferSimulationUtils.sol";
import "./LibOrderTransferSimulation.sol";
contract OrderValidationUtils is
LibAssetData,
OrderTransferSimulationUtils
Addresses,
AssetBalance
{
using LibBytes for bytes;
using LibSafeMath for uint256;
constructor (
address _exchange,
address _chaiBridge
)
public
LibAssetData(
_exchange,
_chaiBridge
)
{}
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
/// @param order The order structure.
/// @param signature Signature provided by maker that proves the order's authenticity.
@ -65,23 +55,22 @@ contract OrderValidationUtils is
)
{
// Get info specific to order
orderInfo = _EXCHANGE.getOrderInfo(order);
orderInfo = IExchange(exchangeAddress).getOrderInfo(order);
// Validate the maker's signature
address makerAddress = order.makerAddress;
isValidSignature = _EXCHANGE.isValidOrderSignature(
isValidSignature = IExchange(exchangeAddress).isValidOrderSignature(
order,
signature
);
// Get the transferable amount of the `makerAsset`
uint256 transferableMakerAssetAmount = getTransferableAssetAmount(makerAddress, order.makerAssetData);
uint256 transferableMakerAssetAmount = _getTransferableConvertedMakerAssetAmount(
order
);
// Assign to stack variables to reduce redundant mloads/sloads
uint256 takerAssetAmount = order.takerAssetAmount;
uint256 makerFee = order.makerFee;
// Get the amount of `takerAsset` that is transferable to maker given the transferability of `makerAsset`, `makerFeeAsset`,
// Get the amount of `takerAsset` that is transferable to maker given the
// transferability of `makerAsset`, `makerFeeAsset`,
// and the total amounts specified in the order
uint256 transferableTakerAssetAmount;
if (order.makerAssetData.equals(order.makerFeeAssetData)) {
@ -89,32 +78,35 @@ contract OrderValidationUtils is
// transferableMakerAssetAmount / (makerAssetAmount + makerFee)
transferableTakerAssetAmount = LibMath.getPartialAmountFloor(
transferableMakerAssetAmount,
order.makerAssetAmount.safeAdd(makerFee),
takerAssetAmount
order.makerAssetAmount.safeAdd(order.makerFee),
order.takerAssetAmount
);
} else {
// If `makerFee` is 0, the % that can be filled is (transferableMakerAssetAmount / makerAssetAmount)
if (makerFee == 0) {
if (order.makerFee == 0) {
transferableTakerAssetAmount = LibMath.getPartialAmountFloor(
transferableMakerAssetAmount,
order.makerAssetAmount,
takerAssetAmount
order.takerAssetAmount
);
// If `makerAsset` does not equal `makerFeeAsset`, the % that can be filled is the lower of
// (transferableMakerAssetAmount / makerAssetAmount) and (transferableMakerAssetFeeAmount / makerFee)
} else {
// Get the transferable amount of the `makerFeeAsset`
uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount(makerAddress, order.makerFeeAssetData);
uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount(
makerAddress,
order.makerFeeAssetData
);
uint256 transferableMakerToTakerAmount = LibMath.getPartialAmountFloor(
transferableMakerAssetAmount,
order.makerAssetAmount,
takerAssetAmount
order.takerAssetAmount
);
uint256 transferableMakerFeeToTakerAmount = LibMath.getPartialAmountFloor(
transferableMakerFeeAssetAmount,
makerFee,
takerAssetAmount
order.makerFee,
order.takerAssetAmount
);
transferableTakerAssetAmount = LibSafeMath.min256(transferableMakerToTakerAmount, transferableMakerFeeToTakerAmount);
}
@ -122,16 +114,17 @@ contract OrderValidationUtils is
// `fillableTakerAssetAmount` is the lower of the order's remaining `takerAssetAmount` and the `transferableTakerAssetAmount`
fillableTakerAssetAmount = LibSafeMath.min256(
takerAssetAmount.safeSub(orderInfo.orderTakerAssetFilledAmount),
order.takerAssetAmount.safeSub(orderInfo.orderTakerAssetFilledAmount),
transferableTakerAssetAmount
);
// Execute the maker transfers.
fillableTakerAssetAmount = getSimulatedOrderMakerTransferResults(
fillableTakerAssetAmount = LibOrderTransferSimulation.getSimulatedOrderMakerTransferResults(
exchangeAddress,
order,
order.takerAddress,
fillableTakerAssetAmount
) == OrderTransferResults.TransfersSuccessful ? fillableTakerAssetAmount : 0;
) == LibOrderTransferSimulation.OrderTransferResults.TransfersSuccessful ? fillableTakerAssetAmount : 0;
if (!_isAssetDataValid(order.takerAssetData)) {
fillableTakerAssetAmount = 0;
@ -181,7 +174,7 @@ contract OrderValidationUtils is
return (ordersInfo, fillableTakerAssetAmounts, isValidSignature);
}
/// @dev Gets the amount of an asset transferable by the owner.
/// @dev Gets the amount of an asset transferable by the maker of an order.
/// @param ownerAddress Address of the owner of the asset.
/// @param assetData Description of tokens, per the AssetProxy contract specification.
/// @return The amount of the asset tranferable by the owner.
@ -193,7 +186,26 @@ contract OrderValidationUtils is
public
returns (uint256 transferableAssetAmount)
{
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData);
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(
ownerAddress,
assetData
);
transferableAssetAmount = LibSafeMath.min256(balance, allowance);
return transferableAssetAmount;
}
/// @dev Gets the amount of an asset transferable by the maker of an order.
/// Similar to `getTransferableAssetAmount()`, but can handle maker asset
/// types that depend on taker assets being transferred first (e.g., Dydx bridge).
/// @param order The order.
/// @return transferableAssetAmount Amount of maker asset that can be transferred.
function _getTransferableConvertedMakerAssetAmount(
LibOrder.Order memory order
)
internal
returns (uint256 transferableAssetAmount)
{
(uint256 balance, uint256 allowance) = _getConvertibleMakerBalanceAndAssetProxyAllowance(order);
transferableAssetAmount = LibSafeMath.min256(balance, allowance);
return transferableAssetAmount;
}
@ -221,7 +233,8 @@ contract OrderValidationUtils is
}
// Get array of values and array of assetDatas
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
(, , bytes[] memory nestedAssetData) =
LibAssetData.decodeMultiAssetData(assetData);
uint256 length = nestedAssetData.length;
for (uint256 i = 0; i != length; i++) {

View File

@ -8,7 +8,7 @@
"main": "lib/src/index.js",
"scripts": {
"build": "yarn pre_build && tsc -b",
"test": "yarn assert_deployable && echo !!! Tests are run via @0x/contracts-integrations !!!",
"test": "yarn assert_deployable",
"assert_deployable": "node -e \"const bytecodeLen = (require('./generated-artifacts/DevUtils.json').compilerOutput.evm.bytecode.object.length-2)/2; assert(bytecodeLen<=0x6000,'DevUtils contract is too big to deploy, per EIP-170. '+bytecodeLen+'>'+0x6000)\"",
"build:ci": "yarn build",
"pre_build": "run-s compile quantify_bytecode contracts:gen generate_contract_wrappers contracts:copy",
@ -27,8 +27,8 @@
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
},
"config": {
"publicInterfaceContracts": "DevUtils,LibAssetData,LibTransactionDecoder",
"abis": "./test/generated-artifacts/@(DevUtils|EthBalanceChecker|LibAssetData|LibTransactionDecoder|OrderTransferSimulationUtils|OrderValidationUtils).json",
"publicInterfaceContracts": "DevUtils,LibAssetData,LibOrderTransferSimulation,LibTransactionDecoder",
"abis": "./test/generated-artifacts/@(Addresses|AssetBalance|DevUtils|EthBalanceChecker|ExternalFunctions|LibAssetData|LibOrderTransferSimulation|LibTransactionDecoder|OrderTransferSimulationUtils|OrderValidationUtils).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
},
"repository": {
@ -41,12 +41,17 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
"devDependencies": {
"@0x/contracts-asset-proxy": "^3.1.3",
"@0x/contracts-erc20": "^3.0.6",
"@0x/contracts-test-utils": "^5.1.3",
"@0x/types": "^3.1.1",
"@0x/abi-gen": "^5.1.2",
"@0x/assert": "^3.0.5",
"@0x/contracts-gen": "^2.0.6",
"@0x/sol-compiler": "^4.0.6",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/utils": "^5.2.0",
"@types/node": "*",
"ethereum-types": "^3.0.0",
"ethers": "~4.0.4",

View File

@ -7,9 +7,11 @@ import { ContractArtifact } from 'ethereum-types';
import * as DevUtils from '../generated-artifacts/DevUtils.json';
import * as LibAssetData from '../generated-artifacts/LibAssetData.json';
import * as LibOrderTransferSimulation from '../generated-artifacts/LibOrderTransferSimulation.json';
import * as LibTransactionDecoder from '../generated-artifacts/LibTransactionDecoder.json';
export const artifacts = {
DevUtils: DevUtils as ContractArtifact,
LibAssetData: LibAssetData as ContractArtifact,
LibOrderTransferSimulation: LibOrderTransferSimulation as ContractArtifact,
LibTransactionDecoder: LibTransactionDecoder as ContractArtifact,
};

View File

@ -1,5 +1,5 @@
export { artifacts } from './artifacts';
export { DevUtilsContract, LibAssetDataContract, LibTransactionDecoderContract } from './wrappers';
export { DevUtilsContract } from './wrappers';
export {
ContractArtifact,
ContractChains,

View File

@ -5,4 +5,5 @@
*/
export * from '../generated-wrappers/dev_utils';
export * from '../generated-wrappers/lib_asset_data';
export * from '../generated-wrappers/lib_order_transfer_simulation';
export * from '../generated-wrappers/lib_transaction_decoder';

View File

@ -5,16 +5,24 @@
*/
import { ContractArtifact } from 'ethereum-types';
import * as Addresses from '../test/generated-artifacts/Addresses.json';
import * as AssetBalance from '../test/generated-artifacts/AssetBalance.json';
import * as DevUtils from '../test/generated-artifacts/DevUtils.json';
import * as EthBalanceChecker from '../test/generated-artifacts/EthBalanceChecker.json';
import * as ExternalFunctions from '../test/generated-artifacts/ExternalFunctions.json';
import * as LibAssetData from '../test/generated-artifacts/LibAssetData.json';
import * as LibOrderTransferSimulation from '../test/generated-artifacts/LibOrderTransferSimulation.json';
import * as LibTransactionDecoder from '../test/generated-artifacts/LibTransactionDecoder.json';
import * as OrderTransferSimulationUtils from '../test/generated-artifacts/OrderTransferSimulationUtils.json';
import * as OrderValidationUtils from '../test/generated-artifacts/OrderValidationUtils.json';
export const artifacts = {
Addresses: Addresses as ContractArtifact,
AssetBalance: AssetBalance as ContractArtifact,
DevUtils: DevUtils as ContractArtifact,
EthBalanceChecker: EthBalanceChecker as ContractArtifact,
ExternalFunctions: ExternalFunctions as ContractArtifact,
LibAssetData: LibAssetData as ContractArtifact,
LibOrderTransferSimulation: LibOrderTransferSimulation as ContractArtifact,
LibTransactionDecoder: LibTransactionDecoder as ContractArtifact,
OrderTransferSimulationUtils: OrderTransferSimulationUtils as ContractArtifact,
OrderValidationUtils: OrderValidationUtils as ContractArtifact,

View File

@ -3,9 +3,13 @@
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../test/generated-wrappers/addresses';
export * from '../test/generated-wrappers/asset_balance';
export * from '../test/generated-wrappers/dev_utils';
export * from '../test/generated-wrappers/eth_balance_checker';
export * from '../test/generated-wrappers/external_functions';
export * from '../test/generated-wrappers/lib_asset_data';
export * from '../test/generated-wrappers/lib_order_transfer_simulation';
export * from '../test/generated-wrappers/lib_transaction_decoder';
export * from '../test/generated-wrappers/order_transfer_simulation_utils';
export * from '../test/generated-wrappers/order_validation_utils';

View File

@ -5,10 +5,15 @@
"files": [
"generated-artifacts/DevUtils.json",
"generated-artifacts/LibAssetData.json",
"generated-artifacts/LibOrderTransferSimulation.json",
"generated-artifacts/LibTransactionDecoder.json",
"test/generated-artifacts/Addresses.json",
"test/generated-artifacts/AssetBalance.json",
"test/generated-artifacts/DevUtils.json",
"test/generated-artifacts/EthBalanceChecker.json",
"test/generated-artifacts/ExternalFunctions.json",
"test/generated-artifacts/LibAssetData.json",
"test/generated-artifacts/LibOrderTransferSimulation.json",
"test/generated-artifacts/LibTransactionDecoder.json",
"test/generated-artifacts/OrderTransferSimulationUtils.json",
"test/generated-artifacts/OrderValidationUtils.json"

View File

@ -4,11 +4,11 @@
"changes": [
{
"note": "Add `allowance()` and `balanceOf()` to `LibERC20Token`",
"pr": 2462
"pr": 2464
},
{
"note": "Fix broken tests",
"pr": 2462
"pr": 2456
}
]
},

View File

@ -94,7 +94,8 @@ library LibERC20Token {
/// @dev Retrieves the number of decimals for a token.
/// Returns `18` if the call reverts.
/// @return The number of decimals places for the token.
/// @param token The address of the token contract.
/// @return tokenDecimals The number of decimals places for the token.
function decimals(address token)
internal
view
@ -107,6 +108,50 @@ library LibERC20Token {
}
}
/// @dev Retrieves the allowance for a token, owner, and spender.
/// Returns `0` if the call reverts.
/// @param token The address of the token contract.
/// @param owner The owner of the tokens.
/// @param spender The address the spender.
/// @return allowance The allowance for a token, owner, and spender.
function allowance(address token, address owner, address spender)
internal
view
returns (uint256 allowance_)
{
(bool didSucceed, bytes memory resultData) = token.staticcall(
abi.encodeWithSelector(
IERC20Token(0).allowance.selector,
owner,
spender
)
);
if (didSucceed && resultData.length == 32) {
allowance_ = LibBytes.readUint256(resultData, 0);
}
}
/// @dev Retrieves the balance for a token owner.
/// Returns `0` if the call reverts.
/// @param token The address of the token contract.
/// @param owner The owner of the tokens.
/// @return balance The token balance of an owner.
function balanceOf(address token, address owner)
internal
view
returns (uint256 balance)
{
(bool didSucceed, bytes memory resultData) = token.staticcall(
abi.encodeWithSelector(
IERC20Token(0).balanceOf.selector,
owner
)
);
if (didSucceed && resultData.length == 32) {
balance = LibBytes.readUint256(resultData, 0);
}
}
/// @dev Executes a call on address `target` with calldata `callData`
/// and asserts that either nothing was returned or a single boolean
/// was returned equal to `true`.

View File

@ -5,6 +5,10 @@
{
"note": "Remove dependency on `DevUtils` for asset data encoding/decoding",
"pr": 2462
},
{
"note": "Update tests for refactored `DevUtils`",
"pr": 2464
}
]
},

View File

@ -26,8 +26,9 @@ blockchainTests.fork.resets('DevUtils mainnet tests', env => {
before(async () => {
[noDaiAddress] = await env.getAccountAddressesAsync();
devUtils = await DevUtilsContract.deployFrom0xArtifactAsync(
devUtils = await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync(
devUtilsArtifacts.DevUtils,
devUtilsArtifacts,
env.provider,
env.txDefaults,
devUtilsArtifacts,

View File

@ -19,8 +19,9 @@ blockchainTests('DevUtils.getOrderHash', env => {
exchangeArtifacts,
new BigNumber(chainId),
);
devUtils = await DevUtilsContract.deployFrom0xArtifactAsync(
devUtils = await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync(
artifacts.DevUtils,
artifacts,
env.provider,
env.txDefaults,
artifacts,

View File

@ -1,13 +1,13 @@
import * as crypto from 'crypto';
import { artifacts as proxyArtifacts, TestStaticCallTargetContract } from '@0x/contracts-asset-proxy';
import { artifacts, LibAssetDataContract } from '@0x/contracts-dev-utils';
import { artifacts, DevUtilsContract } from '@0x/contracts-dev-utils';
import { ERC1155MintableContract } from '@0x/contracts-erc1155';
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
import { AssetProxyId } from '@0x/types';
import { BigNumber, hexUtils, LibBytesRevertErrors, StringRevertError } from '@0x/utils';
import { BigNumber, hexUtils, LibBytesRevertErrors } from '@0x/utils';
import { Actor } from '../framework/actors/base';
import { DeploymentManager } from '../framework/deployment_manager';
@ -53,7 +53,7 @@ const KNOWN_STATIC_CALL_ENCODING = {
blockchainTests.resets('LibAssetData', env => {
let deployment: DeploymentManager;
let staticCallTarget: TestStaticCallTargetContract;
let libAssetData: LibAssetDataContract;
let devUtils: DevUtilsContract;
let tokenOwner: Actor;
@ -73,8 +73,9 @@ blockchainTests.resets('LibAssetData', env => {
});
tokenOwner = new Actor({ name: 'Token Owner', deployment });
libAssetData = await LibAssetDataContract.deployFrom0xArtifactAsync(
artifacts.LibAssetData,
devUtils = await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync(
artifacts.DevUtils,
artifacts,
env.provider,
env.txDefaults,
artifacts,
@ -104,7 +105,7 @@ blockchainTests.resets('LibAssetData', env => {
});
it('should have a deployed-to address', () => {
expect(libAssetData.address.slice(0, 2)).to.equal('0x');
expect(devUtils.address.slice(0, 2)).to.equal('0x');
});
describe('encoding and decoding', () => {
@ -117,17 +118,17 @@ blockchainTests.resets('LibAssetData', env => {
];
for (const [assetData, proxyId] of assetDataScenarios) {
expect(await libAssetData.decodeAssetProxyId(assetData).callAsync()).to.equal(proxyId);
expect(await devUtils.decodeAssetProxyId(assetData).callAsync()).to.equal(proxyId);
}
});
it('should encode ERC20 asset data', async () => {
expect(await libAssetData.encodeERC20AssetData(KNOWN_ERC20_ENCODING.address).callAsync()).to.equal(
expect(await devUtils.encodeERC20AssetData(KNOWN_ERC20_ENCODING.address).callAsync()).to.equal(
KNOWN_ERC20_ENCODING.assetData,
);
});
it('should decode ERC20 asset data', async () => {
expect(await libAssetData.decodeERC20AssetData(KNOWN_ERC20_ENCODING.assetData).callAsync()).to.deep.equal([
expect(await devUtils.decodeERC20AssetData(KNOWN_ERC20_ENCODING.assetData).callAsync()).to.deep.equal([
AssetProxyId.ERC20,
KNOWN_ERC20_ENCODING.address,
]);
@ -135,21 +136,23 @@ blockchainTests.resets('LibAssetData', env => {
it('should encode ERC721 asset data', async () => {
expect(
await libAssetData
await devUtils
.encodeERC721AssetData(KNOWN_ERC721_ENCODING.address, KNOWN_ERC721_ENCODING.tokenId)
.callAsync(),
).to.equal(KNOWN_ERC721_ENCODING.assetData);
});
it('should decode ERC721 asset data', async () => {
expect(await libAssetData.decodeERC721AssetData(KNOWN_ERC721_ENCODING.assetData).callAsync()).to.deep.equal(
[AssetProxyId.ERC721, KNOWN_ERC721_ENCODING.address, KNOWN_ERC721_ENCODING.tokenId],
);
expect(await devUtils.decodeERC721AssetData(KNOWN_ERC721_ENCODING.assetData).callAsync()).to.deep.equal([
AssetProxyId.ERC721,
KNOWN_ERC721_ENCODING.address,
KNOWN_ERC721_ENCODING.tokenId,
]);
});
it('should encode ERC1155 asset data', async () => {
expect(
await libAssetData
await devUtils
.encodeERC1155AssetData(
KNOWN_ERC1155_ENCODING.tokenAddress,
KNOWN_ERC1155_ENCODING.tokenIds,
@ -161,9 +164,7 @@ blockchainTests.resets('LibAssetData', env => {
});
it('should decode ERC1155 asset data', async () => {
expect(
await libAssetData.decodeERC1155AssetData(KNOWN_ERC1155_ENCODING.assetData).callAsync(),
).to.deep.equal([
expect(await devUtils.decodeERC1155AssetData(KNOWN_ERC1155_ENCODING.assetData).callAsync()).to.deep.equal([
AssetProxyId.ERC1155,
KNOWN_ERC1155_ENCODING.tokenAddress,
KNOWN_ERC1155_ENCODING.tokenIds,
@ -174,7 +175,7 @@ blockchainTests.resets('LibAssetData', env => {
it('should encode multiasset data', async () => {
expect(
await libAssetData
await devUtils
.encodeMultiAssetData(
KNOWN_MULTI_ASSET_ENCODING.amounts,
KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
@ -184,18 +185,18 @@ blockchainTests.resets('LibAssetData', env => {
});
it('should decode multiasset data', async () => {
expect(
await libAssetData.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData).callAsync(),
).to.deep.equal([
AssetProxyId.MultiAsset,
KNOWN_MULTI_ASSET_ENCODING.amounts,
KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
]);
expect(await devUtils.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData).callAsync()).to.deep.equal(
[
AssetProxyId.MultiAsset,
KNOWN_MULTI_ASSET_ENCODING.amounts,
KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
],
);
});
it('should encode StaticCall data', async () => {
expect(
await libAssetData
await devUtils
.encodeStaticCallAssetData(
KNOWN_STATIC_CALL_ENCODING.staticCallTargetAddress,
KNOWN_STATIC_CALL_ENCODING.staticCallData,
@ -207,7 +208,7 @@ blockchainTests.resets('LibAssetData', env => {
it('should decode StaticCall data', async () => {
expect(
await libAssetData.decodeStaticCallAssetData(KNOWN_STATIC_CALL_ENCODING.assetData).callAsync(),
await devUtils.decodeStaticCallAssetData(KNOWN_STATIC_CALL_ENCODING.assetData).callAsync(),
).to.deep.equal([
AssetProxyId.StaticCall,
KNOWN_STATIC_CALL_ENCODING.staticCallTargetAddress,
@ -227,16 +228,14 @@ blockchainTests.resets('LibAssetData', env => {
];
for (const data of assetData) {
await libAssetData.revertIfInvalidAssetData(data).callAsync();
await devUtils.revertIfInvalidAssetData(data).callAsync();
}
return;
});
it('should revert for invalid assetProxyId', async () => {
const badAssetData = `0x${crypto.randomBytes(4).toString('hex')}${constants.NULL_ADDRESS}`;
await expect(libAssetData.revertIfInvalidAssetData(badAssetData).callAsync()).to.eventually.be.rejectedWith(
StringRevertError,
);
await expect(devUtils.revertIfInvalidAssetData(badAssetData).callAsync()).to.revertWith('WRONG_PROXY_ID');
});
it('should revert for invalid assetData with valid assetProxyId', async () => {
@ -245,8 +244,8 @@ blockchainTests.resets('LibAssetData', env => {
for (const data of assetData) {
const badData = data.substring(0, data.length - 2); // drop one byte but retain assetProxyId
await expect(libAssetData.revertIfInvalidAssetData(badData).callAsync()).to.eventually.be.rejectedWith(
LibBytesRevertErrors.InvalidByteOperationError,
await expect(devUtils.revertIfInvalidAssetData(badData).callAsync()).to.revertWith(
new LibBytesRevertErrors.InvalidByteOperationError(),
);
}
});
@ -254,33 +253,31 @@ blockchainTests.resets('LibAssetData', env => {
describe('getBalance', () => {
it('should query ERC20 balance by asset data', async () => {
const assetData = await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync();
expect(await libAssetData.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(
const assetData = await devUtils.encodeERC20AssetData(erc20Token.address).callAsync();
expect(await devUtils.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(
constants.INITIAL_ERC20_BALANCE,
);
});
it('should return 0 if ERC20 token does not exist', async () => {
const assetData = await libAssetData.encodeERC20AssetData(constants.NULL_ADDRESS).callAsync();
const balance = await libAssetData.getBalance(tokenOwner.address, assetData).callAsync();
const assetData = await devUtils.encodeERC20AssetData(constants.NULL_ADDRESS).callAsync();
const balance = await devUtils.getBalance(tokenOwner.address, assetData).callAsync();
expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should query ERC721 balance by asset data', async () => {
const assetData = await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync();
expect(await libAssetData.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1);
const assetData = await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync();
expect(await devUtils.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1);
});
it('should return 0 if ERC721 token does not exist', async () => {
const assetData = await libAssetData
.encodeERC721AssetData(constants.NULL_ADDRESS, erc721TokenId)
.callAsync();
const balance = await libAssetData.getBalance(tokenOwner.address, assetData).callAsync();
const assetData = await devUtils.encodeERC721AssetData(constants.NULL_ADDRESS, erc721TokenId).callAsync();
const balance = await devUtils.getBalance(tokenOwner.address, assetData).callAsync();
expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should query ERC1155 balances by asset data', async () => {
const assetData = await libAssetData
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155Token.address,
[erc1155TokenId],
@ -288,11 +285,11 @@ blockchainTests.resets('LibAssetData', env => {
constants.NULL_BYTES,
)
.callAsync();
expect(await libAssetData.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1);
expect(await devUtils.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1);
});
it('should return 0 if ERC1155 token does not exist', async () => {
const assetData = await libAssetData
const assetData = await devUtils
.encodeERC1155AssetData(
constants.NULL_ADDRESS,
[erc1155TokenId],
@ -300,84 +297,84 @@ blockchainTests.resets('LibAssetData', env => {
constants.NULL_BYTES,
)
.callAsync();
const balance = await libAssetData.getBalance(tokenOwner.address, assetData).callAsync();
const balance = await devUtils.getBalance(tokenOwner.address, assetData).callAsync();
expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should query multi-asset batch balance by asset data', async () => {
const assetData = await libAssetData
const assetData = await devUtils
.encodeMultiAssetData(
[new BigNumber(1), new BigNumber(1)],
[
await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync(),
await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(),
await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(),
await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(),
],
)
.callAsync();
expect(await libAssetData.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1);
expect(await devUtils.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1);
});
it('should query multi-asset batch balance by asset data, skipping over a nested asset if its amount == 0', async () => {
const assetData = await libAssetData
const assetData = await devUtils
.encodeMultiAssetData(
[constants.ZERO_AMOUNT, new BigNumber(1)],
[
await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync(),
await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(),
await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(),
await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(),
],
)
.callAsync();
expect(await libAssetData.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1);
expect(await devUtils.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(1);
});
it('should return a balance of 0 if the balance for a nested asset is 0', async () => {
const assetData = await libAssetData
const assetData = await devUtils
.encodeMultiAssetData(
[new BigNumber(1), new BigNumber(1)],
[
await libAssetData.encodeERC20AssetData(secondErc20Token.address).callAsync(),
await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync(),
await devUtils.encodeERC20AssetData(secondErc20Token.address).callAsync(),
await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(),
],
)
.callAsync();
expect(await libAssetData.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(
expect(await devUtils.getBalance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(
constants.ZERO_AMOUNT,
);
});
it('should return a balance of 0 if the assetData does not correspond to an AssetProxy contract', async () => {
const fakeAssetData = '0x01020304';
const balance = await libAssetData.getBalance(tokenOwner.address, fakeAssetData).callAsync();
const balance = await devUtils.getBalance(tokenOwner.address, fakeAssetData).callAsync();
expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should return a balance of MAX_UINT256 if the the StaticCallProxy assetData contains data for a successful staticcall', async () => {
const staticCallData = staticCallTarget.isOddNumber(new BigNumber(1)).getABIEncodedTransactionData();
const expectedResultHash = hexUtils.hash(hexUtils.leftPad(1));
const assetData = await libAssetData
const assetData = await devUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
.callAsync();
const balance = await libAssetData.getBalance(tokenOwner.address, assetData).callAsync();
const balance = await devUtils.getBalance(tokenOwner.address, assetData).callAsync();
expect(balance).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
});
it('should return a balance of 0 if the the StaticCallProxy assetData contains data for an unsuccessful staticcall', async () => {
const staticCallData = staticCallTarget.isOddNumber(new BigNumber(0)).getABIEncodedTransactionData();
const expectedResultHash = hexUtils.hash(hexUtils.leftPad(1));
const assetData = await libAssetData
const assetData = await devUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
.callAsync();
const balance = await libAssetData.getBalance(tokenOwner.address, assetData).callAsync();
const balance = await devUtils.getBalance(tokenOwner.address, assetData).callAsync();
expect(balance).to.bignumber.equal(constants.ZERO_AMOUNT);
});
});
describe('getAssetProxyAllowance', () => {
it('should query ERC20 allowances by asset data', async () => {
const assetData = await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync();
expect(
await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
).to.bignumber.equal(constants.MAX_UINT256);
const assetData = await devUtils.encodeERC20AssetData(erc20Token.address).callAsync();
expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(
constants.MAX_UINT256,
);
});
it('should query ERC721 approval by asset data', async () => {
@ -390,21 +387,21 @@ blockchainTests.resets('LibAssetData', env => {
.awaitTransactionSuccessAsync({
from: tokenOwner.address,
});
const assetData = await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync();
expect(
await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
).to.bignumber.equal(1);
const assetData = await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync();
expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(
1,
);
});
it('should query ERC721 approvalForAll by assetData', async () => {
const assetData = await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync();
expect(
await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
const assetData = await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync();
expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(
constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
);
});
it('should query ERC1155 allowances by asset data', async () => {
const assetData = await libAssetData
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155Token.address,
[erc1155TokenId],
@ -412,9 +409,9 @@ blockchainTests.resets('LibAssetData', env => {
constants.NULL_BYTES,
)
.callAsync();
expect(
await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(
constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
);
});
it('should query multi-asset allowances by asset data', async () => {
@ -424,18 +421,18 @@ blockchainTests.resets('LibAssetData', env => {
.awaitTransactionSuccessAsync({
from: tokenOwner.address,
});
const assetData = await libAssetData
const assetData = await devUtils
.encodeMultiAssetData(
[new BigNumber(1), new BigNumber(1)],
[
await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync(),
await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(),
await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(),
await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(),
],
)
.callAsync();
expect(
await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
).to.bignumber.equal(1);
expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(
1,
);
return;
});
@ -446,60 +443,60 @@ blockchainTests.resets('LibAssetData', env => {
.awaitTransactionSuccessAsync({
from: tokenOwner.address,
});
const assetData = await libAssetData
const assetData = await devUtils
.encodeMultiAssetData(
[constants.ZERO_AMOUNT, new BigNumber(1)],
[
await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync(),
await libAssetData.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(),
await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(),
await devUtils.encodeERC721AssetData(erc721Token.address, erc721TokenId).callAsync(),
],
)
.callAsync();
expect(
await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(
constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
);
return;
});
it('should return an allowance of 0 if the allowance for a nested asset is 0', async () => {
const assetData = await libAssetData
const assetData = await devUtils
.encodeMultiAssetData(
[new BigNumber(1), new BigNumber(1)],
[
await libAssetData.encodeERC20AssetData(secondErc20Token.address).callAsync(),
await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync(),
await devUtils.encodeERC20AssetData(secondErc20Token.address).callAsync(),
await devUtils.encodeERC20AssetData(erc20Token.address).callAsync(),
],
)
.callAsync();
expect(
await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
).to.bignumber.equal(constants.ZERO_AMOUNT);
expect(await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync()).to.bignumber.equal(
constants.ZERO_AMOUNT,
);
});
it('should return an allowance of 0 if the assetData does not correspond to an AssetProxy contract', async () => {
const fakeAssetData = '0x01020304';
const allowance = await libAssetData.getAssetProxyAllowance(tokenOwner.address, fakeAssetData).callAsync();
const allowance = await devUtils.getAssetProxyAllowance(tokenOwner.address, fakeAssetData).callAsync();
expect(allowance).to.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should return an allowance of MAX_UINT256 for any staticCallAssetData', async () => {
const staticCallData = AssetProxyId.StaticCall;
const assetData = await libAssetData
const assetData = await devUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, constants.KECCAK256_NULL)
.callAsync();
const allowance = await libAssetData.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync();
const allowance = await devUtils.getAssetProxyAllowance(tokenOwner.address, assetData).callAsync();
expect(allowance).to.bignumber.equal(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
});
});
describe('getBatchBalances', () => {
it('should query balances for a batch of asset data strings', async () => {
const erc20AssetData = await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync();
const erc721AssetData = await libAssetData
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20Token.address).callAsync();
const erc721AssetData = await devUtils
.encodeERC721AssetData(erc721Token.address, erc721TokenId)
.callAsync();
expect(
await libAssetData.getBatchBalances(tokenOwner.address, [erc20AssetData, erc721AssetData]).callAsync(),
await devUtils.getBatchBalances(tokenOwner.address, [erc20AssetData, erc721AssetData]).callAsync(),
).to.deep.equal([new BigNumber(constants.INITIAL_ERC20_BALANCE), new BigNumber(1)]);
});
});
@ -512,9 +509,9 @@ blockchainTests.resets('LibAssetData', env => {
.awaitTransactionSuccessAsync({
from: tokenOwner.address,
});
const assetData = await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync();
const assetData = await devUtils.encodeERC20AssetData(erc20Token.address).callAsync();
expect(
await libAssetData.getBalanceAndAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
await devUtils.getBalanceAndAssetProxyAllowance(tokenOwner.address, assetData).callAsync(),
).to.deep.equal([new BigNumber(constants.INITIAL_ERC20_BALANCE), allowance]);
});
});
@ -526,9 +523,9 @@ blockchainTests.resets('LibAssetData', env => {
.awaitTransactionSuccessAsync({
from: tokenOwner.address,
});
const assetData = await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync();
const assetData = await devUtils.encodeERC20AssetData(erc20Token.address).callAsync();
expect(
await libAssetData.getBatchBalancesAndAssetProxyAllowances(tokenOwner.address, [assetData]).callAsync(),
await devUtils.getBatchBalancesAndAssetProxyAllowances(tokenOwner.address, [assetData]).callAsync(),
).to.deep.equal([[new BigNumber(constants.INITIAL_ERC20_BALANCE)], [allowance]]);
});
});
@ -541,12 +538,12 @@ blockchainTests.resets('LibAssetData', env => {
.awaitTransactionSuccessAsync({
from: tokenOwner.address,
});
const erc20AssetData = await libAssetData.encodeERC20AssetData(erc20Token.address).callAsync();
const erc721AssetData = await libAssetData
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20Token.address).callAsync();
const erc721AssetData = await devUtils
.encodeERC721AssetData(erc721Token.address, erc721TokenId)
.callAsync();
expect(
await libAssetData
await devUtils
.getBatchAssetProxyAllowances(tokenOwner.address, [erc20AssetData, erc721AssetData])
.callAsync(),
).to.deep.equal([allowance, constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS]);

View File

@ -1,14 +1,8 @@
import { ExchangeContract } from '@0x/contracts-exchange';
import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { artifacts as exchangeArtifacts, ExchangeContract } from '@0x/contracts-exchange';
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import { artifacts, LibTransactionDecoderContract } from '@0x/contracts-dev-utils';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
import { artifacts, DevUtilsContract } from '@0x/contracts-dev-utils';
const order = {
makerAddress: '0xe36ea790bc9d7ab70c55260c66d52b1eca985f84',
@ -30,25 +24,31 @@ const takerAssetFillAmount = new BigNumber('100000000000000000000');
const signature =
'0x1ce8e3c600d933423172b5021158a6be2e818613ff8e762d70ef490c752fd98a626a215f09f169668990414de75a53da221c294a3002f796d004827258b641876e03';
describe('LibTransactionDecoder', () => {
let libTxDecoder: LibTransactionDecoderContract;
const exchangeInterface = new ExchangeContract(constants.NULL_ADDRESS, provider, txDefaults);
blockchainTests('LibTransactionDecoder', env => {
let devUtils: DevUtilsContract;
const exchangeInterface = new ExchangeContract(constants.NULL_ADDRESS, { isEIP1193: true } as any);
before(async () => {
await blockchainLifecycle.startAsync();
libTxDecoder = await LibTransactionDecoderContract.deployFrom0xArtifactAsync(
artifacts.LibTransactionDecoder,
provider,
txDefaults,
artifacts,
const exchange = await ExchangeContract.deployFrom0xArtifactAsync(
exchangeArtifacts.Exchange,
env.provider,
env.txDefaults,
exchangeArtifacts,
new BigNumber(1),
);
devUtils = await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync(
artifacts.DevUtils,
artifacts,
env.provider,
env.txDefaults,
artifacts,
exchange.address,
constants.NULL_ADDRESS,
);
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
it('should decode an Exchange.batchCancelOrders() transaction', async () => {
const input = exchangeInterface.batchCancelOrders([order, order]).getABIEncodedTransactionData();
expect(await libTxDecoder.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([
expect(await devUtils.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([
'batchCancelOrders',
[order, order],
[],
@ -61,7 +61,7 @@ describe('LibTransactionDecoder', () => {
[func]([order, order], [takerAssetFillAmount, takerAssetFillAmount], [signature, signature])
.getABIEncodedTransactionData();
it(`should decode an Exchange.${func}() transaction`, async () => {
expect(await libTxDecoder.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([
expect(await devUtils.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([
func,
[order, order],
[takerAssetFillAmount, takerAssetFillAmount],
@ -72,7 +72,7 @@ describe('LibTransactionDecoder', () => {
it('should decode an Exchange.cancelOrder() transaction', async () => {
const input = exchangeInterface.cancelOrder(order).getABIEncodedTransactionData();
expect(await libTxDecoder.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([
expect(await devUtils.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([
'cancelOrder',
[order],
[],
@ -85,7 +85,7 @@ describe('LibTransactionDecoder', () => {
[func](order, takerAssetFillAmount, signature)
.getABIEncodedTransactionData();
it(`should decode an Exchange.${func}() transaction`, async () => {
expect(await libTxDecoder.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([
expect(await devUtils.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([
func,
[order],
[takerAssetFillAmount],
@ -104,7 +104,7 @@ describe('LibTransactionDecoder', () => {
[func]([order, order], takerAssetFillAmount, [signature, signature])
.getABIEncodedTransactionData();
it(`should decode an Exchange.${func}() transaction`, async () => {
expect(await libTxDecoder.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([
expect(await devUtils.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([
func,
[order, order],
[takerAssetFillAmount],
@ -130,7 +130,7 @@ describe('LibTransactionDecoder', () => {
const input = exchangeInterface
.matchOrders(order, complementaryOrder, signature, signature)
.getABIEncodedTransactionData();
expect(await libTxDecoder.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([
expect(await devUtils.decodeZeroExTransactionData(input).callAsync()).to.deep.equal([
'matchOrders',
[order, complementaryOrder],
[order.takerAssetAmount, complementaryOrder.takerAssetAmount],

View File

@ -195,8 +195,9 @@ export class DeploymentManager {
exchange,
staking.stakingProxy,
]);
const devUtils = await DevUtilsContract.deployFrom0xArtifactAsync(
const devUtils = await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync(
devUtilsArtifacts.DevUtils,
devUtilsArtifacts,
environment.provider,
environment.txDefaults,
devUtilsArtifacts,

View File

@ -55,6 +55,7 @@ export enum {{contractName}}Events {
{{/if}}
/* istanbul ignore next */
// tslint:disable:array-type
// tslint:disable:no-parameter-reassignment
// tslint:disable-next-line:class-name
export class {{contractName}}Contract extends BaseContract {

View File

@ -18,6 +18,14 @@
{
"note": "Update `ERC20BridgeSampler` on mainnet and kovan.",
"pr": 2459
},
{
"note": "Remove `libTransactionDecoder`",
"pr": 2456
},
{
"note": "Update snapshot addresses",
"pr": 2464
}
],
"timestamp": 1580811564

View File

@ -13,7 +13,6 @@
"dutchAuction": "0x0000000000000000000000000000000000000000",
"coordinatorRegistry": "0x45797531b873fd5e519477a070a955764c1a5b07",
"coordinator": "0x38a795580d0f687e399913a00ddef6a17612c722",
"libTransactionDecoder": "0x5f20e82643ce007d87692eb1b3d3fc059588b224",
"multiAssetProxy": "0xef701d5389ae74503d633396c4d654eabedc9d78",
"staticCallProxy": "0x3517b88c19508c08650616019062b898ab65ed29",
"erc1155Proxy": "0x7eefbd48fd63d441ec7435d024ec7c5131019add",
@ -43,7 +42,6 @@
"dutchAuction": "0x0000000000000000000000000000000000000000",
"coordinatorRegistry": "0x403cc23e88c17c4652fb904784d1af640a6722d9",
"coordinator": "0x6ff734d96104965c9c1b0108f83abc46e6e501df",
"libTransactionDecoder": "0xb20f3b07afb0e38b6151b9be4f53218bdd7dc231",
"multiAssetProxy": "0xab8fbd189c569ccdee3a4d929bb7f557be4028f6",
"staticCallProxy": "0xe1b97e47aa3796276033a5341e884d2ba46b6ac1",
"erc1155Proxy": "0x19bb6caa3bc34d39e5a23cedfa3e6c7e7f3c931d",
@ -69,7 +67,6 @@
"assetProxyOwner": "0x0000000000000000000000000000000000000000",
"zeroExGovernor": "0x3f46b98061a3e1e1f41dff296ec19402c298f8a9",
"forwarder": "0xd67f2f346f6e85db70632d9f18f50e04192ab54d",
"libTransactionDecoder": "0x34b37611db8190469b735fb2a007d8236c29eb88",
"orderValidator": "0x0000000000000000000000000000000000000000",
"dutchAuction": "0x0000000000000000000000000000000000000000",
"coordinatorRegistry": "0x1084b6a398e47907bae43fec3ff4b677db6e4fee",
@ -100,7 +97,6 @@
"zeroExGovernor": "0x6ff734d96104965c9c1b0108f83abc46e6e501df",
"forwarder": "0x2759a4c639fa4882d6d64973630ef81faf901d27",
"orderValidator": "0x0000000000000000000000000000000000000000",
"libTransactionDecoder": "0x067b5997c9058eade0bb03d8fb5e6db7feda80a3",
"dutchAuction": "0x0000000000000000000000000000000000000000",
"coordinatorRegistry": "0x09fb99968c016a3ff537bf58fb3d9fe55a7975d5",
"coordinator": "0xd29e59e51e8ab5f94121efaeebd935ca4214e257",
@ -127,21 +123,20 @@
"etherToken": "0x0b1ba0af832d7c05fd64161e0db78e85978e8082",
"exchange": "0x48bacb9266a570d521063ef5dd96e61686dbe788",
"assetProxyOwner": "0x0000000000000000000000000000000000000000",
"erc20BridgeProxy": "0x8ea76477cfaca8f7ea06477fd3c09a740ac6012a",
"erc20BridgeProxy": "0x038f9b392fb9a9676dbaddf78ea5fdbf6c7d9710",
"zeroExGovernor": "0x0000000000000000000000000000000000000000",
"libTransactionDecoder": "0xb48e1b16829c7f5bd62b76cb878a6bb1c4625d7a",
"forwarder": "0x5d3ad3561a1235273cbcb4e82fce63a0073d19be",
"forwarder": "0xe704967449b57b2382b7fa482718748c13c63190",
"orderValidator": "0x0000000000000000000000000000000000000000",
"dutchAuction": "0x0000000000000000000000000000000000000000",
"coordinatorRegistry": "0xaa86dda78e9434aca114b6676fc742a18d15a1cc",
"coordinator": "0x4d3d5c850dd5bd9d6f4adda3dd039a3c8054ca29",
"multiAssetProxy": "0xcfc18cec799fbd1793b5c43e773c98d4d61cc2db",
"staticCallProxy": "0x6dfff22588be9b3ef8cf0ad6dc9b84796f9fb45f",
"devUtils": "0xa31e64ea55b9b6bbb9d6a676738e9a5b23149f84",
"devUtils": "0x74341e87b1c4db7d5ed95f92b37509f2525a7a90",
"exchangeV2": "0x48bacb9266a570d521063ef5dd96e61686dbe788",
"zrxVault": "0x1941ff73d1154774d87521d2d0aaad5d19c8df60",
"staking": "0x0d8b0dd11f5d34ed41d556def5f841900d5b1c6b",
"stakingProxy": "0x38ef19fdf8e8415f18c307ed71967e19aac28ba1",
"zrxVault": "0xc4df27466183c0fe2a5924d6ea56e334deff146a",
"staking": "0xf23276778860e420acfc18ebeebf7e829b06965c",
"stakingProxy": "0x8a063452f7df2614db1bca3a85ef35da40cf0835",
"uniswapBridge": "0x0000000000000000000000000000000000000000",
"eth2DaiBridge": "0x0000000000000000000000000000000000000000",
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",

View File

@ -14,7 +14,6 @@ export interface ContractAddresses {
forwarder: string;
coordinatorRegistry: string;
coordinator: string;
libTransactionDecoder: string;
multiAssetProxy: string;
staticCallProxy: string;
erc1155Proxy: string;

View File

@ -1,4 +1,17 @@
[
{
"version": "3.5.0",
"changes": [
{
"note": "Update `DevUtils` artifact",
"pr": 2464
},
{
"note": "Remove `LibTransactionDecoder` artifact",
"pr": 2464
}
]
},
{
"timestamp": 1580988106,
"version": "3.4.1",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,6 @@ import * as Forwarder from '../artifacts/Forwarder.json';
import * as IAssetProxy from '../artifacts/IAssetProxy.json';
import * as IValidator from '../artifacts/IValidator.json';
import * as IWallet from '../artifacts/IWallet.json';
import * as LibTransactionDecoder from '../artifacts/LibTransactionDecoder.json';
import * as MultiAssetProxy from '../artifacts/MultiAssetProxy.json';
import * as Staking from '../artifacts/Staking.json';
import * as StakingProxy from '../artifacts/StakingProxy.json';
@ -43,7 +42,6 @@ export {
IAssetProxy,
IValidator,
IWallet,
LibTransactionDecoder,
MultiAssetProxy,
StaticCallProxy,
WETH9,

View File

@ -19,7 +19,6 @@
"./artifacts/ERC721Token.json",
"./artifacts/Exchange.json",
"./artifacts/Forwarder.json",
"./artifacts/LibTransactionDecoder.json",
"./artifacts/IAssetProxy.json",
"./artifacts/IValidator.json",
"./artifacts/IWallet.json",

View File

@ -3,8 +3,12 @@
"version": "13.5.0",
"changes": [
{
"note": "export `evmbytecodeoutputlinkreferences` type.",
"note": "Export `EvmBytecodeOutputLinkReferences` type.",
"pr": 2462
},
{
"note": "Remove `LibTransactionDecoder`",
"pr": 2464
}
]
},

View File

@ -11,7 +11,6 @@ import { ERC20TokenContract } from './generated-wrappers/erc20_token';
import { ERC721TokenContract } from './generated-wrappers/erc721_token';
import { ExchangeContract } from './generated-wrappers/exchange';
import { ForwarderContract } from './generated-wrappers/forwarder';
import { LibTransactionDecoderContract } from './generated-wrappers/lib_transaction_decoder';
import { StakingContract } from './generated-wrappers/staking';
import { WETH9Contract } from './generated-wrappers/weth9';
import { ContractWrappersConfig } from './types';
@ -50,10 +49,6 @@ export class ContractWrappers {
* An instance of the StakingContract class containing methods for interacting with the Staking contracts.
*/
public staking: StakingContract;
/**
* An instance of the LibTransactionDecoder class containing methods for interacting with the LibTransactionDecoder smart contract.
*/
public libTransactionDecoder: LibTransactionDecoderContract;
private readonly _web3Wrapper: Web3Wrapper;
/**
@ -78,7 +73,6 @@ export class ContractWrappers {
ForwarderContract,
StakingContract,
WETH9Contract,
LibTransactionDecoderContract,
];
contractsArray.forEach(contract => {
this._web3Wrapper.abiDecoder.addABI(contract.ABI(), contract.contractName);
@ -93,10 +87,6 @@ export class ContractWrappers {
this.staking = new StakingContract(contractAddresses.stakingProxy, this.getProvider());
this.devUtils = new DevUtilsContract(contractAddresses.devUtils, this.getProvider());
this.coordinator = new CoordinatorContract(contractAddresses.coordinator, this.getProvider());
this.libTransactionDecoder = new LibTransactionDecoderContract(
contractAddresses.libTransactionDecoder,
this.getProvider(),
);
this.contractAddresses = contractAddresses;
}
/**

View File

@ -81,7 +81,6 @@ export {
StakingProxyStakingContractAttachedToProxyEventArgs,
StakingProxyStakingContractDetachedFromProxyEventArgs,
} from './generated-wrappers/staking_proxy';
export { LibTransactionDecoderContract } from './generated-wrappers/lib_transaction_decoder';
export {
BlockRange,
SupportedProvider,

View File

@ -1,4 +1,13 @@
[
{
"version": "3.2.0",
"changes": [
{
"note": "Refactor into public libraries.",
"pr": 2464
}
]
},
{
"timestamp": 1580988106,
"version": "3.1.3",

View File

@ -1,4 +1,21 @@
[
{
"version": "6.1.0",
"changes": [
{
"note": "Update `DevUtils` deployment",
"pr": 2456
},
{
"note": "Remove `LibTransactionDecoder` deployment",
"pr": 2456
},
{
"note": "Use contract package artifacts in ganache migrations",
"pr": 2456
}
]
},
{
"timestamp": 1580988106,
"version": "6.0.2",

View File

@ -63,7 +63,6 @@
"dependencies": {
"@0x/base-contract": "^6.1.2",
"@0x/contract-addresses": "^4.4.0",
"@0x/contract-artifacts": "^3.4.1",
"@0x/contract-wrappers": "^13.4.2",
"@0x/contracts-asset-proxy": "^3.1.3",
"@0x/contracts-coordinator": "^3.0.6",

View File

@ -1,7 +1,6 @@
import { ContractAddresses, getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
import * as artifacts from '@0x/contract-artifacts';
import { ForwarderContract } from '@0x/contract-wrappers';
import {
artifacts as assetProxyArtifacts,
ERC1155ProxyContract,
ERC20BridgeProxyContract,
ERC20ProxyContract,
@ -9,12 +8,17 @@ import {
MultiAssetProxyContract,
StaticCallProxyContract,
} from '@0x/contracts-asset-proxy';
import { CoordinatorContract, CoordinatorRegistryContract } from '@0x/contracts-coordinator';
import { DevUtilsContract, LibTransactionDecoderContract } from '@0x/contracts-dev-utils';
import { ERC1155MintableContract } from '@0x/contracts-erc1155';
import { DummyERC20TokenContract, WETH9Contract } from '@0x/contracts-erc20';
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
import { ExchangeContract } from '@0x/contracts-exchange';
import {
artifacts as coordinatorArtifacts,
CoordinatorContract,
CoordinatorRegistryContract,
} from '@0x/contracts-coordinator';
import { artifacts as devUtilsArtifacts, DevUtilsContract } from '@0x/contracts-dev-utils';
import { artifacts as erc1155Artifacts, ERC1155MintableContract } from '@0x/contracts-erc1155';
import { artifacts as erc20Artifacts, DummyERC20TokenContract, WETH9Contract } from '@0x/contracts-erc20';
import { artifacts as erc721Artifacts, DummyERC721TokenContract } from '@0x/contracts-erc721';
import { artifacts as exchangeArtifacts, ExchangeContract } from '@0x/contracts-exchange';
import { artifacts as forwarderArtifacts, ForwarderContract } from '@0x/contracts-exchange-forwarder';
import {
artifacts as stakingArtifacts,
StakingProxyContract,
@ -28,6 +32,18 @@ import { SupportedProvider, TxData } from 'ethereum-types';
import { constants } from './utils/constants';
import { erc20TokenInfo, erc721TokenInfo } from './utils/token_info';
const allArtifacts = {
...assetProxyArtifacts,
...coordinatorArtifacts,
...devUtilsArtifacts,
...erc1155Artifacts,
...erc20Artifacts,
...erc721Artifacts,
...exchangeArtifacts,
...forwarderArtifacts,
...stakingArtifacts,
};
/**
* Creates and deploys all the contracts that are required for the latest
* version of the 0x protocol.
@ -44,24 +60,24 @@ export async function runMigrationsAsync(
// Proxies
const erc20Proxy = await ERC20ProxyContract.deployFrom0xArtifactAsync(
artifacts.ERC20Proxy,
assetProxyArtifacts.ERC20Proxy,
provider,
txDefaults,
artifacts,
allArtifacts,
);
const erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync(
artifacts.ERC721Proxy,
assetProxyArtifacts.ERC721Proxy,
provider,
txDefaults,
artifacts,
allArtifacts,
);
// ZRX
const zrxToken = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
artifacts.DummyERC20Token,
erc20Artifacts.DummyERC20Token,
provider,
txDefaults,
artifacts,
allArtifacts,
'0x Protocol Token',
'ZRX',
new BigNumber(18),
@ -69,14 +85,19 @@ export async function runMigrationsAsync(
);
// Ether token
const etherToken = await WETH9Contract.deployFrom0xArtifactAsync(artifacts.WETH9, provider, txDefaults, artifacts);
const etherToken = await WETH9Contract.deployFrom0xArtifactAsync(
erc20Artifacts.WETH9,
provider,
txDefaults,
allArtifacts,
);
// Exchange
const exchange = await ExchangeContract.deployFrom0xArtifactAsync(
artifacts.Exchange,
exchangeArtifacts.Exchange,
provider,
txDefaults,
artifacts,
allArtifacts,
chainId,
);
@ -85,10 +106,10 @@ export async function runMigrationsAsync(
const totalSupply = new BigNumber(1000000000000000000000000000);
// tslint:disable-next-line:no-unused-variable
const dummyErc20Token = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
artifacts.DummyERC20Token,
erc20Artifacts.DummyERC20Token,
provider,
txDefaults,
artifacts,
allArtifacts,
token.name,
token.symbol,
token.decimals,
@ -99,34 +120,34 @@ export async function runMigrationsAsync(
// ERC721
// tslint:disable-next-line:no-unused-variable
const cryptoKittieToken = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
artifacts.DummyERC721Token,
erc721Artifacts.DummyERC721Token,
provider,
txDefaults,
artifacts,
allArtifacts,
erc721TokenInfo[0].name,
erc721TokenInfo[0].symbol,
);
// 1155 Asset Proxy
const erc1155Proxy = await ERC1155ProxyContract.deployFrom0xArtifactAsync(
artifacts.ERC1155Proxy,
assetProxyArtifacts.ERC1155Proxy,
provider,
txDefaults,
artifacts,
allArtifacts,
);
const staticCallProxy = await StaticCallProxyContract.deployFrom0xArtifactAsync(
artifacts.StaticCallProxy,
assetProxyArtifacts.StaticCallProxy,
provider,
txDefaults,
artifacts,
allArtifacts,
);
const multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
artifacts.MultiAssetProxy,
assetProxyArtifacts.MultiAssetProxy,
provider,
txDefaults,
artifacts,
allArtifacts,
);
await erc20Proxy.addAuthorizedAddress(exchange.address).awaitTransactionSuccessAsync(txDefaults);
@ -152,45 +173,46 @@ export async function runMigrationsAsync(
// CoordinatorRegistry
const coordinatorRegistry = await CoordinatorRegistryContract.deployFrom0xArtifactAsync(
artifacts.CoordinatorRegistry,
coordinatorArtifacts.CoordinatorRegistry,
provider,
txDefaults,
artifacts,
allArtifacts,
);
// Coordinator
const coordinator = await CoordinatorContract.deployFrom0xArtifactAsync(
artifacts.Coordinator,
coordinatorArtifacts.Coordinator,
provider,
txDefaults,
artifacts,
allArtifacts,
exchange.address,
chainId,
);
// Dev Utils
const devUtils = await DevUtilsContract.deployFrom0xArtifactAsync(
artifacts.DevUtils,
const devUtils = await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync(
devUtilsArtifacts.DevUtils,
devUtilsArtifacts,
provider,
txDefaults,
artifacts,
allArtifacts,
exchange.address,
constants.NULL_ADDRESS,
);
// tslint:disable-next-line:no-unused-variable
const erc1155DummyToken = await ERC1155MintableContract.deployFrom0xArtifactAsync(
artifacts.ERC1155Mintable,
erc1155Artifacts.ERC1155Mintable,
provider,
txDefaults,
artifacts,
allArtifacts,
);
const erc20BridgeProxy = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync(
artifacts.ERC20BridgeProxy,
assetProxyArtifacts.ERC20BridgeProxy,
provider,
txDefaults,
{},
allArtifacts,
);
await exchange.registerAssetProxy(erc20BridgeProxy.address).awaitTransactionSuccessAsync(txDefaults);
await erc20BridgeProxy.addAuthorizedAddress(exchange.address).awaitTransactionSuccessAsync(txDefaults);
@ -199,10 +221,10 @@ export async function runMigrationsAsync(
const zrxProxy = erc20Proxy.address;
const zrxVault = await ZrxVaultContract.deployFrom0xArtifactAsync(
artifacts.ZrxVault,
stakingArtifacts.ZrxVault,
provider,
txDefaults,
{},
allArtifacts,
zrxProxy,
zrxToken.address,
);
@ -213,16 +235,16 @@ export async function runMigrationsAsync(
stakingArtifacts.TestStaking,
provider,
txDefaults,
{},
allArtifacts,
etherToken.address,
zrxVault.address,
);
const stakingProxy = await StakingProxyContract.deployFrom0xArtifactAsync(
artifacts.StakingProxy,
stakingArtifacts.StakingProxy,
provider,
txDefaults,
{},
allArtifacts,
stakingLogic.address,
);
@ -245,23 +267,15 @@ export async function runMigrationsAsync(
// in the constructor
const { exchangeV2: exchangeV2Address } = getContractAddressesForChainOrThrow(chainId.toNumber());
const forwarder = await ForwarderContract.deployFrom0xArtifactAsync(
artifacts.Forwarder,
forwarderArtifacts.Forwarder,
provider,
txDefaults,
artifacts,
allArtifacts,
exchange.address,
exchangeV2Address || constants.NULL_ADDRESS,
etherToken.address,
);
// LibTransactionDecoder
const libTransactionDecoder = await LibTransactionDecoderContract.deployFrom0xArtifactAsync(
artifacts.LibTransactionDecoder,
provider,
txDefaults,
artifacts,
);
const contractAddresses = {
erc20Proxy: erc20Proxy.address,
erc721Proxy: erc721Proxy.address,
@ -273,7 +287,6 @@ export async function runMigrationsAsync(
erc20BridgeProxy: erc20BridgeProxy.address,
zeroExGovernor: constants.NULL_ADDRESS,
forwarder: forwarder.address,
libTransactionDecoder: libTransactionDecoder.address,
orderValidator: constants.NULL_ADDRESS,
dutchAuction: constants.NULL_ADDRESS,
coordinatorRegistry: coordinatorRegistry.address,

View File

@ -9,11 +9,7 @@ import {
UniswapBridgeContract,
} from '@0x/contracts-asset-proxy';
import { artifacts as coordinatorArtifacts, CoordinatorContract } from '@0x/contracts-coordinator';
import {
artifacts as devUtilsArtifacts,
DevUtilsContract,
LibTransactionDecoderContract,
} from '@0x/contracts-dev-utils';
import { artifacts as devUtilsArtifacts, DevUtilsContract } from '@0x/contracts-dev-utils';
import { artifacts as exchangeArtifacts, ExchangeContract } from '@0x/contracts-exchange';
import { artifacts as forwarderArtifacts, ForwarderContract } from '@0x/contracts-exchange-forwarder';
import {
@ -249,8 +245,9 @@ export async function runMigrationsAsync(supportedProvider: SupportedProvider, t
]);
await submitAndExecuteTransactionAsync(governor, governor.address, batchTransactionData);
await DevUtilsContract.deployFrom0xArtifactAsync(
await DevUtilsContract.deployWithLibrariesFrom0xArtifactAsync(
devUtilsArtifacts.DevUtils,
devUtilsArtifacts,
provider,
txDefaults,
devUtilsArtifacts,
@ -276,13 +273,6 @@ export async function runMigrationsAsync(supportedProvider: SupportedProvider, t
deployedAddresses.exchangeV2,
deployedAddresses.etherToken,
);
await LibTransactionDecoderContract.deployFrom0xArtifactAsync(
devUtilsArtifacts.LibTransactionDecoder,
provider,
txDefaults,
devUtilsArtifacts,
);
}
(async () => {