Add LibAssetData to contracts/asset-proxy (#1779)
* Stop restarting node unnecesssarily during test * Add new, empty LibAssetData * Support encoding & decoding of ERC20 asset data * Support encoding & decoding of ERC721 asset data * Support encoding & decoding of ERC1155 asset data * Support encoding & decoding of multi-asset data * Support querying ERC20 balance from asset data * Support querying ERC721 balance from asset data * Support querying ERC1155 balance from asset data * Support querying balance from multi-asset data * Support querying ERC20 allowance from asset data * Support querying ERC721 allowance from asset data * Support querying ERC1155 allowance from asset data * In tests, wait for allowance set before checking * Introduce temporary variable `assetDataBody` * Handle edge case in multi-asset balance query * Support multi-asset allowance query by asset data * Move variable declaration up for readability. * Make all solhint-disable's cite specific rules And move the directives to the ends of lines whenever possible * Rename query tests to include " by asset data" * Extract test helper method * Extract another test helper method * Support batch queries of allowances & balances * In LibAssetData.sol, use IERC1155, not ...Mintable * Rename balance*() return vars: amount -> balance * Fix bug in ERC721 balance query Was using method balanceOf(), but needed to be using ownerOf(). getERC721TokenOwner() method lifted from @0x/extensions/contracts/src/OrderValidator/OrderValidator.sol * Reuse new en/decoders; avoid abi.decode(). * Start lowest allowance/balance from 0, not MAX_INT * Properly implement ERC1155 balance querying * Split lines for readability * Also check isApprovedForAll in 721 allowance query * Add neglected division of allowances by amounts * Rename methods: balanceOf -> getBalance * Rename methods: allowance -> getAllowance * Add methods: getBalanceAndAllowance() & batch...() * Rename return vars: amount -> allowance * Add devdoc comments * Rename batchGet* methods to getBatch* * Remove refactoring relic * Add revert messages to all require() calls * Reduce gas usage for ERC1155 asset data decoding * Don't use dockerized solc for ERC20 contracts Because they demand solc version 0.4.26, and it seems as though the tag for that version has been deleted from dockerhub. Without this, @0x/contracts-erc20 was failing to build. * Rename batch functions to use plurals * Skip dockerized solc for contracts needing 0.4.26 I seems as though the tag for that version has been deleted from dockerhub. Without this, these contracts were failing to build. * Make revert reasons follow snake case convention
This commit is contained in:
parent
bbc06be091
commit
0de2b6983b
@ -30,6 +30,7 @@
|
||||
"src/MultiAssetProxy.sol",
|
||||
"src/interfaces/IAssetData.sol",
|
||||
"src/interfaces/IAssetProxy.sol",
|
||||
"src/interfaces/IAuthorizable.sol"
|
||||
"src/interfaces/IAuthorizable.sol",
|
||||
"src/libs/LibAssetData.sol"
|
||||
]
|
||||
}
|
||||
|
420
contracts/asset-proxy/contracts/src/libs/LibAssetData.sol
Normal file
420
contracts/asset-proxy/contracts/src/libs/LibAssetData.sol
Normal file
@ -0,0 +1,420 @@
|
||||
/*
|
||||
|
||||
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.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
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";
|
||||
|
||||
|
||||
library LibAssetData {
|
||||
bytes4 constant public ERC20_PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
|
||||
bytes4 constant public ERC721_PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
|
||||
bytes4 constant public ERC1155_PROXY_ID = bytes4(keccak256("ERC1155Assets(address,uint256[],uint256[],bytes)"));
|
||||
bytes4 constant public MULTI_ASSET_PROXY_ID = bytes4(keccak256("MultiAsset(uint256[],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)
|
||||
public
|
||||
view
|
||||
returns (uint256 balance)
|
||||
{
|
||||
bytes4 proxyId = LibBytes.readBytes4(assetData, 0);
|
||||
if (proxyId == ERC20_PROXY_ID) {
|
||||
address tokenAddress = LibBytes.readAddress(assetData, 16);
|
||||
return IERC20Token(tokenAddress).balanceOf(owner);
|
||||
} else if (proxyId == ERC721_PROXY_ID) {
|
||||
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
||||
return getERC721TokenOwner(tokenAddress, tokenId) == owner ? 1 : 0;
|
||||
} else if (proxyId == ERC1155_PROXY_ID) {
|
||||
uint256 lowestTokenBalance = 0;
|
||||
(
|
||||
,
|
||||
address tokenAddress,
|
||||
uint256[] memory tokenIds,
|
||||
uint256[] memory tokenValues,
|
||||
) = decodeERC1155AssetData(assetData);
|
||||
for (uint256 i = 0; i < tokenIds.length; i++) {
|
||||
uint256 tokenBalance = IERC1155(tokenAddress).balanceOf(owner, tokenIds[i]) / tokenValues[i];
|
||||
if (tokenBalance < lowestTokenBalance || lowestTokenBalance == 0) {
|
||||
lowestTokenBalance = tokenBalance;
|
||||
}
|
||||
}
|
||||
return lowestTokenBalance;
|
||||
} else if (proxyId == MULTI_ASSET_PROXY_ID) {
|
||||
uint256 lowestAssetBalance = 0;
|
||||
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
||||
for (uint256 i = 0; i < nestedAssetData.length; i++) {
|
||||
uint256 assetBalance = getBalance(owner, nestedAssetData[i]) / assetAmounts[i];
|
||||
if (assetBalance < lowestAssetBalance || lowestAssetBalance == 0) {
|
||||
lowestAssetBalance = assetBalance;
|
||||
}
|
||||
}
|
||||
return lowestAssetBalance;
|
||||
} else {
|
||||
revert("UNSUPPORTED_PROXY_IDENTIFIER");
|
||||
}
|
||||
}
|
||||
|
||||
/// @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)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory balances)
|
||||
{
|
||||
balances = new uint256[](assetData.length);
|
||||
for (uint256 i = 0; i < assetData.length; i++) {
|
||||
balances[i] = getBalance(owner, assetData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// @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)
|
||||
public
|
||||
view
|
||||
returns (uint256 allowance)
|
||||
{
|
||||
bytes4 proxyId = LibBytes.readBytes4(assetData, 0);
|
||||
|
||||
if (proxyId == ERC20_PROXY_ID) {
|
||||
address tokenAddress = LibBytes.readAddress(assetData, 16);
|
||||
return IERC20Token(tokenAddress).allowance(owner, spender);
|
||||
} else if (proxyId == ERC721_PROXY_ID) {
|
||||
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
||||
IERC721Token token = IERC721Token(tokenAddress);
|
||||
if (spender == token.getApproved(tokenId) || token.isApprovedForAll(owner, spender)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else if (proxyId == ERC1155_PROXY_ID) {
|
||||
(, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
|
||||
if (IERC1155(tokenAddress).isApprovedForAll(owner, spender)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else if (proxyId == MULTI_ASSET_PROXY_ID) {
|
||||
uint256 lowestAssetAllowance = 0;
|
||||
// solhint-disable-next-line indent
|
||||
(, uint256[] memory amounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
||||
for (uint256 i = 0; i < nestedAssetData.length; i++) {
|
||||
uint256 assetAllowance = getAllowance(owner, spender, nestedAssetData[i]) / amounts[i];
|
||||
if (assetAllowance < lowestAssetAllowance || lowestAssetAllowance == 0) {
|
||||
lowestAssetAllowance = assetAllowance;
|
||||
}
|
||||
}
|
||||
return lowestAssetAllowance;
|
||||
} else {
|
||||
revert("UNSUPPORTED_PROXY_IDENTIFIER");
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Calls getAllowance() for each element of 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 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 spender, bytes[] memory assetData)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory allowances)
|
||||
{
|
||||
allowances = new uint256[](assetData.length);
|
||||
for (uint256 i = 0; i < assetData.length; i++) {
|
||||
allowances[i] = getAllowance(owner, spender, assetData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// @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)
|
||||
public
|
||||
view
|
||||
returns (uint256 balance, uint256 allowance)
|
||||
{
|
||||
balance = getBalance(owner, assetData);
|
||||
allowance = getAllowance(owner, spender, assetData);
|
||||
}
|
||||
|
||||
/// @dev Calls getBatchBalances() and getBatchAllowances() for each element
|
||||
/// of 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 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 spender, bytes[] memory assetData)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory balances, uint256[] memory allowances)
|
||||
{
|
||||
balances = getBatchBalances(owner, assetData);
|
||||
allowances = getBatchAllowances(owner, spender, 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
|
||||
/// token to be traded.
|
||||
/// @return AssetProxy-compliant data describing the asset.
|
||||
function encodeERC20AssetData(address tokenAddress)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory assetData)
|
||||
{
|
||||
return abi.encodeWithSelector(ERC20_PROXY_ID, 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 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,
|
||||
address tokenAddress
|
||||
)
|
||||
{
|
||||
proxyId = LibBytes.readBytes4(assetData, 0);
|
||||
|
||||
require(proxyId == ERC20_PROXY_ID, "WRONG_PROXY_ID");
|
||||
|
||||
tokenAddress = LibBytes.readAddress(assetData, 16);
|
||||
}
|
||||
|
||||
/// @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.
|
||||
/// @return AssetProxy-compliant asset data describing the asset.
|
||||
function encodeERC721AssetData(
|
||||
address tokenAddress,
|
||||
uint256 tokenId
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory assetData)
|
||||
{
|
||||
return abi.encodeWithSelector(ERC721_PROXY_ID, 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
|
||||
/// token to be traded.
|
||||
function decodeERC721AssetData(bytes memory assetData)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
bytes4 proxyId,
|
||||
address tokenAddress,
|
||||
uint256 tokenId
|
||||
)
|
||||
{
|
||||
proxyId = LibBytes.readBytes4(assetData, 0);
|
||||
|
||||
require(proxyId == ERC721_PROXY_ID, "WRONG_PROXY_ID");
|
||||
|
||||
tokenAddress = LibBytes.readAddress(assetData, 16);
|
||||
tokenId = LibBytes.readUint256(assetData, 36);
|
||||
}
|
||||
|
||||
/// @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 ...
|
||||
/// @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 abi.encodeWithSelector(ERC1155_PROXY_ID, 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
|
||||
/// 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`.
|
||||
function decodeERC1155AssetData(bytes memory assetData)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
bytes4 proxyId,
|
||||
address tokenAddress,
|
||||
uint256[] memory tokenIds,
|
||||
uint256[] memory tokenValues,
|
||||
bytes memory callbackData
|
||||
)
|
||||
{
|
||||
proxyId = LibBytes.readBytes4(assetData, 0);
|
||||
|
||||
require(proxyId == ERC1155_PROXY_ID, "WRONG_PROXY_ID");
|
||||
|
||||
assembly {
|
||||
// Skip selector and length to get to the first parameter:
|
||||
assetData := add(assetData, 36)
|
||||
// Read the value of the first parameter:
|
||||
tokenAddress := mload(assetData)
|
||||
// Point to the next parameter's data:
|
||||
tokenIds := add(assetData, mload(add(assetData, 32)))
|
||||
// Point to the next parameter's data:
|
||||
tokenValues := add(assetData, mload(add(assetData, 64)))
|
||||
// Point to the next parameter's data:
|
||||
callbackData := add(assetData, mload(add(assetData, 96)))
|
||||
}
|
||||
}
|
||||
|
||||
/// @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)
|
||||
{
|
||||
assetData = abi.encodeWithSelector(MULTI_ASSET_PROXY_ID, 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 proxyId,
|
||||
uint256[] memory amounts,
|
||||
bytes[] memory nestedAssetData
|
||||
)
|
||||
{
|
||||
proxyId = LibBytes.readBytes4(assetData, 0);
|
||||
|
||||
require(proxyId == MULTI_ASSET_PROXY_ID, "WRONG_PROXY_ID");
|
||||
|
||||
// solhint-disable-next-line indent
|
||||
(amounts, nestedAssetData) = abi.decode(LibBytes.slice(assetData, 4, assetData.length), (uint256[], bytes[]));
|
||||
}
|
||||
|
||||
/// @dev Calls `token.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned token.
|
||||
/// @param token Address of ERC721 token.
|
||||
/// @param tokenId The identifier for the specific NFT.
|
||||
/// @return Owner of tokenId or null address if unowned.
|
||||
function getERC721TokenOwner(address token, uint256 tokenId)
|
||||
public
|
||||
view
|
||||
returns (address owner)
|
||||
{
|
||||
assembly {
|
||||
// load free memory pointer
|
||||
let cdStart := mload(64)
|
||||
|
||||
// bytes4(keccak256(ownerOf(uint256))) = 0x6352211e
|
||||
mstore(cdStart, 0x6352211e00000000000000000000000000000000000000000000000000000000)
|
||||
mstore(add(cdStart, 4), tokenId)
|
||||
|
||||
// staticcall `ownerOf(tokenId)`
|
||||
// `ownerOf` will revert if tokenId is not owned
|
||||
let success := staticcall(
|
||||
gas, // forward all gas
|
||||
token, // call token contract
|
||||
cdStart, // start of calldata
|
||||
36, // length of input is 36 bytes
|
||||
cdStart, // write output over input
|
||||
32 // size of output is 32 bytes
|
||||
)
|
||||
|
||||
// Success implies that tokenId is owned
|
||||
// Copy owner from return data if successful
|
||||
if success {
|
||||
owner := mload(cdStart)
|
||||
}
|
||||
}
|
||||
|
||||
// Owner initialized to address(0), no need to modify if call is unsuccessful
|
||||
return owner;
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./generated-artifacts/@(ERC1155Proxy|ERC20Proxy|ERC721Proxy|IAssetData|IAssetProxy|IAuthorizable|MixinAuthorizable|MultiAssetProxy).json",
|
||||
"abis": "./generated-artifacts/@(ERC1155Proxy|ERC20Proxy|ERC721Proxy|IAssetData|IAssetProxy|IAuthorizable|LibAssetData|MixinAuthorizable|MultiAssetProxy).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
|
@ -11,12 +11,14 @@ import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json';
|
||||
import * as IAssetData from '../generated-artifacts/IAssetData.json';
|
||||
import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
|
||||
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
|
||||
import * as LibAssetData from '../generated-artifacts/LibAssetData.json';
|
||||
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
|
||||
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
|
||||
export const artifacts = {
|
||||
LibAssetData: LibAssetData as ContractArtifact,
|
||||
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
|
||||
ERC20Proxy: ERC20Proxy as ContractArtifact,
|
||||
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
||||
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
|
||||
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||
IAssetData: IAssetData as ContractArtifact,
|
||||
|
@ -9,5 +9,6 @@ export * from '../generated-wrappers/erc721_proxy';
|
||||
export * from '../generated-wrappers/i_asset_data';
|
||||
export * from '../generated-wrappers/i_asset_proxy';
|
||||
export * from '../generated-wrappers/i_authorizable';
|
||||
export * from '../generated-wrappers/lib_asset_data';
|
||||
export * from '../generated-wrappers/mixin_authorizable';
|
||||
export * from '../generated-wrappers/multi_asset_proxy';
|
||||
|
426
contracts/asset-proxy/test/lib_asset_data.ts
Normal file
426
contracts/asset-proxy/test/lib_asset_data.ts
Normal file
@ -0,0 +1,426 @@
|
||||
// TODO: change test titles to say "... from asset data"
|
||||
import * as chai from 'chai';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
|
||||
import {
|
||||
artifacts as erc1155Artifacts,
|
||||
ERC1155MintableContract,
|
||||
ERC1155TransferSingleEventArgs,
|
||||
IERC1155MintableContract,
|
||||
} from '@0x/contracts-erc1155';
|
||||
import { artifacts as erc20Artifacts, DummyERC20TokenContract, IERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { artifacts as erc721Artifacts, DummyERC721TokenContract, IERC721TokenContract } from '@0x/contracts-erc721';
|
||||
import { chaiSetup, constants, LogDecoder, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { artifacts, LibAssetDataContract } from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
const KNOWN_ERC20_ENCODING = {
|
||||
address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
|
||||
assetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48',
|
||||
};
|
||||
const KNOWN_ERC721_ENCODING = {
|
||||
address: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
|
||||
tokenId: new BigNumber(1),
|
||||
assetData:
|
||||
'0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001',
|
||||
};
|
||||
const KNOWN_ERC1155_ENCODING = {
|
||||
tokenAddress: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48',
|
||||
tokenIds: [new BigNumber(100), new BigNumber(1001), new BigNumber(10001)],
|
||||
tokenValues: [new BigNumber(200), new BigNumber(2001), new BigNumber(20001)],
|
||||
callbackData:
|
||||
'0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001',
|
||||
assetData:
|
||||
'0xa7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000',
|
||||
};
|
||||
const KNOWN_MULTI_ASSET_ENCODING = {
|
||||
amounts: [new BigNumber(70), new BigNumber(1), new BigNumber(18)],
|
||||
nestedAssetData: [
|
||||
KNOWN_ERC20_ENCODING.assetData,
|
||||
KNOWN_ERC721_ENCODING.assetData,
|
||||
KNOWN_ERC1155_ENCODING.assetData,
|
||||
],
|
||||
assetData:
|
||||
'0x94cfcdd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000046000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000204a7cb5fb70000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000002711000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000007d10000000000000000000000000000000000000000000000000000000000004e210000000000000000000000000000000000000000000000000000000000000044025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c4800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||
};
|
||||
|
||||
describe('LibAssetData', () => {
|
||||
let libAssetData: LibAssetDataContract;
|
||||
|
||||
let tokenOwnerAddress: string;
|
||||
let approvedSpenderAddress: string;
|
||||
let anotherApprovedSpenderAddress: string;
|
||||
|
||||
let erc20TokenAddress: string;
|
||||
const erc20TokenTotalSupply = new BigNumber(1);
|
||||
|
||||
let erc721TokenAddress: string;
|
||||
const firstERC721TokenId = new BigNumber(1);
|
||||
const numberOfERC721Tokens = 10;
|
||||
|
||||
let erc1155MintableAddress: string;
|
||||
let erc1155TokenId: BigNumber;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
|
||||
libAssetData = await LibAssetDataContract.deployFrom0xArtifactAsync(
|
||||
artifacts.LibAssetData,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
|
||||
[
|
||||
tokenOwnerAddress,
|
||||
approvedSpenderAddress,
|
||||
anotherApprovedSpenderAddress,
|
||||
] = await web3Wrapper.getAvailableAddressesAsync();
|
||||
|
||||
erc20TokenAddress = (await DummyERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
erc20Artifacts.DummyERC20Token,
|
||||
provider,
|
||||
txDefaults,
|
||||
'Dummy',
|
||||
'DUM',
|
||||
new BigNumber(1),
|
||||
erc20TokenTotalSupply,
|
||||
)).address;
|
||||
|
||||
const erc721TokenContract = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
|
||||
erc721Artifacts.DummyERC721Token,
|
||||
provider,
|
||||
txDefaults,
|
||||
'Dummy',
|
||||
'DUM',
|
||||
);
|
||||
erc721TokenAddress = erc721TokenContract.address;
|
||||
// mint `numberOfERC721Tokens` tokens
|
||||
const transactionMinedPromises = [];
|
||||
for (let i = 0; i < numberOfERC721Tokens; i++) {
|
||||
transactionMinedPromises.push(
|
||||
web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc721TokenContract.mint.sendTransactionAsync(
|
||||
tokenOwnerAddress,
|
||||
firstERC721TokenId.plus(i - 1),
|
||||
),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
),
|
||||
);
|
||||
}
|
||||
await Promise.all(transactionMinedPromises);
|
||||
|
||||
const erc1155MintableContract = await ERC1155MintableContract.deployFrom0xArtifactAsync(
|
||||
erc1155Artifacts.ERC1155Mintable,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
erc1155MintableAddress = erc1155MintableContract.address;
|
||||
// Somewhat re-inventing the wheel here, but the prior art currently
|
||||
// exists only as an unexported test util in the erc1155 package
|
||||
// (Erc1155Wrapper.mintFungibleTokensAsync() in erc1155/test/utils/).
|
||||
// This is concise enough to justify duplication, but it sure is ugly.
|
||||
// tslint:disable-next-line no-unnecessary-type-assertion
|
||||
erc1155TokenId = ((await new LogDecoder(web3Wrapper, erc1155Artifacts).getTxWithDecodedLogsAsync(
|
||||
await erc1155MintableContract.create.sendTransactionAsync('uri:Dummy', /*isNonFungible:*/ false),
|
||||
)).logs[0] as LogWithDecodedArgs<ERC1155TransferSingleEventArgs>).args.id;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc1155MintableContract.mintFungible.sendTransactionAsync(
|
||||
erc1155TokenId,
|
||||
[tokenOwnerAddress],
|
||||
[new BigNumber(1)],
|
||||
),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
});
|
||||
|
||||
async function setERC20AllowanceAsync(): Promise<any> {
|
||||
return web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await new IERC20TokenContract(
|
||||
erc20Artifacts.IERC20Token.compilerOutput.abi,
|
||||
erc20TokenAddress,
|
||||
provider,
|
||||
).approve.sendTransactionAsync(approvedSpenderAddress, new BigNumber(1), { from: tokenOwnerAddress }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
}
|
||||
|
||||
async function setERC721AllowanceAsync(): Promise<any> {
|
||||
return web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await new IERC721TokenContract(
|
||||
erc721Artifacts.IERC721Token.compilerOutput.abi,
|
||||
erc721TokenAddress,
|
||||
provider,
|
||||
).approve.sendTransactionAsync(approvedSpenderAddress, new BigNumber(1), { from: tokenOwnerAddress }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
}
|
||||
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
it('should have a deployed-to address', () => {
|
||||
expect(libAssetData.address.slice(0, 2)).to.equal('0x');
|
||||
});
|
||||
|
||||
it('should encode ERC20 asset data', async () => {
|
||||
expect(await libAssetData.encodeERC20AssetData.callAsync(KNOWN_ERC20_ENCODING.address)).to.equal(
|
||||
KNOWN_ERC20_ENCODING.assetData,
|
||||
);
|
||||
});
|
||||
|
||||
it('should decode ERC20 asset data', async () => {
|
||||
expect(await libAssetData.decodeERC20AssetData.callAsync(KNOWN_ERC20_ENCODING.assetData)).to.deep.equal([
|
||||
AssetProxyId.ERC20,
|
||||
KNOWN_ERC20_ENCODING.address,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should encode ERC721 asset data', async () => {
|
||||
expect(
|
||||
await libAssetData.encodeERC721AssetData.callAsync(
|
||||
KNOWN_ERC721_ENCODING.address,
|
||||
KNOWN_ERC721_ENCODING.tokenId,
|
||||
),
|
||||
).to.equal(KNOWN_ERC721_ENCODING.assetData);
|
||||
});
|
||||
|
||||
it('should decode ERC721 asset data', async () => {
|
||||
expect(await libAssetData.decodeERC721AssetData.callAsync(KNOWN_ERC721_ENCODING.assetData)).to.deep.equal([
|
||||
AssetProxyId.ERC721,
|
||||
KNOWN_ERC721_ENCODING.address,
|
||||
KNOWN_ERC721_ENCODING.tokenId,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should encode ERC1155 asset data', async () => {
|
||||
expect(
|
||||
await libAssetData.encodeERC1155AssetData.callAsync(
|
||||
KNOWN_ERC1155_ENCODING.tokenAddress,
|
||||
KNOWN_ERC1155_ENCODING.tokenIds,
|
||||
KNOWN_ERC1155_ENCODING.tokenValues,
|
||||
KNOWN_ERC1155_ENCODING.callbackData,
|
||||
),
|
||||
).to.equal(KNOWN_ERC1155_ENCODING.assetData);
|
||||
});
|
||||
|
||||
it('should decode ERC1155 asset data', async () => {
|
||||
expect(await libAssetData.decodeERC1155AssetData.callAsync(KNOWN_ERC1155_ENCODING.assetData)).to.deep.equal([
|
||||
AssetProxyId.ERC1155,
|
||||
KNOWN_ERC1155_ENCODING.tokenAddress,
|
||||
KNOWN_ERC1155_ENCODING.tokenIds,
|
||||
KNOWN_ERC1155_ENCODING.tokenValues,
|
||||
KNOWN_ERC1155_ENCODING.callbackData,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should encode multiasset data', async () => {
|
||||
expect(
|
||||
await libAssetData.encodeMultiAssetData.callAsync(
|
||||
KNOWN_MULTI_ASSET_ENCODING.amounts,
|
||||
KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
|
||||
),
|
||||
).to.equal(KNOWN_MULTI_ASSET_ENCODING.assetData);
|
||||
});
|
||||
|
||||
it('should decode multiasset data', async () => {
|
||||
expect(await libAssetData.decodeMultiAssetData.callAsync(KNOWN_MULTI_ASSET_ENCODING.assetData)).to.deep.equal([
|
||||
AssetProxyId.MultiAsset,
|
||||
KNOWN_MULTI_ASSET_ENCODING.amounts,
|
||||
KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should query ERC20 balance by asset data', async () => {
|
||||
expect(
|
||||
await libAssetData.getBalance.callAsync(
|
||||
tokenOwnerAddress,
|
||||
await libAssetData.encodeERC20AssetData.callAsync(erc20TokenAddress),
|
||||
),
|
||||
).to.bignumber.equal(erc20TokenTotalSupply);
|
||||
});
|
||||
|
||||
it('should query ERC721 balance by asset data', async () => {
|
||||
expect(
|
||||
await libAssetData.getBalance.callAsync(
|
||||
tokenOwnerAddress,
|
||||
await libAssetData.encodeERC721AssetData.callAsync(erc721TokenAddress, firstERC721TokenId),
|
||||
),
|
||||
).to.bignumber.equal(1);
|
||||
});
|
||||
|
||||
it('should query ERC1155 balances by asset data', async () => {
|
||||
expect(
|
||||
await libAssetData.getBalance.callAsync(
|
||||
tokenOwnerAddress,
|
||||
await libAssetData.encodeERC1155AssetData.callAsync(
|
||||
erc1155MintableAddress,
|
||||
[erc1155TokenId],
|
||||
[new BigNumber(1)], // token values
|
||||
'0x', // callback data
|
||||
),
|
||||
),
|
||||
).to.bignumber.equal(1);
|
||||
});
|
||||
|
||||
it('should query multi-asset batch balance by asset data', async () => {
|
||||
expect(
|
||||
await libAssetData.getBalance.callAsync(
|
||||
tokenOwnerAddress,
|
||||
await libAssetData.encodeMultiAssetData.callAsync(
|
||||
[new BigNumber(1), new BigNumber(1)],
|
||||
[
|
||||
await libAssetData.encodeERC20AssetData.callAsync(erc20TokenAddress),
|
||||
await libAssetData.encodeERC721AssetData.callAsync(erc721TokenAddress, firstERC721TokenId),
|
||||
],
|
||||
),
|
||||
),
|
||||
).to.bignumber.equal(Math.min(erc20TokenTotalSupply.toNumber(), numberOfERC721Tokens));
|
||||
});
|
||||
|
||||
it('should query ERC20 allowances by asset data', async () => {
|
||||
await setERC20AllowanceAsync();
|
||||
expect(
|
||||
await libAssetData.getAllowance.callAsync(
|
||||
tokenOwnerAddress,
|
||||
approvedSpenderAddress,
|
||||
await libAssetData.encodeERC20AssetData.callAsync(erc20TokenAddress),
|
||||
),
|
||||
).to.bignumber.equal(1);
|
||||
});
|
||||
|
||||
it('should query ERC721 approval by asset data', async () => {
|
||||
await setERC721AllowanceAsync();
|
||||
expect(
|
||||
await libAssetData.getAllowance.callAsync(
|
||||
tokenOwnerAddress,
|
||||
approvedSpenderAddress,
|
||||
await libAssetData.encodeERC721AssetData.callAsync(erc721TokenAddress, firstERC721TokenId),
|
||||
),
|
||||
).to.bignumber.equal(1);
|
||||
});
|
||||
|
||||
it('should query ERC721 approvalForAll by assetData', async () => {
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await new IERC721TokenContract(
|
||||
erc721Artifacts.IERC721Token.compilerOutput.abi,
|
||||
erc721TokenAddress,
|
||||
provider,
|
||||
).setApprovalForAll.sendTransactionAsync(anotherApprovedSpenderAddress, true, {
|
||||
from: tokenOwnerAddress,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
expect(
|
||||
await libAssetData.getAllowance.callAsync(
|
||||
tokenOwnerAddress,
|
||||
anotherApprovedSpenderAddress,
|
||||
await libAssetData.encodeERC721AssetData.callAsync(erc721TokenAddress, firstERC721TokenId),
|
||||
),
|
||||
).to.bignumber.equal(1);
|
||||
});
|
||||
|
||||
it('should query ERC1155 allowances by asset data', async () => {
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await new IERC1155MintableContract(
|
||||
erc1155Artifacts.IERC1155Mintable.compilerOutput.abi,
|
||||
erc1155MintableAddress,
|
||||
provider,
|
||||
).setApprovalForAll.sendTransactionAsync(approvedSpenderAddress, true, { from: tokenOwnerAddress }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
expect(
|
||||
await libAssetData.getAllowance.callAsync(
|
||||
tokenOwnerAddress,
|
||||
approvedSpenderAddress,
|
||||
await libAssetData.encodeERC1155AssetData.callAsync(
|
||||
erc1155MintableAddress,
|
||||
[erc1155TokenId],
|
||||
[new BigNumber(1)],
|
||||
'0x',
|
||||
),
|
||||
),
|
||||
).to.bignumber.equal(1);
|
||||
});
|
||||
|
||||
it('should query multi-asset allowances by asset data', async () => {
|
||||
await setERC20AllowanceAsync();
|
||||
await setERC721AllowanceAsync();
|
||||
expect(
|
||||
await libAssetData.getAllowance.callAsync(
|
||||
tokenOwnerAddress,
|
||||
approvedSpenderAddress,
|
||||
await libAssetData.encodeMultiAssetData.callAsync(
|
||||
[new BigNumber(1), new BigNumber(1)],
|
||||
[
|
||||
await libAssetData.encodeERC20AssetData.callAsync(erc20TokenAddress),
|
||||
await libAssetData.encodeERC721AssetData.callAsync(erc721TokenAddress, firstERC721TokenId),
|
||||
],
|
||||
),
|
||||
),
|
||||
).to.bignumber.equal(1);
|
||||
return;
|
||||
});
|
||||
|
||||
it('should query balances for a batch of asset data strings', async () => {
|
||||
expect(
|
||||
await libAssetData.getBatchBalances.callAsync(tokenOwnerAddress, [
|
||||
await libAssetData.encodeERC20AssetData.callAsync(erc20TokenAddress),
|
||||
await libAssetData.encodeERC721AssetData.callAsync(erc721TokenAddress, firstERC721TokenId),
|
||||
]),
|
||||
).to.deep.equal([new BigNumber(erc20TokenTotalSupply), new BigNumber(1)]);
|
||||
});
|
||||
|
||||
it('should query allowances for a batch of asset data strings', async () => {
|
||||
await setERC20AllowanceAsync();
|
||||
await setERC721AllowanceAsync();
|
||||
expect(
|
||||
await libAssetData.getBatchAllowances.callAsync(tokenOwnerAddress, approvedSpenderAddress, [
|
||||
await libAssetData.encodeERC20AssetData.callAsync(erc20TokenAddress),
|
||||
await libAssetData.encodeERC721AssetData.callAsync(erc721TokenAddress, firstERC721TokenId),
|
||||
]),
|
||||
).to.deep.equal([new BigNumber(1), new BigNumber(1)]);
|
||||
});
|
||||
|
||||
describe('getERC721TokenOwner', async () => {
|
||||
it('should return the null address when tokenId is not owned', async () => {
|
||||
const nonexistentTokenId = new BigNumber(1234567890);
|
||||
expect(
|
||||
await libAssetData.getERC721TokenOwner.callAsync(erc721TokenAddress, nonexistentTokenId),
|
||||
).to.be.equal(constants.NULL_ADDRESS);
|
||||
});
|
||||
it('should return the owner address when tokenId is owned', async () => {
|
||||
expect(
|
||||
await libAssetData.getERC721TokenOwner.callAsync(erc721TokenAddress, firstERC721TokenId),
|
||||
).to.be.equal(tokenOwnerAddress);
|
||||
});
|
||||
});
|
||||
|
||||
it('should query balance and allowance together, from asset data', async () => {
|
||||
await setERC20AllowanceAsync();
|
||||
expect(
|
||||
await libAssetData.getBalanceAndAllowance.callAsync(
|
||||
tokenOwnerAddress,
|
||||
approvedSpenderAddress,
|
||||
await libAssetData.encodeERC20AssetData.callAsync(erc20TokenAddress),
|
||||
),
|
||||
).to.deep.equal([new BigNumber(erc20TokenTotalSupply), new BigNumber(1)]);
|
||||
});
|
||||
|
||||
it('should query balances and allowances together, from an asset data array', async () => {
|
||||
await setERC20AllowanceAsync();
|
||||
expect(
|
||||
await libAssetData.getBatchBalancesAndAllowances.callAsync(tokenOwnerAddress, approvedSpenderAddress, [
|
||||
await libAssetData.encodeERC20AssetData.callAsync(erc20TokenAddress),
|
||||
]),
|
||||
).to.deep.equal([[new BigNumber(erc20TokenTotalSupply)], [new BigNumber(1)]]);
|
||||
});
|
||||
});
|
@ -9,6 +9,7 @@
|
||||
"generated-artifacts/IAssetData.json",
|
||||
"generated-artifacts/IAssetProxy.json",
|
||||
"generated-artifacts/IAuthorizable.json",
|
||||
"generated-artifacts/LibAssetData.json",
|
||||
"generated-artifacts/MixinAuthorizable.json",
|
||||
"generated-artifacts/MultiAssetProxy.json"
|
||||
],
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"artifactsDir": "./generated-artifacts",
|
||||
"contractsDir": "./contracts",
|
||||
"useDockerisedSolc": true,
|
||||
"useDockerisedSolc": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"optimizer": {
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"artifactsDir": "./generated-artifacts",
|
||||
"contractsDir": "./contracts",
|
||||
"useDockerisedSolc": true,
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"artifactsDir": "./generated-artifacts",
|
||||
"contractsDir": "./contracts",
|
||||
"useDockerisedSolc": true,
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"artifactsDir": "./generated-artifacts",
|
||||
"contractsDir": "./contracts",
|
||||
"useDockerisedSolc": true,
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"artifactsDir": "./generated-artifacts",
|
||||
"contractsDir": "./contracts",
|
||||
"useDockerisedSolc": true,
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
|
@ -23,11 +23,6 @@ describe('LibAddressArray', () => {
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
// Deploy LibAddressArray
|
||||
lib = await TestLibAddressArrayContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestLibAddressArray,
|
||||
@ -35,10 +30,7 @@ describe('LibAddressArray', () => {
|
||||
txDefaults,
|
||||
);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user