Merge pull request #2440 from 0xProject/feat/dev-utils/chai-bridge-validation

Add ChaiBridge order balance/allowance checks to DevUtils
This commit is contained in:
Amir Bandeali 2020-01-17 11:46:27 -08:00 committed by GitHub
commit 28d1f3eef0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 578 additions and 72 deletions

View File

@ -18,10 +18,22 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
contract PotLike {
function chi() external returns (uint256);
function rho() external returns (uint256);
function drip() external returns (uint256);
function join(uint256) external;
function exit(uint256) external;
}
// The actual Chai contract can be found here: https://github.com/dapphub/chai // The actual Chai contract can be found here: https://github.com/dapphub/chai
contract IChai { contract IChai is
IERC20Token
{
/// @dev Withdraws Dai owned by `src` /// @dev Withdraws Dai owned by `src`
/// @param src Address that owns Dai. /// @param src Address that owns Dai.
/// @param wad Amount of Dai to withdraw. /// @param wad Amount of Dai to withdraw.
@ -30,4 +42,25 @@ contract IChai {
uint256 wad uint256 wad
) )
external; external;
/// @dev Queries Dai balance of Chai holder.
/// @param usr Address of Chai holder.
/// @return Dai balance.
function dai(address usr)
external
returns (uint256);
/// @dev Queries the Pot contract used by the Chai contract.
function pot()
external
returns (PotLike);
/// @dev Deposits Dai in exchange for Chai
/// @param dst Address to receive Chai.
/// @param wad Amount of Dai to deposit.
function join(
address dst,
uint256 wad
)
external;
} }

View File

@ -15,6 +15,7 @@ export {
UniswapBridgeContract, UniswapBridgeContract,
KyberBridgeContract, KyberBridgeContract,
ChaiBridgeContract, ChaiBridgeContract,
IChaiContract,
} from './wrappers'; } from './wrappers';
export { ERC20Wrapper } from './erc20_wrapper'; export { ERC20Wrapper } from './erc20_wrapper';

View File

