Cherry pick DevUtils
refactor code from #2456
This commit is contained in:
parent
8635849977
commit
4016808fa4
@ -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",
|
||||
|
51
contracts/dev-utils/contracts/src/Addresses.sol
Normal file
51
contracts/dev-utils/contracts/src/Addresses.sol
Normal 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);
|
||||
}
|
||||
}
|
374
contracts/dev-utils/contracts/src/AssetBalance.sol
Normal file
374
contracts/dev-utils/contracts/src/AssetBalance.sol
Normal 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)
|
||||
);
|
||||
}
|
||||
}
|
@ -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
|
||||
{}
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.16;
|
||||
|
||||
|
||||
contract EthBalanceChecker {
|
||||
|
322
contracts/dev-utils/contracts/src/ExternalFunctions.sol
Normal file
322
contracts/dev-utils/contracts/src/ExternalFunctions.sol
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
227
contracts/dev-utils/contracts/src/LibOrderTransferSimulation.sol
Normal file
227
contracts/dev-utils/contracts/src/LibOrderTransferSimulation.sol
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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++) {
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
export { artifacts } from './artifacts';
|
||||
export { DevUtilsContract, LibAssetDataContract, LibTransactionDecoderContract } from './wrappers';
|
||||
export { DevUtilsContract } from './wrappers';
|
||||
export {
|
||||
ContractArtifact,
|
||||
ContractChains,
|
||||
|
@ -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';
|
||||
|
@ -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,
|
||||
|
@ -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';
|
||||
|
@ -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"
|
||||
|
@ -4,11 +4,11 @@
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `allowance()` and `balanceOf()` to `LibERC20Token`",
|
||||
"pr": 2462
|
||||
"pr": 2464
|
||||
},
|
||||
{
|
||||
"note": "Fix broken tests",
|
||||
"pr": 2462
|
||||
"pr": 2456
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -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`.
|
||||
|
@ -5,6 +5,10 @@
|
||||
{
|
||||
"note": "Remove dependency on `DevUtils` for asset data encoding/decoding",
|
||||
"pr": 2462
|
||||
},
|
||||
{
|
||||
"note": "Update tests for refactored `DevUtils`",
|
||||
"pr": 2464
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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]);
|
||||
|
@ -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],
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -14,7 +14,6 @@ export interface ContractAddresses {
|
||||
forwarder: string;
|
||||
coordinatorRegistry: string;
|
||||
coordinator: string;
|
||||
libTransactionDecoder: string;
|
||||
multiAssetProxy: string;
|
||||
staticCallProxy: string;
|
||||
erc1155Proxy: string;
|
||||
|
@ -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",
|
||||
|
367
packages/contract-artifacts/artifacts/DevUtils.json
generated
367
packages/contract-artifacts/artifacts/DevUtils.json
generated
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -3,8 +3,12 @@
|
||||
"version": "13.5.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "export `evmbytecodeoutputlinkreferences` type.",
|
||||
"note": "Export `EvmBytecodeOutputLinkReferences` type.",
|
||||
"pr": 2462
|
||||
},
|
||||
{
|
||||
"note": "Remove `LibTransactionDecoder`",
|
||||
"pr": 2464
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -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;
|
||||
}
|
||||
/**
|
||||
|
@ -81,7 +81,6 @@ export {
|
||||
StakingProxyStakingContractAttachedToProxyEventArgs,
|
||||
StakingProxyStakingContractDetachedFromProxyEventArgs,
|
||||
} from './generated-wrappers/staking_proxy';
|
||||
export { LibTransactionDecoderContract } from './generated-wrappers/lib_transaction_decoder';
|
||||
export {
|
||||
BlockRange,
|
||||
SupportedProvider,
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "3.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Refactor into public libraries.",
|
||||
"pr": 2464
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1580988106,
|
||||
"version": "3.1.3",
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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 () => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user