Refactor contracts to only use allowances for AssetProxies (spender is no longer an input)
This commit is contained in:
@@ -24,6 +24,7 @@ import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/libs/LibAssetProxyIds.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
|
||||
|
||||
contract LibAssetData is
|
||||
@@ -33,68 +34,74 @@ contract LibAssetData is
|
||||
|
||||
using LibBytes for bytes;
|
||||
|
||||
/// @dev Returns the owner's balance of the token(s) specified in
|
||||
/// assetData. When the asset data contains multiple tokens (eg in
|
||||
/// ERC1155 or Multi-Asset), the return value indicates how many
|
||||
/// complete "baskets" of those tokens are owned by owner.
|
||||
/// @param owner Owner of the tokens specified by assetData.
|
||||
/// @param assetData Description of tokens, per the AssetProxy contract
|
||||
/// specification.
|
||||
/// @return Number of tokens (or token baskets) held by owner.
|
||||
function getBalance(address owner, bytes memory assetData)
|
||||
// solhint-disable var-name-mixedcase
|
||||
IExchange internal _EXCHANGE;
|
||||
address internal _ERC20_PROXY_ADDRESS;
|
||||
address internal _ERC721_PROXY_ADDRESS;
|
||||
address internal _ERC1155_PROXY_ADDRESS;
|
||||
// solhint-enable var-name-mixedcase
|
||||
|
||||
constructor (address _exchange)
|
||||
public
|
||||
{
|
||||
_EXCHANGE = IExchange(_exchange);
|
||||
_ERC20_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC20_PROXY_ID);
|
||||
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC721_PROXY_ID);
|
||||
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC1155_PROXY_ID);
|
||||
}
|
||||
|
||||
/// @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
|
||||
view
|
||||
returns (uint256 balance)
|
||||
{
|
||||
bytes4 proxyId = assetData.readBytes4(0);
|
||||
bytes4 assetProxyId = assetData.readBytes4(0);
|
||||
|
||||
if (proxyId == ERC20_PROXY_ID) {
|
||||
if (assetProxyId == ERC20_PROXY_ID) {
|
||||
address tokenAddress = assetData.readAddress(16);
|
||||
balance = IERC20Token(tokenAddress).balanceOf(owner);
|
||||
} else if (proxyId == ERC721_PROXY_ID) {
|
||||
balance = IERC20Token(tokenAddress).balanceOf(ownerAddress);
|
||||
} else if (assetProxyId == ERC721_PROXY_ID) {
|
||||
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
||||
balance = getERC721TokenOwner(tokenAddress, tokenId) == owner ? 1 : 0;
|
||||
} else if (proxyId == ERC1155_PROXY_ID) {
|
||||
(
|
||||
,
|
||||
address tokenAddress,
|
||||
uint256[] memory tokenIds,
|
||||
uint256[] memory tokenValues,
|
||||
) = decodeERC1155AssetData(assetData);
|
||||
for (uint256 i = 0; i < tokenIds.length; i++) {
|
||||
uint256 totalBalance = IERC1155(tokenAddress).balanceOf(owner, tokenIds[i]);
|
||||
balance = getERC721TokenOwner(tokenAddress, tokenId) == ownerAddress ? 1 : 0;
|
||||
} else if (assetProxyId == ERC1155_PROXY_ID) {
|
||||
(, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData);
|
||||
uint256 length = tokenIds.length;
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
uint256 totalBalance = IERC1155(tokenAddress).balanceOf(ownerAddress, tokenIds[i]);
|
||||
uint256 scaledBalance = totalBalance / tokenValues[i];
|
||||
if (scaledBalance < balance || balance == 0) {
|
||||
balance = scaledBalance;
|
||||
}
|
||||
}
|
||||
} else if (proxyId == MULTI_ASSET_PROXY_ID) {
|
||||
(
|
||||
,
|
||||
uint256[] memory assetAmounts,
|
||||
bytes[] memory nestedAssetData
|
||||
) = decodeMultiAssetData(assetData);
|
||||
for (uint256 i = 0; i < nestedAssetData.length; i++) {
|
||||
uint256 totalBalance = getBalance(owner, nestedAssetData[i]);
|
||||
} else if (assetProxyId == MULTI_ASSET_PROXY_ID) {
|
||||
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
||||
uint256 length = nestedAssetData.length;
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]);
|
||||
uint256 scaledBalance = totalBalance / assetAmounts[i];
|
||||
if (scaledBalance < balance || balance == 0) {
|
||||
balance = scaledBalance;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
revert("UNSUPPORTED_PROXY_ID");
|
||||
}
|
||||
}
|
||||
|
||||
// Balance will be 0 if assetProxyId is unknown
|
||||
return balance;
|
||||
}
|
||||
|
||||
/// @dev Calls getBalance() for each element of assetData.
|
||||
/// @param owner Owner of the tokens specified by assetData.
|
||||
/// @param assetData Array of token descriptors, each encoded per the
|
||||
/// AssetProxy contract specification.
|
||||
/// @return Array of token balances from getBalance(), with each element
|
||||
/// corresponding to the same-indexed element in the assetData input.
|
||||
function getBatchBalances(address owner, bytes[] memory 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
|
||||
view
|
||||
returns (uint256[] memory balances)
|
||||
@@ -102,83 +109,65 @@ contract LibAssetData is
|
||||
uint256 length = assetData.length;
|
||||
balances = new uint256[](length);
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
balances[i] = getBalance(owner, assetData[i]);
|
||||
balances[i] = getBalance(ownerAddress, assetData[i]);
|
||||
}
|
||||
return balances;
|
||||
}
|
||||
|
||||
/// @dev Returns the number of token(s) (described by assetData) that
|
||||
/// spender is authorized to spend. When the asset data contains
|
||||
/// multiple tokens (eg for Multi-Asset), the return value indicates
|
||||
/// how many complete "baskets" of those tokens may be spent by spender.
|
||||
/// @param owner Owner of the tokens specified by assetData.
|
||||
/// @param spender Address whose authority to spend is in question.
|
||||
/// @param assetData Description of tokens, per the AssetProxy contract
|
||||
/// specification.
|
||||
/// @return Number of tokens (or token baskets) that the spender is
|
||||
/// authorized to spend.
|
||||
function getAllowance(
|
||||
address owner,
|
||||
address spender,
|
||||
bytes memory assetData
|
||||
)
|
||||
/// @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
|
||||
view
|
||||
returns (uint256 allowance)
|
||||
{
|
||||
bytes4 proxyId = assetData.readBytes4(0);
|
||||
bytes4 assetProxyId = assetData.readBytes4(0);
|
||||
|
||||
if (proxyId == ERC20_PROXY_ID) {
|
||||
address tokenAddress = assetData.readAddress(16);
|
||||
allowance = IERC20Token(tokenAddress).allowance(owner, spender);
|
||||
} else if (proxyId == ERC721_PROXY_ID) {
|
||||
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
||||
IERC721Token token = IERC721Token(tokenAddress);
|
||||
if (token.isApprovedForAll(owner, spender)) {
|
||||
allowance = _MAX_UINT256;
|
||||
} else if (token.getApproved(tokenId) == spender) {
|
||||
allowance = 1;
|
||||
}
|
||||
} else if (proxyId == ERC1155_PROXY_ID) {
|
||||
(, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
|
||||
allowance = IERC1155(tokenAddress).isApprovedForAll(owner, spender) ? _MAX_UINT256 : 0;
|
||||
} else if (proxyId == MULTI_ASSET_PROXY_ID) {
|
||||
(
|
||||
,
|
||||
uint256[] memory amounts,
|
||||
bytes[] memory nestedAssetData
|
||||
) = decodeMultiAssetData(assetData);
|
||||
for (uint256 i = 0; i < nestedAssetData.length; i++) {
|
||||
uint256 totalAllowance = getAllowance(
|
||||
owner,
|
||||
spender,
|
||||
nestedAssetData[i]
|
||||
);
|
||||
if (assetProxyId == MULTI_ASSET_PROXY_ID) {
|
||||
(, uint256[] memory amounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
||||
uint256 length = nestedAssetData.length;
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]);
|
||||
uint256 scaledAllowance = totalAllowance / amounts[i];
|
||||
if (scaledAllowance < allowance || allowance == 0) {
|
||||
allowance = scaledAllowance;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
revert("UNSUPPORTED_PROXY_ID");
|
||||
}
|
||||
|
||||
if (assetProxyId == ERC20_PROXY_ID) {
|
||||
address tokenAddress = assetData.readAddress(16);
|
||||
allowance = IERC20Token(tokenAddress).allowance(ownerAddress, _ERC20_PROXY_ADDRESS);
|
||||
} else if (assetProxyId == ERC721_PROXY_ID) {
|
||||
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
||||
IERC721Token token = IERC721Token(tokenAddress);
|
||||
address assetProxyAddress = _ERC721_PROXY_ADDRESS;
|
||||
if (token.isApprovedForAll(ownerAddress, assetProxyAddress)) {
|
||||
allowance = _MAX_UINT256;
|
||||
} else if (token.getApproved(tokenId) == assetProxyAddress) {
|
||||
allowance = 1;
|
||||
}
|
||||
} else if (assetProxyId == ERC1155_PROXY_ID) {
|
||||
(, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
|
||||
allowance = IERC1155(tokenAddress).isApprovedForAll(ownerAddress, _ERC1155_PROXY_ADDRESS) ? _MAX_UINT256 : 0;
|
||||
}
|
||||
|
||||
// Allowance will be 0 if the assetProxyId is unknown
|
||||
return allowance;
|
||||
}
|
||||
|
||||
/// @dev Calls getAllowance() for each element of assetData.
|
||||
/// @param owner Owner of the tokens specified by assetData.
|
||||
/// @param spenders Array of addresses whose authority to spend is in question for each corresponding assetData.
|
||||
/// @param assetData Description of tokens, per the AssetProxy contract
|
||||
/// specification.
|
||||
/// @return An array of token allowances from getAllowance(), with each
|
||||
/// element corresponding to the same-indexed element in the assetData
|
||||
/// input.
|
||||
function getBatchAllowances(
|
||||
address owner,
|
||||
address[] memory spenders,
|
||||
bytes[] memory assetData
|
||||
)
|
||||
/// @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
|
||||
view
|
||||
returns (uint256[] memory allowances)
|
||||
@@ -186,63 +175,44 @@ contract LibAssetData is
|
||||
uint256 length = assetData.length;
|
||||
allowances = new uint256[](length);
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
allowances[i] = getAllowance(owner, spenders[i], assetData[i]);
|
||||
allowances[i] = getAssetProxyAllowance(ownerAddress, assetData[i]);
|
||||
}
|
||||
return allowances;
|
||||
}
|
||||
|
||||
/// @dev Calls getBalance() and getAllowance() for assetData.
|
||||
/// @param owner Owner of the tokens specified by assetData.
|
||||
/// @param spender Address whose authority to spend is in question.
|
||||
/// @param assetData Description of tokens, per the AssetProxy contract
|
||||
/// specification.
|
||||
/// @return Number of tokens (or token baskets) held by owner, and number
|
||||
/// of tokens (or token baskets) that the spender is authorized to
|
||||
/// spend.
|
||||
function getBalanceAndAllowance(
|
||||
address owner,
|
||||
address spender,
|
||||
bytes memory 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
|
||||
view
|
||||
returns (uint256 balance, uint256 allowance)
|
||||
{
|
||||
balance = getBalance(owner, assetData);
|
||||
allowance = getAllowance(owner, spender, assetData);
|
||||
balance = getBalance(ownerAddress, assetData);
|
||||
allowance = getAssetProxyAllowance(ownerAddress, assetData);
|
||||
return (balance, allowance);
|
||||
}
|
||||
|
||||
/// @dev Calls getBatchBalances() and getBatchAllowances() for each element
|
||||
/// of assetData.
|
||||
/// @param owner Owner of the tokens specified by assetData.
|
||||
/// @param spenders Array of addresses whose authority to spend is in question for each corresponding assetData.
|
||||
/// @param assetData Description of tokens, per the AssetProxy contract
|
||||
/// specification.
|
||||
/// @return An array of token balances from getBalance(), and an array of
|
||||
/// token allowances from getAllowance(), with each element
|
||||
/// corresponding to the same-indexed element in the assetData input.
|
||||
function getBatchBalancesAndAllowances(
|
||||
address owner,
|
||||
address[] memory spenders,
|
||||
bytes[] memory assetData
|
||||
)
|
||||
/// @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
|
||||
view
|
||||
returns (
|
||||
uint256[] memory balances,
|
||||
uint256[] memory allowances
|
||||
)
|
||||
returns (uint256[] memory balances, uint256[] memory allowances)
|
||||
{
|
||||
balances = getBatchBalances(owner, assetData);
|
||||
allowances = getBatchAllowances(owner, spenders, assetData);
|
||||
balances = getBatchBalances(ownerAddress, assetData);
|
||||
allowances = getBatchAssetProxyAllowances(ownerAddress, assetData);
|
||||
return (balances, allowances);
|
||||
}
|
||||
|
||||
/// @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
|
||||
/// token to be traded.
|
||||
/// @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
|
||||
@@ -253,41 +223,34 @@ contract LibAssetData is
|
||||
return assetData;
|
||||
}
|
||||
|
||||
/// @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 ERC-20 AssetProxy identifier, and the address of the ERC-20
|
||||
/// contract hosting this asset.
|
||||
/// @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 ERC-20 AssetProxy identifier, and the address of the ERC-20
|
||||
/// contract hosting this asset.
|
||||
function decodeERC20AssetData(bytes memory assetData)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
bytes4 proxyId,
|
||||
bytes4 assetProxyId,
|
||||
address tokenAddress
|
||||
)
|
||||
{
|
||||
proxyId = assetData.readBytes4(0);
|
||||
assetProxyId = assetData.readBytes4(0);
|
||||
|
||||
require(
|
||||
proxyId == ERC20_PROXY_ID,
|
||||
assetProxyId == ERC20_PROXY_ID,
|
||||
"WRONG_PROXY_ID"
|
||||
);
|
||||
|
||||
tokenAddress = assetData.readAddress(16);
|
||||
return (proxyId, tokenAddress);
|
||||
return (assetProxyId, tokenAddress);
|
||||
}
|
||||
|
||||
/// @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
|
||||
/// token to be traded.
|
||||
/// @param tokenId The identifier of the specific token to be traded.
|
||||
/// @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
|
||||
)
|
||||
function encodeERC721AssetData(address tokenAddress, uint256 tokenId)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory assetData)
|
||||
@@ -300,41 +263,37 @@ contract LibAssetData is
|
||||
return assetData;
|
||||
}
|
||||
|
||||
/// @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.
|
||||
/// @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
|
||||
/// token to be traded.
|
||||
/// contract hosting this asset, and the identifier of the specific
|
||||
/// asset to be traded.
|
||||
function decodeERC721AssetData(bytes memory assetData)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
bytes4 proxyId,
|
||||
bytes4 assetProxyId,
|
||||
address tokenAddress,
|
||||
uint256 tokenId
|
||||
)
|
||||
{
|
||||
proxyId = assetData.readBytes4(0);
|
||||
assetProxyId = assetData.readBytes4(0);
|
||||
|
||||
require(
|
||||
proxyId == ERC721_PROXY_ID,
|
||||
assetProxyId == ERC721_PROXY_ID,
|
||||
"WRONG_PROXY_ID"
|
||||
);
|
||||
|
||||
tokenAddress = assetData.readAddress(16);
|
||||
tokenId = assetData.readUint256(36);
|
||||
return (proxyId, tokenAddress, tokenId);
|
||||
return (assetProxyId, tokenAddress, tokenId);
|
||||
}
|
||||
|
||||
/// @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
|
||||
/// token(s) to be traded.
|
||||
/// @param tokenIds The identifiers of the specific tokens to be traded.
|
||||
/// @param tokenValues The amounts of each token to be traded.
|
||||
/// @param callbackData ...
|
||||
/// @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,
|
||||
@@ -356,32 +315,30 @@ contract LibAssetData is
|
||||
return assetData;
|
||||
}
|
||||
|
||||
/// @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.
|
||||
/// @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
|
||||
/// tokens to be traded, an array of token 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`.
|
||||
/// 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 proxyId,
|
||||
bytes4 assetProxyId,
|
||||
address tokenAddress,
|
||||
uint256[] memory tokenIds,
|
||||
uint256[] memory tokenValues,
|
||||
bytes memory callbackData
|
||||
)
|
||||
{
|
||||
proxyId = assetData.readBytes4(0);
|
||||
assetProxyId = assetData.readBytes4(0);
|
||||
|
||||
require(
|
||||
proxyId == ERC1155_PROXY_ID,
|
||||
assetProxyId == ERC1155_PROXY_ID,
|
||||
"WRONG_PROXY_ID"
|
||||
);
|
||||
|
||||
@@ -399,7 +356,7 @@ contract LibAssetData is
|
||||
}
|
||||
|
||||
return (
|
||||
proxyId,
|
||||
assetProxyId,
|
||||
tokenAddress,
|
||||
tokenIds,
|
||||
tokenValues,
|
||||
@@ -407,16 +364,11 @@ contract LibAssetData is
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Encode data for multiple assets, per the AssetProxy contract
|
||||
/// specification.
|
||||
/// @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.
|
||||
/// @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
|
||||
)
|
||||
function encodeMultiAssetData(uint256[] memory amounts, bytes[] memory nestedAssetData)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory assetData)
|
||||
@@ -429,28 +381,25 @@ contract LibAssetData is
|
||||
return assetData;
|
||||
}
|
||||
|
||||
/// @dev Decode multi-asset data from the format described in the
|
||||
/// AssetProxy contract specification.
|
||||
/// @param assetData AssetProxy-compliant data describing a multi-asset
|
||||
/// basket.
|
||||
/// @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.
|
||||
/// 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 proxyId,
|
||||
bytes4 assetProxyId,
|
||||
uint256[] memory amounts,
|
||||
bytes[] memory nestedAssetData
|
||||
)
|
||||
{
|
||||
proxyId = assetData.readBytes4(0);
|
||||
assetProxyId = assetData.readBytes4(0);
|
||||
|
||||
require(
|
||||
proxyId == MULTI_ASSET_PROXY_ID,
|
||||
assetProxyId == MULTI_ASSET_PROXY_ID,
|
||||
"WRONG_PROXY_ID"
|
||||
);
|
||||
|
||||
@@ -462,14 +411,14 @@ contract LibAssetData is
|
||||
// solhint-enable indent
|
||||
}
|
||||
|
||||
/// @dev Calls `token.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned token.
|
||||
/// @param tokenAddress Address of ERC721 token.
|
||||
/// @dev Calls `asset.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned asset.
|
||||
/// @param tokenAddress Address of ERC721 asset.
|
||||
/// @param tokenId The identifier for the specific NFT.
|
||||
/// @return Owner of tokenId or null address if unowned.
|
||||
function getERC721TokenOwner(address tokenAddress, uint256 tokenId)
|
||||
public
|
||||
view
|
||||
returns (address owner)
|
||||
returns (address ownerAddress)
|
||||
{
|
||||
bytes memory ownerOfCalldata = abi.encodeWithSelector(
|
||||
0x6352211e,
|
||||
@@ -478,7 +427,7 @@ contract LibAssetData is
|
||||
|
||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
|
||||
|
||||
owner = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
|
||||
return owner;
|
||||
ownerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
|
||||
return ownerAddress;
|
||||
}
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ 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-asset-proxy/contracts/src/libs/LibAssetData.sol";
|
||||
import "./LibAssetData.sol";
|
||||
|
||||
|
||||
contract OrderValidationUtils is
|
||||
@@ -33,23 +33,26 @@ contract OrderValidationUtils is
|
||||
using LibBytes for bytes;
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
IExchange internal EXCHANGE;
|
||||
bytes internal ZRX_ASSET_DATA;
|
||||
address internal ERC20_PROXY_ADDRESS;
|
||||
bytes internal _ZRX_ASSET_DATA;
|
||||
// solhint-enable var-name-mixedcase
|
||||
|
||||
constructor (address _exchange, bytes memory _zrxAssetData)
|
||||
public
|
||||
LibAssetData(_exchange)
|
||||
{
|
||||
EXCHANGE = IExchange(_exchange);
|
||||
ZRX_ASSET_DATA = _zrxAssetData;
|
||||
ERC20_PROXY_ADDRESS = EXCHANGE.getAssetProxy(ERC20_PROXY_ID);
|
||||
_ZRX_ASSET_DATA = _zrxAssetData;
|
||||
}
|
||||
|
||||
/// @dev Fetches information for order and maker/taker of order.
|
||||
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
|
||||
/// @param order The order structure.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return OrderInfo, the remaining amount fillable by the taker, and validity of signature for given order.
|
||||
/// @param signature Signature provided by maker that proves the order's authenticity.
|
||||
/// `0x01` can always be provided if the signature does not need to be validated.
|
||||
/// @return orderInfo The hash, status, and `takerAssetAmount` already filled for the given order.
|
||||
/// @return fillableTakerAssetAmount The amount of the order's `takerAssetAmount` that is fillable given all on-chain state.
|
||||
/// If the `takerAssetData` encodes data for multiple assets, `fillableTakerAssetAmount` will represent a "scaled"
|
||||
/// amount, meaning it must be multiplied by all the individual asset amounts within the `takerAssetData` to get the final
|
||||
/// amount of each asset that can be filled.
|
||||
/// @return isValidSignature The validity of the provided signature.
|
||||
function getOrderRelevantState(LibOrder.Order memory order, bytes memory signature)
|
||||
public
|
||||
view
|
||||
@@ -60,74 +63,80 @@ contract OrderValidationUtils is
|
||||
)
|
||||
{
|
||||
// Get info specific to order
|
||||
orderInfo = EXCHANGE.getOrderInfo(order);
|
||||
orderInfo = _EXCHANGE.getOrderInfo(order);
|
||||
|
||||
// Validate the maker's signature
|
||||
// If the signature does not need to be validated, `0x01` can be supplied for the signature to always return `false`.
|
||||
address makerAddress = order.makerAddress;
|
||||
isValidSignature = EXCHANGE.isValidSignature(
|
||||
isValidSignature = _EXCHANGE.isValidSignature(
|
||||
orderInfo.orderHash,
|
||||
makerAddress,
|
||||
signature
|
||||
);
|
||||
|
||||
// Get the transferable amount of the `makerAsset`
|
||||
uint256 transferableMakerAssetAmount = getTransferableAssetAmount(order.makerAssetData, makerAddress);
|
||||
uint256 transferableMakerAssetAmount = getTransferableAssetAmount(makerAddress, order.makerAssetData);
|
||||
|
||||
// Assign to stack variables to reduce redundant mloads
|
||||
// Assign to stack variables to reduce redundant mloads/sloads
|
||||
uint256 takerAssetAmount = order.takerAssetAmount;
|
||||
uint256 makerFee = order.makerFee;
|
||||
bytes memory zrxAssetData = _ZRX_ASSET_DATA;
|
||||
|
||||
// Get the amount of `takerAsset` that is purchasable given the transferability of `makerAsset` and `makerFeeAsset`
|
||||
uint256 purchasableTakerAssetAmount;
|
||||
if (order.makerAssetData.equals(ZRX_ASSET_DATA)) {
|
||||
// Get the amount of `takerAsset` that is transferable to maker given the transferability of `makerAsset` and `makerFeeAsset`
|
||||
// and the total amounts specified in the order
|
||||
uint256 transferableTakerAssetAmount;
|
||||
if (order.makerAssetData.equals(zrxAssetData)) {
|
||||
// If `makerAsset` equals `makerFeeAsset`, the % that can be filled is
|
||||
// transferableMakerAssetAmount / (makerAssetAmount + makerFee)
|
||||
purchasableTakerAssetAmount = getPartialAmountFloor(
|
||||
transferableTakerAssetAmount = getPartialAmountFloor(
|
||||
transferableMakerAssetAmount,
|
||||
safeAdd(order.makerAssetAmount, makerFee),
|
||||
takerAssetAmount
|
||||
);
|
||||
} else {
|
||||
// Get the transferable amount of the `makerFeeAsset`
|
||||
uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount(ZRX_ASSET_DATA, makerAddress);
|
||||
uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount(makerAddress, zrxAssetData);
|
||||
|
||||
// If `makerAsset` does not equal `makerFeeAsset`, the % that can be filled is the lower of
|
||||
// (transferableMakerAssetAmount / makerAssetAmount) and (transferableMakerAssetFeeAmount / makerFee)
|
||||
// If `makerFee` is 0, we default to using `transferableMakerAssetAmount`
|
||||
purchasableTakerAssetAmount = makerFee == 0
|
||||
? getPartialAmountFloor(
|
||||
// If `makerFee` is 0, the % that can be filled is (transferableMakerAssetAmount / makerAssetAmount)
|
||||
if (makerFee == 0) {
|
||||
transferableTakerAssetAmount = getPartialAmountFloor(
|
||||
transferableMakerAssetAmount,
|
||||
order.makerAssetAmount,
|
||||
takerAssetAmount
|
||||
)
|
||||
: min256(
|
||||
getPartialAmountFloor(
|
||||
transferableMakerAssetAmount,
|
||||
order.makerAssetAmount,
|
||||
takerAssetAmount
|
||||
),
|
||||
getPartialAmountFloor(
|
||||
transferableMakerFeeAssetAmount,
|
||||
makerFee,
|
||||
takerAssetAmount
|
||||
)
|
||||
);
|
||||
|
||||
// If `makerAsset` does not equal `makerFeeAsset`, the % that can be filled is the lower of
|
||||
// (transferableMakerAssetAmount / makerAssetAmount) and (transferableMakerAssetFeeAmount / makerFee)
|
||||
} else {
|
||||
uint256 transferableMakerToTakerAmount = getPartialAmountFloor(
|
||||
transferableMakerAssetAmount,
|
||||
order.makerAssetAmount,
|
||||
takerAssetAmount
|
||||
);
|
||||
uint256 transferableMakerFeeToTakerAmount = getPartialAmountFloor(
|
||||
transferableMakerFeeAssetAmount,
|
||||
makerFee,
|
||||
takerAssetAmount
|
||||
);
|
||||
transferableTakerAssetAmount = min256(transferableMakerToTakerAmount, transferableMakerFeeToTakerAmount);
|
||||
}
|
||||
}
|
||||
|
||||
// `fillableTakerAssetAmount` is the lower of the order's remaining `takerAssetAmount` and the `purchasableTakerAssetAmount`
|
||||
|
||||
// `fillableTakerAssetAmount` is the lower of the order's remaining `takerAssetAmount` and the `transferableTakerAssetAmount`
|
||||
fillableTakerAssetAmount = min256(
|
||||
safeSub(takerAssetAmount, orderInfo.orderTakerAssetFilledAmount),
|
||||
purchasableTakerAssetAmount
|
||||
transferableTakerAssetAmount
|
||||
);
|
||||
|
||||
return (orderInfo, fillableTakerAssetAmount, isValidSignature);
|
||||
}
|
||||
|
||||
/// @dev Fetches information for all passed in orders and the makers/takers of each order.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @return Arrays of OrderInfo, fillable takerAssetAmounts, and validity of signatures that correspond to each order.
|
||||
/// @dev Fetches all order-relevant information needed to validate if the supplied orders are fillable.
|
||||
/// @param orders Array of order structures.
|
||||
/// @param signatures Array of signatures provided by makers that prove the authenticity of the orders.
|
||||
/// `0x01` can always be provided if a signature does not need to be validated.
|
||||
/// @return ordersInfo Array of the hash, status, and `takerAssetAmount` already filled for each order.
|
||||
/// @return fillableTakerAssetAmounts Array of amounts for each order's `takerAssetAmount` that is fillable given all on-chain state.
|
||||
/// @return isValidSignature Array containing the validity of each provided signature.
|
||||
function getOrderRelevantStates(LibOrder.Order[] memory orders, bytes[] memory signatures)
|
||||
public
|
||||
view
|
||||
@@ -152,39 +161,17 @@ contract OrderValidationUtils is
|
||||
return (ordersInfo, fillableTakerAssetAmounts, isValidSignature);
|
||||
}
|
||||
|
||||
/// @dev Gets the address of the AssetProxy that corresponds to the given assetData.
|
||||
/// @param assetData Description of tokens, per the AssetProxy contract specification.
|
||||
/// @return Address of the AssetProxy contract.
|
||||
function getAssetProxyAddress(bytes memory assetData)
|
||||
public
|
||||
view
|
||||
returns (address assetProxyAddress)
|
||||
{
|
||||
if (assetData.equals(ZRX_ASSET_DATA)) {
|
||||
return ERC20_PROXY_ADDRESS;
|
||||
}
|
||||
bytes4 assetProxyId = assetData.readBytes4(0);
|
||||
assetProxyAddress = EXCHANGE.getAssetProxy(assetProxyId);
|
||||
return assetProxyAddress;
|
||||
}
|
||||
|
||||
/// @dev Gets the amount of an asset transferable by the owner.
|
||||
/// @param assetData Description of tokens, per the AssetProxy contract specification.
|
||||
/// @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.
|
||||
function getTransferableAssetAmount(bytes memory assetData, address ownerAddress)
|
||||
function getTransferableAssetAmount(address ownerAddress, bytes memory assetData)
|
||||
public
|
||||
view
|
||||
returns (uint256 transferableAssetAmount)
|
||||
{
|
||||
uint256 assetBalance = getBalance(ownerAddress, assetData);
|
||||
address assetProxyAddress = getAssetProxyAddress(assetData);
|
||||
uint256 assetAllowance = getAllowance(
|
||||
ownerAddress,
|
||||
assetProxyAddress,
|
||||
assetData
|
||||
);
|
||||
transferableAssetAmount = min256(assetBalance, assetAllowance);
|
||||
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData);
|
||||
transferableAssetAmount = min256(balance, allowance);
|
||||
return transferableAssetAmount;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user