@ -37,14 +37,24 @@ contract DevUtils is
LibEIP712ExchangeDomain, LibEIP712ExchangeDomain,
EthBalanceChecker EthBalanceChecker
{ {
constructor (address _exchange) constructor (
address _exchange,
address _chaiBridge
)
public public
OrderValidationUtils(_exchange) OrderValidationUtils(
_exchange,
_chaiBridge
)
OrderTransferSimulationUtils(_exchange) OrderTransferSimulationUtils(_exchange)
LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants
{} {}
function getOrderHash(LibOrder.Order memory order, uint256 chainId, address exchange) function getOrderHash(
LibOrder.Order memory order,
uint256 chainId,
address exchange
)
public public
pure pure
returns (bytes32 orderHash) returns (bytes32 orderHash)

View File

@ -26,10 +26,14 @@ import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol"; import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.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 { contract LibAssetData is
DeploymentConstants
{
// 2^256 - 1 // 2^256 - 1
uint256 constant internal _MAX_UINT256 = uint256(-1); uint256 constant internal _MAX_UINT256 = uint256(-1);
@ -41,9 +45,13 @@ contract LibAssetData {
address internal _ERC721_PROXY_ADDRESS; address internal _ERC721_PROXY_ADDRESS;
address internal _ERC1155_PROXY_ADDRESS; address internal _ERC1155_PROXY_ADDRESS;
address internal _STATIC_CALL_PROXY_ADDRESS; address internal _STATIC_CALL_PROXY_ADDRESS;
address internal _CHAI_BRIDGE_ADDRESS;
// solhint-enable var-name-mixedcase // solhint-enable var-name-mixedcase
constructor (address _exchange) constructor (
address _exchange,
address _chaiBridge
)
public public
{ {
_EXCHANGE = IExchange(_exchange); _EXCHANGE = IExchange(_exchange);
@ -51,6 +59,7 @@ contract LibAssetData {
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector); _ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector);
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector); _ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
_STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).StaticCall.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 /// @dev Returns the owner's balance of the assets(s) specified in
@ -62,7 +71,6 @@ contract LibAssetData {
/// @return Number of assets (or asset baskets) held by owner. /// @return Number of assets (or asset baskets) held by owner.
function getBalance(address ownerAddress, bytes memory assetData) function getBalance(address ownerAddress, bytes memory assetData)
public public
view
returns (uint256 balance) returns (uint256 balance)
{ {
// Get id of AssetProxy contract // Get id of AssetProxy contract
@ -71,16 +79,8 @@ contract LibAssetData {
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) { if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
// Get ERC20 token address // Get ERC20 token address
address tokenAddress = assetData.readAddress(16); address tokenAddress = assetData.readAddress(16);
balance = _erc20BalanceOf(tokenAddress, ownerAddress);
// 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;
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
// Get ERC721 token address and id // Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData); (, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
@ -94,6 +94,7 @@ contract LibAssetData {
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata); (bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0); address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
balance = currentOwnerAddress == ownerAddress ? 1 : 0; balance = currentOwnerAddress == ownerAddress ? 1 : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address, array of ids, and array of values // Get ERC1155 token address, array of ids, and array of values
(, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData); (, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData);
@ -125,6 +126,7 @@ contract LibAssetData {
balance = scaledBalance; balance = scaledBalance;
} }
} }
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// Encode data for `staticCallProxy.transferFrom(assetData,...)` // Encode data for `staticCallProxy.transferFrom(assetData,...)`
bytes memory transferFromData = abi.encodeWithSelector( bytes memory transferFromData = abi.encodeWithSelector(
@ -140,6 +142,17 @@ contract LibAssetData {
// Success means that the staticcall can be made an unlimited amount of times // Success means that the staticcall can be made an unlimited amount of times
balance = success ? _MAX_UINT256 : 0; 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) { } else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
// Get array of values and array of assetDatas // Get array of values and array of assetDatas
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData); (, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
@ -176,7 +189,6 @@ contract LibAssetData {
/// corresponding to the same-indexed element in the assetData input. /// corresponding to the same-indexed element in the assetData input.
function getBatchBalances(address ownerAddress, bytes[] memory assetData) function getBatchBalances(address ownerAddress, bytes[] memory assetData)
public public
view
returns (uint256[] memory balances) returns (uint256[] memory balances)
{ {
uint256 length = assetData.length; uint256 length = assetData.length;
@ -197,7 +209,6 @@ contract LibAssetData {
/// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend. /// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getAssetProxyAllowance(address ownerAddress, bytes memory assetData) function getAssetProxyAllowance(address ownerAddress, bytes memory assetData)
public public
view
returns (uint256 allowance) returns (uint256 allowance)
{ {
// Get id of AssetProxy contract // Get id of AssetProxy contract
@ -243,6 +254,7 @@ contract LibAssetData {
// Query allowance // Query allowance
(bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData); (bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData);
allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0; allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) { } else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
// Get ERC721 token address and id // Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData); (, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
@ -268,6 +280,7 @@ contract LibAssetData {
// Allowance is 2^256 - 1 if `isApprovedForAll` returned true // Allowance is 2^256 - 1 if `isApprovedForAll` returned true
allowance = _MAX_UINT256; allowance = _MAX_UINT256;
} }
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) { } else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address // Get ERC1155 token address
(, address tokenAddress, , , ) = decodeERC1155AssetData(assetData); (, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
@ -282,9 +295,26 @@ contract LibAssetData {
// Query allowance // Query allowance
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData); (bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0; allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// The StaticCallProxy does not require any approvals // The StaticCallProxy does not require any approvals
allowance = _MAX_UINT256; 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 // Allowance will be 0 if the assetProxyId is unknown
@ -298,7 +328,6 @@ contract LibAssetData {
/// element corresponding to the same-indexed element in the assetData input. /// element corresponding to the same-indexed element in the assetData input.
function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData) function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
public public
view
returns (uint256[] memory allowances) returns (uint256[] memory allowances)
{ {
uint256 length = assetData.length; uint256 length = assetData.length;
@ -316,7 +345,6 @@ contract LibAssetData {
/// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend. /// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData) function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData)
public public
view
returns (uint256 balance, uint256 allowance) returns (uint256 balance, uint256 allowance)
{ {
balance = getBalance(ownerAddress, assetData); balance = getBalance(ownerAddress, assetData);
@ -332,7 +360,6 @@ contract LibAssetData {
/// corresponding to the same-indexed element in the assetData input. /// corresponding to the same-indexed element in the assetData input.
function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData) function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
public public
view
returns (uint256[] memory balances, uint256[] memory allowances) returns (uint256[] memory balances, uint256[] memory allowances)
{ {
balances = getBatchBalances(ownerAddress, assetData); balances = getBatchBalances(ownerAddress, assetData);
@ -613,6 +640,35 @@ contract LibAssetData {
); );
} }
/// @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
)
{
assetProxyId = assetData.readBytes4(0);
require(
assetProxyId == IAssetData(address(0)).ERC20Bridge.selector,
"WRONG_PROXY_ID"
);
(tokenAddress, bridgeAddress, bridgeData) = abi.decode(
assetData.slice(4, assetData.length),
(address, address, bytes)
);
}
/// @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) function revertIfInvalidAssetData(bytes memory assetData)
public public
pure pure
@ -629,8 +685,50 @@ contract LibAssetData {
decodeMultiAssetData(assetData); decodeMultiAssetData(assetData);
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) { } else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
decodeStaticCallAssetData(assetData); decodeStaticCallAssetData(assetData);
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
decodeERC20BridgeAssetData(assetData);
} else { } else {
revert("WRONG_PROXY_ID"); revert("WRONG_PROXY_ID");
} }
} }
/// @dev Queries balance of an ERC20 token. Returns 0 if call was unsuccessful.
/// @param tokenAddress Address of ERC20 token.
/// @param ownerAddress Address of owner of ERC20 token.
/// @return balance ERC20 token balance of owner.
function _erc20BalanceOf(
address tokenAddress,
address ownerAddress
)
internal
view
returns (uint256 balance)
{
// Encode data for `balanceOf(ownerAddress)`
bytes memory balanceOfData = abi.encodeWithSelector(
IERC20Token(address(0)).balanceOf.selector,
ownerAddress
);
// Query balance
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
return balance;
}
/// @dev Converts an amount of Chai into its equivalent Dai amount.
/// Also accumulates Dai from DSR if called after the last time it was collected.
/// @param chaiAmount Amount of Chai to converts.
function _convertChaiToDaiAmount(uint256 chaiAmount)
internal
returns (uint256 daiAmount)
{
PotLike pot = IChai(_getChaiAddress()).pot();
// Accumulate savings if called after last time savings were collected
uint256 chiMultiplier = (now > pot.rho())
? pot.drip()
: pot.chi();
daiAmount = LibMath.getPartialAmountFloor(chiMultiplier, 10**27, chaiAmount);
return daiAmount;
}
} }

View File

@ -35,9 +35,15 @@ contract OrderValidationUtils is
using LibBytes for bytes; using LibBytes for bytes;
using LibSafeMath for uint256; using LibSafeMath for uint256;
constructor (address _exchange) constructor (
address _exchange,
address _chaiBridge
)
public public
LibAssetData(_exchange) LibAssetData(
_exchange,
_chaiBridge
)
{} {}
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable. /// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
@ -173,7 +179,6 @@ contract OrderValidationUtils is
/// the individual asset amounts located within the `assetData`. /// the individual asset amounts located within the `assetData`.
function getTransferableAssetAmount(address ownerAddress, bytes memory assetData) function getTransferableAssetAmount(address ownerAddress, bytes memory assetData)
public public
view
returns (uint256 transferableAssetAmount) returns (uint256 transferableAssetAmount)
{ {
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData); (uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData);

View File

@ -14,7 +14,7 @@ import { contractAddresses, dydxAccountOwner } from '../mainnet_fork_utils';
import { dydxEvents } from './abi/dydxEvents'; import { dydxEvents } from './abi/dydxEvents';
blockchainTests.fork.resets('Mainnet dydx bridge tests', env => { blockchainTests.fork.skip('Mainnet dydx bridge tests', env => {
let testContract: DydxBridgeContract; let testContract: DydxBridgeContract;
// random account to receive tokens from dydx // random account to receive tokens from dydx
const receiver = '0x986ccf5234d9cfbb25246f1a5bfa51f4ccfcb308'; const receiver = '0x986ccf5234d9cfbb25246f1a5bfa51f4ccfcb308';

View File

@ -0,0 +1,76 @@
import { IChaiContract } from '@0x/contracts-asset-proxy';
import { artifacts as devUtilsArtifacts, DevUtilsContract } from '@0x/contracts-dev-utils';
import { ERC20TokenContract } from '@0x/contracts-erc20';
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
import { assetDataUtils } from '@0x/order-utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { contractAddresses } from '../mainnet_fork_utils';
blockchainTests.fork.resets('DevUtils mainnet tests', env => {
const daiAddress = '0x6b175474e89094c44da98b954eedeac495271d0f';
const chaiAddress = '0x06af07097c9eeb7fd685c692751d5c66db49c215';
const daiHolder = '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b';
let noDaiAddress: string;
const assetData = assetDataUtils.encodeERC20BridgeAssetData(
daiAddress,
contractAddresses.chaiBridge,
constants.NULL_BYTES,
);
const dai = new ERC20TokenContract(daiAddress, env.provider, env.txDefaults);
const chai = new IChaiContract(chaiAddress, env.provider, env.txDefaults);
let devUtils: DevUtilsContract;
const daiDepositAmount = Web3Wrapper.toBaseUnitAmount(1000, 18);
before(async () => {
[noDaiAddress] = await env.getAccountAddressesAsync();
devUtils = await DevUtilsContract.deployFrom0xArtifactAsync(
devUtilsArtifacts.DevUtils,
env.provider,
env.txDefaults,
devUtilsArtifacts,
contractAddresses.exchange,
contractAddresses.chaiBridge,
);
await dai.approve(chai.address, constants.MAX_UINT256).awaitTransactionSuccessAsync({ from: daiHolder });
await chai.join(daiHolder, daiDepositAmount).awaitTransactionSuccessAsync({ from: daiHolder });
});
describe('LibAssetData', () => {
describe('ChaiBridge getBalance', () => {
it('should return the correct non-zero Dai balance for a Chai holder', async () => {
const expectedDaiBalance = await chai.dai(daiHolder).callAsync();
const daiBalance = await devUtils.getBalance(daiHolder, assetData).callAsync();
expect(daiBalance).bignumber.eq(expectedDaiBalance);
});
it('should return a balance of 0 when Chai balance is 0', async () => {
const daiBalance = await devUtils.getBalance(noDaiAddress, assetData).callAsync();
expect(daiBalance).bignumber.eq(constants.ZERO_AMOUNT);
});
});
describe('ChaiBridge getProxyAllowance', () => {
it('should return the correct non-zero non-unlimited allowance', async () => {
const chaiBalance = await chai.balanceOf(daiHolder).callAsync();
await chai
.approve(contractAddresses.chaiBridge, chaiBalance)
.awaitTransactionSuccessAsync({ from: daiHolder });
const daiBalance = await chai.dai(daiHolder).callAsync();
const allowance = await devUtils.getAssetProxyAllowance(daiHolder, assetData).callAsync();
expect(allowance).to.bignumber.eq(daiBalance);
});
it('should return an unlimited allowance of Dai when Chai allowance is also unlimited', async () => {
await chai
.approve(contractAddresses.chaiBridge, constants.MAX_UINT256)
.awaitTransactionSuccessAsync({ from: daiHolder });
const allowance = await devUtils.getAssetProxyAllowance(daiHolder, assetData).callAsync();
expect(allowance).to.bignumber.eq(constants.MAX_UINT256);
});
it('should return an allowance of 0 when Chai allowance is 0', async () => {
const allowance = await devUtils.getAssetProxyAllowance(noDaiAddress, assetData).callAsync();
expect(allowance).to.bignumber.eq(constants.ZERO_AMOUNT);
});
});
});
});

View File

@ -25,6 +25,7 @@ blockchainTests('DevUtils.getOrderHash', env => {
env.txDefaults, env.txDefaults,
artifacts, artifacts,
exchange.address, exchange.address,
constants.NULL_ADDRESS,
); );
}); });

View File

@ -79,6 +79,7 @@ blockchainTests.resets('LibAssetData', env => {
env.txDefaults, env.txDefaults,
artifacts, artifacts,
deployment.exchange.address, deployment.exchange.address,
constants.NULL_ADDRESS,
); );
staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync( staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync(

View File

@ -203,6 +203,7 @@ export class DeploymentManager {
environment.txDefaults, environment.txDefaults,
devUtilsArtifacts, devUtilsArtifacts,
exchange.address, exchange.address,
constants.NULL_ADDRESS,
); );
const assetDataEncoder = new IAssetDataContract(constants.NULL_ADDRESS, environment.provider); const assetDataEncoder = new IAssetDataContract(constants.NULL_ADDRESS, environment.provider);

View File

@ -7,7 +7,7 @@ import { BigNumber } from '@0x/utils';
import { contractAddresses, getContractwrappers } from './mainnet_fork_utils'; import { contractAddresses, getContractwrappers } from './mainnet_fork_utils';
blockchainTests.fork.resets('Mainnet configs tests', env => { blockchainTests.live('Mainnet configs tests', env => {
let contractWrappers: ContractWrappers; let contractWrappers: ContractWrappers;
before(async () => { before(async () => {

View File

@ -20,6 +20,7 @@ export let providerConfigs: Web3Config = {
shouldUseInProcessGanache: true, shouldUseInProcessGanache: true,
shouldAllowUnlimitedContractSize: true, shouldAllowUnlimitedContractSize: true,
hardfork: 'istanbul', hardfork: 'istanbul',
unlocked_accounts: ['0x6cc5f688a315f3dc28a7781717a9a798a59fda7b', '0x55dc8f21d20d4c6ed3c82916a438a413ca68e335'],
}; };
export const provider: Web3ProviderEngine = web3Factory.getRpcProvider(providerConfigs); export const provider: Web3ProviderEngine = web3Factory.getRpcProvider(providerConfigs);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -175,6 +175,7 @@ export async function runMigrationsAsync(
txDefaults, txDefaults,
artifacts, artifacts,
exchange.address, exchange.address,
constants.NULL_ADDRESS,
); );
// tslint:disable-next-line:no-unused-variable // tslint:disable-next-line:no-unused-variable

View File

@ -113,7 +113,7 @@ export async function runMigrationsAsync(supportedProvider: SupportedProvider, t
assetProxyArtifacts, assetProxyArtifacts,
); );
await ChaiBridgeContract.deployFrom0xArtifactAsync( const chaiBridge = await ChaiBridgeContract.deployFrom0xArtifactAsync(
assetProxyArtifacts.ChaiBridge, assetProxyArtifacts.ChaiBridge,
provider, provider,
txDefaults, txDefaults,
@ -251,6 +251,7 @@ export async function runMigrationsAsync(supportedProvider: SupportedProvider, t
txDefaults, txDefaults,
devUtilsArtifacts, devUtilsArtifacts,
exchange.address, exchange.address,
chaiBridge.address,
); );
await CoordinatorContract.deployFrom0xArtifactAsync( await CoordinatorContract.deployFrom0xArtifactAsync(