Feature/liquidity provider sandbox (#16)
* Update liquidity provider feature to use sandbox * add support for liquidity provider feature in the exchange proxy swap quote consumer * Move to off-chain liquidity provider registry * Update ILiquidityProvider interface * Remove some unused artifacts and wrappers * Consolidate ILiquidityProvider * prettier * lint * Address PR feedback * Add failover to sandbox * Add test for failover behavior in LiquidityProviderSandbox * Update changelogs * Emit events for the new LiquidityProvider scenarios * Fix swap quote consumer bug * post-rebase fixes * `@0x/contracts-zero-ex`: bump feature versions * Add default field to TokenAdjacencyGraph * update addresses Co-authored-by: Lawrence Forman <me@merklejerk.com>
This commit is contained in:
parent
75dcd687e2
commit
7403c0255a
@ -5,6 +5,18 @@
|
|||||||
{
|
{
|
||||||
"note": "Rewrite the ZeroEx contract in Yul",
|
"note": "Rewrite the ZeroEx contract in Yul",
|
||||||
"pr": 23
|
"pr": 23
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Update LiquidityProviderFeature to use off-chain registry and sandbox",
|
||||||
|
"pr": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Update ILiquidityProvider interface",
|
||||||
|
"pr": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Update ProtocolFeeUnfunded event to emit order hash",
|
||||||
|
"pr": 16
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -45,19 +45,4 @@ library LibLiquidityProviderRichErrors {
|
|||||||
minBuyAmount
|
minBuyAmount
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function NoLiquidityProviderForMarketError(
|
|
||||||
address xAsset,
|
|
||||||
address yAsset
|
|
||||||
)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (bytes memory)
|
|
||||||
{
|
|
||||||
return abi.encodeWithSelector(
|
|
||||||
bytes4(keccak256("NoLiquidityProviderForMarketError(address,address)")),
|
|
||||||
xAsset,
|
|
||||||
yAsset
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
74
contracts/zero-ex/contracts/src/external/ILiquidityProviderSandbox.sol
vendored
Normal file
74
contracts/zero-ex/contracts/src/external/ILiquidityProviderSandbox.sol
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2020 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.6.5;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
|
interface ILiquidityProviderSandbox {
|
||||||
|
|
||||||
|
/// @dev Calls `sellTokenForToken` on the given `provider` contract to
|
||||||
|
/// trigger a trade.
|
||||||
|
/// @param provider The address of the on-chain liquidity provider.
|
||||||
|
/// @param inputToken The token being sold.
|
||||||
|
/// @param outputToken The token being bought.
|
||||||
|
/// @param recipient The recipient of the bought tokens.
|
||||||
|
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||||
|
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||||
|
function executeSellTokenForToken(
|
||||||
|
address provider,
|
||||||
|
address inputToken,
|
||||||
|
address outputToken,
|
||||||
|
address recipient,
|
||||||
|
uint256 minBuyAmount,
|
||||||
|
bytes calldata auxiliaryData
|
||||||
|
)
|
||||||
|
external;
|
||||||
|
|
||||||
|
/// @dev Calls `sellEthForToken` on the given `provider` contract to
|
||||||
|
/// trigger a trade.
|
||||||
|
/// @param provider The address of the on-chain liquidity provider.
|
||||||
|
/// @param outputToken The token being bought.
|
||||||
|
/// @param recipient The recipient of the bought tokens.
|
||||||
|
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||||
|
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||||
|
function executeSellEthForToken(
|
||||||
|
address provider,
|
||||||
|
address outputToken,
|
||||||
|
address recipient,
|
||||||
|
uint256 minBuyAmount,
|
||||||
|
bytes calldata auxiliaryData
|
||||||
|
)
|
||||||
|
external;
|
||||||
|
|
||||||
|
/// @dev Calls `sellTokenForEth` on the given `provider` contract to
|
||||||
|
/// trigger a trade.
|
||||||
|
/// @param provider The address of the on-chain liquidity provider.
|
||||||
|
/// @param inputToken The token being sold.
|
||||||
|
/// @param recipient The recipient of the bought tokens.
|
||||||
|
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
|
||||||
|
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||||
|
function executeSellTokenForEth(
|
||||||
|
address provider,
|
||||||
|
address inputToken,
|
||||||
|
address recipient,
|
||||||
|
uint256 minBuyAmount,
|
||||||
|
bytes calldata auxiliaryData
|
||||||
|
)
|
||||||
|
external;
|
||||||
|
}
|
139
contracts/zero-ex/contracts/src/external/LiquidityProviderSandbox.sol
vendored
Normal file
139
contracts/zero-ex/contracts/src/external/LiquidityProviderSandbox.sol
vendored
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 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.6.5;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/src/v06/errors/LibOwnableRichErrorsV06.sol";
|
||||||
|
import "../vendor/ILiquidityProvider.sol";
|
||||||
|
import "../vendor/v3/IERC20Bridge.sol";
|
||||||
|
import "./ILiquidityProviderSandbox.sol";
|
||||||
|
|
||||||
|
|
||||||
|
/// @dev A permissionless contract through which the ZeroEx contract can
|
||||||
|
/// safely trigger a trade on an external `ILiquidityProvider` contract.
|
||||||
|
contract LiquidityProviderSandbox is
|
||||||
|
ILiquidityProviderSandbox
|
||||||
|
{
|
||||||
|
using LibRichErrorsV06 for bytes;
|
||||||
|
|
||||||
|
/// @dev Store the owner as an immutable.
|
||||||
|
address public immutable owner;
|
||||||
|
|
||||||
|
constructor(address owner_)
|
||||||
|
public
|
||||||
|
{
|
||||||
|
owner = owner_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Allows only the (immutable) owner to call a function.
|
||||||
|
modifier onlyOwner() virtual {
|
||||||
|
if (msg.sender != owner) {
|
||||||
|
LibOwnableRichErrorsV06.OnlyOwnerError(
|
||||||
|
msg.sender,
|
||||||
|
owner
|
||||||
|
).rrevert();
|
||||||
|
}
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Calls `sellTokenForToken` on the given `provider` contract to
|
||||||
|
/// trigger a trade.
|
||||||
|
/// @param provider The address of the on-chain liquidity provider.
|
||||||
|
/// @param inputToken The token being sold.
|
||||||
|
/// @param outputToken The token being bought.
|
||||||
|
/// @param recipient The recipient of the bought tokens.
|
||||||
|
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||||
|
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||||
|
function executeSellTokenForToken(
|
||||||
|
address provider,
|
||||||
|
address inputToken,
|
||||||
|
address outputToken,
|
||||||
|
address recipient,
|
||||||
|
uint256 minBuyAmount,
|
||||||
|
bytes calldata auxiliaryData
|
||||||
|
)
|
||||||
|
external
|
||||||
|
onlyOwner
|
||||||
|
override
|
||||||
|
{
|
||||||
|
try ILiquidityProvider(provider).sellTokenForToken(
|
||||||
|
inputToken,
|
||||||
|
outputToken,
|
||||||
|
recipient,
|
||||||
|
minBuyAmount,
|
||||||
|
auxiliaryData
|
||||||
|
) {} catch {
|
||||||
|
IERC20Bridge(provider).bridgeTransferFrom(
|
||||||
|
outputToken,
|
||||||
|
provider,
|
||||||
|
recipient,
|
||||||
|
minBuyAmount,
|
||||||
|
auxiliaryData
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Calls `sellEthForToken` on the given `provider` contract to
|
||||||
|
/// trigger a trade.
|
||||||
|
/// @param provider The address of the on-chain liquidity provider.
|
||||||
|
/// @param outputToken The token being bought.
|
||||||
|
/// @param recipient The recipient of the bought tokens.
|
||||||
|
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||||
|
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||||
|
function executeSellEthForToken(
|
||||||
|
address provider,
|
||||||
|
address outputToken,
|
||||||
|
address recipient,
|
||||||
|
uint256 minBuyAmount,
|
||||||
|
bytes calldata auxiliaryData
|
||||||
|
)
|
||||||
|
external
|
||||||
|
onlyOwner
|
||||||
|
override
|
||||||
|
{
|
||||||
|
ILiquidityProvider(provider).sellEthForToken(
|
||||||
|
outputToken,
|
||||||
|
recipient,
|
||||||
|
minBuyAmount,
|
||||||
|
auxiliaryData
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Calls `sellTokenForEth` on the given `provider` contract to
|
||||||
|
/// trigger a trade.
|
||||||
|
/// @param provider The address of the on-chain liquidity provider.
|
||||||
|
/// @param inputToken The token being sold.
|
||||||
|
/// @param recipient The recipient of the bought tokens.
|
||||||
|
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
|
||||||
|
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||||
|
function executeSellTokenForEth(
|
||||||
|
address provider,
|
||||||
|
address inputToken,
|
||||||
|
address recipient,
|
||||||
|
uint256 minBuyAmount,
|
||||||
|
bytes calldata auxiliaryData
|
||||||
|
)
|
||||||
|
external
|
||||||
|
onlyOwner
|
||||||
|
override
|
||||||
|
{
|
||||||
|
ILiquidityProvider(provider).sellTokenForEth(
|
||||||
|
inputToken,
|
||||||
|
payable(recipient),
|
||||||
|
minBuyAmount,
|
||||||
|
auxiliaryData
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -22,45 +22,30 @@ pragma experimental ABIEncoderV2;
|
|||||||
|
|
||||||
/// @dev Feature to swap directly with an on-chain liquidity provider.
|
/// @dev Feature to swap directly with an on-chain liquidity provider.
|
||||||
interface ILiquidityProviderFeature {
|
interface ILiquidityProviderFeature {
|
||||||
event LiquidityProviderForMarketUpdated(
|
|
||||||
address indexed xAsset,
|
|
||||||
address indexed yAsset,
|
|
||||||
address providerAddress
|
|
||||||
);
|
|
||||||
|
|
||||||
|
/// @dev Sells `sellAmount` of `inputToken` to the liquidity provider
|
||||||
|
/// at the given `provider` address.
|
||||||
|
/// @param inputToken The token being sold.
|
||||||
|
/// @param outputToken The token being bought.
|
||||||
|
/// @param provider The address of the on-chain liquidity provider
|
||||||
|
/// to trade with.
|
||||||
|
/// @param recipient The recipient of the bought tokens. If equal to
|
||||||
|
/// address(0), `msg.sender` is assumed to be the recipient.
|
||||||
|
/// @param sellAmount The amount of `inputToken` to sell.
|
||||||
|
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to
|
||||||
|
/// buy. Reverts if this amount is not satisfied.
|
||||||
|
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||||
|
/// @return boughtAmount The amount of `outputToken` bought.
|
||||||
function sellToLiquidityProvider(
|
function sellToLiquidityProvider(
|
||||||
address makerToken,
|
address inputToken,
|
||||||
address takerToken,
|
address outputToken,
|
||||||
address payable recipient,
|
address payable provider,
|
||||||
|
address recipient,
|
||||||
uint256 sellAmount,
|
uint256 sellAmount,
|
||||||
uint256 minBuyAmount
|
uint256 minBuyAmount,
|
||||||
|
bytes calldata auxiliaryData
|
||||||
)
|
)
|
||||||
external
|
external
|
||||||
payable
|
payable
|
||||||
returns (uint256 boughtAmount);
|
returns (uint256 boughtAmount);
|
||||||
|
|
||||||
/// @dev Sets address of the liquidity provider for a market given
|
|
||||||
/// (xAsset, yAsset).
|
|
||||||
/// @param xAsset First asset managed by the liquidity provider.
|
|
||||||
/// @param yAsset Second asset managed by the liquidity provider.
|
|
||||||
/// @param providerAddress Address of the liquidity provider.
|
|
||||||
function setLiquidityProviderForMarket(
|
|
||||||
address xAsset,
|
|
||||||
address yAsset,
|
|
||||||
address providerAddress
|
|
||||||
)
|
|
||||||
external;
|
|
||||||
|
|
||||||
/// @dev Returns the address of the liquidity provider for a market given
|
|
||||||
/// (xAsset, yAsset), or reverts if pool does not exist.
|
|
||||||
/// @param xAsset First asset managed by the liquidity provider.
|
|
||||||
/// @param yAsset Second asset managed by the liquidity provider.
|
|
||||||
/// @return providerAddress Address of the liquidity provider.
|
|
||||||
function getLiquidityProviderForMarket(
|
|
||||||
address xAsset,
|
|
||||||
address yAsset
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (address providerAddress);
|
|
||||||
}
|
}
|
||||||
|
@ -20,15 +20,13 @@ pragma solidity ^0.6.5;
|
|||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
|
||||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
|
||||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
||||||
import "../errors/LibLiquidityProviderRichErrors.sol";
|
import "../errors/LibLiquidityProviderRichErrors.sol";
|
||||||
|
import "../external/ILiquidityProviderSandbox.sol";
|
||||||
|
import "../external/LiquidityProviderSandbox.sol";
|
||||||
import "../fixins/FixinCommon.sol";
|
import "../fixins/FixinCommon.sol";
|
||||||
import "../migrations/LibMigrate.sol";
|
import "../migrations/LibMigrate.sol";
|
||||||
import "../storage/LibLiquidityProviderStorage.sol";
|
|
||||||
import "../vendor/v3/IERC20Bridge.sol";
|
|
||||||
import "./IFeature.sol";
|
import "./IFeature.sol";
|
||||||
import "./ILiquidityProviderFeature.sol";
|
import "./ILiquidityProviderFeature.sol";
|
||||||
import "./libs/LibTokenSpender.sol";
|
import "./libs/LibTokenSpender.sol";
|
||||||
@ -39,7 +37,6 @@ contract LiquidityProviderFeature is
|
|||||||
ILiquidityProviderFeature,
|
ILiquidityProviderFeature,
|
||||||
FixinCommon
|
FixinCommon
|
||||||
{
|
{
|
||||||
using LibERC20TokenV06 for IERC20TokenV06;
|
|
||||||
using LibSafeMathV06 for uint256;
|
using LibSafeMathV06 for uint256;
|
||||||
using LibRichErrorsV06 for bytes;
|
using LibRichErrorsV06 for bytes;
|
||||||
|
|
||||||
@ -50,16 +47,24 @@ contract LiquidityProviderFeature is
|
|||||||
|
|
||||||
/// @dev ETH pseudo-token address.
|
/// @dev ETH pseudo-token address.
|
||||||
address constant internal ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
address constant internal ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||||
/// @dev The WETH contract address.
|
/// @dev The sandbox contract address.
|
||||||
IEtherTokenV06 public immutable weth;
|
ILiquidityProviderSandbox public immutable sandbox;
|
||||||
|
|
||||||
/// @dev Store the WETH address in an immutable.
|
/// @dev Event for data pipeline.
|
||||||
/// @param weth_ The weth token.
|
event LiquidityProviderSwap(
|
||||||
constructor(IEtherTokenV06 weth_)
|
address inputToken,
|
||||||
|
address outputToken,
|
||||||
|
uint256 inputTokenAmount,
|
||||||
|
uint256 outputTokenAmount,
|
||||||
|
address provider,
|
||||||
|
address recipient
|
||||||
|
);
|
||||||
|
|
||||||
|
constructor(address zeroEx)
|
||||||
public
|
public
|
||||||
FixinCommon()
|
FixinCommon()
|
||||||
{
|
{
|
||||||
weth = weth_;
|
sandbox = new LiquidityProviderSandbox(zeroEx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Initialize and register this feature.
|
/// @dev Initialize and register this feature.
|
||||||
@ -70,131 +75,102 @@ contract LiquidityProviderFeature is
|
|||||||
returns (bytes4 success)
|
returns (bytes4 success)
|
||||||
{
|
{
|
||||||
_registerFeatureFunction(this.sellToLiquidityProvider.selector);
|
_registerFeatureFunction(this.sellToLiquidityProvider.selector);
|
||||||
_registerFeatureFunction(this.setLiquidityProviderForMarket.selector);
|
|
||||||
_registerFeatureFunction(this.getLiquidityProviderForMarket.selector);
|
|
||||||
return LibMigrate.MIGRATE_SUCCESS;
|
return LibMigrate.MIGRATE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev Sells `sellAmount` of `inputToken` to the liquidity provider
|
||||||
|
/// at the given `provider` address.
|
||||||
|
/// @param inputToken The token being sold.
|
||||||
|
/// @param outputToken The token being bought.
|
||||||
|
/// @param provider The address of the on-chain liquidity provider
|
||||||
|
/// to trade with.
|
||||||
|
/// @param recipient The recipient of the bought tokens. If equal to
|
||||||
|
/// address(0), `msg.sender` is assumed to be the recipient.
|
||||||
|
/// @param sellAmount The amount of `inputToken` to sell.
|
||||||
|
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to
|
||||||
|
/// buy. Reverts if this amount is not satisfied.
|
||||||
|
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
|
||||||
|
/// @return boughtAmount The amount of `outputToken` bought.
|
||||||
function sellToLiquidityProvider(
|
function sellToLiquidityProvider(
|
||||||
address makerToken,
|
address inputToken,
|
||||||
address takerToken,
|
address outputToken,
|
||||||
address payable recipient,
|
address payable provider,
|
||||||
|
address recipient,
|
||||||
uint256 sellAmount,
|
uint256 sellAmount,
|
||||||
uint256 minBuyAmount
|
uint256 minBuyAmount,
|
||||||
|
bytes calldata auxiliaryData
|
||||||
)
|
)
|
||||||
external
|
external
|
||||||
override
|
override
|
||||||
payable
|
payable
|
||||||
returns (uint256 boughtAmount)
|
returns (uint256 boughtAmount)
|
||||||
{
|
{
|
||||||
address providerAddress = getLiquidityProviderForMarket(makerToken, takerToken);
|
|
||||||
if (recipient == address(0)) {
|
if (recipient == address(0)) {
|
||||||
recipient = msg.sender;
|
recipient = msg.sender;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (takerToken == ETH_TOKEN_ADDRESS) {
|
if (inputToken == ETH_TOKEN_ADDRESS) {
|
||||||
// Wrap ETH.
|
provider.transfer(sellAmount);
|
||||||
weth.deposit{value: sellAmount}();
|
|
||||||
weth.transfer(providerAddress, sellAmount);
|
|
||||||
} else {
|
} else {
|
||||||
LibTokenSpender.spendERC20Tokens(
|
LibTokenSpender.spendERC20Tokens(
|
||||||
IERC20TokenV06(takerToken),
|
IERC20TokenV06(inputToken),
|
||||||
msg.sender,
|
msg.sender,
|
||||||
providerAddress,
|
provider,
|
||||||
sellAmount
|
sellAmount
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (makerToken == ETH_TOKEN_ADDRESS) {
|
if (inputToken == ETH_TOKEN_ADDRESS) {
|
||||||
uint256 balanceBefore = weth.balanceOf(address(this));
|
uint256 balanceBefore = IERC20TokenV06(outputToken).balanceOf(recipient);
|
||||||
IERC20Bridge(providerAddress).bridgeTransferFrom(
|
sandbox.executeSellEthForToken(
|
||||||
address(weth),
|
provider,
|
||||||
address(0),
|
outputToken,
|
||||||
address(this),
|
|
||||||
minBuyAmount,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
boughtAmount = weth.balanceOf(address(this)).safeSub(balanceBefore);
|
|
||||||
// Unwrap wETH and send ETH to recipient.
|
|
||||||
weth.withdraw(boughtAmount);
|
|
||||||
recipient.transfer(boughtAmount);
|
|
||||||
} else {
|
|
||||||
uint256 balanceBefore = IERC20TokenV06(makerToken).balanceOf(recipient);
|
|
||||||
IERC20Bridge(providerAddress).bridgeTransferFrom(
|
|
||||||
makerToken,
|
|
||||||
address(0),
|
|
||||||
recipient,
|
recipient,
|
||||||
minBuyAmount,
|
minBuyAmount,
|
||||||
""
|
auxiliaryData
|
||||||
);
|
);
|
||||||
boughtAmount = IERC20TokenV06(makerToken).balanceOf(recipient).safeSub(balanceBefore);
|
boughtAmount = IERC20TokenV06(outputToken).balanceOf(recipient).safeSub(balanceBefore);
|
||||||
|
} else if (outputToken == ETH_TOKEN_ADDRESS) {
|
||||||
|
uint256 balanceBefore = recipient.balance;
|
||||||
|
sandbox.executeSellTokenForEth(
|
||||||
|
provider,
|
||||||
|
inputToken,
|
||||||
|
recipient,
|
||||||
|
minBuyAmount,
|
||||||
|
auxiliaryData
|
||||||
|
);
|
||||||
|
boughtAmount = recipient.balance.safeSub(balanceBefore);
|
||||||
|
} else {
|
||||||
|
uint256 balanceBefore = IERC20TokenV06(outputToken).balanceOf(recipient);
|
||||||
|
sandbox.executeSellTokenForToken(
|
||||||
|
provider,
|
||||||
|
inputToken,
|
||||||
|
outputToken,
|
||||||
|
recipient,
|
||||||
|
minBuyAmount,
|
||||||
|
auxiliaryData
|
||||||
|
);
|
||||||
|
boughtAmount = IERC20TokenV06(outputToken).balanceOf(recipient).safeSub(balanceBefore);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boughtAmount < minBuyAmount) {
|
if (boughtAmount < minBuyAmount) {
|
||||||
LibLiquidityProviderRichErrors.LiquidityProviderIncompleteSellError(
|
LibLiquidityProviderRichErrors.LiquidityProviderIncompleteSellError(
|
||||||
providerAddress,
|
provider,
|
||||||
makerToken,
|
outputToken,
|
||||||
takerToken,
|
inputToken,
|
||||||
sellAmount,
|
sellAmount,
|
||||||
boughtAmount,
|
boughtAmount,
|
||||||
minBuyAmount
|
minBuyAmount
|
||||||
).rrevert();
|
).rrevert();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Sets address of the liquidity provider for a market given
|
emit LiquidityProviderSwap(
|
||||||
/// (xAsset, yAsset).
|
inputToken,
|
||||||
/// @param xAsset First asset managed by the liquidity provider.
|
outputToken,
|
||||||
/// @param yAsset Second asset managed by the liquidity provider.
|
sellAmount,
|
||||||
/// @param providerAddress Address of the liquidity provider.
|
boughtAmount,
|
||||||
function setLiquidityProviderForMarket(
|
provider,
|
||||||
address xAsset,
|
recipient
|
||||||
address yAsset,
|
|
||||||
address providerAddress
|
|
||||||
)
|
|
||||||
external
|
|
||||||
override
|
|
||||||
onlyOwner
|
|
||||||
{
|
|
||||||
LibLiquidityProviderStorage.getStorage()
|
|
||||||
.addressBook[xAsset][yAsset] = providerAddress;
|
|
||||||
LibLiquidityProviderStorage.getStorage()
|
|
||||||
.addressBook[yAsset][xAsset] = providerAddress;
|
|
||||||
emit LiquidityProviderForMarketUpdated(
|
|
||||||
xAsset,
|
|
||||||
yAsset,
|
|
||||||
providerAddress
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Returns the address of the liquidity provider for a market given
|
|
||||||
/// (xAsset, yAsset), or reverts if pool does not exist.
|
|
||||||
/// @param xAsset First asset managed by the liquidity provider.
|
|
||||||
/// @param yAsset Second asset managed by the liquidity provider.
|
|
||||||
/// @return providerAddress Address of the liquidity provider.
|
|
||||||
function getLiquidityProviderForMarket(
|
|
||||||
address xAsset,
|
|
||||||
address yAsset
|
|
||||||
)
|
|
||||||
public
|
|
||||||
view
|
|
||||||
override
|
|
||||||
returns (address providerAddress)
|
|
||||||
{
|
|
||||||
if (xAsset == ETH_TOKEN_ADDRESS) {
|
|
||||||
providerAddress = LibLiquidityProviderStorage.getStorage()
|
|
||||||
.addressBook[address(weth)][yAsset];
|
|
||||||
} else if (yAsset == ETH_TOKEN_ADDRESS) {
|
|
||||||
providerAddress = LibLiquidityProviderStorage.getStorage()
|
|
||||||
.addressBook[xAsset][address(weth)];
|
|
||||||
} else {
|
|
||||||
providerAddress = LibLiquidityProviderStorage.getStorage()
|
|
||||||
.addressBook[xAsset][yAsset];
|
|
||||||
}
|
|
||||||
if (providerAddress == address(0)) {
|
|
||||||
LibLiquidityProviderRichErrors.NoLiquidityProviderForMarketError(
|
|
||||||
xAsset,
|
|
||||||
yAsset
|
|
||||||
).rrevert();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ contract TransformERC20Feature is
|
|||||||
/// @dev Name of this feature.
|
/// @dev Name of this feature.
|
||||||
string public constant override FEATURE_NAME = "TransformERC20";
|
string public constant override FEATURE_NAME = "TransformERC20";
|
||||||
/// @dev Version of this feature.
|
/// @dev Version of this feature.
|
||||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 2, 0);
|
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 3, 0);
|
||||||
|
|
||||||
/// @dev Initialize and register this feature.
|
/// @dev Initialize and register this feature.
|
||||||
/// Should be delegatecalled by `Migrate.migrate()`.
|
/// Should be delegatecalled by `Migrate.migrate()`.
|
||||||
|
@ -37,7 +37,7 @@ contract UniswapFeature is
|
|||||||
/// @dev Name of this feature.
|
/// @dev Name of this feature.
|
||||||
string public constant override FEATURE_NAME = "UniswapFeature";
|
string public constant override FEATURE_NAME = "UniswapFeature";
|
||||||
/// @dev Version of this feature.
|
/// @dev Version of this feature.
|
||||||
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
|
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 0);
|
||||||
/// @dev WETH contract.
|
/// @dev WETH contract.
|
||||||
IEtherTokenV06 private immutable WETH;
|
IEtherTokenV06 private immutable WETH;
|
||||||
/// @dev AllowanceTarget instance.
|
/// @dev AllowanceTarget instance.
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2020 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.6.5;
|
|
||||||
pragma experimental ABIEncoderV2;
|
|
||||||
|
|
||||||
import "./LibStorage.sol";
|
|
||||||
|
|
||||||
|
|
||||||
/// @dev Storage helpers for `LiquidityProviderFeature`.
|
|
||||||
library LibLiquidityProviderStorage {
|
|
||||||
|
|
||||||
/// @dev Storage bucket for this feature.
|
|
||||||
struct Storage {
|
|
||||||
// Mapping of taker token -> maker token -> liquidity provider address
|
|
||||||
// Note that addressBook[x][y] == addressBook[y][x] will always hold.
|
|
||||||
mapping (address => mapping (address => address)) addressBook;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Get the storage bucket for this contract.
|
|
||||||
function getStorage() internal pure returns (Storage storage stor) {
|
|
||||||
uint256 storageSlot = LibStorage.getStorageSlot(
|
|
||||||
LibStorage.StorageId.LiquidityProvider
|
|
||||||
);
|
|
||||||
// Dip into assembly to change the slot pointed to by the local
|
|
||||||
// variable `stor`.
|
|
||||||
// See https://solidity.readthedocs.io/en/v0.6.8/assembly.html?highlight=slot#access-to-external-variables-functions-and-libraries
|
|
||||||
assembly { stor_slot := storageSlot }
|
|
||||||
}
|
|
||||||
}
|
|
@ -36,8 +36,7 @@ library LibStorage {
|
|||||||
TokenSpender,
|
TokenSpender,
|
||||||
TransformERC20,
|
TransformERC20,
|
||||||
MetaTransactions,
|
MetaTransactions,
|
||||||
ReentrancyGuard,
|
ReentrancyGuard
|
||||||
LiquidityProvider
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Get the storage slot given a storage ID. We assign unique, well-spaced
|
/// @dev Get the storage slot given a storage ID. We assign unique, well-spaced
|
||||||
|
@ -1,19 +1,15 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2020 ZeroEx Intl.
|
Copyright 2020 ZeroEx Intl.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.6.5;
|
pragma solidity ^0.6.5;
|
||||||
|
@ -32,28 +32,26 @@ contract TestFillQuoteTransformerBridge {
|
|||||||
uint256 amount;
|
uint256 amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes4 private constant ERC20_BRIDGE_PROXY_ID = 0xdc1600f3;
|
function sellTokenForToken(
|
||||||
|
address takerToken,
|
||||||
function bridgeTransferFrom(
|
address makerToken,
|
||||||
address tokenAddress,
|
address recipient,
|
||||||
address from,
|
uint256 minBuyAmount,
|
||||||
address to,
|
bytes calldata auxiliaryData
|
||||||
uint256 amount,
|
|
||||||
bytes calldata bridgeData
|
|
||||||
)
|
)
|
||||||
external
|
external
|
||||||
returns (bytes4 success)
|
returns (uint256 boughtAmount)
|
||||||
{
|
{
|
||||||
FillBehavior memory behavior = abi.decode(bridgeData, (FillBehavior));
|
FillBehavior memory behavior = abi.decode(auxiliaryData, (FillBehavior));
|
||||||
TestMintableERC20Token(tokenAddress).mint(
|
boughtAmount = LibMathV06.getPartialAmountFloor(
|
||||||
to,
|
|
||||||
LibMathV06.getPartialAmountFloor(
|
|
||||||
behavior.makerAssetMintRatio,
|
behavior.makerAssetMintRatio,
|
||||||
1e18,
|
1e18,
|
||||||
behavior.amount
|
behavior.amount
|
||||||
)
|
|
||||||
);
|
);
|
||||||
return ERC20_BRIDGE_PROXY_ID;
|
TestMintableERC20Token(makerToken).mint(
|
||||||
|
recipient,
|
||||||
|
boughtAmount
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function encodeBehaviorData(FillBehavior calldata behavior)
|
function encodeBehaviorData(FillBehavior calldata behavior)
|
||||||
|
135
contracts/zero-ex/contracts/test/TestLiquidityProvider.sol
Normal file
135
contracts/zero-ex/contracts/test/TestLiquidityProvider.sol
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2020 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.6.5;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract TestLiquidityProvider {
|
||||||
|
event SellTokenForToken(
|
||||||
|
address inputToken,
|
||||||
|
address outputToken,
|
||||||
|
address recipient,
|
||||||
|
uint256 minBuyAmount,
|
||||||
|
uint256 inputTokenBalance
|
||||||
|
);
|
||||||
|
|
||||||
|
event SellEthForToken(
|
||||||
|
address outputToken,
|
||||||
|
address recipient,
|
||||||
|
uint256 minBuyAmount,
|
||||||
|
uint256 ethBalance
|
||||||
|
);
|
||||||
|
|
||||||
|
event SellTokenForEth(
|
||||||
|
address inputToken,
|
||||||
|
address recipient,
|
||||||
|
uint256 minBuyAmount,
|
||||||
|
uint256 inputTokenBalance
|
||||||
|
);
|
||||||
|
|
||||||
|
IERC20TokenV06 public immutable xAsset;
|
||||||
|
IERC20TokenV06 public immutable yAsset;
|
||||||
|
|
||||||
|
constructor(IERC20TokenV06 xAsset_, IERC20TokenV06 yAsset_)
|
||||||
|
public
|
||||||
|
{
|
||||||
|
xAsset = xAsset_;
|
||||||
|
yAsset = yAsset_;
|
||||||
|
}
|
||||||
|
|
||||||
|
receive() external payable {}
|
||||||
|
|
||||||
|
/// @dev Trades `inputToken` for `outputToken`. The amount of `inputToken`
|
||||||
|
/// to sell must be transferred to the contract prior to calling this
|
||||||
|
/// function to trigger the trade.
|
||||||
|
/// @param inputToken The token being sold.
|
||||||
|
/// @param outputToken The token being bought.
|
||||||
|
/// @param recipient The recipient of the bought tokens.
|
||||||
|
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||||
|
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
|
||||||
|
/// @return boughtAmount The amount of `outputToken` bought.
|
||||||
|
function sellTokenForToken(
|
||||||
|
address inputToken,
|
||||||
|
address outputToken,
|
||||||
|
address recipient,
|
||||||
|
uint256 minBuyAmount,
|
||||||
|
bytes calldata auxiliaryData
|
||||||
|
)
|
||||||
|
external
|
||||||
|
returns (uint256 boughtAmount)
|
||||||
|
{
|
||||||
|
emit SellTokenForToken(
|
||||||
|
inputToken,
|
||||||
|
outputToken,
|
||||||
|
recipient,
|
||||||
|
minBuyAmount,
|
||||||
|
IERC20TokenV06(inputToken).balanceOf(address(this))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Trades ETH for token. ETH must be sent to the contract prior to
|
||||||
|
/// calling this function to trigger the trade.
|
||||||
|
/// @param outputToken The token being bought.
|
||||||
|
/// @param recipient The recipient of the bought tokens.
|
||||||
|
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
|
||||||
|
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
|
||||||
|
/// @return boughtAmount The amount of `outputToken` bought.
|
||||||
|
function sellEthForToken(
|
||||||
|
address outputToken,
|
||||||
|
address recipient,
|
||||||
|
uint256 minBuyAmount,
|
||||||
|
bytes calldata auxiliaryData
|
||||||
|
)
|
||||||
|
external
|
||||||
|
returns (uint256 boughtAmount)
|
||||||
|
{
|
||||||
|
emit SellEthForToken(
|
||||||
|
outputToken,
|
||||||
|
recipient,
|
||||||
|
minBuyAmount,
|
||||||
|
address(this).balance
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Trades token for ETH. The token must be sent to the contract prior
|
||||||
|
/// to calling this function to trigger the trade.
|
||||||
|
/// @param inputToken The token being sold.
|
||||||
|
/// @param recipient The recipient of the bought tokens.
|
||||||
|
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
|
||||||
|
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
|
||||||
|
/// @return boughtAmount The amount of ETH bought.
|
||||||
|
function sellTokenForEth(
|
||||||
|
address inputToken,
|
||||||
|
address payable recipient,
|
||||||
|
uint256 minBuyAmount,
|
||||||
|
bytes calldata auxiliaryData
|
||||||
|
)
|
||||||
|
external
|
||||||
|
returns (uint256 boughtAmount)
|
||||||
|
{
|
||||||
|
emit SellTokenForEth(
|
||||||
|
inputToken,
|
||||||
|
recipient,
|
||||||
|
minBuyAmount,
|
||||||
|
IERC20TokenV06(inputToken).balanceOf(address(this))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -40,9 +40,9 @@
|
|||||||
"publish:private": "yarn build && gitpkg publish"
|
"publish:private": "yarn build && gitpkg publish"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,SignatureValidatorFeature,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature",
|
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,SignatureValidatorFeature,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProvider",
|
||||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|FeeCollector|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|ILiquidityProvider|ILiquidityProviderFeature|IMetaTransactionsFeature|IOwnableFeature|ISignatureValidatorFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibLiquidityProviderRichErrors|LibLiquidityProviderStorage|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibOrderHash|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSignedCallData|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpender|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LogMetadataTransformer|MetaTransactionsFeature|MixinAdapterAddresses|MixinBalancer|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|OwnableFeature|PayTakerTransformer|SignatureValidatorFeature|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestLibSignature|TestLibTokenSpender|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestProtocolFees|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx).json"
|
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|FeeCollector|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IOwnableFeature|ISignatureValidatorFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibOrderHash|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSignedCallData|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpender|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAdapterAddresses|MixinBalancer|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|OwnableFeature|PayTakerTransformer|SignatureValidatorFeature|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestLibSignature|TestLibTokenSpender|TestLiquidityProvider|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestProtocolFees|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx).json"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -12,6 +12,7 @@ import * as FullMigration from '../generated-artifacts/FullMigration.json';
|
|||||||
import * as IAllowanceTarget from '../generated-artifacts/IAllowanceTarget.json';
|
import * as IAllowanceTarget from '../generated-artifacts/IAllowanceTarget.json';
|
||||||
import * as IERC20Transformer from '../generated-artifacts/IERC20Transformer.json';
|
import * as IERC20Transformer from '../generated-artifacts/IERC20Transformer.json';
|
||||||
import * as IFlashWallet from '../generated-artifacts/IFlashWallet.json';
|
import * as IFlashWallet from '../generated-artifacts/IFlashWallet.json';
|
||||||
|
import * as ILiquidityProvider from '../generated-artifacts/ILiquidityProvider.json';
|
||||||
import * as InitialMigration from '../generated-artifacts/InitialMigration.json';
|
import * as InitialMigration from '../generated-artifacts/InitialMigration.json';
|
||||||
import * as IOwnableFeature from '../generated-artifacts/IOwnableFeature.json';
|
import * as IOwnableFeature from '../generated-artifacts/IOwnableFeature.json';
|
||||||
import * as ISimpleFunctionRegistryFeature from '../generated-artifacts/ISimpleFunctionRegistryFeature.json';
|
import * as ISimpleFunctionRegistryFeature from '../generated-artifacts/ISimpleFunctionRegistryFeature.json';
|
||||||
@ -54,4 +55,5 @@ export const artifacts = {
|
|||||||
LogMetadataTransformer: LogMetadataTransformer as ContractArtifact,
|
LogMetadataTransformer: LogMetadataTransformer as ContractArtifact,
|
||||||
BridgeAdapter: BridgeAdapter as ContractArtifact,
|
BridgeAdapter: BridgeAdapter as ContractArtifact,
|
||||||
LiquidityProviderFeature: LiquidityProviderFeature as ContractArtifact,
|
LiquidityProviderFeature: LiquidityProviderFeature as ContractArtifact,
|
||||||
|
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
|
||||||
};
|
};
|
||||||
|
@ -10,6 +10,7 @@ export * from '../generated-wrappers/full_migration';
|
|||||||
export * from '../generated-wrappers/i_allowance_target';
|
export * from '../generated-wrappers/i_allowance_target';
|
||||||
export * from '../generated-wrappers/i_erc20_transformer';
|
export * from '../generated-wrappers/i_erc20_transformer';
|
||||||
export * from '../generated-wrappers/i_flash_wallet';
|
export * from '../generated-wrappers/i_flash_wallet';
|
||||||
|
export * from '../generated-wrappers/i_liquidity_provider';
|
||||||
export * from '../generated-wrappers/i_ownable_feature';
|
export * from '../generated-wrappers/i_ownable_feature';
|
||||||
export * from '../generated-wrappers/i_simple_function_registry_feature';
|
export * from '../generated-wrappers/i_simple_function_registry_feature';
|
||||||
export * from '../generated-wrappers/i_token_spender_feature';
|
export * from '../generated-wrappers/i_token_spender_feature';
|
||||||
|
@ -28,6 +28,7 @@ import * as IFlashWallet from '../test/generated-artifacts/IFlashWallet.json';
|
|||||||
import * as IGasToken from '../test/generated-artifacts/IGasToken.json';
|
import * as IGasToken from '../test/generated-artifacts/IGasToken.json';
|
||||||
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
|
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
|
||||||
import * as ILiquidityProviderFeature from '../test/generated-artifacts/ILiquidityProviderFeature.json';
|
import * as ILiquidityProviderFeature from '../test/generated-artifacts/ILiquidityProviderFeature.json';
|
||||||
|
import * as ILiquidityProviderSandbox from '../test/generated-artifacts/ILiquidityProviderSandbox.json';
|
||||||
import * as IMetaTransactionsFeature from '../test/generated-artifacts/IMetaTransactionsFeature.json';
|
import * as IMetaTransactionsFeature from '../test/generated-artifacts/IMetaTransactionsFeature.json';
|
||||||
import * as InitialMigration from '../test/generated-artifacts/InitialMigration.json';
|
import * as InitialMigration from '../test/generated-artifacts/InitialMigration.json';
|
||||||
import * as IOwnableFeature from '../test/generated-artifacts/IOwnableFeature.json';
|
import * as IOwnableFeature from '../test/generated-artifacts/IOwnableFeature.json';
|
||||||
@ -43,7 +44,6 @@ import * as LibBootstrap from '../test/generated-artifacts/LibBootstrap.json';
|
|||||||
import * as LibCommonRichErrors from '../test/generated-artifacts/LibCommonRichErrors.json';
|
import * as LibCommonRichErrors from '../test/generated-artifacts/LibCommonRichErrors.json';
|
||||||
import * as LibERC20Transformer from '../test/generated-artifacts/LibERC20Transformer.json';
|
import * as LibERC20Transformer from '../test/generated-artifacts/LibERC20Transformer.json';
|
||||||
import * as LibLiquidityProviderRichErrors from '../test/generated-artifacts/LibLiquidityProviderRichErrors.json';
|
import * as LibLiquidityProviderRichErrors from '../test/generated-artifacts/LibLiquidityProviderRichErrors.json';
|
||||||
import * as LibLiquidityProviderStorage from '../test/generated-artifacts/LibLiquidityProviderStorage.json';
|
|
||||||
import * as LibMetaTransactionsRichErrors from '../test/generated-artifacts/LibMetaTransactionsRichErrors.json';
|
import * as LibMetaTransactionsRichErrors from '../test/generated-artifacts/LibMetaTransactionsRichErrors.json';
|
||||||
import * as LibMetaTransactionsStorage from '../test/generated-artifacts/LibMetaTransactionsStorage.json';
|
import * as LibMetaTransactionsStorage from '../test/generated-artifacts/LibMetaTransactionsStorage.json';
|
||||||
import * as LibMigrate from '../test/generated-artifacts/LibMigrate.json';
|
import * as LibMigrate from '../test/generated-artifacts/LibMigrate.json';
|
||||||
@ -66,6 +66,7 @@ import * as LibTransformERC20RichErrors from '../test/generated-artifacts/LibTra
|
|||||||
import * as LibTransformERC20Storage from '../test/generated-artifacts/LibTransformERC20Storage.json';
|
import * as LibTransformERC20Storage from '../test/generated-artifacts/LibTransformERC20Storage.json';
|
||||||
import * as LibWalletRichErrors from '../test/generated-artifacts/LibWalletRichErrors.json';
|
import * as LibWalletRichErrors from '../test/generated-artifacts/LibWalletRichErrors.json';
|
||||||
import * as LiquidityProviderFeature from '../test/generated-artifacts/LiquidityProviderFeature.json';
|
import * as LiquidityProviderFeature from '../test/generated-artifacts/LiquidityProviderFeature.json';
|
||||||
|
import * as LiquidityProviderSandbox from '../test/generated-artifacts/LiquidityProviderSandbox.json';
|
||||||
import * as LogMetadataTransformer from '../test/generated-artifacts/LogMetadataTransformer.json';
|
import * as LogMetadataTransformer from '../test/generated-artifacts/LogMetadataTransformer.json';
|
||||||
import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransactionsFeature.json';
|
import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransactionsFeature.json';
|
||||||
import * as MixinAdapterAddresses from '../test/generated-artifacts/MixinAdapterAddresses.json';
|
import * as MixinAdapterAddresses from '../test/generated-artifacts/MixinAdapterAddresses.json';
|
||||||
@ -95,6 +96,7 @@ import * as TestFullMigration from '../test/generated-artifacts/TestFullMigratio
|
|||||||
import * as TestInitialMigration from '../test/generated-artifacts/TestInitialMigration.json';
|
import * as TestInitialMigration from '../test/generated-artifacts/TestInitialMigration.json';
|
||||||
import * as TestLibSignature from '../test/generated-artifacts/TestLibSignature.json';
|
import * as TestLibSignature from '../test/generated-artifacts/TestLibSignature.json';
|
||||||
import * as TestLibTokenSpender from '../test/generated-artifacts/TestLibTokenSpender.json';
|
import * as TestLibTokenSpender from '../test/generated-artifacts/TestLibTokenSpender.json';
|
||||||
|
import * as TestLiquidityProvider from '../test/generated-artifacts/TestLiquidityProvider.json';
|
||||||
import * as TestMetaTransactionsTransformERC20Feature from '../test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json';
|
import * as TestMetaTransactionsTransformERC20Feature from '../test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json';
|
||||||
import * as TestMigrator from '../test/generated-artifacts/TestMigrator.json';
|
import * as TestMigrator from '../test/generated-artifacts/TestMigrator.json';
|
||||||
import * as TestMintableERC20Token from '../test/generated-artifacts/TestMintableERC20Token.json';
|
import * as TestMintableERC20Token from '../test/generated-artifacts/TestMintableERC20Token.json';
|
||||||
@ -137,6 +139,8 @@ export const artifacts = {
|
|||||||
FlashWallet: FlashWallet as ContractArtifact,
|
FlashWallet: FlashWallet as ContractArtifact,
|
||||||
IAllowanceTarget: IAllowanceTarget as ContractArtifact,
|
IAllowanceTarget: IAllowanceTarget as ContractArtifact,
|
||||||
IFlashWallet: IFlashWallet as ContractArtifact,
|
IFlashWallet: IFlashWallet as ContractArtifact,
|
||||||
|
ILiquidityProviderSandbox: ILiquidityProviderSandbox as ContractArtifact,
|
||||||
|
LiquidityProviderSandbox: LiquidityProviderSandbox as ContractArtifact,
|
||||||
TransformerDeployer: TransformerDeployer as ContractArtifact,
|
TransformerDeployer: TransformerDeployer as ContractArtifact,
|
||||||
BootstrapFeature: BootstrapFeature as ContractArtifact,
|
BootstrapFeature: BootstrapFeature as ContractArtifact,
|
||||||
IBootstrapFeature: IBootstrapFeature as ContractArtifact,
|
IBootstrapFeature: IBootstrapFeature as ContractArtifact,
|
||||||
@ -168,7 +172,6 @@ export const artifacts = {
|
|||||||
InitialMigration: InitialMigration as ContractArtifact,
|
InitialMigration: InitialMigration as ContractArtifact,
|
||||||
LibBootstrap: LibBootstrap as ContractArtifact,
|
LibBootstrap: LibBootstrap as ContractArtifact,
|
||||||
LibMigrate: LibMigrate as ContractArtifact,
|
LibMigrate: LibMigrate as ContractArtifact,
|
||||||
LibLiquidityProviderStorage: LibLiquidityProviderStorage as ContractArtifact,
|
|
||||||
LibMetaTransactionsStorage: LibMetaTransactionsStorage as ContractArtifact,
|
LibMetaTransactionsStorage: LibMetaTransactionsStorage as ContractArtifact,
|
||||||
LibOwnableStorage: LibOwnableStorage as ContractArtifact,
|
LibOwnableStorage: LibOwnableStorage as ContractArtifact,
|
||||||
LibProxyStorage: LibProxyStorage as ContractArtifact,
|
LibProxyStorage: LibProxyStorage as ContractArtifact,
|
||||||
@ -217,6 +220,7 @@ export const artifacts = {
|
|||||||
TestInitialMigration: TestInitialMigration as ContractArtifact,
|
TestInitialMigration: TestInitialMigration as ContractArtifact,
|
||||||
TestLibSignature: TestLibSignature as ContractArtifact,
|
TestLibSignature: TestLibSignature as ContractArtifact,
|
||||||
TestLibTokenSpender: TestLibTokenSpender as ContractArtifact,
|
TestLibTokenSpender: TestLibTokenSpender as ContractArtifact,
|
||||||
|
TestLiquidityProvider: TestLiquidityProvider as ContractArtifact,
|
||||||
TestMetaTransactionsTransformERC20Feature: TestMetaTransactionsTransformERC20Feature as ContractArtifact,
|
TestMetaTransactionsTransformERC20Feature: TestMetaTransactionsTransformERC20Feature as ContractArtifact,
|
||||||
TestMigrator: TestMigrator as ContractArtifact,
|
TestMigrator: TestMigrator as ContractArtifact,
|
||||||
TestMintTokenERC20Transformer: TestMintTokenERC20Transformer as ContractArtifact,
|
TestMintTokenERC20Transformer: TestMintTokenERC20Transformer as ContractArtifact,
|
||||||
|
@ -1,16 +1,25 @@
|
|||||||
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
|
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||||
import { blockchainTests, constants, expect, randomAddress, verifyEventsFromLogs } from '@0x/contracts-test-utils';
|
import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils';
|
||||||
import { BigNumber, OwnableRevertErrors, ZeroExRevertErrors } from '@0x/utils';
|
import { BigNumber, OwnableRevertErrors, ZeroExRevertErrors } from '@0x/utils';
|
||||||
|
|
||||||
import { IOwnableFeatureContract, IZeroExContract, LiquidityProviderFeatureContract } from '../../src/wrappers';
|
import { IOwnableFeatureContract, IZeroExContract, LiquidityProviderFeatureContract } from '../../src/wrappers';
|
||||||
import { artifacts } from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
import { abis } from '../utils/abis';
|
import { abis } from '../utils/abis';
|
||||||
import { fullMigrateAsync } from '../utils/migration';
|
import { fullMigrateAsync } from '../utils/migration';
|
||||||
import { IERC20BridgeEvents, TestBridgeContract, TestWethContract } from '../wrappers';
|
import {
|
||||||
|
LiquidityProviderSandboxContract,
|
||||||
|
TestBridgeContract,
|
||||||
|
TestBridgeEvents,
|
||||||
|
TestLiquidityProviderContract,
|
||||||
|
TestLiquidityProviderEvents,
|
||||||
|
TestWethContract,
|
||||||
|
} from '../wrappers';
|
||||||
|
|
||||||
blockchainTests('LiquidityProvider feature', env => {
|
blockchainTests('LiquidityProvider feature', env => {
|
||||||
let zeroEx: IZeroExContract;
|
let zeroEx: IZeroExContract;
|
||||||
let feature: LiquidityProviderFeatureContract;
|
let feature: LiquidityProviderFeatureContract;
|
||||||
|
let sandbox: LiquidityProviderSandboxContract;
|
||||||
|
let liquidityProvider: TestLiquidityProviderContract;
|
||||||
let token: DummyERC20TokenContract;
|
let token: DummyERC20TokenContract;
|
||||||
let weth: TestWethContract;
|
let weth: TestWethContract;
|
||||||
let owner: string;
|
let owner: string;
|
||||||
@ -47,102 +56,112 @@ blockchainTests('LiquidityProvider feature', env => {
|
|||||||
env.provider,
|
env.provider,
|
||||||
env.txDefaults,
|
env.txDefaults,
|
||||||
artifacts,
|
artifacts,
|
||||||
weth.address,
|
zeroEx.address,
|
||||||
|
);
|
||||||
|
sandbox = new LiquidityProviderSandboxContract(
|
||||||
|
await featureImpl.sandbox().callAsync(),
|
||||||
|
env.provider,
|
||||||
|
env.txDefaults,
|
||||||
);
|
);
|
||||||
await new IOwnableFeatureContract(zeroEx.address, env.provider, env.txDefaults, abis)
|
await new IOwnableFeatureContract(zeroEx.address, env.provider, env.txDefaults, abis)
|
||||||
.migrate(featureImpl.address, featureImpl.migrate().getABIEncodedTransactionData(), owner)
|
.migrate(featureImpl.address, featureImpl.migrate().getABIEncodedTransactionData(), owner)
|
||||||
.awaitTransactionSuccessAsync();
|
.awaitTransactionSuccessAsync();
|
||||||
});
|
|
||||||
describe('Registry', () => {
|
|
||||||
it('`getLiquidityProviderForMarket` reverts if address is not set', async () => {
|
|
||||||
const [xAsset, yAsset] = [randomAddress(), randomAddress()];
|
|
||||||
let tx = feature.getLiquidityProviderForMarket(xAsset, yAsset).awaitTransactionSuccessAsync();
|
|
||||||
expect(tx).to.revertWith(
|
|
||||||
new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(xAsset, yAsset),
|
|
||||||
);
|
|
||||||
tx = feature.getLiquidityProviderForMarket(yAsset, xAsset).awaitTransactionSuccessAsync();
|
|
||||||
return expect(tx).to.revertWith(
|
|
||||||
new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(yAsset, xAsset),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it('can set/get a liquidity provider address for a given market', async () => {
|
|
||||||
const expectedAddress = randomAddress();
|
|
||||||
await feature
|
|
||||||
.setLiquidityProviderForMarket(token.address, weth.address, expectedAddress)
|
|
||||||
.awaitTransactionSuccessAsync();
|
|
||||||
let actualAddress = await feature.getLiquidityProviderForMarket(token.address, weth.address).callAsync();
|
|
||||||
expect(actualAddress).to.equal(expectedAddress);
|
|
||||||
actualAddress = await feature.getLiquidityProviderForMarket(weth.address, token.address).callAsync();
|
|
||||||
expect(actualAddress).to.equal(expectedAddress);
|
|
||||||
});
|
|
||||||
it('can update a liquidity provider address for a given market', async () => {
|
|
||||||
const expectedAddress = randomAddress();
|
|
||||||
await feature
|
|
||||||
.setLiquidityProviderForMarket(token.address, weth.address, expectedAddress)
|
|
||||||
.awaitTransactionSuccessAsync();
|
|
||||||
let actualAddress = await feature.getLiquidityProviderForMarket(token.address, weth.address).callAsync();
|
|
||||||
expect(actualAddress).to.equal(expectedAddress);
|
|
||||||
actualAddress = await feature.getLiquidityProviderForMarket(weth.address, token.address).callAsync();
|
|
||||||
expect(actualAddress).to.equal(expectedAddress);
|
|
||||||
});
|
|
||||||
it('can effectively remove a liquidity provider for a market by setting the address to 0', async () => {
|
|
||||||
await feature
|
|
||||||
.setLiquidityProviderForMarket(token.address, weth.address, constants.NULL_ADDRESS)
|
|
||||||
.awaitTransactionSuccessAsync();
|
|
||||||
const tx = feature
|
|
||||||
.getLiquidityProviderForMarket(token.address, weth.address)
|
|
||||||
.awaitTransactionSuccessAsync();
|
|
||||||
return expect(tx).to.revertWith(
|
|
||||||
new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(token.address, weth.address),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it('reverts if non-owner attempts to set an address', async () => {
|
|
||||||
const tx = feature
|
|
||||||
.setLiquidityProviderForMarket(randomAddress(), randomAddress(), randomAddress())
|
|
||||||
.awaitTransactionSuccessAsync({ from: taker });
|
|
||||||
return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker, owner));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
blockchainTests.resets('Swap', () => {
|
|
||||||
let liquidityProvider: TestBridgeContract;
|
|
||||||
const ETH_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
|
||||||
|
|
||||||
before(async () => {
|
liquidityProvider = await TestLiquidityProviderContract.deployFrom0xArtifactAsync(
|
||||||
liquidityProvider = await TestBridgeContract.deployFrom0xArtifactAsync(
|
artifacts.TestLiquidityProvider,
|
||||||
artifacts.TestBridge,
|
|
||||||
env.provider,
|
env.provider,
|
||||||
env.txDefaults,
|
env.txDefaults,
|
||||||
artifacts,
|
artifacts,
|
||||||
token.address,
|
token.address,
|
||||||
weth.address,
|
weth.address,
|
||||||
);
|
);
|
||||||
await feature
|
|
||||||
.setLiquidityProviderForMarket(token.address, weth.address, liquidityProvider.address)
|
|
||||||
.awaitTransactionSuccessAsync();
|
|
||||||
});
|
});
|
||||||
it('Cannot execute a swap for a market without a liquidity provider set', async () => {
|
blockchainTests.resets('Sandbox', () => {
|
||||||
const [xAsset, yAsset] = [randomAddress(), randomAddress()];
|
it('Cannot call sandbox `executeSellTokenForToken` function directly', async () => {
|
||||||
const tx = feature
|
const tx = sandbox
|
||||||
.sellToLiquidityProvider(
|
.executeSellTokenForToken(
|
||||||
xAsset,
|
liquidityProvider.address,
|
||||||
yAsset,
|
token.address,
|
||||||
constants.NULL_ADDRESS,
|
weth.address,
|
||||||
constants.ONE_ETHER,
|
taker,
|
||||||
constants.ZERO_AMOUNT,
|
constants.ZERO_AMOUNT,
|
||||||
|
constants.NULL_BYTES,
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ from: taker });
|
.awaitTransactionSuccessAsync({ from: taker });
|
||||||
return expect(tx).to.revertWith(
|
return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker));
|
||||||
new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(xAsset, yAsset),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
it('Cannot call sandbox `executeSellEthForToken` function directly', async () => {
|
||||||
|
const tx = sandbox
|
||||||
|
.executeSellEthForToken(
|
||||||
|
liquidityProvider.address,
|
||||||
|
token.address,
|
||||||
|
taker,
|
||||||
|
constants.ZERO_AMOUNT,
|
||||||
|
constants.NULL_BYTES,
|
||||||
|
)
|
||||||
|
.awaitTransactionSuccessAsync({ from: taker });
|
||||||
|
return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker));
|
||||||
|
});
|
||||||
|
it('Cannot call sandbox `executeSellTokenForEth` function directly', async () => {
|
||||||
|
const tx = sandbox
|
||||||
|
.executeSellTokenForEth(
|
||||||
|
liquidityProvider.address,
|
||||||
|
token.address,
|
||||||
|
taker,
|
||||||
|
constants.ZERO_AMOUNT,
|
||||||
|
constants.NULL_BYTES,
|
||||||
|
)
|
||||||
|
.awaitTransactionSuccessAsync({ from: taker });
|
||||||
|
return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
blockchainTests.resets('Swap', () => {
|
||||||
|
const ETH_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
||||||
|
|
||||||
it('Successfully executes an ERC20-ERC20 swap', async () => {
|
it('Successfully executes an ERC20-ERC20 swap', async () => {
|
||||||
const tx = await feature
|
const tx = await feature
|
||||||
.sellToLiquidityProvider(
|
.sellToLiquidityProvider(
|
||||||
weth.address,
|
|
||||||
token.address,
|
token.address,
|
||||||
|
weth.address,
|
||||||
|
liquidityProvider.address,
|
||||||
constants.NULL_ADDRESS,
|
constants.NULL_ADDRESS,
|
||||||
constants.ONE_ETHER,
|
constants.ONE_ETHER,
|
||||||
constants.ZERO_AMOUNT,
|
constants.ZERO_AMOUNT,
|
||||||
|
constants.NULL_BYTES,
|
||||||
|
)
|
||||||
|
.awaitTransactionSuccessAsync({ from: taker });
|
||||||
|
verifyEventsFromLogs(
|
||||||
|
tx.logs,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
inputToken: token.address,
|
||||||
|
outputToken: weth.address,
|
||||||
|
recipient: taker,
|
||||||
|
minBuyAmount: constants.ZERO_AMOUNT,
|
||||||
|
inputTokenBalance: constants.ONE_ETHER,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
TestLiquidityProviderEvents.SellTokenForToken,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('Successfully executes an ERC20-ERC20 swap (backwards-compatibility)', async () => {
|
||||||
|
const bridge = await TestBridgeContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.TestBridge,
|
||||||
|
env.provider,
|
||||||
|
env.txDefaults,
|
||||||
|
artifacts,
|
||||||
|
weth.address,
|
||||||
|
token.address,
|
||||||
|
);
|
||||||
|
const tx = await feature
|
||||||
|
.sellToLiquidityProvider(
|
||||||
|
token.address,
|
||||||
|
weth.address,
|
||||||
|
bridge.address,
|
||||||
|
constants.NULL_ADDRESS,
|
||||||
|
constants.ONE_ETHER,
|
||||||
|
constants.ZERO_AMOUNT,
|
||||||
|
constants.NULL_BYTES,
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ from: taker });
|
.awaitTransactionSuccessAsync({ from: taker });
|
||||||
verifyEventsFromLogs(
|
verifyEventsFromLogs(
|
||||||
@ -153,22 +172,24 @@ blockchainTests('LiquidityProvider feature', env => {
|
|||||||
outputToken: weth.address,
|
outputToken: weth.address,
|
||||||
inputTokenAmount: constants.ONE_ETHER,
|
inputTokenAmount: constants.ONE_ETHER,
|
||||||
outputTokenAmount: constants.ZERO_AMOUNT,
|
outputTokenAmount: constants.ZERO_AMOUNT,
|
||||||
from: constants.NULL_ADDRESS,
|
from: bridge.address,
|
||||||
to: taker,
|
to: taker,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
IERC20BridgeEvents.ERC20BridgeTransfer,
|
TestBridgeEvents.ERC20BridgeTransfer,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('Reverts if cannot fulfill the minimum buy amount', async () => {
|
it('Reverts if cannot fulfill the minimum buy amount', async () => {
|
||||||
const minBuyAmount = new BigNumber(1);
|
const minBuyAmount = new BigNumber(1);
|
||||||
const tx = feature
|
const tx = feature
|
||||||
.sellToLiquidityProvider(
|
.sellToLiquidityProvider(
|
||||||
weth.address,
|
|
||||||
token.address,
|
token.address,
|
||||||
|
weth.address,
|
||||||
|
liquidityProvider.address,
|
||||||
constants.NULL_ADDRESS,
|
constants.NULL_ADDRESS,
|
||||||
constants.ONE_ETHER,
|
constants.ONE_ETHER,
|
||||||
minBuyAmount,
|
minBuyAmount,
|
||||||
|
constants.NULL_BYTES,
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ from: taker });
|
.awaitTransactionSuccessAsync({ from: taker });
|
||||||
return expect(tx).to.revertWith(
|
return expect(tx).to.revertWith(
|
||||||
@ -185,36 +206,38 @@ blockchainTests('LiquidityProvider feature', env => {
|
|||||||
it('Successfully executes an ETH-ERC20 swap', async () => {
|
it('Successfully executes an ETH-ERC20 swap', async () => {
|
||||||
const tx = await feature
|
const tx = await feature
|
||||||
.sellToLiquidityProvider(
|
.sellToLiquidityProvider(
|
||||||
token.address,
|
|
||||||
ETH_TOKEN_ADDRESS,
|
ETH_TOKEN_ADDRESS,
|
||||||
|
token.address,
|
||||||
|
liquidityProvider.address,
|
||||||
constants.NULL_ADDRESS,
|
constants.NULL_ADDRESS,
|
||||||
constants.ONE_ETHER,
|
constants.ONE_ETHER,
|
||||||
constants.ZERO_AMOUNT,
|
constants.ZERO_AMOUNT,
|
||||||
|
constants.NULL_BYTES,
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ from: taker, value: constants.ONE_ETHER });
|
.awaitTransactionSuccessAsync({ from: taker, value: constants.ONE_ETHER });
|
||||||
verifyEventsFromLogs(
|
verifyEventsFromLogs(
|
||||||
tx.logs,
|
tx.logs,
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
inputToken: weth.address,
|
|
||||||
outputToken: token.address,
|
outputToken: token.address,
|
||||||
inputTokenAmount: constants.ONE_ETHER,
|
recipient: taker,
|
||||||
outputTokenAmount: constants.ZERO_AMOUNT,
|
minBuyAmount: constants.ZERO_AMOUNT,
|
||||||
from: constants.NULL_ADDRESS,
|
ethBalance: constants.ONE_ETHER,
|
||||||
to: taker,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
IERC20BridgeEvents.ERC20BridgeTransfer,
|
TestLiquidityProviderEvents.SellEthForToken,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('Successfully executes an ERC20-ETH swap', async () => {
|
it('Successfully executes an ERC20-ETH swap', async () => {
|
||||||
const tx = await feature
|
const tx = await feature
|
||||||
.sellToLiquidityProvider(
|
.sellToLiquidityProvider(
|
||||||
ETH_TOKEN_ADDRESS,
|
|
||||||
token.address,
|
token.address,
|
||||||
|
ETH_TOKEN_ADDRESS,
|
||||||
|
liquidityProvider.address,
|
||||||
constants.NULL_ADDRESS,
|
constants.NULL_ADDRESS,
|
||||||
constants.ONE_ETHER,
|
constants.ONE_ETHER,
|
||||||
constants.ZERO_AMOUNT,
|
constants.ZERO_AMOUNT,
|
||||||
|
constants.NULL_BYTES,
|
||||||
)
|
)
|
||||||
.awaitTransactionSuccessAsync({ from: taker });
|
.awaitTransactionSuccessAsync({ from: taker });
|
||||||
verifyEventsFromLogs(
|
verifyEventsFromLogs(
|
||||||
@ -222,14 +245,12 @@ blockchainTests('LiquidityProvider feature', env => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
inputToken: token.address,
|
inputToken: token.address,
|
||||||
outputToken: weth.address,
|
recipient: taker,
|
||||||
inputTokenAmount: constants.ONE_ETHER,
|
minBuyAmount: constants.ZERO_AMOUNT,
|
||||||
outputTokenAmount: constants.ZERO_AMOUNT,
|
inputTokenBalance: constants.ONE_ETHER,
|
||||||
from: constants.NULL_ADDRESS,
|
|
||||||
to: zeroEx.address,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
IERC20BridgeEvents.ERC20BridgeTransfer,
|
TestLiquidityProviderEvents.SellTokenForEth,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -26,6 +26,7 @@ export * from '../test/generated-wrappers/i_flash_wallet';
|
|||||||
export * from '../test/generated-wrappers/i_gas_token';
|
export * from '../test/generated-wrappers/i_gas_token';
|
||||||
export * from '../test/generated-wrappers/i_liquidity_provider';
|
export * from '../test/generated-wrappers/i_liquidity_provider';
|
||||||
export * from '../test/generated-wrappers/i_liquidity_provider_feature';
|
export * from '../test/generated-wrappers/i_liquidity_provider_feature';
|
||||||
|
export * from '../test/generated-wrappers/i_liquidity_provider_sandbox';
|
||||||
export * from '../test/generated-wrappers/i_meta_transactions_feature';
|
export * from '../test/generated-wrappers/i_meta_transactions_feature';
|
||||||
export * from '../test/generated-wrappers/i_ownable_feature';
|
export * from '../test/generated-wrappers/i_ownable_feature';
|
||||||
export * from '../test/generated-wrappers/i_signature_validator_feature';
|
export * from '../test/generated-wrappers/i_signature_validator_feature';
|
||||||
@ -41,7 +42,6 @@ export * from '../test/generated-wrappers/lib_bootstrap';
|
|||||||
export * from '../test/generated-wrappers/lib_common_rich_errors';
|
export * from '../test/generated-wrappers/lib_common_rich_errors';
|
||||||
export * from '../test/generated-wrappers/lib_erc20_transformer';
|
export * from '../test/generated-wrappers/lib_erc20_transformer';
|
||||||
export * from '../test/generated-wrappers/lib_liquidity_provider_rich_errors';
|
export * from '../test/generated-wrappers/lib_liquidity_provider_rich_errors';
|
||||||
export * from '../test/generated-wrappers/lib_liquidity_provider_storage';
|
|
||||||
export * from '../test/generated-wrappers/lib_meta_transactions_rich_errors';
|
export * from '../test/generated-wrappers/lib_meta_transactions_rich_errors';
|
||||||
export * from '../test/generated-wrappers/lib_meta_transactions_storage';
|
export * from '../test/generated-wrappers/lib_meta_transactions_storage';
|
||||||
export * from '../test/generated-wrappers/lib_migrate';
|
export * from '../test/generated-wrappers/lib_migrate';
|
||||||
@ -64,6 +64,7 @@ export * from '../test/generated-wrappers/lib_transform_erc20_rich_errors';
|
|||||||
export * from '../test/generated-wrappers/lib_transform_erc20_storage';
|
export * from '../test/generated-wrappers/lib_transform_erc20_storage';
|
||||||
export * from '../test/generated-wrappers/lib_wallet_rich_errors';
|
export * from '../test/generated-wrappers/lib_wallet_rich_errors';
|
||||||
export * from '../test/generated-wrappers/liquidity_provider_feature';
|
export * from '../test/generated-wrappers/liquidity_provider_feature';
|
||||||
|
export * from '../test/generated-wrappers/liquidity_provider_sandbox';
|
||||||
export * from '../test/generated-wrappers/log_metadata_transformer';
|
export * from '../test/generated-wrappers/log_metadata_transformer';
|
||||||
export * from '../test/generated-wrappers/meta_transactions_feature';
|
export * from '../test/generated-wrappers/meta_transactions_feature';
|
||||||
export * from '../test/generated-wrappers/mixin_adapter_addresses';
|
export * from '../test/generated-wrappers/mixin_adapter_addresses';
|
||||||
@ -93,6 +94,7 @@ export * from '../test/generated-wrappers/test_full_migration';
|
|||||||
export * from '../test/generated-wrappers/test_initial_migration';
|
export * from '../test/generated-wrappers/test_initial_migration';
|
||||||
export * from '../test/generated-wrappers/test_lib_signature';
|
export * from '../test/generated-wrappers/test_lib_signature';
|
||||||
export * from '../test/generated-wrappers/test_lib_token_spender';
|
export * from '../test/generated-wrappers/test_lib_token_spender';
|
||||||
|
export * from '../test/generated-wrappers/test_liquidity_provider';
|
||||||
export * from '../test/generated-wrappers/test_meta_transactions_transform_erc20_feature';
|
export * from '../test/generated-wrappers/test_meta_transactions_transform_erc20_feature';
|
||||||
export * from '../test/generated-wrappers/test_migrator';
|
export * from '../test/generated-wrappers/test_migrator';
|
||||||
export * from '../test/generated-wrappers/test_mint_token_erc20_transformer';
|
export * from '../test/generated-wrappers/test_mint_token_erc20_transformer';
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"generated-artifacts/IAllowanceTarget.json",
|
"generated-artifacts/IAllowanceTarget.json",
|
||||||
"generated-artifacts/IERC20Transformer.json",
|
"generated-artifacts/IERC20Transformer.json",
|
||||||
"generated-artifacts/IFlashWallet.json",
|
"generated-artifacts/IFlashWallet.json",
|
||||||
|
"generated-artifacts/ILiquidityProvider.json",
|
||||||
"generated-artifacts/IOwnableFeature.json",
|
"generated-artifacts/IOwnableFeature.json",
|
||||||
"generated-artifacts/ISimpleFunctionRegistryFeature.json",
|
"generated-artifacts/ISimpleFunctionRegistryFeature.json",
|
||||||
"generated-artifacts/ITokenSpenderFeature.json",
|
"generated-artifacts/ITokenSpenderFeature.json",
|
||||||
@ -50,6 +51,7 @@
|
|||||||
"test/generated-artifacts/IGasToken.json",
|
"test/generated-artifacts/IGasToken.json",
|
||||||
"test/generated-artifacts/ILiquidityProvider.json",
|
"test/generated-artifacts/ILiquidityProvider.json",
|
||||||
"test/generated-artifacts/ILiquidityProviderFeature.json",
|
"test/generated-artifacts/ILiquidityProviderFeature.json",
|
||||||
|
"test/generated-artifacts/ILiquidityProviderSandbox.json",
|
||||||
"test/generated-artifacts/IMetaTransactionsFeature.json",
|
"test/generated-artifacts/IMetaTransactionsFeature.json",
|
||||||
"test/generated-artifacts/IOwnableFeature.json",
|
"test/generated-artifacts/IOwnableFeature.json",
|
||||||
"test/generated-artifacts/ISignatureValidatorFeature.json",
|
"test/generated-artifacts/ISignatureValidatorFeature.json",
|
||||||
@ -65,7 +67,6 @@
|
|||||||
"test/generated-artifacts/LibCommonRichErrors.json",
|
"test/generated-artifacts/LibCommonRichErrors.json",
|
||||||
"test/generated-artifacts/LibERC20Transformer.json",
|
"test/generated-artifacts/LibERC20Transformer.json",
|
||||||
"test/generated-artifacts/LibLiquidityProviderRichErrors.json",
|
"test/generated-artifacts/LibLiquidityProviderRichErrors.json",
|
||||||
"test/generated-artifacts/LibLiquidityProviderStorage.json",
|
|
||||||
"test/generated-artifacts/LibMetaTransactionsRichErrors.json",
|
"test/generated-artifacts/LibMetaTransactionsRichErrors.json",
|
||||||
"test/generated-artifacts/LibMetaTransactionsStorage.json",
|
"test/generated-artifacts/LibMetaTransactionsStorage.json",
|
||||||
"test/generated-artifacts/LibMigrate.json",
|
"test/generated-artifacts/LibMigrate.json",
|
||||||
@ -88,6 +89,7 @@
|
|||||||
"test/generated-artifacts/LibTransformERC20Storage.json",
|
"test/generated-artifacts/LibTransformERC20Storage.json",
|
||||||
"test/generated-artifacts/LibWalletRichErrors.json",
|
"test/generated-artifacts/LibWalletRichErrors.json",
|
||||||
"test/generated-artifacts/LiquidityProviderFeature.json",
|
"test/generated-artifacts/LiquidityProviderFeature.json",
|
||||||
|
"test/generated-artifacts/LiquidityProviderSandbox.json",
|
||||||
"test/generated-artifacts/LogMetadataTransformer.json",
|
"test/generated-artifacts/LogMetadataTransformer.json",
|
||||||
"test/generated-artifacts/MetaTransactionsFeature.json",
|
"test/generated-artifacts/MetaTransactionsFeature.json",
|
||||||
"test/generated-artifacts/MixinAdapterAddresses.json",
|
"test/generated-artifacts/MixinAdapterAddresses.json",
|
||||||
@ -117,6 +119,7 @@
|
|||||||
"test/generated-artifacts/TestInitialMigration.json",
|
"test/generated-artifacts/TestInitialMigration.json",
|
||||||
"test/generated-artifacts/TestLibSignature.json",
|
"test/generated-artifacts/TestLibSignature.json",
|
||||||
"test/generated-artifacts/TestLibTokenSpender.json",
|
"test/generated-artifacts/TestLibTokenSpender.json",
|
||||||
|
"test/generated-artifacts/TestLiquidityProvider.json",
|
||||||
"test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json",
|
"test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json",
|
||||||
"test/generated-artifacts/TestMigrator.json",
|
"test/generated-artifacts/TestMigrator.json",
|
||||||
"test/generated-artifacts/TestMintTokenERC20Transformer.json",
|
"test/generated-artifacts/TestMintTokenERC20Transformer.json",
|
||||||
|
@ -1,4 +1,17 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "5.1.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Add support for LiquidityProvider feature in the swap quote consumer",
|
||||||
|
"pr": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Remove support for MultiBridge 😞",
|
||||||
|
"pr": 16
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1604620645,
|
"timestamp": 1604620645,
|
||||||
"version": "5.0.3",
|
"version": "5.0.3",
|
||||||
|
@ -20,8 +20,7 @@ pragma solidity ^0.6;
|
|||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
|
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
|
||||||
import "./interfaces/ILiquidityProvider.sol";
|
import "@0x/contracts-zero-ex/contracts/src/vendor/ILiquidityProvider.sol";
|
||||||
import "./interfaces/ILiquidityProviderRegistry.sol";
|
|
||||||
import "./ApproximateBuys.sol";
|
import "./ApproximateBuys.sol";
|
||||||
import "./SamplerUtils.sol";
|
import "./SamplerUtils.sol";
|
||||||
|
|
||||||
@ -34,37 +33,26 @@ contract LiquidityProviderSampler is
|
|||||||
uint256 constant private DEFAULT_CALL_GAS = 400e3; // 400k
|
uint256 constant private DEFAULT_CALL_GAS = 400e3; // 400k
|
||||||
|
|
||||||
/// @dev Sample sell quotes from an arbitrary on-chain liquidity provider.
|
/// @dev Sample sell quotes from an arbitrary on-chain liquidity provider.
|
||||||
/// @param registryAddress Address of the liquidity provider registry contract.
|
/// @param providerAddress Address of the liquidity provider.
|
||||||
/// @param takerToken Address of the taker token (what to sell).
|
/// @param takerToken Address of the taker token (what to sell).
|
||||||
/// @param makerToken Address of the maker token (what to buy).
|
/// @param makerToken Address of the maker token (what to buy).
|
||||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||||
/// amount.
|
/// amount.
|
||||||
function sampleSellsFromLiquidityProviderRegistry(
|
function sampleSellsFromLiquidityProvider(
|
||||||
address registryAddress,
|
address providerAddress,
|
||||||
address takerToken,
|
address takerToken,
|
||||||
address makerToken,
|
address makerToken,
|
||||||
uint256[] memory takerTokenAmounts
|
uint256[] memory takerTokenAmounts
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
view
|
view
|
||||||
returns (uint256[] memory makerTokenAmounts, address providerAddress)
|
returns (uint256[] memory makerTokenAmounts)
|
||||||
{
|
{
|
||||||
// Initialize array of maker token amounts.
|
// Initialize array of maker token amounts.
|
||||||
uint256 numSamples = takerTokenAmounts.length;
|
uint256 numSamples = takerTokenAmounts.length;
|
||||||
makerTokenAmounts = new uint256[](numSamples);
|
makerTokenAmounts = new uint256[](numSamples);
|
||||||
|
|
||||||
// Query registry for provider address.
|
|
||||||
providerAddress = _getLiquidityProviderFromRegistry(
|
|
||||||
registryAddress,
|
|
||||||
takerToken,
|
|
||||||
makerToken
|
|
||||||
);
|
|
||||||
// If provider doesn't exist, return all zeros.
|
|
||||||
if (providerAddress == address(0)) {
|
|
||||||
return (makerTokenAmounts, providerAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint256 i = 0; i < numSamples; i++) {
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
try
|
try
|
||||||
ILiquidityProvider(providerAddress).getSellQuote
|
ILiquidityProvider(providerAddress).getSellQuote
|
||||||
@ -81,68 +69,33 @@ contract LiquidityProviderSampler is
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Sample buy quotes from an arbitrary on-chain liquidity provider.
|
/// @dev Sample buy quotes from an arbitrary on-chain liquidity provider.
|
||||||
/// @param registryAddress Address of the liquidity provider registry contract.
|
/// @param providerAddress Address of the liquidity provider.
|
||||||
/// @param takerToken Address of the taker token (what to sell).
|
/// @param takerToken Address of the taker token (what to sell).
|
||||||
/// @param makerToken Address of the maker token (what to buy).
|
/// @param makerToken Address of the maker token (what to buy).
|
||||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||||
/// amount.
|
/// amount.
|
||||||
function sampleBuysFromLiquidityProviderRegistry(
|
function sampleBuysFromLiquidityProvider(
|
||||||
address registryAddress,
|
address providerAddress,
|
||||||
address takerToken,
|
address takerToken,
|
||||||
address makerToken,
|
address makerToken,
|
||||||
uint256[] memory makerTokenAmounts
|
uint256[] memory makerTokenAmounts
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
view
|
view
|
||||||
returns (uint256[] memory takerTokenAmounts, address providerAddress)
|
returns (uint256[] memory takerTokenAmounts)
|
||||||
{
|
{
|
||||||
providerAddress = _getLiquidityProviderFromRegistry(
|
|
||||||
registryAddress,
|
|
||||||
takerToken,
|
|
||||||
makerToken
|
|
||||||
);
|
|
||||||
takerTokenAmounts = _sampleApproximateBuys(
|
takerTokenAmounts = _sampleApproximateBuys(
|
||||||
ApproximateBuyQuoteOpts({
|
ApproximateBuyQuoteOpts({
|
||||||
makerTokenData: abi.encode(makerToken, registryAddress),
|
makerTokenData: abi.encode(makerToken, providerAddress),
|
||||||
takerTokenData: abi.encode(takerToken, registryAddress),
|
takerTokenData: abi.encode(takerToken, providerAddress),
|
||||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromLiquidityProviderRegistry
|
getSellQuoteCallback: _sampleSellForApproximateBuyFromLiquidityProvider
|
||||||
}),
|
}),
|
||||||
makerTokenAmounts
|
makerTokenAmounts
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Returns the address of a liquidity provider for the given market
|
function _sampleSellForApproximateBuyFromLiquidityProvider(
|
||||||
/// (takerToken, makerToken), from a registry of liquidity providers.
|
|
||||||
/// Returns address(0) if no such provider exists in the registry.
|
|
||||||
/// @param takerToken Taker asset managed by liquidity provider.
|
|
||||||
/// @param makerToken Maker asset managed by liquidity provider.
|
|
||||||
/// @return providerAddress Address of the liquidity provider.
|
|
||||||
function _getLiquidityProviderFromRegistry(
|
|
||||||
address registryAddress,
|
|
||||||
address takerToken,
|
|
||||||
address makerToken
|
|
||||||
)
|
|
||||||
private
|
|
||||||
view
|
|
||||||
returns (address providerAddress)
|
|
||||||
{
|
|
||||||
if (registryAddress == address(0)) {
|
|
||||||
return address(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes memory callData = abi.encodeWithSelector(
|
|
||||||
ILiquidityProviderRegistry.getLiquidityProviderForMarket.selector,
|
|
||||||
takerToken,
|
|
||||||
makerToken
|
|
||||||
);
|
|
||||||
(bool didSucceed, bytes memory returnData) = registryAddress.staticcall(callData);
|
|
||||||
if (didSucceed && returnData.length == 32) {
|
|
||||||
return LibBytesV06.readAddress(returnData, 12);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function _sampleSellForApproximateBuyFromLiquidityProviderRegistry(
|
|
||||||
bytes memory takerTokenData,
|
bytes memory takerTokenData,
|
||||||
bytes memory makerTokenData,
|
bytes memory makerTokenData,
|
||||||
uint256 sellAmount
|
uint256 sellAmount
|
||||||
@ -151,15 +104,15 @@ contract LiquidityProviderSampler is
|
|||||||
view
|
view
|
||||||
returns (uint256 buyAmount)
|
returns (uint256 buyAmount)
|
||||||
{
|
{
|
||||||
(address takerToken, address plpRegistryAddress) =
|
(address takerToken, address providerAddress) =
|
||||||
abi.decode(takerTokenData, (address, address));
|
abi.decode(takerTokenData, (address, address));
|
||||||
(address makerToken) =
|
(address makerToken) =
|
||||||
abi.decode(makerTokenData, (address));
|
abi.decode(makerTokenData, (address));
|
||||||
try
|
try
|
||||||
this.sampleSellsFromLiquidityProviderRegistry
|
this.sampleSellsFromLiquidityProvider
|
||||||
{gas: DEFAULT_CALL_GAS}
|
{gas: DEFAULT_CALL_GAS}
|
||||||
(plpRegistryAddress, takerToken, makerToken, _toSingleValueArray(sellAmount))
|
(providerAddress, takerToken, makerToken, _toSingleValueArray(sellAmount))
|
||||||
returns (uint256[] memory amounts, address)
|
returns (uint256[] memory amounts)
|
||||||
{
|
{
|
||||||
return amounts[0];
|
return amounts[0];
|
||||||
} catch (bytes memory) {
|
} catch (bytes memory) {
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2020 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.6;
|
|
||||||
|
|
||||||
|
|
||||||
interface ILiquidityProvider {
|
|
||||||
|
|
||||||
/// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
|
|
||||||
/// @param tokenAddress The address of the ERC20 token to transfer.
|
|
||||||
/// @param from Address to transfer asset from.
|
|
||||||
/// @param to Address to transfer asset to.
|
|
||||||
/// @param amount Amount of asset to transfer.
|
|
||||||
/// @param bridgeData Arbitrary asset data needed by the bridge contract.
|
|
||||||
/// @return success The magic bytes `0xdc1600f3` if successful.
|
|
||||||
function bridgeTransferFrom(
|
|
||||||
address tokenAddress,
|
|
||||||
address from,
|
|
||||||
address to,
|
|
||||||
uint256 amount,
|
|
||||||
bytes calldata bridgeData
|
|
||||||
)
|
|
||||||
external
|
|
||||||
returns (bytes4 success);
|
|
||||||
|
|
||||||
/// @dev Quotes the amount of `makerToken` that would be obtained by
|
|
||||||
/// selling `sellAmount` of `takerToken`.
|
|
||||||
/// @param takerToken Address of the taker token (what to sell).
|
|
||||||
/// @param makerToken Address of the maker token (what to buy).
|
|
||||||
/// @param sellAmount Amount of `takerToken` to sell.
|
|
||||||
/// @return makerTokenAmount Amount of `makerToken` that would be obtained.
|
|
||||||
function getSellQuote(
|
|
||||||
address takerToken,
|
|
||||||
address makerToken,
|
|
||||||
uint256 sellAmount
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256 makerTokenAmount);
|
|
||||||
|
|
||||||
/// @dev Quotes the amount of `takerToken` that would need to be sold in
|
|
||||||
/// order to obtain `buyAmount` of `makerToken`.
|
|
||||||
/// @param takerToken Address of the taker token (what to sell).
|
|
||||||
/// @param makerToken Address of the maker token (what to buy).
|
|
||||||
/// @param buyAmount Amount of `makerToken` to buy.
|
|
||||||
/// @return takerTokenAmount Amount of `takerToken` that would need to be sold.
|
|
||||||
function getBuyQuote(
|
|
||||||
address takerToken,
|
|
||||||
address makerToken,
|
|
||||||
uint256 buyAmount
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256 takerTokenAmount);
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2020 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.6;
|
|
||||||
|
|
||||||
|
|
||||||
interface ILiquidityProviderRegistry {
|
|
||||||
|
|
||||||
/// @dev Returns the address of a liquidity provider for the given market
|
|
||||||
/// (takerToken, makerToken), reverting if the pool does not exist.
|
|
||||||
/// @param takerToken Taker asset managed by liquidity provider.
|
|
||||||
/// @param makerToken Maker asset managed by liquidity provider.
|
|
||||||
/// @return providerAddress Address of the liquidity provider.
|
|
||||||
function getLiquidityProviderForMarket(
|
|
||||||
address takerToken,
|
|
||||||
address makerToken
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (address providerAddress);
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
pragma solidity ^0.6;
|
|
||||||
pragma experimental ABIEncoderV2;
|
|
||||||
|
|
||||||
|
|
||||||
contract DummyLiquidityProviderRegistry
|
|
||||||
{
|
|
||||||
address private constant NULL_ADDRESS = address(0x0);
|
|
||||||
|
|
||||||
mapping (address => mapping (address => address)) internal _gAddressBook;
|
|
||||||
|
|
||||||
/// @dev Sets address of pool for a market given market (xAsset, yAsset).
|
|
||||||
/// @param xToken First asset managed by pool.
|
|
||||||
/// @param yToken Second asset managed by pool.
|
|
||||||
/// @param poolAddress Address of pool.
|
|
||||||
function setLiquidityProviderForMarket(
|
|
||||||
address xToken,
|
|
||||||
address yToken,
|
|
||||||
address poolAddress
|
|
||||||
)
|
|
||||||
external
|
|
||||||
{
|
|
||||||
_gAddressBook[xToken][yToken] = poolAddress;
|
|
||||||
_gAddressBook[yToken][xToken] = poolAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Returns the address of pool for a market given market (xAsset, yAsset), or reverts if pool does not exist.
|
|
||||||
/// @param xToken First asset managed by pool.
|
|
||||||
/// @param yToken Second asset managed by pool.
|
|
||||||
/// @return poolAddress Address of pool.
|
|
||||||
function getLiquidityProviderForMarket(
|
|
||||||
address xToken,
|
|
||||||
address yToken
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (address poolAddress)
|
|
||||||
{
|
|
||||||
poolAddress = _gAddressBook[xToken][yToken];
|
|
||||||
require(
|
|
||||||
poolAddress != NULL_ADDRESS,
|
|
||||||
"Registry/MARKET_PAIR_NOT_SET"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -36,9 +36,9 @@
|
|||||||
"publish:private": "yarn build && gitpkg publish"
|
"publish:private": "yarn build && gitpkg publish"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"publicInterfaceContracts": "ERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider",
|
"publicInterfaceContracts": "ERC20BridgeSampler",
|
||||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||||
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalancerSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|ILiquidityProvider|ILiquidityProviderRegistry|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json",
|
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalancerSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json",
|
||||||
"postpublish": {
|
"postpublish": {
|
||||||
"assets": []
|
"assets": []
|
||||||
}
|
}
|
||||||
@ -94,6 +94,7 @@
|
|||||||
"@0x/contracts-gen": "^2.0.18",
|
"@0x/contracts-gen": "^2.0.18",
|
||||||
"@0x/contracts-test-utils": "^5.3.10",
|
"@0x/contracts-test-utils": "^5.3.10",
|
||||||
"@0x/contracts-utils": "^4.5.7",
|
"@0x/contracts-utils": "^4.5.7",
|
||||||
|
"@0x/contracts-zero-ex": "^0.8.0",
|
||||||
"@0x/mesh-rpc-client": "^9.4.2",
|
"@0x/mesh-rpc-client": "^9.4.2",
|
||||||
"@0x/migrations": "^6.4.7",
|
"@0x/migrations": "^6.4.7",
|
||||||
"@0x/sol-compiler": "^4.2.7",
|
"@0x/sol-compiler": "^4.2.7",
|
||||||
|
@ -5,15 +5,5 @@
|
|||||||
*/
|
*/
|
||||||
import { ContractArtifact } from 'ethereum-types';
|
import { ContractArtifact } from 'ethereum-types';
|
||||||
|
|
||||||
import * as DummyLiquidityProvider from '../generated-artifacts/DummyLiquidityProvider.json';
|
|
||||||
import * as DummyLiquidityProviderRegistry from '../generated-artifacts/DummyLiquidityProviderRegistry.json';
|
|
||||||
import * as ERC20BridgeSampler from '../generated-artifacts/ERC20BridgeSampler.json';
|
import * as ERC20BridgeSampler from '../generated-artifacts/ERC20BridgeSampler.json';
|
||||||
import * as ILiquidityProvider from '../generated-artifacts/ILiquidityProvider.json';
|
export const artifacts = { ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact };
|
||||||
import * as ILiquidityProviderRegistry from '../generated-artifacts/ILiquidityProviderRegistry.json';
|
|
||||||
export const artifacts = {
|
|
||||||
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
|
|
||||||
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
|
|
||||||
ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
|
|
||||||
DummyLiquidityProviderRegistry: DummyLiquidityProviderRegistry as ContractArtifact,
|
|
||||||
DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact,
|
|
||||||
};
|
|
||||||
|
@ -147,10 +147,10 @@ export {
|
|||||||
GetMarketOrdersRfqtOpts,
|
GetMarketOrdersRfqtOpts,
|
||||||
KyberFillData,
|
KyberFillData,
|
||||||
LiquidityProviderFillData,
|
LiquidityProviderFillData,
|
||||||
|
LiquidityProviderRegistry,
|
||||||
MarketDepth,
|
MarketDepth,
|
||||||
MarketDepthSide,
|
MarketDepthSide,
|
||||||
MooniswapFillData,
|
MooniswapFillData,
|
||||||
MultiBridgeFillData,
|
|
||||||
MultiHopFillData,
|
MultiHopFillData,
|
||||||
NativeCollapsedFill,
|
NativeCollapsedFill,
|
||||||
NativeFillData,
|
NativeFillData,
|
||||||
|
@ -34,7 +34,7 @@ import { getSwapMinBuyAmount } from './utils';
|
|||||||
|
|
||||||
// tslint:disable-next-line:custom-no-magic-numbers
|
// tslint:disable-next-line:custom-no-magic-numbers
|
||||||
const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
|
const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
|
||||||
const { NULL_ADDRESS, ZERO_AMOUNT } = constants;
|
const { NULL_ADDRESS, NULL_BYTES, ZERO_AMOUNT } = constants;
|
||||||
|
|
||||||
export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||||
public readonly provider: ZeroExProvider;
|
public readonly provider: ZeroExProvider;
|
||||||
@ -96,9 +96,16 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
|||||||
const buyToken = getTokenFromAssetData(quote.makerAssetData);
|
const buyToken = getTokenFromAssetData(quote.makerAssetData);
|
||||||
const sellAmount = quote.worstCaseQuoteInfo.totalTakerAssetAmount;
|
const sellAmount = quote.worstCaseQuoteInfo.totalTakerAssetAmount;
|
||||||
let minBuyAmount = getSwapMinBuyAmount(quote);
|
let minBuyAmount = getSwapMinBuyAmount(quote);
|
||||||
|
let ethAmount = quote.worstCaseQuoteInfo.protocolFeeInWeiAmount;
|
||||||
|
if (isFromETH) {
|
||||||
|
ethAmount = ethAmount.plus(sellAmount);
|
||||||
|
}
|
||||||
|
const { buyTokenFeeAmount, sellTokenFeeAmount, recipient: feeRecipient } = affiliateFee;
|
||||||
|
|
||||||
// VIP routes.
|
// VIP routes.
|
||||||
if (isDirectUniswapCompatible(quote, optsWithDefaults)) {
|
if (
|
||||||
|
isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap])
|
||||||
|
) {
|
||||||
const source = quote.orders[0].fills[0].source;
|
const source = quote.orders[0].fills[0].source;
|
||||||
const fillData = quote.orders[0].fills[0].fillData as UniswapV2FillData;
|
const fillData = quote.orders[0].fills[0].fillData as UniswapV2FillData;
|
||||||
return {
|
return {
|
||||||
@ -124,6 +131,26 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.LiquidityProvider])) {
|
||||||
|
const target = quote.orders[0].makerAddress;
|
||||||
|
return {
|
||||||
|
calldataHexString: this._exchangeProxy
|
||||||
|
.sellToLiquidityProvider(
|
||||||
|
isFromETH ? ETH_TOKEN_ADDRESS : sellToken,
|
||||||
|
isToETH ? ETH_TOKEN_ADDRESS : buyToken,
|
||||||
|
target,
|
||||||
|
NULL_ADDRESS,
|
||||||
|
sellAmount,
|
||||||
|
minBuyAmount,
|
||||||
|
NULL_BYTES,
|
||||||
|
)
|
||||||
|
.getABIEncodedTransactionData(),
|
||||||
|
ethAmount: isFromETH ? sellAmount : ZERO_AMOUNT,
|
||||||
|
toAddress: this._exchangeProxy.address,
|
||||||
|
allowanceTarget: this.contractAddresses.exchangeProxyAllowanceTarget,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Build up the transforms.
|
// Build up the transforms.
|
||||||
const transforms = [];
|
const transforms = [];
|
||||||
if (isFromETH) {
|
if (isFromETH) {
|
||||||
@ -198,8 +225,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This transformer pays affiliate fees.
|
// This transformer pays affiliate fees.
|
||||||
const { buyTokenFeeAmount, sellTokenFeeAmount, recipient: feeRecipient } = affiliateFee;
|
|
||||||
|
|
||||||
if (buyTokenFeeAmount.isGreaterThan(0) && feeRecipient !== NULL_ADDRESS) {
|
if (buyTokenFeeAmount.isGreaterThan(0) && feeRecipient !== NULL_ADDRESS) {
|
||||||
transforms.push({
|
transforms.push({
|
||||||
deploymentNonce: this.transformerNonces.affiliateFeeTransformer,
|
deploymentNonce: this.transformerNonces.affiliateFeeTransformer,
|
||||||
@ -216,7 +241,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
|||||||
// Adjust the minimum buy amount by the fee.
|
// Adjust the minimum buy amount by the fee.
|
||||||
minBuyAmount = BigNumber.max(0, minBuyAmount.minus(buyTokenFeeAmount));
|
minBuyAmount = BigNumber.max(0, minBuyAmount.minus(buyTokenFeeAmount));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sellTokenFeeAmount.isGreaterThan(0) && feeRecipient !== NULL_ADDRESS) {
|
if (sellTokenFeeAmount.isGreaterThan(0) && feeRecipient !== NULL_ADDRESS) {
|
||||||
throw new Error('Affiliate fees denominated in sell token are not yet supported');
|
throw new Error('Affiliate fees denominated in sell token are not yet supported');
|
||||||
}
|
}
|
||||||
@ -240,11 +264,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
|||||||
)
|
)
|
||||||
.getABIEncodedTransactionData();
|
.getABIEncodedTransactionData();
|
||||||
|
|
||||||
let ethAmount = quote.worstCaseQuoteInfo.protocolFeeInWeiAmount;
|
|
||||||
if (isFromETH) {
|
|
||||||
ethAmount = ethAmount.plus(sellAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
calldataHexString,
|
calldataHexString,
|
||||||
ethAmount,
|
ethAmount,
|
||||||
@ -266,7 +285,11 @@ function isBuyQuote(quote: SwapQuote): quote is MarketBuySwapQuote {
|
|||||||
return quote.type === MarketOperation.Buy;
|
return quote.type === MarketOperation.Buy;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isDirectUniswapCompatible(quote: SwapQuote, opts: ExchangeProxyContractOpts): boolean {
|
function isDirectSwapCompatible(
|
||||||
|
quote: SwapQuote,
|
||||||
|
opts: ExchangeProxyContractOpts,
|
||||||
|
directSources: ERC20BridgeSource[],
|
||||||
|
): boolean {
|
||||||
// Must not be a mtx.
|
// Must not be a mtx.
|
||||||
if (opts.isMetaTransaction) {
|
if (opts.isMetaTransaction) {
|
||||||
return false;
|
return false;
|
||||||
@ -285,8 +308,7 @@ function isDirectUniswapCompatible(quote: SwapQuote, opts: ExchangeProxyContract
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const fill = order.fills[0];
|
const fill = order.fills[0];
|
||||||
// And that fill must be uniswap v2 or sushiswap.
|
if (!directSources.includes(fill.source)) {
|
||||||
if (![ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap].includes(fill.source)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -5,7 +5,7 @@ import { MarketOperation, SwapQuote } from '../types';
|
|||||||
import { ERC20BridgeSource } from '../utils/market_operation_utils/types';
|
import { ERC20BridgeSource } from '../utils/market_operation_utils/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the mminimum buy token amount for market operations by inferring
|
* Compute the minimum buy token amount for market operations by inferring
|
||||||
* the slippage from the orders in a quote. We cannot rely on
|
* the slippage from the orders in a quote. We cannot rely on
|
||||||
* `worstCaseQuoteInfo.makerAssetAmount` because that does not stop at
|
* `worstCaseQuoteInfo.makerAssetAmount` because that does not stop at
|
||||||
* maximum slippage.
|
* maximum slippage.
|
||||||
|
@ -165,8 +165,9 @@ export class SwapQuoter {
|
|||||||
expiryBufferMs,
|
expiryBufferMs,
|
||||||
permittedOrderFeeTypes,
|
permittedOrderFeeTypes,
|
||||||
samplerGasLimit,
|
samplerGasLimit,
|
||||||
liquidityProviderRegistryAddress,
|
|
||||||
rfqt,
|
rfqt,
|
||||||
|
tokenAdjacencyGraph,
|
||||||
|
liquidityProviderRegistry,
|
||||||
} = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options);
|
} = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options);
|
||||||
const provider = providerUtils.standardizeOrThrow(supportedProvider);
|
const provider = providerUtils.standardizeOrThrow(supportedProvider);
|
||||||
assert.isValidOrderbook('orderbook', orderbook);
|
assert.isValidOrderbook('orderbook', orderbook);
|
||||||
@ -208,13 +209,21 @@ export class SwapQuoter {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
this._marketOperationUtils = new MarketOperationUtils(
|
this._marketOperationUtils = new MarketOperationUtils(
|
||||||
new DexOrderSampler(samplerContract, samplerOverrides, provider),
|
new DexOrderSampler(
|
||||||
|
samplerContract,
|
||||||
|
samplerOverrides,
|
||||||
|
provider,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
tokenAdjacencyGraph,
|
||||||
|
liquidityProviderRegistry,
|
||||||
|
),
|
||||||
this._contractAddresses,
|
this._contractAddresses,
|
||||||
{
|
{
|
||||||
chainId,
|
chainId,
|
||||||
exchangeAddress: this._contractAddresses.exchange,
|
exchangeAddress: this._contractAddresses.exchange,
|
||||||
},
|
},
|
||||||
liquidityProviderRegistryAddress,
|
|
||||||
);
|
);
|
||||||
this._swapQuoteCalculator = new SwapQuoteCalculator(this._marketOperationUtils);
|
this._swapQuoteCalculator = new SwapQuoteCalculator(this._marketOperationUtils);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,13 @@ import { TakerRequestQueryParams } from '@0x/quote-server';
|
|||||||
import { SignedOrder } from '@0x/types';
|
import { SignedOrder } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
import { ERC20BridgeSource, GetMarketOrdersOpts, OptimizedMarketOrder } from './utils/market_operation_utils/types';
|
import {
|
||||||
|
ERC20BridgeSource,
|
||||||
|
GetMarketOrdersOpts,
|
||||||
|
LiquidityProviderRegistry,
|
||||||
|
OptimizedMarketOrder,
|
||||||
|
TokenAdjacencyGraph,
|
||||||
|
} from './utils/market_operation_utils/types';
|
||||||
import { QuoteReport } from './utils/quote_report_generator';
|
import { QuoteReport } from './utils/quote_report_generator';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -310,11 +316,12 @@ export interface SwapQuoterOpts extends OrderPrunerOpts {
|
|||||||
ethereumRpcUrl?: string;
|
ethereumRpcUrl?: string;
|
||||||
contractAddresses?: AssetSwapperContractAddresses;
|
contractAddresses?: AssetSwapperContractAddresses;
|
||||||
samplerGasLimit?: number;
|
samplerGasLimit?: number;
|
||||||
liquidityProviderRegistryAddress?: string;
|
|
||||||
multiBridgeAddress?: string;
|
multiBridgeAddress?: string;
|
||||||
ethGasStationUrl?: string;
|
ethGasStationUrl?: string;
|
||||||
rfqt?: SwapQuoterRfqtOpts;
|
rfqt?: SwapQuoterRfqtOpts;
|
||||||
samplerOverrides?: SamplerOverrides;
|
samplerOverrides?: SamplerOverrides;
|
||||||
|
tokenAdjacencyGraph?: TokenAdjacencyGraph;
|
||||||
|
liquidityProviderRegistry?: LiquidityProviderRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,6 +13,7 @@ import {
|
|||||||
FeeSchedule,
|
FeeSchedule,
|
||||||
FillData,
|
FillData,
|
||||||
GetMarketOrdersOpts,
|
GetMarketOrdersOpts,
|
||||||
|
LiquidityProviderRegistry,
|
||||||
MultiHopFillData,
|
MultiHopFillData,
|
||||||
SnowSwapFillData,
|
SnowSwapFillData,
|
||||||
SushiSwapFillData,
|
SushiSwapFillData,
|
||||||
@ -24,8 +25,7 @@ import {
|
|||||||
/**
|
/**
|
||||||
* Valid sources for market sell.
|
* Valid sources for market sell.
|
||||||
*/
|
*/
|
||||||
export const SELL_SOURCE_FILTER = new SourceFilters(
|
export const SELL_SOURCE_FILTER = new SourceFilters([
|
||||||
[
|
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Uniswap,
|
ERC20BridgeSource.Uniswap,
|
||||||
ERC20BridgeSource.UniswapV2,
|
ERC20BridgeSource.UniswapV2,
|
||||||
@ -44,15 +44,13 @@ export const SELL_SOURCE_FILTER = new SourceFilters(
|
|||||||
ERC20BridgeSource.MultiHop,
|
ERC20BridgeSource.MultiHop,
|
||||||
ERC20BridgeSource.Dodo,
|
ERC20BridgeSource.Dodo,
|
||||||
ERC20BridgeSource.Cream,
|
ERC20BridgeSource.Cream,
|
||||||
],
|
ERC20BridgeSource.LiquidityProvider,
|
||||||
[ERC20BridgeSource.MultiBridge],
|
]);
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Valid sources for market buy.
|
* Valid sources for market buy.
|
||||||
*/
|
*/
|
||||||
export const BUY_SOURCE_FILTER = new SourceFilters(
|
export const BUY_SOURCE_FILTER = new SourceFilters([
|
||||||
[
|
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Uniswap,
|
ERC20BridgeSource.Uniswap,
|
||||||
ERC20BridgeSource.UniswapV2,
|
ERC20BridgeSource.UniswapV2,
|
||||||
@ -70,9 +68,8 @@ export const BUY_SOURCE_FILTER = new SourceFilters(
|
|||||||
ERC20BridgeSource.MultiHop,
|
ERC20BridgeSource.MultiHop,
|
||||||
ERC20BridgeSource.Dodo,
|
ERC20BridgeSource.Dodo,
|
||||||
ERC20BridgeSource.Cream,
|
ERC20BridgeSource.Cream,
|
||||||
],
|
ERC20BridgeSource.LiquidityProvider,
|
||||||
[ERC20BridgeSource.MultiBridge],
|
]);
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 0x Protocol Fee Multiplier
|
* 0x Protocol Fee Multiplier
|
||||||
@ -352,6 +349,8 @@ export const MAINNET_KYBER_TOKEN_RESERVE_IDS: { [token: string]: string } = {
|
|||||||
'0xaa42414e44000000000000000000000000000000000000000000000000000000',
|
'0xaa42414e44000000000000000000000000000000000000000000000000000000',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const LIQUIDITY_PROVIDER_REGISTRY: LiquidityProviderRegistry = {};
|
||||||
|
|
||||||
export const MAINNET_SUSHI_SWAP_ROUTER = '0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F';
|
export const MAINNET_SUSHI_SWAP_ROUTER = '0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F';
|
||||||
|
|
||||||
export const MAINNET_SHELL_POOLS = {
|
export const MAINNET_SHELL_POOLS = {
|
||||||
@ -544,5 +543,5 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = {
|
|||||||
exchangeProxyOverhead: () => ZERO_AMOUNT,
|
exchangeProxyOverhead: () => ZERO_AMOUNT,
|
||||||
allowFallback: true,
|
allowFallback: true,
|
||||||
shouldGenerateQuoteReport: false,
|
shouldGenerateQuoteReport: false,
|
||||||
tokenAdjacencyGraph: {},
|
tokenAdjacencyGraph: { default: [] },
|
||||||
};
|
};
|
||||||
|
@ -78,7 +78,6 @@ export async function getRfqtIndicativeQuotesAsync(
|
|||||||
|
|
||||||
export class MarketOperationUtils {
|
export class MarketOperationUtils {
|
||||||
private readonly _wethAddress: string;
|
private readonly _wethAddress: string;
|
||||||
private readonly _multiBridge: string;
|
|
||||||
private readonly _sellSources: SourceFilters;
|
private readonly _sellSources: SourceFilters;
|
||||||
private readonly _buySources: SourceFilters;
|
private readonly _buySources: SourceFilters;
|
||||||
private readonly _feeSources = new SourceFilters(FEE_QUOTE_SOURCES);
|
private readonly _feeSources = new SourceFilters(FEE_QUOTE_SOURCES);
|
||||||
@ -108,19 +107,10 @@ export class MarketOperationUtils {
|
|||||||
private readonly _sampler: DexOrderSampler,
|
private readonly _sampler: DexOrderSampler,
|
||||||
private readonly contractAddresses: AssetSwapperContractAddresses,
|
private readonly contractAddresses: AssetSwapperContractAddresses,
|
||||||
private readonly _orderDomain: OrderDomain,
|
private readonly _orderDomain: OrderDomain,
|
||||||
private readonly _liquidityProviderRegistry: string = NULL_ADDRESS,
|
|
||||||
) {
|
) {
|
||||||
this._wethAddress = contractAddresses.etherToken.toLowerCase();
|
this._wethAddress = contractAddresses.etherToken.toLowerCase();
|
||||||
this._multiBridge = contractAddresses.multiBridge.toLowerCase();
|
this._buySources = BUY_SOURCE_FILTER;
|
||||||
const optionalQuoteSources = [];
|
this._sellSources = SELL_SOURCE_FILTER;
|
||||||
if (this._liquidityProviderRegistry !== NULL_ADDRESS) {
|
|
||||||
optionalQuoteSources.push(ERC20BridgeSource.LiquidityProvider);
|
|
||||||
}
|
|
||||||
if (this._multiBridge !== NULL_ADDRESS) {
|
|
||||||
optionalQuoteSources.push(ERC20BridgeSource.MultiBridge);
|
|
||||||
}
|
|
||||||
this._buySources = BUY_SOURCE_FILTER.validate(optionalQuoteSources);
|
|
||||||
this._sellSources = SELL_SOURCE_FILTER.validate(optionalQuoteSources);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -176,42 +166,21 @@ export class MarketOperationUtils {
|
|||||||
// Get native order fillable amounts.
|
// Get native order fillable amounts.
|
||||||
this._sampler.getOrderFillableTakerAmounts(nativeOrders, this.contractAddresses.exchange),
|
this._sampler.getOrderFillableTakerAmounts(nativeOrders, this.contractAddresses.exchange),
|
||||||
// Get ETH -> maker token price.
|
// Get ETH -> maker token price.
|
||||||
this._sampler.getMedianSellRate(
|
this._sampler.getMedianSellRate(feeSourceFilters.sources, makerToken, this._wethAddress, ONE_ETHER),
|
||||||
feeSourceFilters.sources,
|
|
||||||
makerToken,
|
|
||||||
this._wethAddress,
|
|
||||||
ONE_ETHER,
|
|
||||||
this._liquidityProviderRegistry,
|
|
||||||
this._multiBridge,
|
|
||||||
),
|
|
||||||
// Get ETH -> taker token price.
|
// Get ETH -> taker token price.
|
||||||
this._sampler.getMedianSellRate(
|
this._sampler.getMedianSellRate(feeSourceFilters.sources, takerToken, this._wethAddress, ONE_ETHER),
|
||||||
feeSourceFilters.sources,
|
|
||||||
takerToken,
|
|
||||||
this._wethAddress,
|
|
||||||
ONE_ETHER,
|
|
||||||
this._liquidityProviderRegistry,
|
|
||||||
this._multiBridge,
|
|
||||||
),
|
|
||||||
// Get sell quotes for taker -> maker.
|
// Get sell quotes for taker -> maker.
|
||||||
this._sampler.getSellQuotes(
|
this._sampler.getSellQuotes(
|
||||||
quoteSourceFilters.exclude(offChainSources).sources,
|
quoteSourceFilters.exclude(offChainSources).sources,
|
||||||
makerToken,
|
makerToken,
|
||||||
takerToken,
|
takerToken,
|
||||||
sampleAmounts,
|
sampleAmounts,
|
||||||
this._wethAddress,
|
|
||||||
_opts.tokenAdjacencyGraph,
|
|
||||||
this._liquidityProviderRegistry,
|
|
||||||
this._multiBridge,
|
|
||||||
),
|
),
|
||||||
this._sampler.getTwoHopSellQuotes(
|
this._sampler.getTwoHopSellQuotes(
|
||||||
quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [],
|
quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [],
|
||||||
makerToken,
|
makerToken,
|
||||||
takerToken,
|
takerToken,
|
||||||
takerAmount,
|
takerAmount,
|
||||||
this._wethAddress,
|
|
||||||
_opts.tokenAdjacencyGraph,
|
|
||||||
this._liquidityProviderRegistry,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -327,41 +296,21 @@ export class MarketOperationUtils {
|
|||||||
// Get native order fillable amounts.
|
// Get native order fillable amounts.
|
||||||
this._sampler.getOrderFillableMakerAmounts(nativeOrders, this.contractAddresses.exchange),
|
this._sampler.getOrderFillableMakerAmounts(nativeOrders, this.contractAddresses.exchange),
|
||||||
// Get ETH -> makerToken token price.
|
// Get ETH -> makerToken token price.
|
||||||
this._sampler.getMedianSellRate(
|
this._sampler.getMedianSellRate(feeSourceFilters.sources, makerToken, this._wethAddress, ONE_ETHER),
|
||||||
feeSourceFilters.sources,
|
|
||||||
makerToken,
|
|
||||||
this._wethAddress,
|
|
||||||
ONE_ETHER,
|
|
||||||
this._liquidityProviderRegistry,
|
|
||||||
this._multiBridge,
|
|
||||||
),
|
|
||||||
// Get ETH -> taker token price.
|
// Get ETH -> taker token price.
|
||||||
this._sampler.getMedianSellRate(
|
this._sampler.getMedianSellRate(feeSourceFilters.sources, takerToken, this._wethAddress, ONE_ETHER),
|
||||||
feeSourceFilters.sources,
|
|
||||||
takerToken,
|
|
||||||
this._wethAddress,
|
|
||||||
ONE_ETHER,
|
|
||||||
this._liquidityProviderRegistry,
|
|
||||||
this._multiBridge,
|
|
||||||
),
|
|
||||||
// Get buy quotes for taker -> maker.
|
// Get buy quotes for taker -> maker.
|
||||||
this._sampler.getBuyQuotes(
|
this._sampler.getBuyQuotes(
|
||||||
quoteSourceFilters.exclude(offChainSources).sources,
|
quoteSourceFilters.exclude(offChainSources).sources,
|
||||||
makerToken,
|
makerToken,
|
||||||
takerToken,
|
takerToken,
|
||||||
sampleAmounts,
|
sampleAmounts,
|
||||||
this._wethAddress,
|
|
||||||
_opts.tokenAdjacencyGraph,
|
|
||||||
this._liquidityProviderRegistry,
|
|
||||||
),
|
),
|
||||||
this._sampler.getTwoHopBuyQuotes(
|
this._sampler.getTwoHopBuyQuotes(
|
||||||
quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [],
|
quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [],
|
||||||
makerToken,
|
makerToken,
|
||||||
takerToken,
|
takerToken,
|
||||||
makerAmount,
|
makerAmount,
|
||||||
this._wethAddress,
|
|
||||||
_opts.tokenAdjacencyGraph,
|
|
||||||
this._liquidityProviderRegistry,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
const isPriceAwareRfqEnabled =
|
const isPriceAwareRfqEnabled =
|
||||||
@ -391,10 +340,6 @@ export class MarketOperationUtils {
|
|||||||
offChainBalancerQuotes,
|
offChainBalancerQuotes,
|
||||||
offChainCreamQuotes,
|
offChainCreamQuotes,
|
||||||
] = await Promise.all([samplerPromise, rfqtPromise, offChainBalancerPromise, offChainCreamPromise]);
|
] = await Promise.all([samplerPromise, rfqtPromise, offChainBalancerPromise, offChainCreamPromise]);
|
||||||
// Attach the MultiBridge address to the sample fillData
|
|
||||||
(dexQuotes.find(quotes => quotes[0] && quotes[0].source === ERC20BridgeSource.MultiBridge) || []).forEach(
|
|
||||||
q => (q.fillData = { poolAddress: this._multiBridge }),
|
|
||||||
);
|
|
||||||
const [makerTokenDecimals, takerTokenDecimals] = tokenDecimals;
|
const [makerTokenDecimals, takerTokenDecimals] = tokenDecimals;
|
||||||
return {
|
return {
|
||||||
side: MarketOperation.Buy,
|
side: MarketOperation.Buy,
|
||||||
@ -482,7 +427,6 @@ export class MarketOperationUtils {
|
|||||||
getNativeOrderTokens(orders[0])[1],
|
getNativeOrderTokens(orders[0])[1],
|
||||||
this._wethAddress,
|
this._wethAddress,
|
||||||
ONE_ETHER,
|
ONE_ETHER,
|
||||||
this._wethAddress,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
...batchNativeOrders.map((orders, i) =>
|
...batchNativeOrders.map((orders, i) =>
|
||||||
@ -491,8 +435,6 @@ export class MarketOperationUtils {
|
|||||||
getNativeOrderTokens(orders[0])[0],
|
getNativeOrderTokens(orders[0])[0],
|
||||||
getNativeOrderTokens(orders[0])[1],
|
getNativeOrderTokens(orders[0])[1],
|
||||||
[makerAmounts[i]],
|
[makerAmounts[i]],
|
||||||
this._wethAddress,
|
|
||||||
_opts.tokenAdjacencyGraph,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
import { LiquidityProviderRegistry } from './types';
|
||||||
|
|
||||||
|
// tslint:disable completed-docs
|
||||||
|
export function getLiquidityProvidersForPair(
|
||||||
|
registry: LiquidityProviderRegistry,
|
||||||
|
takerToken: string,
|
||||||
|
makerToken: string,
|
||||||
|
): string[] {
|
||||||
|
return Object.entries(registry)
|
||||||
|
.filter(([, tokens]) => [makerToken, takerToken].every(t => tokens.includes(t)))
|
||||||
|
.map(([providerAddress]) => providerAddress);
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
import { NULL_ADDRESS, TOKENS } from './constants';
|
|
||||||
|
|
||||||
// tslint:disable completed-docs
|
|
||||||
|
|
||||||
export function getMultiBridgeIntermediateToken(takerToken: string, makerToken: string): string {
|
|
||||||
let intermediateToken = NULL_ADDRESS;
|
|
||||||
if (takerToken !== TOKENS.WETH && makerToken !== TOKENS.WETH) {
|
|
||||||
intermediateToken = TOKENS.WETH;
|
|
||||||
} else if (takerToken === TOKENS.USDC || makerToken === TOKENS.USDC) {
|
|
||||||
intermediateToken = TOKENS.DAI;
|
|
||||||
}
|
|
||||||
return intermediateToken;
|
|
||||||
}
|
|
@ -21,19 +21,11 @@ export function getIntermediateTokens(
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
||||||
wethAddress: string,
|
|
||||||
): string[] {
|
): string[] {
|
||||||
let intermediateTokens = [];
|
const intermediateTokens = _.intersection(
|
||||||
if (makerToken === wethAddress) {
|
_.get(tokenAdjacencyGraph, takerToken, tokenAdjacencyGraph.default),
|
||||||
intermediateTokens = _.get(tokenAdjacencyGraph, takerToken, [] as string[]);
|
_.get(tokenAdjacencyGraph, makerToken, tokenAdjacencyGraph.default),
|
||||||
} else if (takerToken === wethAddress) {
|
|
||||||
intermediateTokens = _.get(tokenAdjacencyGraph, makerToken, [] as string[]);
|
|
||||||
} else {
|
|
||||||
intermediateTokens = _.union(
|
|
||||||
_.intersection(_.get(tokenAdjacencyGraph, takerToken, []), _.get(tokenAdjacencyGraph, makerToken, [])),
|
|
||||||
[wethAddress],
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
return _.uniqBy(intermediateTokens, a => a.toLowerCase()).filter(
|
return _.uniqBy(intermediateTokens, a => a.toLowerCase()).filter(
|
||||||
token => token.toLowerCase() !== makerToken.toLowerCase() && token.toLowerCase() !== takerToken.toLowerCase(),
|
token => token.toLowerCase() !== makerToken.toLowerCase() && token.toLowerCase() !== takerToken.toLowerCase(),
|
||||||
);
|
);
|
||||||
|
@ -15,7 +15,6 @@ import {
|
|||||||
WALLET_SIGNATURE,
|
WALLET_SIGNATURE,
|
||||||
ZERO_AMOUNT,
|
ZERO_AMOUNT,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import { getMultiBridgeIntermediateToken } from './multibridge_utils';
|
|
||||||
import {
|
import {
|
||||||
AggregationError,
|
AggregationError,
|
||||||
BalancerFillData,
|
BalancerFillData,
|
||||||
@ -28,7 +27,6 @@ import {
|
|||||||
KyberFillData,
|
KyberFillData,
|
||||||
LiquidityProviderFillData,
|
LiquidityProviderFillData,
|
||||||
MooniswapFillData,
|
MooniswapFillData,
|
||||||
MultiBridgeFillData,
|
|
||||||
MultiHopFillData,
|
MultiHopFillData,
|
||||||
NativeCollapsedFill,
|
NativeCollapsedFill,
|
||||||
OptimizedMarketOrder,
|
OptimizedMarketOrder,
|
||||||
@ -193,8 +191,6 @@ function getBridgeAddressFromFill(fill: CollapsedFill, opts: CreateOrderFromPath
|
|||||||
return opts.contractAddresses.creamBridge;
|
return opts.contractAddresses.creamBridge;
|
||||||
case ERC20BridgeSource.LiquidityProvider:
|
case ERC20BridgeSource.LiquidityProvider:
|
||||||
return (fill.fillData as LiquidityProviderFillData).poolAddress;
|
return (fill.fillData as LiquidityProviderFillData).poolAddress;
|
||||||
case ERC20BridgeSource.MultiBridge:
|
|
||||||
return (fill.fillData as MultiBridgeFillData).poolAddress;
|
|
||||||
case ERC20BridgeSource.MStable:
|
case ERC20BridgeSource.MStable:
|
||||||
return opts.contractAddresses.mStableBridge;
|
return opts.contractAddresses.mStableBridge;
|
||||||
case ERC20BridgeSource.Mooniswap:
|
case ERC20BridgeSource.Mooniswap:
|
||||||
@ -301,13 +297,6 @@ export function createBridgeOrder(
|
|||||||
createSushiSwapBridgeData(sushiSwapFillData.tokenAddressPath, sushiSwapFillData.router),
|
createSushiSwapBridgeData(sushiSwapFillData.tokenAddressPath, sushiSwapFillData.router),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case ERC20BridgeSource.MultiBridge:
|
|
||||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
|
||||||
makerToken,
|
|
||||||
bridgeAddress,
|
|
||||||
createMultiBridgeData(takerToken, makerToken),
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case ERC20BridgeSource.Kyber:
|
case ERC20BridgeSource.Kyber:
|
||||||
const kyberFillData = (fill as CollapsedFill<KyberFillData>).fillData!; // tslint:disable-line:no-non-null-assertion
|
const kyberFillData = (fill as CollapsedFill<KyberFillData>).fillData!; // tslint:disable-line:no-non-null-assertion
|
||||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||||
@ -372,15 +361,6 @@ function createBridgeData(tokenAddress: string): string {
|
|||||||
return encoder.encode({ tokenAddress });
|
return encoder.encode({ tokenAddress });
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMultiBridgeData(takerToken: string, makerToken: string): string {
|
|
||||||
const intermediateToken = getMultiBridgeIntermediateToken(takerToken, makerToken);
|
|
||||||
const encoder = AbiEncoder.create([
|
|
||||||
{ name: 'takerToken', type: 'address' },
|
|
||||||
{ name: 'intermediateToken', type: 'address' },
|
|
||||||
]);
|
|
||||||
return encoder.encode({ takerToken, intermediateToken });
|
|
||||||
}
|
|
||||||
|
|
||||||
function createBalancerBridgeData(takerToken: string, poolAddress: string): string {
|
function createBalancerBridgeData(takerToken: string, poolAddress: string): string {
|
||||||
const encoder = AbiEncoder.create([
|
const encoder = AbiEncoder.create([
|
||||||
{ name: 'takerToken', type: 'address' },
|
{ name: 'takerToken', type: 'address' },
|
||||||
|
@ -2,7 +2,7 @@ import { BigNumber } from '@0x/utils';
|
|||||||
|
|
||||||
import { MarketOperation } from '../../types';
|
import { MarketOperation } from '../../types';
|
||||||
|
|
||||||
import { POSITIVE_INF, SOURCE_FLAGS, ZERO_AMOUNT } from './constants';
|
import { POSITIVE_INF, ZERO_AMOUNT } from './constants';
|
||||||
import { createBridgeOrder, createNativeOrder, CreateOrderFromPathOpts, getMakerTakerTokens } from './orders';
|
import { createBridgeOrder, createNativeOrder, CreateOrderFromPathOpts, getMakerTakerTokens } from './orders';
|
||||||
import { getCompleteRate, getRate } from './rate_utils';
|
import { getCompleteRate, getRate } from './rate_utils';
|
||||||
import {
|
import {
|
||||||
@ -202,7 +202,7 @@ export class Path {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return doSourcesConflict(this.sourceFlags);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isValidNextFill(fill: Fill): boolean {
|
public isValidNextFill(fill: Fill): boolean {
|
||||||
@ -215,7 +215,7 @@ export class Path {
|
|||||||
if (fill.parent) {
|
if (fill.parent) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return doSourcesConflict(this.sourceFlags | fill.flags);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _collapseFills(): ReadonlyArray<CollapsedFill> {
|
private _collapseFills(): ReadonlyArray<CollapsedFill> {
|
||||||
@ -268,9 +268,3 @@ export interface CollapsedPath extends Path {
|
|||||||
readonly collapsedFills: ReadonlyArray<CollapsedFill>;
|
readonly collapsedFills: ReadonlyArray<CollapsedFill>;
|
||||||
readonly orders: OptimizedMarketOrder[];
|
readonly orders: OptimizedMarketOrder[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const MULTIBRIDGE_SOURCES = SOURCE_FLAGS.LiquidityProvider | SOURCE_FLAGS.Uniswap;
|
|
||||||
export function doSourcesConflict(flags: number): boolean {
|
|
||||||
const multiBridgeConflict = flags & SOURCE_FLAGS.MultiBridge && flags & MULTIBRIDGE_SOURCES;
|
|
||||||
return !multiBridgeConflict;
|
|
||||||
}
|
|
||||||
|
@ -8,7 +8,7 @@ import { BalancerPoolsCache } from './balancer_utils';
|
|||||||
import { BancorService } from './bancor_service';
|
import { BancorService } from './bancor_service';
|
||||||
import { CreamPoolsCache } from './cream_utils';
|
import { CreamPoolsCache } from './cream_utils';
|
||||||
import { SamplerOperations } from './sampler_operations';
|
import { SamplerOperations } from './sampler_operations';
|
||||||
import { BatchedOperation } from './types';
|
import { BatchedOperation, LiquidityProviderRegistry, TokenAdjacencyGraph } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate sample amounts up to `maxFillAmount`.
|
* Generate sample amounts up to `maxFillAmount`.
|
||||||
@ -40,8 +40,18 @@ export class DexOrderSampler extends SamplerOperations {
|
|||||||
balancerPoolsCache?: BalancerPoolsCache,
|
balancerPoolsCache?: BalancerPoolsCache,
|
||||||
creamPoolsCache?: CreamPoolsCache,
|
creamPoolsCache?: CreamPoolsCache,
|
||||||
getBancorServiceFn?: () => BancorService,
|
getBancorServiceFn?: () => BancorService,
|
||||||
|
tokenAdjacencyGraph?: TokenAdjacencyGraph,
|
||||||
|
liquidityProviderRegistry?: LiquidityProviderRegistry,
|
||||||
) {
|
) {
|
||||||
super(_samplerContract, provider, balancerPoolsCache, creamPoolsCache, getBancorServiceFn);
|
super(
|
||||||
|
_samplerContract,
|
||||||
|
provider,
|
||||||
|
balancerPoolsCache,
|
||||||
|
creamPoolsCache,
|
||||||
|
getBancorServiceFn,
|
||||||
|
tokenAdjacencyGraph,
|
||||||
|
liquidityProviderRegistry,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Type overloads for `executeAsync()`. Could skip this if we would upgrade TS. */
|
/* Type overloads for `executeAsync()`. Could skip this if we would upgrade TS. */
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import { SupportedProvider } from '@0x/dev-utils';
|
import { SupportedProvider } from '@0x/dev-utils';
|
||||||
import { SignedOrder } from '@0x/types';
|
import { SignedOrder } from '@0x/types';
|
||||||
import { BigNumber, NULL_ADDRESS } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { ERC20BridgeSamplerContract } from '../../wrappers';
|
import { ERC20BridgeSamplerContract } from '../../wrappers';
|
||||||
|
|
||||||
import { BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote } from './balancer_utils';
|
import { BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote } from './balancer_utils';
|
||||||
import { BancorService } from './bancor_service';
|
import { BancorService } from './bancor_service';
|
||||||
import { MAINNET_SUSHI_SWAP_ROUTER, MAX_UINT256, NULL_BYTES, ZERO_AMOUNT } from './constants';
|
import { LIQUIDITY_PROVIDER_REGISTRY, MAINNET_SUSHI_SWAP_ROUTER, MAX_UINT256, ZERO_AMOUNT } from './constants';
|
||||||
import { CreamPoolsCache } from './cream_utils';
|
import { CreamPoolsCache } from './cream_utils';
|
||||||
import { getCurveInfosForPair, getSnowSwapInfosForPair, getSwerveInfosForPair } from './curve_utils';
|
import { getCurveInfosForPair, getSnowSwapInfosForPair, getSwerveInfosForPair } from './curve_utils';
|
||||||
import { getKyberReserveIdsForPair } from './kyber_utils';
|
import { getKyberReserveIdsForPair } from './kyber_utils';
|
||||||
import { getMultiBridgeIntermediateToken } from './multibridge_utils';
|
import { getLiquidityProvidersForPair } from './liquidity_provider_utils';
|
||||||
import { getIntermediateTokens } from './multihop_utils';
|
import { getIntermediateTokens } from './multihop_utils';
|
||||||
import { SamplerContractOperation } from './sampler_contract_operation';
|
import { SamplerContractOperation } from './sampler_contract_operation';
|
||||||
import { getShellsForPair } from './shell_utils';
|
import { getShellsForPair } from './shell_utils';
|
||||||
@ -28,8 +28,8 @@ import {
|
|||||||
HopInfo,
|
HopInfo,
|
||||||
KyberFillData,
|
KyberFillData,
|
||||||
LiquidityProviderFillData,
|
LiquidityProviderFillData,
|
||||||
|
LiquidityProviderRegistry,
|
||||||
MooniswapFillData,
|
MooniswapFillData,
|
||||||
MultiBridgeFillData,
|
|
||||||
MultiHopFillData,
|
MultiHopFillData,
|
||||||
ShellFillData,
|
ShellFillData,
|
||||||
SnowSwapFillData,
|
SnowSwapFillData,
|
||||||
@ -47,7 +47,6 @@ import {
|
|||||||
*/
|
*/
|
||||||
export const TWO_HOP_SOURCE_FILTERS = SourceFilters.all().exclude([
|
export const TWO_HOP_SOURCE_FILTERS = SourceFilters.all().exclude([
|
||||||
ERC20BridgeSource.MultiHop,
|
ERC20BridgeSource.MultiHop,
|
||||||
ERC20BridgeSource.MultiBridge,
|
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
]);
|
]);
|
||||||
/**
|
/**
|
||||||
@ -80,6 +79,8 @@ export class SamplerOperations {
|
|||||||
public readonly balancerPoolsCache: BalancerPoolsCache = new BalancerPoolsCache(),
|
public readonly balancerPoolsCache: BalancerPoolsCache = new BalancerPoolsCache(),
|
||||||
public readonly creamPoolsCache: CreamPoolsCache = new CreamPoolsCache(),
|
public readonly creamPoolsCache: CreamPoolsCache = new CreamPoolsCache(),
|
||||||
protected readonly getBancorServiceFn?: () => BancorService, // for dependency injection in tests
|
protected readonly getBancorServiceFn?: () => BancorService, // for dependency injection in tests
|
||||||
|
protected readonly tokenAdjacencyGraph: TokenAdjacencyGraph = { default: [] },
|
||||||
|
public readonly liquidityProviderRegistry: LiquidityProviderRegistry = LIQUIDITY_PROVIDER_REGISTRY,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public async getBancorServiceAsync(): Promise<BancorService> {
|
public async getBancorServiceAsync(): Promise<BancorService> {
|
||||||
@ -221,64 +222,32 @@ export class SamplerOperations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getLiquidityProviderSellQuotes(
|
public getLiquidityProviderSellQuotes(
|
||||||
registryAddress: string,
|
providerAddress: string,
|
||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
takerFillAmounts: BigNumber[],
|
takerFillAmounts: BigNumber[],
|
||||||
): SourceQuoteOperation<LiquidityProviderFillData> {
|
): SourceQuoteOperation<LiquidityProviderFillData> {
|
||||||
return new SamplerContractOperation({
|
return new SamplerContractOperation({
|
||||||
source: ERC20BridgeSource.LiquidityProvider,
|
source: ERC20BridgeSource.LiquidityProvider,
|
||||||
fillData: {} as LiquidityProviderFillData, // tslint:disable-line:no-object-literal-type-assertion
|
fillData: { poolAddress: providerAddress },
|
||||||
contract: this._samplerContract,
|
contract: this._samplerContract,
|
||||||
function: this._samplerContract.sampleSellsFromLiquidityProviderRegistry,
|
function: this._samplerContract.sampleSellsFromLiquidityProvider,
|
||||||
params: [registryAddress, takerToken, makerToken, takerFillAmounts],
|
params: [providerAddress, takerToken, makerToken, takerFillAmounts],
|
||||||
callback: (callResults: string, fillData: LiquidityProviderFillData): BigNumber[] => {
|
|
||||||
const [samples, poolAddress] = this._samplerContract.getABIDecodedReturnData<[BigNumber[], string]>(
|
|
||||||
'sampleSellsFromLiquidityProviderRegistry',
|
|
||||||
callResults,
|
|
||||||
);
|
|
||||||
fillData.poolAddress = poolAddress;
|
|
||||||
return samples;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getLiquidityProviderBuyQuotes(
|
public getLiquidityProviderBuyQuotes(
|
||||||
registryAddress: string,
|
providerAddress: string,
|
||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
makerFillAmounts: BigNumber[],
|
makerFillAmounts: BigNumber[],
|
||||||
): SourceQuoteOperation<LiquidityProviderFillData> {
|
): SourceQuoteOperation<LiquidityProviderFillData> {
|
||||||
return new SamplerContractOperation({
|
return new SamplerContractOperation({
|
||||||
source: ERC20BridgeSource.LiquidityProvider,
|
source: ERC20BridgeSource.LiquidityProvider,
|
||||||
fillData: {} as LiquidityProviderFillData, // tslint:disable-line:no-object-literal-type-assertion
|
fillData: { poolAddress: providerAddress },
|
||||||
contract: this._samplerContract,
|
contract: this._samplerContract,
|
||||||
function: this._samplerContract.sampleBuysFromLiquidityProviderRegistry,
|
function: this._samplerContract.sampleBuysFromLiquidityProvider,
|
||||||
params: [registryAddress, takerToken, makerToken, makerFillAmounts],
|
params: [providerAddress, takerToken, makerToken, makerFillAmounts],
|
||||||
callback: (callResults: string, fillData: LiquidityProviderFillData): BigNumber[] => {
|
|
||||||
const [samples, poolAddress] = this._samplerContract.getABIDecodedReturnData<[BigNumber[], string]>(
|
|
||||||
'sampleBuysFromLiquidityProviderRegistry',
|
|
||||||
callResults,
|
|
||||||
);
|
|
||||||
fillData.poolAddress = poolAddress;
|
|
||||||
return samples;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public getMultiBridgeSellQuotes(
|
|
||||||
multiBridgeAddress: string,
|
|
||||||
makerToken: string,
|
|
||||||
intermediateToken: string,
|
|
||||||
takerToken: string,
|
|
||||||
takerFillAmounts: BigNumber[],
|
|
||||||
): SourceQuoteOperation<MultiBridgeFillData> {
|
|
||||||
return new SamplerContractOperation({
|
|
||||||
source: ERC20BridgeSource.MultiBridge,
|
|
||||||
fillData: { poolAddress: multiBridgeAddress },
|
|
||||||
contract: this._samplerContract,
|
|
||||||
function: this._samplerContract.sampleSellsFromMultiBridge,
|
|
||||||
params: [multiBridgeAddress, takerToken, intermediateToken, makerToken, takerFillAmounts],
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,34 +638,15 @@ export class SamplerOperations {
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
sellAmount: BigNumber,
|
sellAmount: BigNumber,
|
||||||
wethAddress: string,
|
|
||||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
|
||||||
liquidityProviderRegistryAddress?: string,
|
|
||||||
): BatchedOperation<Array<DexSample<MultiHopFillData>>> {
|
): BatchedOperation<Array<DexSample<MultiHopFillData>>> {
|
||||||
const _sources = TWO_HOP_SOURCE_FILTERS.getAllowed(sources);
|
const _sources = TWO_HOP_SOURCE_FILTERS.getAllowed(sources);
|
||||||
if (_sources.length === 0) {
|
if (_sources.length === 0) {
|
||||||
return SamplerOperations.constant([]);
|
return SamplerOperations.constant([]);
|
||||||
}
|
}
|
||||||
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph, wethAddress);
|
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph);
|
||||||
const subOps = intermediateTokens.map(intermediateToken => {
|
const subOps = intermediateTokens.map(intermediateToken => {
|
||||||
const firstHopOps = this._getSellQuoteOperations(
|
const firstHopOps = this._getSellQuoteOperations(_sources, intermediateToken, takerToken, [ZERO_AMOUNT]);
|
||||||
_sources,
|
const secondHopOps = this._getSellQuoteOperations(_sources, makerToken, intermediateToken, [ZERO_AMOUNT]);
|
||||||
intermediateToken,
|
|
||||||
takerToken,
|
|
||||||
[ZERO_AMOUNT],
|
|
||||||
wethAddress,
|
|
||||||
tokenAdjacencyGraph,
|
|
||||||
liquidityProviderRegistryAddress,
|
|
||||||
);
|
|
||||||
const secondHopOps = this._getSellQuoteOperations(
|
|
||||||
_sources,
|
|
||||||
makerToken,
|
|
||||||
intermediateToken,
|
|
||||||
[ZERO_AMOUNT],
|
|
||||||
wethAddress,
|
|
||||||
tokenAdjacencyGraph,
|
|
||||||
liquidityProviderRegistryAddress,
|
|
||||||
);
|
|
||||||
return new SamplerContractOperation({
|
return new SamplerContractOperation({
|
||||||
contract: this._samplerContract,
|
contract: this._samplerContract,
|
||||||
source: ERC20BridgeSource.MultiHop,
|
source: ERC20BridgeSource.MultiHop,
|
||||||
@ -747,34 +697,19 @@ export class SamplerOperations {
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
buyAmount: BigNumber,
|
buyAmount: BigNumber,
|
||||||
wethAddress: string,
|
|
||||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
|
||||||
liquidityProviderRegistryAddress?: string,
|
|
||||||
): BatchedOperation<Array<DexSample<MultiHopFillData>>> {
|
): BatchedOperation<Array<DexSample<MultiHopFillData>>> {
|
||||||
const _sources = TWO_HOP_SOURCE_FILTERS.getAllowed(sources);
|
const _sources = TWO_HOP_SOURCE_FILTERS.getAllowed(sources);
|
||||||
if (_sources.length === 0) {
|
if (_sources.length === 0) {
|
||||||
return SamplerOperations.constant([]);
|
return SamplerOperations.constant([]);
|
||||||
}
|
}
|
||||||
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph, wethAddress);
|
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph);
|
||||||
const subOps = intermediateTokens.map(intermediateToken => {
|
const subOps = intermediateTokens.map(intermediateToken => {
|
||||||
const firstHopOps = this._getBuyQuoteOperations(
|
const firstHopOps = this._getBuyQuoteOperations(_sources, intermediateToken, takerToken, [
|
||||||
_sources,
|
new BigNumber(0),
|
||||||
intermediateToken,
|
]);
|
||||||
takerToken,
|
const secondHopOps = this._getBuyQuoteOperations(_sources, makerToken, intermediateToken, [
|
||||||
[new BigNumber(0)],
|
new BigNumber(0),
|
||||||
wethAddress,
|
]);
|
||||||
tokenAdjacencyGraph, // TODO is this a bad idea?
|
|
||||||
liquidityProviderRegistryAddress,
|
|
||||||
);
|
|
||||||
const secondHopOps = this._getBuyQuoteOperations(
|
|
||||||
_sources,
|
|
||||||
makerToken,
|
|
||||||
intermediateToken,
|
|
||||||
[new BigNumber(0)],
|
|
||||||
wethAddress,
|
|
||||||
tokenAdjacencyGraph,
|
|
||||||
liquidityProviderRegistryAddress,
|
|
||||||
);
|
|
||||||
return new SamplerContractOperation({
|
return new SamplerContractOperation({
|
||||||
contract: this._samplerContract,
|
contract: this._samplerContract,
|
||||||
source: ERC20BridgeSource.MultiHop,
|
source: ERC20BridgeSource.MultiHop,
|
||||||
@ -853,17 +788,10 @@ export class SamplerOperations {
|
|||||||
): SourceQuoteOperation<ShellFillData> {
|
): SourceQuoteOperation<ShellFillData> {
|
||||||
return new SamplerContractOperation({
|
return new SamplerContractOperation({
|
||||||
source: ERC20BridgeSource.Shell,
|
source: ERC20BridgeSource.Shell,
|
||||||
|
fillData: { poolAddress },
|
||||||
contract: this._samplerContract,
|
contract: this._samplerContract,
|
||||||
function: this._samplerContract.sampleSellsFromShell,
|
function: this._samplerContract.sampleSellsFromShell,
|
||||||
params: [poolAddress, takerToken, makerToken, takerFillAmounts],
|
params: [poolAddress, takerToken, makerToken, takerFillAmounts],
|
||||||
callback: (callResults: string, fillData: ShellFillData): BigNumber[] => {
|
|
||||||
const samples = this._samplerContract.getABIDecodedReturnData<BigNumber[]>(
|
|
||||||
'sampleSellsFromShell',
|
|
||||||
callResults,
|
|
||||||
);
|
|
||||||
fillData.poolAddress = poolAddress;
|
|
||||||
return samples;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -875,17 +803,10 @@ export class SamplerOperations {
|
|||||||
): SourceQuoteOperation {
|
): SourceQuoteOperation {
|
||||||
return new SamplerContractOperation({
|
return new SamplerContractOperation({
|
||||||
source: ERC20BridgeSource.Shell,
|
source: ERC20BridgeSource.Shell,
|
||||||
|
fillData: { poolAddress },
|
||||||
contract: this._samplerContract,
|
contract: this._samplerContract,
|
||||||
function: this._samplerContract.sampleBuysFromShell,
|
function: this._samplerContract.sampleBuysFromShell,
|
||||||
params: [poolAddress, takerToken, makerToken, makerFillAmounts],
|
params: [poolAddress, takerToken, makerToken, makerFillAmounts],
|
||||||
callback: (callResults: string, fillData: ShellFillData): BigNumber[] => {
|
|
||||||
const samples = this._samplerContract.getABIDecodedReturnData<BigNumber[]>(
|
|
||||||
'sampleBuysFromShell',
|
|
||||||
callResults,
|
|
||||||
);
|
|
||||||
fillData.poolAddress = poolAddress;
|
|
||||||
return samples;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -936,52 +857,36 @@ export class SamplerOperations {
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
takerFillAmount: BigNumber,
|
takerFillAmount: BigNumber,
|
||||||
liquidityProviderRegistryAddress?: string,
|
|
||||||
multiBridgeAddress?: string,
|
|
||||||
): BatchedOperation<BigNumber> {
|
): BatchedOperation<BigNumber> {
|
||||||
if (makerToken.toLowerCase() === takerToken.toLowerCase()) {
|
if (makerToken.toLowerCase() === takerToken.toLowerCase()) {
|
||||||
return SamplerOperations.constant(new BigNumber(1));
|
return SamplerOperations.constant(new BigNumber(1));
|
||||||
}
|
}
|
||||||
const getSellQuotes = this.getSellQuotes(
|
const subOps = this._getSellQuoteOperations(sources, makerToken, takerToken, [takerFillAmount], {
|
||||||
sources,
|
default: [],
|
||||||
makerToken,
|
});
|
||||||
takerToken,
|
|
||||||
[takerFillAmount],
|
|
||||||
NULL_ADDRESS, // weth address
|
|
||||||
{}, // token adjacency
|
|
||||||
liquidityProviderRegistryAddress,
|
|
||||||
multiBridgeAddress,
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
encodeCall: () => {
|
encodeCall: () => {
|
||||||
const encodedCall = getSellQuotes.encodeCall();
|
const subCalls = subOps.map(op => op.encodeCall());
|
||||||
// All soures were excluded
|
return this._samplerContract.batchCall(subCalls).getABIEncodedTransactionData();
|
||||||
if (encodedCall === NULL_BYTES) {
|
|
||||||
return NULL_BYTES;
|
|
||||||
}
|
|
||||||
return this._samplerContract.batchCall([encodedCall]).getABIEncodedTransactionData();
|
|
||||||
},
|
},
|
||||||
handleCallResults: callResults => {
|
handleCallResults: callResults => {
|
||||||
if (callResults === NULL_BYTES) {
|
|
||||||
return ZERO_AMOUNT;
|
|
||||||
}
|
|
||||||
const rawSubCallResults = this._samplerContract.getABIDecodedReturnData<string[]>(
|
const rawSubCallResults = this._samplerContract.getABIDecodedReturnData<string[]>(
|
||||||
'batchCall',
|
'batchCall',
|
||||||
callResults,
|
callResults,
|
||||||
);
|
);
|
||||||
const samples = getSellQuotes.handleCallResults(rawSubCallResults[0]);
|
const samples = subOps.map((op, i) => op.handleCallResults(rawSubCallResults[i]));
|
||||||
if (samples.length === 0) {
|
if (samples.length === 0) {
|
||||||
return ZERO_AMOUNT;
|
return ZERO_AMOUNT;
|
||||||
}
|
}
|
||||||
const flatSortedSamples = samples
|
const flatSortedSamples = samples
|
||||||
.reduce((acc, v) => acc.concat(...v))
|
.reduce((acc, v) => acc.concat(...v))
|
||||||
.filter(v => !v.output.isZero())
|
.filter(v => !v.isZero())
|
||||||
.sort((a, b) => a.output.comparedTo(b.output));
|
.sort((a, b) => a.comparedTo(b));
|
||||||
if (flatSortedSamples.length === 0) {
|
if (flatSortedSamples.length === 0) {
|
||||||
return ZERO_AMOUNT;
|
return ZERO_AMOUNT;
|
||||||
}
|
}
|
||||||
const medianSample = flatSortedSamples[Math.floor(flatSortedSamples.length / 2)];
|
const medianSample = flatSortedSamples[Math.floor(flatSortedSamples.length / 2)];
|
||||||
return medianSample.output.div(medianSample.input);
|
return medianSample.div(takerFillAmount);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -991,21 +896,8 @@ export class SamplerOperations {
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
takerFillAmounts: BigNumber[],
|
takerFillAmounts: BigNumber[],
|
||||||
wethAddress: string,
|
|
||||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
|
||||||
liquidityProviderRegistryAddress?: string,
|
|
||||||
multiBridgeAddress?: string,
|
|
||||||
): BatchedOperation<DexSample[][]> {
|
): BatchedOperation<DexSample[][]> {
|
||||||
const subOps = this._getSellQuoteOperations(
|
const subOps = this._getSellQuoteOperations(sources, makerToken, takerToken, takerFillAmounts);
|
||||||
sources,
|
|
||||||
makerToken,
|
|
||||||
takerToken,
|
|
||||||
takerFillAmounts,
|
|
||||||
wethAddress,
|
|
||||||
tokenAdjacencyGraph,
|
|
||||||
liquidityProviderRegistryAddress,
|
|
||||||
multiBridgeAddress,
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
encodeCall: () => {
|
encodeCall: () => {
|
||||||
const subCalls = subOps.map(op => op.encodeCall());
|
const subCalls = subOps.map(op => op.encodeCall());
|
||||||
@ -1034,19 +926,8 @@ export class SamplerOperations {
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
makerFillAmounts: BigNumber[],
|
makerFillAmounts: BigNumber[],
|
||||||
wethAddress: string,
|
|
||||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
|
||||||
liquidityProviderRegistryAddress?: string,
|
|
||||||
): BatchedOperation<DexSample[][]> {
|
): BatchedOperation<DexSample[][]> {
|
||||||
const subOps = this._getBuyQuoteOperations(
|
const subOps = this._getBuyQuoteOperations(sources, makerToken, takerToken, makerFillAmounts);
|
||||||
sources,
|
|
||||||
makerToken,
|
|
||||||
takerToken,
|
|
||||||
makerFillAmounts,
|
|
||||||
wethAddress,
|
|
||||||
tokenAdjacencyGraph,
|
|
||||||
liquidityProviderRegistryAddress,
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
encodeCall: () => {
|
encodeCall: () => {
|
||||||
const subCalls = subOps.map(op => op.encodeCall());
|
const subCalls = subOps.map(op => op.encodeCall());
|
||||||
@ -1075,21 +956,12 @@ export class SamplerOperations {
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
takerFillAmounts: BigNumber[],
|
takerFillAmounts: BigNumber[],
|
||||||
wethAddress: string,
|
tokenAdjacencyGraph: TokenAdjacencyGraph = this.tokenAdjacencyGraph,
|
||||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
|
||||||
liquidityProviderRegistryAddress?: string,
|
|
||||||
multiBridgeAddress?: string,
|
|
||||||
): SourceQuoteOperation[] {
|
): SourceQuoteOperation[] {
|
||||||
const _sources = BATCH_SOURCE_FILTERS.exclude(
|
|
||||||
liquidityProviderRegistryAddress ? [] : [ERC20BridgeSource.LiquidityProvider],
|
|
||||||
)
|
|
||||||
.exclude(multiBridgeAddress || multiBridgeAddress === NULL_ADDRESS ? [] : [ERC20BridgeSource.MultiBridge])
|
|
||||||
.getAllowed(sources);
|
|
||||||
|
|
||||||
// Find the adjacent tokens in the provided tooken adjacency graph,
|
// Find the adjacent tokens in the provided tooken adjacency graph,
|
||||||
// e.g if this is DAI->USDC we may check for DAI->WETH->USDC
|
// e.g if this is DAI->USDC we may check for DAI->WETH->USDC
|
||||||
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph, wethAddress);
|
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph);
|
||||||
|
const _sources = BATCH_SOURCE_FILTERS.getAllowed(sources);
|
||||||
return _.flatten(
|
return _.flatten(
|
||||||
_sources.map(
|
_sources.map(
|
||||||
(source): SourceQuoteOperation | SourceQuoteOperation[] => {
|
(source): SourceQuoteOperation | SourceQuoteOperation[] => {
|
||||||
@ -1144,30 +1016,12 @@ export class SamplerOperations {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
case ERC20BridgeSource.LiquidityProvider:
|
case ERC20BridgeSource.LiquidityProvider:
|
||||||
if (liquidityProviderRegistryAddress === undefined) {
|
return getLiquidityProvidersForPair(
|
||||||
throw new Error(
|
this.liquidityProviderRegistry,
|
||||||
'Cannot sample liquidity from a LiquidityProvider liquidity pool, if a registry is not provided.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return this.getLiquidityProviderSellQuotes(
|
|
||||||
liquidityProviderRegistryAddress,
|
|
||||||
makerToken,
|
|
||||||
takerToken,
|
takerToken,
|
||||||
takerFillAmounts,
|
|
||||||
);
|
|
||||||
case ERC20BridgeSource.MultiBridge:
|
|
||||||
if (multiBridgeAddress === undefined) {
|
|
||||||
throw new Error(
|
|
||||||
'Cannot sample liquidity from MultiBridge if an address is not provided.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const intermediateToken = getMultiBridgeIntermediateToken(takerToken, makerToken);
|
|
||||||
return this.getMultiBridgeSellQuotes(
|
|
||||||
multiBridgeAddress,
|
|
||||||
makerToken,
|
makerToken,
|
||||||
intermediateToken,
|
).map(pool =>
|
||||||
takerToken,
|
this.getLiquidityProviderSellQuotes(pool, makerToken, takerToken, takerFillAmounts),
|
||||||
takerFillAmounts,
|
|
||||||
);
|
);
|
||||||
case ERC20BridgeSource.MStable:
|
case ERC20BridgeSource.MStable:
|
||||||
return this.getMStableSellQuotes(makerToken, takerToken, takerFillAmounts);
|
return this.getMStableSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||||
@ -1216,18 +1070,11 @@ export class SamplerOperations {
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
makerFillAmounts: BigNumber[],
|
makerFillAmounts: BigNumber[],
|
||||||
wethAddress: string,
|
|
||||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
|
||||||
liquidityProviderRegistryAddress?: string,
|
|
||||||
): SourceQuoteOperation[] {
|
): SourceQuoteOperation[] {
|
||||||
const _sources = BATCH_SOURCE_FILTERS.exclude(
|
|
||||||
liquidityProviderRegistryAddress ? [] : [ERC20BridgeSource.LiquidityProvider],
|
|
||||||
).getAllowed(sources);
|
|
||||||
|
|
||||||
// Find the adjacent tokens in the provided tooken adjacency graph,
|
// Find the adjacent tokens in the provided tooken adjacency graph,
|
||||||
// e.g if this is DAI->USDC we may check for DAI->WETH->USDC
|
// e.g if this is DAI->USDC we may check for DAI->WETH->USDC
|
||||||
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph, wethAddress);
|
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph);
|
||||||
|
const _sources = BATCH_SOURCE_FILTERS.getAllowed(sources);
|
||||||
return _.flatten(
|
return _.flatten(
|
||||||
_sources.map(
|
_sources.map(
|
||||||
(source): SourceQuoteOperation | SourceQuoteOperation[] => {
|
(source): SourceQuoteOperation | SourceQuoteOperation[] => {
|
||||||
@ -1282,16 +1129,12 @@ export class SamplerOperations {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
case ERC20BridgeSource.LiquidityProvider:
|
case ERC20BridgeSource.LiquidityProvider:
|
||||||
if (liquidityProviderRegistryAddress === undefined) {
|
return getLiquidityProvidersForPair(
|
||||||
throw new Error(
|
this.liquidityProviderRegistry,
|
||||||
'Cannot sample liquidity from a LiquidityProvider liquidity pool, if a registry is not provided.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return this.getLiquidityProviderBuyQuotes(
|
|
||||||
liquidityProviderRegistryAddress,
|
|
||||||
makerToken,
|
|
||||||
takerToken,
|
takerToken,
|
||||||
makerFillAmounts,
|
makerToken,
|
||||||
|
).map(pool =>
|
||||||
|
this.getLiquidityProviderBuyQuotes(pool, makerToken, takerToken, makerFillAmounts),
|
||||||
);
|
);
|
||||||
case ERC20BridgeSource.MStable:
|
case ERC20BridgeSource.MStable:
|
||||||
return this.getMStableBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
return this.getMStableBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||||
|
@ -132,10 +132,6 @@ export interface LiquidityProviderFillData extends FillData {
|
|||||||
poolAddress: string;
|
poolAddress: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MultiBridgeFillData extends FillData {
|
|
||||||
poolAddress: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BancorFillData extends FillData {
|
export interface BancorFillData extends FillData {
|
||||||
path: string[];
|
path: string[];
|
||||||
networkAddress: string;
|
networkAddress: string;
|
||||||
@ -375,6 +371,11 @@ export interface MarketSideLiquidity {
|
|||||||
|
|
||||||
export interface TokenAdjacencyGraph {
|
export interface TokenAdjacencyGraph {
|
||||||
[token: string]: string[];
|
[token: string]: string[];
|
||||||
|
default: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LiquidityProviderRegistry {
|
||||||
|
[address: string]: [string, string];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GenerateOptimizedOrdersOpts {
|
export interface GenerateOptimizedOrdersOpts {
|
||||||
|
@ -3,8 +3,4 @@
|
|||||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||||
* -----------------------------------------------------------------------------
|
* -----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
export * from '../generated-wrappers/dummy_liquidity_provider';
|
|
||||||
export * from '../generated-wrappers/dummy_liquidity_provider_registry';
|
|
||||||
export * from '../generated-wrappers/erc20_bridge_sampler';
|
export * from '../generated-wrappers/erc20_bridge_sampler';
|
||||||
export * from '../generated-wrappers/i_liquidity_provider';
|
|
||||||
export * from '../generated-wrappers/i_liquidity_provider_registry';
|
|
||||||
|
@ -11,15 +11,12 @@ import * as CurveSampler from '../test/generated-artifacts/CurveSampler.json';
|
|||||||
import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json';
|
import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json';
|
||||||
import * as DODOSampler from '../test/generated-artifacts/DODOSampler.json';
|
import * as DODOSampler from '../test/generated-artifacts/DODOSampler.json';
|
||||||
import * as DummyLiquidityProvider from '../test/generated-artifacts/DummyLiquidityProvider.json';
|
import * as DummyLiquidityProvider from '../test/generated-artifacts/DummyLiquidityProvider.json';
|
||||||
import * as DummyLiquidityProviderRegistry from '../test/generated-artifacts/DummyLiquidityProviderRegistry.json';
|
|
||||||
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
|
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
|
||||||
import * as Eth2DaiSampler from '../test/generated-artifacts/Eth2DaiSampler.json';
|
import * as Eth2DaiSampler from '../test/generated-artifacts/Eth2DaiSampler.json';
|
||||||
import * as IBalancer from '../test/generated-artifacts/IBalancer.json';
|
import * as IBalancer from '../test/generated-artifacts/IBalancer.json';
|
||||||
import * as ICurve from '../test/generated-artifacts/ICurve.json';
|
import * as ICurve from '../test/generated-artifacts/ICurve.json';
|
||||||
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
|
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
|
||||||
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
|
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
|
||||||
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
|
|
||||||
import * as ILiquidityProviderRegistry from '../test/generated-artifacts/ILiquidityProviderRegistry.json';
|
|
||||||
import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json';
|
import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json';
|
||||||
import * as IMStable from '../test/generated-artifacts/IMStable.json';
|
import * as IMStable from '../test/generated-artifacts/IMStable.json';
|
||||||
import * as IMultiBridge from '../test/generated-artifacts/IMultiBridge.json';
|
import * as IMultiBridge from '../test/generated-artifacts/IMultiBridge.json';
|
||||||
@ -64,8 +61,6 @@ export const artifacts = {
|
|||||||
ICurve: ICurve as ContractArtifact,
|
ICurve: ICurve as ContractArtifact,
|
||||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||||
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
||||||
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
|
|
||||||
ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
|
|
||||||
IMStable: IMStable as ContractArtifact,
|
IMStable: IMStable as ContractArtifact,
|
||||||
IMooniswap: IMooniswap as ContractArtifact,
|
IMooniswap: IMooniswap as ContractArtifact,
|
||||||
IMultiBridge: IMultiBridge as ContractArtifact,
|
IMultiBridge: IMultiBridge as ContractArtifact,
|
||||||
@ -73,7 +68,6 @@ export const artifacts = {
|
|||||||
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
|
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
|
||||||
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
|
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
|
||||||
DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact,
|
DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact,
|
||||||
DummyLiquidityProviderRegistry: DummyLiquidityProviderRegistry as ContractArtifact,
|
|
||||||
TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
|
TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
|
||||||
TestNativeOrderSampler: TestNativeOrderSampler as ContractArtifact,
|
TestNativeOrderSampler: TestNativeOrderSampler as ContractArtifact,
|
||||||
};
|
};
|
||||||
|
@ -11,11 +11,7 @@ import { BigNumber, hexUtils } from '@0x/utils';
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { artifacts } from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
import {
|
import { DummyLiquidityProviderContract, TestERC20BridgeSamplerContract } from '../wrappers';
|
||||||
DummyLiquidityProviderContract,
|
|
||||||
DummyLiquidityProviderRegistryContract,
|
|
||||||
TestERC20BridgeSamplerContract,
|
|
||||||
} from '../wrappers';
|
|
||||||
|
|
||||||
// tslint:disable: custom-no-magic-numbers
|
// tslint:disable: custom-no-magic-numbers
|
||||||
|
|
||||||
@ -817,7 +813,6 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const yAsset = randomAddress();
|
const yAsset = randomAddress();
|
||||||
const sampleAmounts = getSampleAmounts(yAsset);
|
const sampleAmounts = getSampleAmounts(yAsset);
|
||||||
let liquidityProvider: DummyLiquidityProviderContract;
|
let liquidityProvider: DummyLiquidityProviderContract;
|
||||||
let registryContract: DummyLiquidityProviderRegistryContract;
|
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
liquidityProvider = await DummyLiquidityProviderContract.deployFrom0xArtifactAsync(
|
liquidityProvider = await DummyLiquidityProviderContract.deployFrom0xArtifactAsync(
|
||||||
@ -826,61 +821,33 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
env.txDefaults,
|
env.txDefaults,
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
registryContract = await DummyLiquidityProviderRegistryContract.deployFrom0xArtifactAsync(
|
|
||||||
artifacts.DummyLiquidityProviderRegistry,
|
|
||||||
env.provider,
|
|
||||||
env.txDefaults,
|
|
||||||
{},
|
|
||||||
);
|
|
||||||
await registryContract
|
|
||||||
.setLiquidityProviderForMarket(xAsset, yAsset, liquidityProvider.address)
|
|
||||||
.awaitTransactionSuccessAsync();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to query sells from the liquidity provider', async () => {
|
it('should be able to query sells from the liquidity provider', async () => {
|
||||||
const [quotes, providerAddress] = await testContract
|
const quotes = await testContract
|
||||||
.sampleSellsFromLiquidityProviderRegistry(registryContract.address, yAsset, xAsset, sampleAmounts)
|
.sampleSellsFromLiquidityProvider(liquidityProvider.address, yAsset, xAsset, sampleAmounts)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
quotes.forEach((value, idx) => {
|
quotes.forEach((value, idx) => {
|
||||||
expect(value).is.bignumber.eql(sampleAmounts[idx].minus(1));
|
expect(value).is.bignumber.eql(sampleAmounts[idx].minus(1));
|
||||||
});
|
});
|
||||||
expect(providerAddress).to.equal(liquidityProvider.address);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to query buys from the liquidity provider', async () => {
|
it('should be able to query buys from the liquidity provider', async () => {
|
||||||
const [quotes, providerAddress] = await testContract
|
const quotes = await testContract
|
||||||
.sampleBuysFromLiquidityProviderRegistry(registryContract.address, yAsset, xAsset, sampleAmounts)
|
.sampleBuysFromLiquidityProvider(liquidityProvider.address, yAsset, xAsset, sampleAmounts)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
quotes.forEach((value, idx) => {
|
quotes.forEach((value, idx) => {
|
||||||
expect(value).is.bignumber.eql(sampleAmounts[idx].plus(1));
|
expect(value).is.bignumber.eql(sampleAmounts[idx].plus(1));
|
||||||
});
|
});
|
||||||
expect(providerAddress).to.equal(liquidityProvider.address);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should just return zeros if the liquidity provider cannot be found', async () => {
|
it('should just return zeros if the liquidity provider does not exist', async () => {
|
||||||
const [quotes, providerAddress] = await testContract
|
const quotes = await testContract
|
||||||
.sampleBuysFromLiquidityProviderRegistry(
|
.sampleBuysFromLiquidityProvider(randomAddress(), yAsset, xAsset, sampleAmounts)
|
||||||
registryContract.address,
|
|
||||||
yAsset,
|
|
||||||
randomAddress(),
|
|
||||||
sampleAmounts,
|
|
||||||
)
|
|
||||||
.callAsync();
|
.callAsync();
|
||||||
quotes.forEach(value => {
|
quotes.forEach(value => {
|
||||||
expect(value).is.bignumber.eql(constants.ZERO_AMOUNT);
|
expect(value).is.bignumber.eql(constants.ZERO_AMOUNT);
|
||||||
});
|
});
|
||||||
expect(providerAddress).to.equal(constants.NULL_ADDRESS);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should just return zeros if the registry does not exist', async () => {
|
|
||||||
const [quotes, providerAddress] = await testContract
|
|
||||||
.sampleBuysFromLiquidityProviderRegistry(randomAddress(), yAsset, xAsset, sampleAmounts)
|
|
||||||
.callAsync();
|
|
||||||
quotes.forEach(value => {
|
|
||||||
expect(value).is.bignumber.eql(constants.ZERO_AMOUNT);
|
|
||||||
});
|
|
||||||
expect(providerAddress).to.equal(constants.NULL_ADDRESS);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ describe('DexSampler tests', () => {
|
|||||||
const wethAddress = getContractAddressesForChainOrThrow(CHAIN_ID).etherToken;
|
const wethAddress = getContractAddressesForChainOrThrow(CHAIN_ID).etherToken;
|
||||||
const exchangeAddress = getContractAddressesForChainOrThrow(CHAIN_ID).exchange;
|
const exchangeAddress = getContractAddressesForChainOrThrow(CHAIN_ID).exchange;
|
||||||
|
|
||||||
const tokenAdjacencyGraph: TokenAdjacencyGraph = {};
|
const tokenAdjacencyGraph: TokenAdjacencyGraph = { default: [wethAddress] };
|
||||||
|
|
||||||
describe('getSampleAmounts()', () => {
|
describe('getSampleAmounts()', () => {
|
||||||
const FILL_AMOUNT = getRandomInteger(1, 1e18);
|
const FILL_AMOUNT = getRandomInteger(1, 1e18);
|
||||||
@ -159,26 +159,31 @@ describe('DexSampler tests', () => {
|
|||||||
it('getLiquidityProviderSellQuotes()', async () => {
|
it('getLiquidityProviderSellQuotes()', async () => {
|
||||||
const expectedMakerToken = randomAddress();
|
const expectedMakerToken = randomAddress();
|
||||||
const expectedTakerToken = randomAddress();
|
const expectedTakerToken = randomAddress();
|
||||||
const registry = randomAddress();
|
|
||||||
const poolAddress = randomAddress();
|
const poolAddress = randomAddress();
|
||||||
const sampler = new MockSamplerContract({
|
const sampler = new MockSamplerContract({
|
||||||
sampleSellsFromLiquidityProviderRegistry: (registryAddress, takerToken, makerToken, _fillAmounts) => {
|
sampleSellsFromLiquidityProvider: (providerAddress, takerToken, makerToken, _fillAmounts) => {
|
||||||
expect(registryAddress).to.eq(registry);
|
expect(providerAddress).to.eq(poolAddress);
|
||||||
expect(takerToken).to.eq(expectedTakerToken);
|
expect(takerToken).to.eq(expectedTakerToken);
|
||||||
expect(makerToken).to.eq(expectedMakerToken);
|
expect(makerToken).to.eq(expectedMakerToken);
|
||||||
return [[toBaseUnitAmount(1001)], poolAddress];
|
return [toBaseUnitAmount(1001)];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const dexOrderSampler = new DexOrderSampler(sampler);
|
const dexOrderSampler = new DexOrderSampler(
|
||||||
|
sampler,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
{ [poolAddress]: [expectedMakerToken, expectedTakerToken] },
|
||||||
|
);
|
||||||
const [result] = await dexOrderSampler.executeAsync(
|
const [result] = await dexOrderSampler.executeAsync(
|
||||||
dexOrderSampler.getSellQuotes(
|
dexOrderSampler.getSellQuotes(
|
||||||
[ERC20BridgeSource.LiquidityProvider],
|
[ERC20BridgeSource.LiquidityProvider],
|
||||||
expectedMakerToken,
|
expectedMakerToken,
|
||||||
expectedTakerToken,
|
expectedTakerToken,
|
||||||
[toBaseUnitAmount(1000)],
|
[toBaseUnitAmount(1000)],
|
||||||
wethAddress,
|
|
||||||
tokenAdjacencyGraph,
|
|
||||||
registry,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(result).to.deep.equal([
|
expect(result).to.deep.equal([
|
||||||
@ -196,26 +201,31 @@ describe('DexSampler tests', () => {
|
|||||||
it('getLiquidityProviderBuyQuotes()', async () => {
|
it('getLiquidityProviderBuyQuotes()', async () => {
|
||||||
const expectedMakerToken = randomAddress();
|
const expectedMakerToken = randomAddress();
|
||||||
const expectedTakerToken = randomAddress();
|
const expectedTakerToken = randomAddress();
|
||||||
const registry = randomAddress();
|
|
||||||
const poolAddress = randomAddress();
|
const poolAddress = randomAddress();
|
||||||
const sampler = new MockSamplerContract({
|
const sampler = new MockSamplerContract({
|
||||||
sampleBuysFromLiquidityProviderRegistry: (registryAddress, takerToken, makerToken, _fillAmounts) => {
|
sampleBuysFromLiquidityProvider: (providerAddress, takerToken, makerToken, _fillAmounts) => {
|
||||||
expect(registryAddress).to.eq(registry);
|
expect(providerAddress).to.eq(poolAddress);
|
||||||
expect(takerToken).to.eq(expectedTakerToken);
|
expect(takerToken).to.eq(expectedTakerToken);
|
||||||
expect(makerToken).to.eq(expectedMakerToken);
|
expect(makerToken).to.eq(expectedMakerToken);
|
||||||
return [[toBaseUnitAmount(999)], poolAddress];
|
return [toBaseUnitAmount(999)];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const dexOrderSampler = new DexOrderSampler(sampler);
|
const dexOrderSampler = new DexOrderSampler(
|
||||||
|
sampler,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
{ [poolAddress]: [expectedMakerToken, expectedTakerToken] },
|
||||||
|
);
|
||||||
const [result] = await dexOrderSampler.executeAsync(
|
const [result] = await dexOrderSampler.executeAsync(
|
||||||
dexOrderSampler.getBuyQuotes(
|
dexOrderSampler.getBuyQuotes(
|
||||||
[ERC20BridgeSource.LiquidityProvider],
|
[ERC20BridgeSource.LiquidityProvider],
|
||||||
expectedMakerToken,
|
expectedMakerToken,
|
||||||
expectedTakerToken,
|
expectedTakerToken,
|
||||||
[toBaseUnitAmount(1000)],
|
[toBaseUnitAmount(1000)],
|
||||||
wethAddress,
|
|
||||||
tokenAdjacencyGraph,
|
|
||||||
registry,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(result).to.deep.equal([
|
expect(result).to.deep.equal([
|
||||||
@ -230,50 +240,6 @@ describe('DexSampler tests', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('getMultiBridgeSellQuotes()', async () => {
|
|
||||||
const expectedTakerToken = randomAddress();
|
|
||||||
const expectedMakerToken = randomAddress();
|
|
||||||
const multiBridge = randomAddress();
|
|
||||||
|
|
||||||
const sampler = new MockSamplerContract({
|
|
||||||
sampleSellsFromMultiBridge: (
|
|
||||||
multiBridgeAddress,
|
|
||||||
takerToken,
|
|
||||||
_intermediateToken,
|
|
||||||
makerToken,
|
|
||||||
_fillAmounts,
|
|
||||||
) => {
|
|
||||||
expect(multiBridgeAddress).to.eq(multiBridge);
|
|
||||||
expect(takerToken).to.eq(expectedTakerToken);
|
|
||||||
expect(makerToken).to.eq(expectedMakerToken);
|
|
||||||
return [toBaseUnitAmount(1001)];
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const dexOrderSampler = new DexOrderSampler(sampler);
|
|
||||||
const [result] = await dexOrderSampler.executeAsync(
|
|
||||||
dexOrderSampler.getSellQuotes(
|
|
||||||
[ERC20BridgeSource.MultiBridge],
|
|
||||||
expectedMakerToken,
|
|
||||||
expectedTakerToken,
|
|
||||||
[toBaseUnitAmount(1000)],
|
|
||||||
wethAddress,
|
|
||||||
tokenAdjacencyGraph,
|
|
||||||
randomAddress(),
|
|
||||||
multiBridge,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
expect(result).to.deep.equal([
|
|
||||||
[
|
|
||||||
{
|
|
||||||
source: 'MultiBridge',
|
|
||||||
output: toBaseUnitAmount(1001),
|
|
||||||
input: toBaseUnitAmount(1000),
|
|
||||||
fillData: { poolAddress: multiBridge },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getEth2DaiSellQuotes()', async () => {
|
it('getEth2DaiSellQuotes()', async () => {
|
||||||
const expectedTakerToken = randomAddress();
|
const expectedTakerToken = randomAddress();
|
||||||
const expectedMakerToken = randomAddress();
|
const expectedMakerToken = randomAddress();
|
||||||
@ -416,15 +382,21 @@ describe('DexSampler tests', () => {
|
|||||||
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue());
|
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue());
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const dexOrderSampler = new DexOrderSampler(sampler);
|
const dexOrderSampler = new DexOrderSampler(
|
||||||
|
sampler,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
tokenAdjacencyGraph,
|
||||||
|
);
|
||||||
const [quotes] = await dexOrderSampler.executeAsync(
|
const [quotes] = await dexOrderSampler.executeAsync(
|
||||||
dexOrderSampler.getSellQuotes(
|
dexOrderSampler.getSellQuotes(
|
||||||
sources,
|
sources,
|
||||||
expectedMakerToken,
|
expectedMakerToken,
|
||||||
expectedTakerToken,
|
expectedTakerToken,
|
||||||
expectedTakerFillAmounts,
|
expectedTakerFillAmounts,
|
||||||
wethAddress,
|
|
||||||
tokenAdjacencyGraph,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
const expectedQuotes = sources.map(s =>
|
const expectedQuotes = sources.map(s =>
|
||||||
@ -561,16 +533,17 @@ describe('DexSampler tests', () => {
|
|||||||
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue());
|
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue());
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const dexOrderSampler = new DexOrderSampler(sampler);
|
const dexOrderSampler = new DexOrderSampler(
|
||||||
const [quotes] = await dexOrderSampler.executeAsync(
|
sampler,
|
||||||
dexOrderSampler.getBuyQuotes(
|
undefined,
|
||||||
sources,
|
undefined,
|
||||||
expectedMakerToken,
|
undefined,
|
||||||
expectedTakerToken,
|
undefined,
|
||||||
expectedMakerFillAmounts,
|
undefined,
|
||||||
wethAddress,
|
|
||||||
tokenAdjacencyGraph,
|
tokenAdjacencyGraph,
|
||||||
),
|
);
|
||||||
|
const [quotes] = await dexOrderSampler.executeAsync(
|
||||||
|
dexOrderSampler.getBuyQuotes(sources, expectedMakerToken, expectedTakerToken, expectedMakerFillAmounts),
|
||||||
);
|
);
|
||||||
const expectedQuotes = sources.map(s =>
|
const expectedQuotes = sources.map(s =>
|
||||||
expectedMakerFillAmounts.map(a => ({
|
expectedMakerFillAmounts.map(a => ({
|
||||||
|
@ -20,7 +20,7 @@ import { constants } from '../src/constants';
|
|||||||
import { ExchangeProxySwapQuoteConsumer } from '../src/quote_consumers/exchange_proxy_swap_quote_consumer';
|
import { ExchangeProxySwapQuoteConsumer } from '../src/quote_consumers/exchange_proxy_swap_quote_consumer';
|
||||||
import { getSwapMinBuyAmount } from '../src/quote_consumers/utils';
|
import { getSwapMinBuyAmount } from '../src/quote_consumers/utils';
|
||||||
import { MarketBuySwapQuote, MarketOperation, MarketSellSwapQuote } from '../src/types';
|
import { MarketBuySwapQuote, MarketOperation, MarketSellSwapQuote } from '../src/types';
|
||||||
import { OptimizedMarketOrder } from '../src/utils/market_operation_utils/types';
|
import { ERC20BridgeSource, OptimizedMarketOrder } from '../src/utils/market_operation_utils/types';
|
||||||
|
|
||||||
import { chaiSetup } from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
|
|
||||||
@ -161,7 +161,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const callDataEncoder = AbiEncoder.createMethod('transformERC20', [
|
const transformERC20Encoder = AbiEncoder.createMethod('transformERC20', [
|
||||||
{ type: 'address', name: 'inputToken' },
|
{ type: 'address', name: 'inputToken' },
|
||||||
{ type: 'address', name: 'outputToken' },
|
{ type: 'address', name: 'outputToken' },
|
||||||
{ type: 'uint256', name: 'inputTokenAmount' },
|
{ type: 'uint256', name: 'inputTokenAmount' },
|
||||||
@ -173,7 +173,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
interface CallArgs {
|
interface TransformERC20Args {
|
||||||
inputToken: string;
|
inputToken: string;
|
||||||
outputToken: string;
|
outputToken: string;
|
||||||
inputTokenAmount: BigNumber;
|
inputTokenAmount: BigNumber;
|
||||||
@ -184,11 +184,31 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
|||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const liquidityProviderEncoder = AbiEncoder.createMethod('sellToLiquidityProvider', [
|
||||||
|
{ type: 'address', name: 'inputToken' },
|
||||||
|
{ type: 'address', name: 'outputToken' },
|
||||||
|
{ type: 'address', name: 'target' },
|
||||||
|
{ type: 'address', name: 'recipient' },
|
||||||
|
{ type: 'uint256', name: 'sellAmount' },
|
||||||
|
{ type: 'uint256', name: 'minBuyAmount' },
|
||||||
|
{ type: 'bytes', name: 'auxiliaryData' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
interface LiquidityProviderArgs {
|
||||||
|
inputToken: string;
|
||||||
|
outputToken: string;
|
||||||
|
target: string;
|
||||||
|
recipient: string;
|
||||||
|
sellAmount: BigNumber;
|
||||||
|
minBuyAmount: BigNumber;
|
||||||
|
auxiliaryData: string;
|
||||||
|
}
|
||||||
|
|
||||||
describe('getCalldataOrThrow()', () => {
|
describe('getCalldataOrThrow()', () => {
|
||||||
it('can produce a sell quote', async () => {
|
it('can produce a sell quote', async () => {
|
||||||
const quote = getRandomSellQuote();
|
const quote = getRandomSellQuote();
|
||||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote);
|
const callInfo = await consumer.getCalldataOrThrowAsync(quote);
|
||||||
const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs;
|
const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args;
|
||||||
expect(callArgs.inputToken).to.eq(TAKER_TOKEN);
|
expect(callArgs.inputToken).to.eq(TAKER_TOKEN);
|
||||||
expect(callArgs.outputToken).to.eq(MAKER_TOKEN);
|
expect(callArgs.outputToken).to.eq(MAKER_TOKEN);
|
||||||
expect(callArgs.inputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount);
|
expect(callArgs.inputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount);
|
||||||
@ -217,7 +237,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
|||||||
it('can produce a buy quote', async () => {
|
it('can produce a buy quote', async () => {
|
||||||
const quote = getRandomBuyQuote();
|
const quote = getRandomBuyQuote();
|
||||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote);
|
const callInfo = await consumer.getCalldataOrThrowAsync(quote);
|
||||||
const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs;
|
const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args;
|
||||||
expect(callArgs.inputToken).to.eq(TAKER_TOKEN);
|
expect(callArgs.inputToken).to.eq(TAKER_TOKEN);
|
||||||
expect(callArgs.outputToken).to.eq(MAKER_TOKEN);
|
expect(callArgs.outputToken).to.eq(MAKER_TOKEN);
|
||||||
expect(callArgs.inputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount);
|
expect(callArgs.inputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount);
|
||||||
@ -246,7 +266,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
|||||||
it('ERC20 -> ERC20 does not have a WETH transformer', async () => {
|
it('ERC20 -> ERC20 does not have a WETH transformer', async () => {
|
||||||
const quote = getRandomSellQuote();
|
const quote = getRandomSellQuote();
|
||||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote);
|
const callInfo = await consumer.getCalldataOrThrowAsync(quote);
|
||||||
const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs;
|
const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args;
|
||||||
const nonces = callArgs.transformations.map(t => t.deploymentNonce);
|
const nonces = callArgs.transformations.map(t => t.deploymentNonce);
|
||||||
expect(nonces).to.not.include(consumer.transformerNonces.wethTransformer);
|
expect(nonces).to.not.include(consumer.transformerNonces.wethTransformer);
|
||||||
});
|
});
|
||||||
@ -256,7 +276,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
|||||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
||||||
extensionContractOpts: { isFromETH: true },
|
extensionContractOpts: { isFromETH: true },
|
||||||
});
|
});
|
||||||
const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs;
|
const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args;
|
||||||
expect(callArgs.transformations[0].deploymentNonce.toNumber()).to.eq(
|
expect(callArgs.transformations[0].deploymentNonce.toNumber()).to.eq(
|
||||||
consumer.transformerNonces.wethTransformer,
|
consumer.transformerNonces.wethTransformer,
|
||||||
);
|
);
|
||||||
@ -270,7 +290,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
|||||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
||||||
extensionContractOpts: { isToETH: true },
|
extensionContractOpts: { isToETH: true },
|
||||||
});
|
});
|
||||||
const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs;
|
const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args;
|
||||||
expect(callArgs.transformations[1].deploymentNonce.toNumber()).to.eq(
|
expect(callArgs.transformations[1].deploymentNonce.toNumber()).to.eq(
|
||||||
consumer.transformerNonces.wethTransformer,
|
consumer.transformerNonces.wethTransformer,
|
||||||
);
|
);
|
||||||
@ -278,7 +298,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
|||||||
expect(wethTransformerData.amount).to.bignumber.eq(MAX_UINT256);
|
expect(wethTransformerData.amount).to.bignumber.eq(MAX_UINT256);
|
||||||
expect(wethTransformerData.token).to.eq(contractAddresses.etherToken);
|
expect(wethTransformerData.token).to.eq(contractAddresses.etherToken);
|
||||||
});
|
});
|
||||||
it('Appends an affiliate fee transformer after the fill if a buy token affiliate fee is provided', async () => {
|
it('Appends an affiliate fee transformer after the fill if a buy token affiliate fee is provided', async () => {
|
||||||
const quote = getRandomSellQuote();
|
const quote = getRandomSellQuote();
|
||||||
const affiliateFee = {
|
const affiliateFee = {
|
||||||
recipient: randomAddress(),
|
recipient: randomAddress(),
|
||||||
@ -288,7 +308,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
|||||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
||||||
extensionContractOpts: { affiliateFee },
|
extensionContractOpts: { affiliateFee },
|
||||||
});
|
});
|
||||||
const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs;
|
const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args;
|
||||||
expect(callArgs.transformations[1].deploymentNonce.toNumber()).to.eq(
|
expect(callArgs.transformations[1].deploymentNonce.toNumber()).to.eq(
|
||||||
consumer.transformerNonces.affiliateFeeTransformer,
|
consumer.transformerNonces.affiliateFeeTransformer,
|
||||||
);
|
);
|
||||||
@ -315,7 +335,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
|||||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
||||||
extensionContractOpts: { isTwoHop: true },
|
extensionContractOpts: { isTwoHop: true },
|
||||||
});
|
});
|
||||||
const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs;
|
const callArgs = transformERC20Encoder.decode(callInfo.calldataHexString) as TransformERC20Args;
|
||||||
expect(callArgs.inputToken).to.eq(TAKER_TOKEN);
|
expect(callArgs.inputToken).to.eq(TAKER_TOKEN);
|
||||||
expect(callArgs.outputToken).to.eq(MAKER_TOKEN);
|
expect(callArgs.outputToken).to.eq(MAKER_TOKEN);
|
||||||
expect(callArgs.inputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount);
|
expect(callArgs.inputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount);
|
||||||
@ -357,5 +377,35 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
|||||||
INTERMEDIATE_TOKEN,
|
INTERMEDIATE_TOKEN,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
it('Uses the `LiquidityProviderFeature` if given a single LiquidityProvider order', async () => {
|
||||||
|
const quote = {
|
||||||
|
...getRandomSellQuote(),
|
||||||
|
orders: [
|
||||||
|
{
|
||||||
|
...getRandomOrder(),
|
||||||
|
fills: [
|
||||||
|
{
|
||||||
|
source: ERC20BridgeSource.LiquidityProvider,
|
||||||
|
sourcePathId: '',
|
||||||
|
input: constants.ZERO_AMOUNT,
|
||||||
|
output: constants.ZERO_AMOUNT,
|
||||||
|
subFills: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const callInfo = await consumer.getCalldataOrThrowAsync(quote);
|
||||||
|
const callArgs = liquidityProviderEncoder.decode(callInfo.calldataHexString) as LiquidityProviderArgs;
|
||||||
|
expect(callArgs).to.deep.equal({
|
||||||
|
inputToken: TAKER_TOKEN,
|
||||||
|
outputToken: MAKER_TOKEN,
|
||||||
|
target: quote.orders[0].makerAddress,
|
||||||
|
recipient: constants.NULL_ADDRESS,
|
||||||
|
sellAmount: quote.worstCaseQuoteInfo.totalTakerAssetAmount,
|
||||||
|
minBuyAmount: getSwapMinBuyAmount(quote),
|
||||||
|
auxiliaryData: constants.NULL_BYTES,
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
} from '@0x/contracts-test-utils';
|
} from '@0x/contracts-test-utils';
|
||||||
import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
|
import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
|
||||||
import { AssetProxyId, ERC20BridgeAssetData, SignedOrder } from '@0x/types';
|
import { AssetProxyId, ERC20BridgeAssetData, SignedOrder } from '@0x/types';
|
||||||
import { BigNumber, fromTokenUnitAmount, hexUtils, NULL_ADDRESS } from '@0x/utils';
|
import { BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as TypeMoq from 'typemoq';
|
import * as TypeMoq from 'typemoq';
|
||||||
@ -63,10 +63,11 @@ const DEFAULT_EXCLUDED = [
|
|||||||
ERC20BridgeSource.Shell,
|
ERC20BridgeSource.Shell,
|
||||||
ERC20BridgeSource.Cream,
|
ERC20BridgeSource.Cream,
|
||||||
ERC20BridgeSource.Dodo,
|
ERC20BridgeSource.Dodo,
|
||||||
|
ERC20BridgeSource.LiquidityProvider,
|
||||||
];
|
];
|
||||||
const BUY_SOURCES = BUY_SOURCE_FILTER.sources;
|
const BUY_SOURCES = BUY_SOURCE_FILTER.sources;
|
||||||
const SELL_SOURCES = SELL_SOURCE_FILTER.sources;
|
const SELL_SOURCES = SELL_SOURCE_FILTER.sources;
|
||||||
const TOKEN_ADJACENCY_GRAPH: TokenAdjacencyGraph = {};
|
const TOKEN_ADJACENCY_GRAPH: TokenAdjacencyGraph = { default: [] };
|
||||||
const PRICE_AWARE_RFQ_ENABLED: PriceAwareRFQFlags = {
|
const PRICE_AWARE_RFQ_ENABLED: PriceAwareRFQFlags = {
|
||||||
isFirmPriceAwareEnabled: true,
|
isFirmPriceAwareEnabled: true,
|
||||||
isIndicativePriceAwareEnabled: true,
|
isIndicativePriceAwareEnabled: true,
|
||||||
@ -77,7 +78,6 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const CHAIN_ID = ChainId.Mainnet;
|
const CHAIN_ID = ChainId.Mainnet;
|
||||||
const contractAddresses = {
|
const contractAddresses = {
|
||||||
...getContractAddressesForChainOrThrow(CHAIN_ID),
|
...getContractAddressesForChainOrThrow(CHAIN_ID),
|
||||||
multiBridge: NULL_ADDRESS,
|
|
||||||
...BRIDGE_ADDRESSES_BY_CHAIN[CHAIN_ID],
|
...BRIDGE_ADDRESSES_BY_CHAIN[CHAIN_ID],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -242,38 +242,6 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function callTradeOperationAndRetainLiquidityProviderParams(
|
|
||||||
tradeOperation: (rates: RatesBySource) => GetMultipleQuotesOperation,
|
|
||||||
rates: RatesBySource,
|
|
||||||
): [{ sources: ERC20BridgeSource[]; liquidityProviderAddress?: string }, GetMultipleQuotesOperation] {
|
|
||||||
const liquidityPoolParams: { sources: ERC20BridgeSource[]; liquidityProviderAddress?: string } = {
|
|
||||||
sources: [],
|
|
||||||
liquidityProviderAddress: undefined,
|
|
||||||
};
|
|
||||||
const fn = (
|
|
||||||
sources: ERC20BridgeSource[],
|
|
||||||
makerToken: string,
|
|
||||||
takerToken: string,
|
|
||||||
fillAmounts: BigNumber[],
|
|
||||||
wethAddress: string,
|
|
||||||
tokenAdjacencyGraph: TokenAdjacencyGraph = TOKEN_ADJACENCY_GRAPH,
|
|
||||||
liquidityProviderAddress?: string,
|
|
||||||
) => {
|
|
||||||
liquidityPoolParams.liquidityProviderAddress = liquidityProviderAddress;
|
|
||||||
liquidityPoolParams.sources = liquidityPoolParams.sources.concat(sources);
|
|
||||||
return tradeOperation(rates)(
|
|
||||||
sources,
|
|
||||||
makerToken,
|
|
||||||
takerToken,
|
|
||||||
fillAmounts,
|
|
||||||
wethAddress,
|
|
||||||
TOKEN_ADJACENCY_GRAPH,
|
|
||||||
liquidityProviderAddress,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
return [liquidityPoolParams, fn];
|
|
||||||
}
|
|
||||||
|
|
||||||
function createGetMultipleBuyQuotesOperationFromRates(rates: RatesBySource): GetMultipleQuotesOperation {
|
function createGetMultipleBuyQuotesOperationFromRates(rates: RatesBySource): GetMultipleQuotesOperation {
|
||||||
return (
|
return (
|
||||||
sources: ERC20BridgeSource[],
|
sources: ERC20BridgeSource[],
|
||||||
@ -335,7 +303,6 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
[ERC20BridgeSource.Bancor]: _.times(NUM_SAMPLES, () => 0),
|
[ERC20BridgeSource.Bancor]: _.times(NUM_SAMPLES, () => 0),
|
||||||
[ERC20BridgeSource.Curve]: _.times(NUM_SAMPLES, () => 0),
|
[ERC20BridgeSource.Curve]: _.times(NUM_SAMPLES, () => 0),
|
||||||
[ERC20BridgeSource.LiquidityProvider]: _.times(NUM_SAMPLES, () => 0),
|
[ERC20BridgeSource.LiquidityProvider]: _.times(NUM_SAMPLES, () => 0),
|
||||||
[ERC20BridgeSource.MultiBridge]: _.times(NUM_SAMPLES, () => 0),
|
|
||||||
[ERC20BridgeSource.MStable]: _.times(NUM_SAMPLES, () => 0),
|
[ERC20BridgeSource.MStable]: _.times(NUM_SAMPLES, () => 0),
|
||||||
[ERC20BridgeSource.Mooniswap]: _.times(NUM_SAMPLES, () => 0),
|
[ERC20BridgeSource.Mooniswap]: _.times(NUM_SAMPLES, () => 0),
|
||||||
[ERC20BridgeSource.Swerve]: _.times(NUM_SAMPLES, () => 0),
|
[ERC20BridgeSource.Swerve]: _.times(NUM_SAMPLES, () => 0),
|
||||||
@ -480,6 +447,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
},
|
},
|
||||||
balancerPoolsCache: new BalancerPoolsCache(),
|
balancerPoolsCache: new BalancerPoolsCache(),
|
||||||
creamPoolsCache: new CreamPoolsCache(),
|
creamPoolsCache: new CreamPoolsCache(),
|
||||||
|
liquidityProviderRegistry: {},
|
||||||
} as any) as DexOrderSampler;
|
} as any) as DexOrderSampler;
|
||||||
|
|
||||||
function replaceSamplerOps(ops: Partial<typeof DEFAULT_OPS> = {}): void {
|
function replaceSamplerOps(ops: Partial<typeof DEFAULT_OPS> = {}): void {
|
||||||
@ -617,54 +585,6 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
expect(_.uniq(sourcesPolled).sort()).to.deep.equals(SELL_SOURCES.slice().sort());
|
expect(_.uniq(sourcesPolled).sort()).to.deep.equals(SELL_SOURCES.slice().sort());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('polls the liquidity provider when the registry is provided in the arguments', async () => {
|
|
||||||
const [args, fn] = callTradeOperationAndRetainLiquidityProviderParams(
|
|
||||||
createGetMultipleSellQuotesOperationFromRates,
|
|
||||||
DEFAULT_RATES,
|
|
||||||
);
|
|
||||||
replaceSamplerOps({
|
|
||||||
getSellQuotes: fn,
|
|
||||||
getTwoHopSellQuotes: (sources: ERC20BridgeSource[], ..._args: any[]) => {
|
|
||||||
if (sources.length !== 0) {
|
|
||||||
args.sources.push(ERC20BridgeSource.MultiHop);
|
|
||||||
args.sources.push(...sources);
|
|
||||||
}
|
|
||||||
return DEFAULT_OPS.getTwoHopSellQuotes(..._args);
|
|
||||||
},
|
|
||||||
getBalancerSellQuotesOffChainAsync: (
|
|
||||||
makerToken: string,
|
|
||||||
takerToken: string,
|
|
||||||
takerFillAmounts: BigNumber[],
|
|
||||||
) => {
|
|
||||||
args.sources = args.sources.concat(ERC20BridgeSource.Balancer);
|
|
||||||
return DEFAULT_OPS.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
|
|
||||||
},
|
|
||||||
getCreamSellQuotesOffChainAsync: (
|
|
||||||
makerToken: string,
|
|
||||||
takerToken: string,
|
|
||||||
takerFillAmounts: BigNumber[],
|
|
||||||
) => {
|
|
||||||
args.sources = args.sources.concat(ERC20BridgeSource.Cream);
|
|
||||||
return DEFAULT_OPS.getCreamSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const registryAddress = randomAddress();
|
|
||||||
const newMarketOperationUtils = new MarketOperationUtils(
|
|
||||||
MOCK_SAMPLER,
|
|
||||||
contractAddresses,
|
|
||||||
ORDER_DOMAIN,
|
|
||||||
registryAddress,
|
|
||||||
);
|
|
||||||
await newMarketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
|
|
||||||
...DEFAULT_OPTS,
|
|
||||||
excludedSources: [],
|
|
||||||
});
|
|
||||||
expect(_.uniq(args.sources).sort()).to.deep.equals(
|
|
||||||
SELL_SOURCES.concat([ERC20BridgeSource.LiquidityProvider]).sort(),
|
|
||||||
);
|
|
||||||
expect(args.liquidityProviderAddress).to.eql(registryAddress);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not poll DEXes in `excludedSources`', async () => {
|
it('does not poll DEXes in `excludedSources`', async () => {
|
||||||
const excludedSources = [ERC20BridgeSource.Uniswap, ERC20BridgeSource.Eth2Dai];
|
const excludedSources = [ERC20BridgeSource.Uniswap, ERC20BridgeSource.Eth2Dai];
|
||||||
let sourcesPolled: ERC20BridgeSource[] = [];
|
let sourcesPolled: ERC20BridgeSource[] = [];
|
||||||
@ -1341,41 +1261,28 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('is able to create a order from LiquidityProvider', async () => {
|
it('is able to create a order from LiquidityProvider', async () => {
|
||||||
const registryAddress = randomAddress();
|
|
||||||
const liquidityProviderAddress = (DEFAULT_FILL_DATA[ERC20BridgeSource.LiquidityProvider] as any)
|
const liquidityProviderAddress = (DEFAULT_FILL_DATA[ERC20BridgeSource.LiquidityProvider] as any)
|
||||||
.poolAddress;
|
.poolAddress;
|
||||||
const xAsset = randomAddress();
|
const rates: RatesBySource = {};
|
||||||
const yAsset = randomAddress();
|
rates[ERC20BridgeSource.LiquidityProvider] = [1, 1, 1, 1];
|
||||||
const toSell = fromTokenUnitAmount(10);
|
MOCK_SAMPLER.liquidityProviderRegistry[liquidityProviderAddress] = [MAKER_TOKEN, TAKER_TOKEN];
|
||||||
|
|
||||||
const [getSellQuotesParams, getSellQuotesFn] = callTradeOperationAndRetainLiquidityProviderParams(
|
|
||||||
createGetMultipleSellQuotesOperationFromRates,
|
|
||||||
{
|
|
||||||
[ERC20BridgeSource.LiquidityProvider]: createDecreasingRates(5),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
getOrderFillableTakerAmounts: () => [constants.ZERO_AMOUNT],
|
getOrderFillableTakerAmounts: () => [constants.ZERO_AMOUNT],
|
||||||
getSellQuotes: getSellQuotesFn,
|
getSellQuotes: createGetMultipleSellQuotesOperationFromRates(rates),
|
||||||
});
|
});
|
||||||
|
|
||||||
const sampler = new MarketOperationUtils(
|
const sampler = new MarketOperationUtils(MOCK_SAMPLER, contractAddresses, ORDER_DOMAIN);
|
||||||
MOCK_SAMPLER,
|
|
||||||
contractAddresses,
|
|
||||||
ORDER_DOMAIN,
|
|
||||||
registryAddress,
|
|
||||||
);
|
|
||||||
const ordersAndReport = await sampler.getMarketSellOrdersAsync(
|
const ordersAndReport = await sampler.getMarketSellOrdersAsync(
|
||||||
[
|
[
|
||||||
createOrder({
|
createOrder({
|
||||||
makerAssetData: assetDataUtils.encodeERC20AssetData(xAsset),
|
makerAssetData: assetDataUtils.encodeERC20AssetData(MAKER_TOKEN),
|
||||||
takerAssetData: assetDataUtils.encodeERC20AssetData(yAsset),
|
takerAssetData: assetDataUtils.encodeERC20AssetData(TAKER_TOKEN),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
Web3Wrapper.toBaseUnitAmount(10, 18),
|
FILL_AMOUNT,
|
||||||
{
|
{
|
||||||
excludedSources: SELL_SOURCES.concat(ERC20BridgeSource.Bancor),
|
includedSources: [ERC20BridgeSource.LiquidityProvider],
|
||||||
|
excludedSources: [],
|
||||||
numSamples: 4,
|
numSamples: 4,
|
||||||
bridgeSlippage: 0,
|
bridgeSlippage: 0,
|
||||||
},
|
},
|
||||||
@ -1390,9 +1297,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
) as ERC20BridgeAssetData;
|
) as ERC20BridgeAssetData;
|
||||||
expect(decodedAssetData.assetProxyId).to.eql(AssetProxyId.ERC20Bridge);
|
expect(decodedAssetData.assetProxyId).to.eql(AssetProxyId.ERC20Bridge);
|
||||||
expect(decodedAssetData.bridgeAddress).to.eql(liquidityProviderAddress);
|
expect(decodedAssetData.bridgeAddress).to.eql(liquidityProviderAddress);
|
||||||
expect(result[0].takerAssetAmount).to.bignumber.eql(toSell);
|
expect(result[0].takerAssetAmount).to.bignumber.eql(FILL_AMOUNT);
|
||||||
expect(getSellQuotesParams.sources).contains(ERC20BridgeSource.LiquidityProvider);
|
|
||||||
expect(getSellQuotesParams.liquidityProviderAddress).is.eql(registryAddress);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('factors in exchange proxy gas overhead', async () => {
|
it('factors in exchange proxy gas overhead', async () => {
|
||||||
@ -1403,20 +1308,16 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
[ERC20BridgeSource.Uniswap]: [1, 1, 1, 1],
|
[ERC20BridgeSource.Uniswap]: [1, 1, 1, 1],
|
||||||
[ERC20BridgeSource.LiquidityProvider]: [0.9999, 0.9999, 0.9999, 0.9999],
|
[ERC20BridgeSource.LiquidityProvider]: [0.9999, 0.9999, 0.9999, 0.9999],
|
||||||
};
|
};
|
||||||
|
MOCK_SAMPLER.liquidityProviderRegistry[randomAddress()] = [MAKER_TOKEN, TAKER_TOKEN];
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
getSellQuotes: createGetMultipleSellQuotesOperationFromRates(rates),
|
getSellQuotes: createGetMultipleSellQuotesOperationFromRates(rates),
|
||||||
getMedianSellRate: createGetMedianSellRate(ETH_TO_MAKER_RATE),
|
getMedianSellRate: createGetMedianSellRate(ETH_TO_MAKER_RATE),
|
||||||
});
|
});
|
||||||
const optimizer = new MarketOperationUtils(
|
const optimizer = new MarketOperationUtils(MOCK_SAMPLER, contractAddresses, ORDER_DOMAIN);
|
||||||
MOCK_SAMPLER,
|
|
||||||
contractAddresses,
|
|
||||||
ORDER_DOMAIN,
|
|
||||||
randomAddress(), // liquidity provider registry
|
|
||||||
);
|
|
||||||
const gasPrice = 100e9; // 100 gwei
|
const gasPrice = 100e9; // 100 gwei
|
||||||
const exchangeProxyOverhead = (sourceFlags: number) =>
|
const exchangeProxyOverhead = (sourceFlags: number) =>
|
||||||
sourceFlags === SOURCE_FLAGS.LiquidityProvider
|
sourceFlags === SOURCE_FLAGS.LiquidityProvider
|
||||||
? new BigNumber(3e4).times(gasPrice)
|
? constants.ZERO_AMOUNT
|
||||||
: new BigNumber(1.3e5).times(gasPrice);
|
: new BigNumber(1.3e5).times(gasPrice);
|
||||||
const improvedOrdersResponse = await optimizer.getMarketSellOrdersAsync(
|
const improvedOrdersResponse = await optimizer.getMarketSellOrdersAsync(
|
||||||
createOrdersFromSellRates(FILL_AMOUNT, rates[ERC20BridgeSource.Native]),
|
createOrdersFromSellRates(FILL_AMOUNT, rates[ERC20BridgeSource.Native]),
|
||||||
@ -1424,12 +1325,12 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
{
|
{
|
||||||
...DEFAULT_OPTS,
|
...DEFAULT_OPTS,
|
||||||
numSamples: 4,
|
numSamples: 4,
|
||||||
excludedSources: [
|
includedSources: [
|
||||||
...(DEFAULT_OPTS.excludedSources as ERC20BridgeSource[]),
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Eth2Dai,
|
ERC20BridgeSource.Uniswap,
|
||||||
ERC20BridgeSource.Kyber,
|
ERC20BridgeSource.LiquidityProvider,
|
||||||
ERC20BridgeSource.Bancor,
|
|
||||||
],
|
],
|
||||||
|
excludedSources: [],
|
||||||
exchangeProxyOverhead,
|
exchangeProxyOverhead,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -1529,54 +1430,6 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
expect(_.uniq(sourcesPolled).sort()).to.deep.equals(BUY_SOURCES.sort());
|
expect(_.uniq(sourcesPolled).sort()).to.deep.equals(BUY_SOURCES.sort());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('polls the liquidity provider when the registry is provided in the arguments', async () => {
|
|
||||||
const [args, fn] = callTradeOperationAndRetainLiquidityProviderParams(
|
|
||||||
createGetMultipleBuyQuotesOperationFromRates,
|
|
||||||
DEFAULT_RATES,
|
|
||||||
);
|
|
||||||
replaceSamplerOps({
|
|
||||||
getBuyQuotes: fn,
|
|
||||||
getTwoHopBuyQuotes: (sources: ERC20BridgeSource[], ..._args: any[]) => {
|
|
||||||
if (sources.length !== 0) {
|
|
||||||
args.sources.push(ERC20BridgeSource.MultiHop);
|
|
||||||
args.sources.push(...sources);
|
|
||||||
}
|
|
||||||
return DEFAULT_OPS.getTwoHopBuyQuotes(..._args);
|
|
||||||
},
|
|
||||||
getBalancerBuyQuotesOffChainAsync: (
|
|
||||||
makerToken: string,
|
|
||||||
takerToken: string,
|
|
||||||
makerFillAmounts: BigNumber[],
|
|
||||||
) => {
|
|
||||||
args.sources = args.sources.concat(ERC20BridgeSource.Balancer);
|
|
||||||
return DEFAULT_OPS.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
|
|
||||||
},
|
|
||||||
getCreamBuyQuotesOffChainAsync: (
|
|
||||||
makerToken: string,
|
|
||||||
takerToken: string,
|
|
||||||
makerFillAmounts: BigNumber[],
|
|
||||||
) => {
|
|
||||||
args.sources = args.sources.concat(ERC20BridgeSource.Cream);
|
|
||||||
return DEFAULT_OPS.getCreamBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const registryAddress = randomAddress();
|
|
||||||
const newMarketOperationUtils = new MarketOperationUtils(
|
|
||||||
MOCK_SAMPLER,
|
|
||||||
contractAddresses,
|
|
||||||
ORDER_DOMAIN,
|
|
||||||
registryAddress,
|
|
||||||
);
|
|
||||||
await newMarketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
|
|
||||||
...DEFAULT_OPTS,
|
|
||||||
excludedSources: [],
|
|
||||||
});
|
|
||||||
expect(_.uniq(args.sources).sort()).to.deep.eq(
|
|
||||||
BUY_SOURCES.concat([ERC20BridgeSource.LiquidityProvider]).sort(),
|
|
||||||
);
|
|
||||||
expect(args.liquidityProviderAddress).to.eql(registryAddress);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not poll DEXes in `excludedSources`', async () => {
|
it('does not poll DEXes in `excludedSources`', async () => {
|
||||||
const excludedSources = [ERC20BridgeSource.Uniswap, ERC20BridgeSource.Eth2Dai];
|
const excludedSources = [ERC20BridgeSource.Uniswap, ERC20BridgeSource.Eth2Dai];
|
||||||
let sourcesPolled: ERC20BridgeSource[] = [];
|
let sourcesPolled: ERC20BridgeSource[] = [];
|
||||||
@ -1874,20 +1727,16 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
[ERC20BridgeSource.Uniswap]: [1, 1, 1, 1],
|
[ERC20BridgeSource.Uniswap]: [1, 1, 1, 1],
|
||||||
[ERC20BridgeSource.LiquidityProvider]: [0.9999, 0.9999, 0.9999, 0.9999],
|
[ERC20BridgeSource.LiquidityProvider]: [0.9999, 0.9999, 0.9999, 0.9999],
|
||||||
};
|
};
|
||||||
|
MOCK_SAMPLER.liquidityProviderRegistry[randomAddress()] = [MAKER_TOKEN, TAKER_TOKEN];
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
|
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
|
||||||
getMedianSellRate: createGetMedianSellRate(ETH_TO_TAKER_RATE),
|
getMedianSellRate: createGetMedianSellRate(ETH_TO_TAKER_RATE),
|
||||||
});
|
});
|
||||||
const optimizer = new MarketOperationUtils(
|
const optimizer = new MarketOperationUtils(MOCK_SAMPLER, contractAddresses, ORDER_DOMAIN);
|
||||||
MOCK_SAMPLER,
|
|
||||||
contractAddresses,
|
|
||||||
ORDER_DOMAIN,
|
|
||||||
randomAddress(), // liquidity provider registry
|
|
||||||
);
|
|
||||||
const gasPrice = 100e9; // 100 gwei
|
const gasPrice = 100e9; // 100 gwei
|
||||||
const exchangeProxyOverhead = (sourceFlags: number) =>
|
const exchangeProxyOverhead = (sourceFlags: number) =>
|
||||||
sourceFlags === SOURCE_FLAGS.LiquidityProvider
|
sourceFlags === SOURCE_FLAGS.LiquidityProvider
|
||||||
? new BigNumber(3e4).times(gasPrice)
|
? constants.ZERO_AMOUNT
|
||||||
: new BigNumber(1.3e5).times(gasPrice);
|
: new BigNumber(1.3e5).times(gasPrice);
|
||||||
const improvedOrdersResponse = await optimizer.getMarketBuyOrdersAsync(
|
const improvedOrdersResponse = await optimizer.getMarketBuyOrdersAsync(
|
||||||
createOrdersFromSellRates(FILL_AMOUNT, rates[ERC20BridgeSource.Native]),
|
createOrdersFromSellRates(FILL_AMOUNT, rates[ERC20BridgeSource.Native]),
|
||||||
@ -1895,11 +1744,12 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
{
|
{
|
||||||
...DEFAULT_OPTS,
|
...DEFAULT_OPTS,
|
||||||
numSamples: 4,
|
numSamples: 4,
|
||||||
excludedSources: [
|
includedSources: [
|
||||||
...(DEFAULT_OPTS.excludedSources as ERC20BridgeSource[]),
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Eth2Dai,
|
ERC20BridgeSource.Uniswap,
|
||||||
ERC20BridgeSource.Kyber,
|
ERC20BridgeSource.LiquidityProvider,
|
||||||
],
|
],
|
||||||
|
excludedSources: [],
|
||||||
exchangeProxyOverhead,
|
exchangeProxyOverhead,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -37,19 +37,12 @@ export type SampleBuysKyberHandler = (
|
|||||||
) => [string, SampleResults];
|
) => [string, SampleResults];
|
||||||
export type SampleBuysMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
|
export type SampleBuysMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
|
||||||
export type SampleSellsLPHandler = (
|
export type SampleSellsLPHandler = (
|
||||||
registryAddress: string,
|
providerAddress: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerTokenAmounts: BigNumber[],
|
takerTokenAmounts: BigNumber[],
|
||||||
) => [SampleResults, string];
|
|
||||||
export type SampleSellsMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
|
|
||||||
export type SampleSellsMBHandler = (
|
|
||||||
multiBridgeAddress: string,
|
|
||||||
takerToken: string,
|
|
||||||
intermediateToken: string,
|
|
||||||
makerToken: string,
|
|
||||||
takerTokenAmounts: BigNumber[],
|
|
||||||
) => SampleResults;
|
) => SampleResults;
|
||||||
|
export type SampleSellsMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
|
||||||
|
|
||||||
const DUMMY_PROVIDER = {
|
const DUMMY_PROVIDER = {
|
||||||
sendAsync: (..._args: any[]): any => {
|
sendAsync: (..._args: any[]): any => {
|
||||||
@ -61,15 +54,14 @@ interface Handlers {
|
|||||||
getOrderFillableMakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
getOrderFillableMakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
||||||
getOrderFillableTakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
getOrderFillableTakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
||||||
sampleSellsFromKyberNetwork: SampleSellsKyberHandler;
|
sampleSellsFromKyberNetwork: SampleSellsKyberHandler;
|
||||||
sampleSellsFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
sampleSellsFromLiquidityProvider: SampleSellsLPHandler;
|
||||||
sampleSellsFromMultiBridge: SampleSellsMBHandler;
|
|
||||||
sampleSellsFromEth2Dai: SampleSellsHandler;
|
sampleSellsFromEth2Dai: SampleSellsHandler;
|
||||||
sampleSellsFromUniswap: SampleSellsHandler;
|
sampleSellsFromUniswap: SampleSellsHandler;
|
||||||
sampleSellsFromUniswapV2: SampleSellsMultihopHandler;
|
sampleSellsFromUniswapV2: SampleSellsMultihopHandler;
|
||||||
sampleBuysFromEth2Dai: SampleBuysHandler;
|
sampleBuysFromEth2Dai: SampleBuysHandler;
|
||||||
sampleBuysFromUniswap: SampleBuysHandler;
|
sampleBuysFromUniswap: SampleBuysHandler;
|
||||||
sampleBuysFromUniswapV2: SampleBuysMultihopHandler;
|
sampleBuysFromUniswapV2: SampleBuysMultihopHandler;
|
||||||
sampleBuysFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
sampleBuysFromLiquidityProvider: SampleSellsLPHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tslint:disable: no-unbound-method
|
// tslint:disable: no-unbound-method
|
||||||
@ -171,35 +163,17 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sampleSellsFromLiquidityProviderRegistry(
|
public sampleSellsFromLiquidityProvider(
|
||||||
registryAddress: string,
|
providerAddress: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerAssetAmounts: BigNumber[],
|
takerAssetAmounts: BigNumber[],
|
||||||
): ContractTxFunctionObj<[BigNumber[], string]> {
|
|
||||||
return this._wrapCall(
|
|
||||||
super.sampleSellsFromLiquidityProviderRegistry,
|
|
||||||
this._handlers.sampleSellsFromLiquidityProviderRegistry,
|
|
||||||
registryAddress,
|
|
||||||
takerToken,
|
|
||||||
makerToken,
|
|
||||||
takerAssetAmounts,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sampleSellsFromMultiBridge(
|
|
||||||
multiBridgeAddress: string,
|
|
||||||
takerToken: string,
|
|
||||||
intermediateToken: string,
|
|
||||||
makerToken: string,
|
|
||||||
takerAssetAmounts: BigNumber[],
|
|
||||||
): ContractTxFunctionObj<BigNumber[]> {
|
): ContractTxFunctionObj<BigNumber[]> {
|
||||||
return this._wrapCall(
|
return this._wrapCall(
|
||||||
super.sampleSellsFromMultiBridge,
|
super.sampleSellsFromLiquidityProvider,
|
||||||
this._handlers.sampleSellsFromMultiBridge,
|
this._handlers.sampleSellsFromLiquidityProvider,
|
||||||
multiBridgeAddress,
|
providerAddress,
|
||||||
takerToken,
|
takerToken,
|
||||||
intermediateToken,
|
|
||||||
makerToken,
|
makerToken,
|
||||||
takerAssetAmounts,
|
takerAssetAmounts,
|
||||||
);
|
);
|
||||||
|
@ -9,15 +9,12 @@ export * from '../test/generated-wrappers/curve_sampler';
|
|||||||
export * from '../test/generated-wrappers/d_o_d_o_sampler';
|
export * from '../test/generated-wrappers/d_o_d_o_sampler';
|
||||||
export * from '../test/generated-wrappers/deployment_constants';
|
export * from '../test/generated-wrappers/deployment_constants';
|
||||||
export * from '../test/generated-wrappers/dummy_liquidity_provider';
|
export * from '../test/generated-wrappers/dummy_liquidity_provider';
|
||||||
export * from '../test/generated-wrappers/dummy_liquidity_provider_registry';
|
|
||||||
export * from '../test/generated-wrappers/erc20_bridge_sampler';
|
export * from '../test/generated-wrappers/erc20_bridge_sampler';
|
||||||
export * from '../test/generated-wrappers/eth2_dai_sampler';
|
export * from '../test/generated-wrappers/eth2_dai_sampler';
|
||||||
export * from '../test/generated-wrappers/i_balancer';
|
export * from '../test/generated-wrappers/i_balancer';
|
||||||
export * from '../test/generated-wrappers/i_curve';
|
export * from '../test/generated-wrappers/i_curve';
|
||||||
export * from '../test/generated-wrappers/i_eth2_dai';
|
export * from '../test/generated-wrappers/i_eth2_dai';
|
||||||
export * from '../test/generated-wrappers/i_kyber_network';
|
export * from '../test/generated-wrappers/i_kyber_network';
|
||||||
export * from '../test/generated-wrappers/i_liquidity_provider';
|
|
||||||
export * from '../test/generated-wrappers/i_liquidity_provider_registry';
|
|
||||||
export * from '../test/generated-wrappers/i_m_stable';
|
export * from '../test/generated-wrappers/i_m_stable';
|
||||||
export * from '../test/generated-wrappers/i_mooniswap';
|
export * from '../test/generated-wrappers/i_mooniswap';
|
||||||
export * from '../test/generated-wrappers/i_multi_bridge';
|
export * from '../test/generated-wrappers/i_multi_bridge';
|
||||||
|
@ -3,26 +3,19 @@
|
|||||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||||
"files": [
|
"files": [
|
||||||
"generated-artifacts/DummyLiquidityProvider.json",
|
|
||||||
"generated-artifacts/DummyLiquidityProviderRegistry.json",
|
|
||||||
"generated-artifacts/ERC20BridgeSampler.json",
|
"generated-artifacts/ERC20BridgeSampler.json",
|
||||||
"generated-artifacts/ILiquidityProvider.json",
|
|
||||||
"generated-artifacts/ILiquidityProviderRegistry.json",
|
|
||||||
"test/generated-artifacts/ApproximateBuys.json",
|
"test/generated-artifacts/ApproximateBuys.json",
|
||||||
"test/generated-artifacts/BalancerSampler.json",
|
"test/generated-artifacts/BalancerSampler.json",
|
||||||
"test/generated-artifacts/CurveSampler.json",
|
"test/generated-artifacts/CurveSampler.json",
|
||||||
"test/generated-artifacts/DODOSampler.json",
|
"test/generated-artifacts/DODOSampler.json",
|
||||||
"test/generated-artifacts/DeploymentConstants.json",
|
"test/generated-artifacts/DeploymentConstants.json",
|
||||||
"test/generated-artifacts/DummyLiquidityProvider.json",
|
"test/generated-artifacts/DummyLiquidityProvider.json",
|
||||||
"test/generated-artifacts/DummyLiquidityProviderRegistry.json",
|
|
||||||
"test/generated-artifacts/ERC20BridgeSampler.json",
|
"test/generated-artifacts/ERC20BridgeSampler.json",
|
||||||
"test/generated-artifacts/Eth2DaiSampler.json",
|
"test/generated-artifacts/Eth2DaiSampler.json",
|
||||||
"test/generated-artifacts/IBalancer.json",
|
"test/generated-artifacts/IBalancer.json",
|
||||||
"test/generated-artifacts/ICurve.json",
|
"test/generated-artifacts/ICurve.json",
|
||||||
"test/generated-artifacts/IEth2Dai.json",
|
"test/generated-artifacts/IEth2Dai.json",
|
||||||
"test/generated-artifacts/IKyberNetwork.json",
|
"test/generated-artifacts/IKyberNetwork.json",
|
||||||
"test/generated-artifacts/ILiquidityProvider.json",
|
|
||||||
"test/generated-artifacts/ILiquidityProviderRegistry.json",
|
|
||||||
"test/generated-artifacts/IMStable.json",
|
"test/generated-artifacts/IMStable.json",
|
||||||
"test/generated-artifacts/IMooniswap.json",
|
"test/generated-artifacts/IMooniswap.json",
|
||||||
"test/generated-artifacts/IMultiBridge.json",
|
"test/generated-artifacts/IMultiBridge.json",
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "5.3.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Add `exchangeProxyLiquidityProviderSandbox` addresses",
|
||||||
|
"pr": 16
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
||||||
"exchangeProxyTransformerDeployer": "0x39dce47a67ad34344eab877eae3ef1fa2a1d50bb",
|
"exchangeProxyTransformerDeployer": "0x39dce47a67ad34344eab877eae3ef1fa2a1d50bb",
|
||||||
"exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18",
|
"exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18",
|
||||||
|
"exchangeProxyLiquidityProviderSandbox": "0xdb971b18ea5075734cec1241732cc1b41031dfc9",
|
||||||
"transformers": {
|
"transformers": {
|
||||||
"wethTransformer": "0x68c0bb685099dc7cb5c5ce2b26185945b357383e",
|
"wethTransformer": "0x68c0bb685099dc7cb5c5ce2b26185945b357383e",
|
||||||
"payTakerTransformer": "0x49b9df2c58491764cf40cb052dd4243df63622c7",
|
"payTakerTransformer": "0x49b9df2c58491764cf40cb052dd4243df63622c7",
|
||||||
@ -72,6 +73,7 @@
|
|||||||
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
||||||
"exchangeProxyTransformerDeployer": "0x1c9a27658dd303a31205a3b245e8993b92d4d502",
|
"exchangeProxyTransformerDeployer": "0x1c9a27658dd303a31205a3b245e8993b92d4d502",
|
||||||
"exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18",
|
"exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18",
|
||||||
|
"exchangeProxyLiquidityProviderSandbox": "0xb8afda68a9834969a69ebd4aab201feff814d170",
|
||||||
"transformers": {
|
"transformers": {
|
||||||
"wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437",
|
"wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437",
|
||||||
"payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6",
|
"payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6",
|
||||||
@ -112,6 +114,7 @@
|
|||||||
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
||||||
"exchangeProxyTransformerDeployer": "0x1c9a27658dd303a31205a3b245e8993b92d4d502",
|
"exchangeProxyTransformerDeployer": "0x1c9a27658dd303a31205a3b245e8993b92d4d502",
|
||||||
"exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18",
|
"exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18",
|
||||||
|
"exchangeProxyLiquidityProviderSandbox": "0xb8afda68a9834969a69ebd4aab201feff814d170",
|
||||||
"transformers": {
|
"transformers": {
|
||||||
"wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437",
|
"wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437",
|
||||||
"payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6",
|
"payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6",
|
||||||
@ -152,6 +155,7 @@
|
|||||||
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
||||||
"exchangeProxyTransformerDeployer": "0x1b62de2dbb5e7aa519e9c442721ecef75702807f",
|
"exchangeProxyTransformerDeployer": "0x1b62de2dbb5e7aa519e9c442721ecef75702807f",
|
||||||
"exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18",
|
"exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18",
|
||||||
|
"exchangeProxyLiquidityProviderSandbox": "0x598d7a659d1f163d94abe3628674f8a2569ff344",
|
||||||
"transformers": {
|
"transformers": {
|
||||||
"wethTransformer": "0x9ce35b5ee9e710535e3988e3f8731d9ca9dba17d",
|
"wethTransformer": "0x9ce35b5ee9e710535e3988e3f8731d9ca9dba17d",
|
||||||
"payTakerTransformer": "0x5a53e7b02a83aa9f60ccf4e424f0442c255bc977",
|
"payTakerTransformer": "0x5a53e7b02a83aa9f60ccf4e424f0442c255bc977",
|
||||||
@ -192,6 +196,7 @@
|
|||||||
"exchangeProxyAllowanceTarget": "0x8362c3ebd90041b30ec45908332e592721642637",
|
"exchangeProxyAllowanceTarget": "0x8362c3ebd90041b30ec45908332e592721642637",
|
||||||
"exchangeProxyTransformerDeployer": "0x5409ed021d9299bf6814279a6a1411a7e866a631",
|
"exchangeProxyTransformerDeployer": "0x5409ed021d9299bf6814279a6a1411a7e866a631",
|
||||||
"exchangeProxyFlashWallet": "0xb9682a8e7920b431f1d412b8510f0077410c8faa",
|
"exchangeProxyFlashWallet": "0xb9682a8e7920b431f1d412b8510f0077410c8faa",
|
||||||
|
"exchangeProxyLiquidityProviderSandbox": "0x0000000000000000000000000000000000000000",
|
||||||
"transformers": {
|
"transformers": {
|
||||||
"wethTransformer": "0xc6b0d3c45a6b5092808196cb00df5c357d55e1d5",
|
"wethTransformer": "0xc6b0d3c45a6b5092808196cb00df5c357d55e1d5",
|
||||||
"payTakerTransformer": "0x7209185959d7227fb77274e1e88151d7c4c368d3",
|
"payTakerTransformer": "0x7209185959d7227fb77274e1e88151d7c4c368d3",
|
||||||
|
@ -33,6 +33,7 @@ export interface ContractAddresses {
|
|||||||
exchangeProxyAllowanceTarget: string;
|
exchangeProxyAllowanceTarget: string;
|
||||||
exchangeProxyTransformerDeployer: string;
|
exchangeProxyTransformerDeployer: string;
|
||||||
exchangeProxyFlashWallet: string;
|
exchangeProxyFlashWallet: string;
|
||||||
|
exchangeProxyLiquidityProviderSandbox: string;
|
||||||
transformers: {
|
transformers: {
|
||||||
wethTransformer: string;
|
wethTransformer: string;
|
||||||
payTakerTransformer: string;
|
payTakerTransformer: string;
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "3.9.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Update IZeroEx artifact and remove some unused artifacts",
|
||||||
|
"pr": 16
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1604376968,
|
"timestamp": 1604376968,
|
||||||
"version": "3.8.2",
|
"version": "3.8.2",
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
{
|
|
||||||
"schemaVersion": "2.0.0",
|
|
||||||
"contractName": "DummyLiquidityProvider",
|
|
||||||
"compilerOutput": {
|
|
||||||
"abi": [
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "", "type": "address" },
|
|
||||||
{ "internalType": "uint256", "name": "buyAmount", "type": "uint256" }
|
|
||||||
],
|
|
||||||
"name": "getBuyQuote",
|
|
||||||
"outputs": [{ "internalType": "uint256", "name": "takerTokenAmount", "type": "uint256" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "", "type": "address" },
|
|
||||||
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" }
|
|
||||||
],
|
|
||||||
"name": "getSellQuote",
|
|
||||||
"outputs": [{ "internalType": "uint256", "name": "makerTokenAmount", "type": "uint256" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"devdoc": {
|
|
||||||
"methods": {
|
|
||||||
"getBuyQuote(address,address,uint256)": {
|
|
||||||
"details": "Quotes the amount of `takerToken` that would need to be sold in order to obtain `buyAmount` of `makerToken`.",
|
|
||||||
"params": { "buyAmount": "Amount of `makerToken` to buy." },
|
|
||||||
"return": "takerTokenAmount Amount of `takerToken` that would need to be sold."
|
|
||||||
},
|
|
||||||
"getSellQuote(address,address,uint256)": {
|
|
||||||
"details": "Quotes the amount of `makerToken` that would be obtained by selling `sellAmount` of `takerToken`.",
|
|
||||||
"params": { "sellAmount": "Amount of `takerToken` to sell." },
|
|
||||||
"return": "makerTokenAmount Amount of `makerToken` that would be obtained."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"evm": {
|
|
||||||
"bytecode": {
|
|
||||||
"object": "0x608060405234801561001057600080fd5b50610159806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063343fbcdd1461003b57806345060eb014610064575b600080fd5b61004e6100493660046100a8565b610077565b60405161005b91906100e8565b60405180910390f35b61004e6100723660046100a8565b61009f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b60010192915050565b6000806000606084860312156100bc578283fd5b83356100c7816100f1565b925060208401356100d7816100f1565b929592945050506040919091013590565b90815260200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461011357600080fd5b5056fea365627a7a72315820981135e6e25d9062a0a9bcf7e08e326cde449b18310db7488d1db4e79ef0f6f36c6578706572696d656e74616cf564736f6c63430005100040"
|
|
||||||
},
|
|
||||||
"deployedBytecode": {
|
|
||||||
"object": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063343fbcdd1461003b57806345060eb014610064575b600080fd5b61004e6100493660046100a8565b610077565b60405161005b91906100e8565b60405180910390f35b61004e6100723660046100a8565b61009f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b60010192915050565b6000806000606084860312156100bc578283fd5b83356100c7816100f1565b925060208401356100d7816100f1565b929592945050506040919091013590565b90815260200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461011357600080fd5b5056fea365627a7a72315820981135e6e25d9062a0a9bcf7e08e326cde449b18310db7488d1db4e79ef0f6f36c6578706572696d656e74616cf564736f6c63430005100040"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compiler": {
|
|
||||||
"name": "solc",
|
|
||||||
"version": "soljson-v0.5.16+commit.9c3226ce.js",
|
|
||||||
"settings": {
|
|
||||||
"optimizer": {
|
|
||||||
"enabled": true,
|
|
||||||
"runs": 1000000,
|
|
||||||
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
|
|
||||||
},
|
|
||||||
"outputSelection": {
|
|
||||||
"*": {
|
|
||||||
"*": [
|
|
||||||
"abi",
|
|
||||||
"devdoc",
|
|
||||||
"evm.bytecode.object",
|
|
||||||
"evm.bytecode.sourceMap",
|
|
||||||
"evm.deployedBytecode.object",
|
|
||||||
"evm.deployedBytecode.sourceMap"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"evmVersion": "istanbul"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chains": {}
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
{
|
|
||||||
"schemaVersion": "2.0.0",
|
|
||||||
"contractName": "DummyLiquidityProviderRegistry",
|
|
||||||
"compilerOutput": {
|
|
||||||
"abi": [
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "xToken", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "yToken", "type": "address" }
|
|
||||||
],
|
|
||||||
"name": "getLiquidityProviderForMarket",
|
|
||||||
"outputs": [{ "internalType": "address", "name": "poolAddress", "type": "address" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "xToken", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "yToken", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "poolAddress", "type": "address" }
|
|
||||||
],
|
|
||||||
"name": "setLiquidityProviderForMarket",
|
|
||||||
"outputs": [],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"devdoc": {
|
|
||||||
"methods": {
|
|
||||||
"getLiquidityProviderForMarket(address,address)": {
|
|
||||||
"details": "Returns the address of pool for a market given market (xAsset, yAsset), or reverts if pool does not exist.",
|
|
||||||
"params": { "xToken": "First asset managed by pool.", "yToken": "Second asset managed by pool." },
|
|
||||||
"return": "Address of pool."
|
|
||||||
},
|
|
||||||
"setLiquidityProviderForMarket(address,address,address)": {
|
|
||||||
"details": "Sets address of pool for a market given market (xAsset, yAsset).",
|
|
||||||
"params": {
|
|
||||||
"poolAddress": "Address of pool.",
|
|
||||||
"xToken": "First asset managed by pool.",
|
|
||||||
"yToken": "Second asset managed by pool."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"evm": {
|
|
||||||
"bytecode": {
|
|
||||||
"object": "0x608060405234801561001057600080fd5b506102a6806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063153f59971461003b57806384da8d1e14610064575b600080fd5b61004e610049366004610192565b610079565b60405161005b919061020b565b60405180910390f35b6100776100723660046101c6565b6100f2565b005b73ffffffffffffffffffffffffffffffffffffffff808316600090815260208181526040808320858516845290915290205416806100ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100e39061022c565b60405180910390fd5b92915050565b73ffffffffffffffffffffffffffffffffffffffff92831660008181526020818152604080832095871683529481528482208054969094167fffffffffffffffffffffffff0000000000000000000000000000000000000000968716811790945581815284822092825291909152919091208054909216179055565b803573ffffffffffffffffffffffffffffffffffffffff811681146100ec57600080fd5b600080604083850312156101a4578182fd5b6101ae848461016e565b91506101bd846020850161016e565b90509250929050565b6000806000606084860312156101da578081fd5b6101e4858561016e565b92506101f3856020860161016e565b9150610202856040860161016e565b90509250925092565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6020808252601c908201527f52656769737472792f4d41524b45545f504149525f4e4f545f5345540000000060408201526060019056fea365627a7a723158200b589233a17eab806bfb7e334f40bc1ba4502479e55b2aa562c069bc440ceb476c6578706572696d656e74616cf564736f6c63430005100040"
|
|
||||||
},
|
|
||||||
"deployedBytecode": {
|
|
||||||
"object": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063153f59971461003b57806384da8d1e14610064575b600080fd5b61004e610049366004610192565b610079565b60405161005b919061020b565b60405180910390f35b6100776100723660046101c6565b6100f2565b005b73ffffffffffffffffffffffffffffffffffffffff808316600090815260208181526040808320858516845290915290205416806100ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100e39061022c565b60405180910390fd5b92915050565b73ffffffffffffffffffffffffffffffffffffffff92831660008181526020818152604080832095871683529481528482208054969094167fffffffffffffffffffffffff0000000000000000000000000000000000000000968716811790945581815284822092825291909152919091208054909216179055565b803573ffffffffffffffffffffffffffffffffffffffff811681146100ec57600080fd5b600080604083850312156101a4578182fd5b6101ae848461016e565b91506101bd846020850161016e565b90509250929050565b6000806000606084860312156101da578081fd5b6101e4858561016e565b92506101f3856020860161016e565b9150610202856040860161016e565b90509250925092565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6020808252601c908201527f52656769737472792f4d41524b45545f504149525f4e4f545f5345540000000060408201526060019056fea365627a7a723158200b589233a17eab806bfb7e334f40bc1ba4502479e55b2aa562c069bc440ceb476c6578706572696d656e74616cf564736f6c63430005100040"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compiler": {
|
|
||||||
"name": "solc",
|
|
||||||
"version": "soljson-v0.5.16+commit.9c3226ce.js",
|
|
||||||
"settings": {
|
|
||||||
"optimizer": {
|
|
||||||
"enabled": true,
|
|
||||||
"runs": 1000000,
|
|
||||||
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
|
|
||||||
},
|
|
||||||
"outputSelection": {
|
|
||||||
"*": {
|
|
||||||
"*": [
|
|
||||||
"abi",
|
|
||||||
"devdoc",
|
|
||||||
"evm.bytecode.object",
|
|
||||||
"evm.bytecode.sourceMap",
|
|
||||||
"evm.deployedBytecode.object",
|
|
||||||
"evm.deployedBytecode.sourceMap"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"evmVersion": "istanbul"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chains": {}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
{
|
|
||||||
"schemaVersion": "2.0.0",
|
|
||||||
"contractName": "ILiquidityProviderRegistry",
|
|
||||||
"compilerOutput": {
|
|
||||||
"abi": [
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "takerToken", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "makerToken", "type": "address" }
|
|
||||||
],
|
|
||||||
"name": "getLiquidityProviderForMarket",
|
|
||||||
"outputs": [{ "internalType": "address", "name": "providerAddress", "type": "address" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"devdoc": {
|
|
||||||
"methods": {
|
|
||||||
"getLiquidityProviderForMarket(address,address)": {
|
|
||||||
"details": "Returns the address of a liquidity provider for the given market (takerToken, makerToken), reverting if the pool does not exist.",
|
|
||||||
"params": {
|
|
||||||
"makerToken": "Maker asset managed by liquidity provider.",
|
|
||||||
"takerToken": "Taker asset managed by liquidity provider."
|
|
||||||
},
|
|
||||||
"return": "Address of the liquidity provider."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"evm": { "bytecode": { "object": "0x" }, "deployedBytecode": { "object": "0x" } }
|
|
||||||
},
|
|
||||||
"compiler": {
|
|
||||||
"name": "solc",
|
|
||||||
"version": "soljson-v0.5.16+commit.9c3226ce.js",
|
|
||||||
"settings": {
|
|
||||||
"optimizer": {
|
|
||||||
"enabled": true,
|
|
||||||
"runs": 1000000,
|
|
||||||
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
|
|
||||||
},
|
|
||||||
"outputSelection": {
|
|
||||||
"*": {
|
|
||||||
"*": [
|
|
||||||
"abi",
|
|
||||||
"devdoc",
|
|
||||||
"evm.bytecode.object",
|
|
||||||
"evm.bytecode.sourceMap",
|
|
||||||
"evm.deployedBytecode.object",
|
|
||||||
"evm.deployedBytecode.sourceMap"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"evmVersion": "istanbul"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chains": {}
|
|
||||||
}
|
|
@ -3,16 +3,6 @@
|
|||||||
"contractName": "IZeroEx",
|
"contractName": "IZeroEx",
|
||||||
"compilerOutput": {
|
"compilerOutput": {
|
||||||
"abi": [
|
"abi": [
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{ "indexed": true, "internalType": "address", "name": "xAsset", "type": "address" },
|
|
||||||
{ "indexed": true, "internalType": "address", "name": "yAsset", "type": "address" },
|
|
||||||
{ "indexed": false, "internalType": "address", "name": "providerAddress", "type": "address" }
|
|
||||||
],
|
|
||||||
"name": "LiquidityProviderForMarketUpdated",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"anonymous": false,
|
"anonymous": false,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
@ -232,16 +222,6 @@
|
|||||||
"stateMutability": "view",
|
"stateMutability": "view",
|
||||||
"type": "function"
|
"type": "function"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "xAsset", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "yAsset", "type": "address" }
|
|
||||||
],
|
|
||||||
"name": "getLiquidityProviderForMarket",
|
|
||||||
"outputs": [{ "internalType": "address", "name": "providerAddress", "type": "address" }],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
@ -390,9 +370,11 @@
|
|||||||
"inputs": [
|
"inputs": [
|
||||||
{ "internalType": "address", "name": "makerToken", "type": "address" },
|
{ "internalType": "address", "name": "makerToken", "type": "address" },
|
||||||
{ "internalType": "address", "name": "takerToken", "type": "address" },
|
{ "internalType": "address", "name": "takerToken", "type": "address" },
|
||||||
{ "internalType": "address payable", "name": "recipient", "type": "address" },
|
{ "internalType": "address payable", "name": "target", "type": "address" },
|
||||||
|
{ "internalType": "address", "name": "recipient", "type": "address" },
|
||||||
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
|
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
|
||||||
{ "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" }
|
{ "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" },
|
||||||
|
{ "internalType": "bytes", "name": "auxiliaryData", "type": "bytes" }
|
||||||
],
|
],
|
||||||
"name": "sellToLiquidityProvider",
|
"name": "sellToLiquidityProvider",
|
||||||
"outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }],
|
"outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }],
|
||||||
@ -411,17 +393,6 @@
|
|||||||
"stateMutability": "payable",
|
"stateMutability": "payable",
|
||||||
"type": "function"
|
"type": "function"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "xAsset", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "yAsset", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "providerAddress", "type": "address" }
|
|
||||||
],
|
|
||||||
"name": "setLiquidityProviderForMarket",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"inputs": [{ "internalType": "address", "name": "quoteSigner", "type": "address" }],
|
"inputs": [{ "internalType": "address", "name": "quoteSigner", "type": "address" }],
|
||||||
"name": "setQuoteSigner",
|
"name": "setQuoteSigner",
|
||||||
@ -536,14 +507,6 @@
|
|||||||
"params": { "selector": "The function selector." },
|
"params": { "selector": "The function selector." },
|
||||||
"returns": { "impl": "The implementation contract address." }
|
"returns": { "impl": "The implementation contract address." }
|
||||||
},
|
},
|
||||||
"getLiquidityProviderForMarket(address,address)": {
|
|
||||||
"details": "Returns the address of the liquidity provider for a market given (xAsset, yAsset), or reverts if pool does not exist.",
|
|
||||||
"params": {
|
|
||||||
"xAsset": "First asset managed by the liquidity provider.",
|
|
||||||
"yAsset": "Second asset managed by the liquidity provider."
|
|
||||||
},
|
|
||||||
"returns": { "providerAddress": "Address of the liquidity provider." }
|
|
||||||
},
|
|
||||||
"getMetaTransactionExecutedBlock((address,address,uint256,uint256,uint256,uint256,bytes,uint256,address,uint256))": {
|
"getMetaTransactionExecutedBlock((address,address,uint256,uint256,uint256,uint256,bytes,uint256,address,uint256))": {
|
||||||
"details": "Get the block at which a meta-transaction has been executed.",
|
"details": "Get the block at which a meta-transaction has been executed.",
|
||||||
"params": { "mtx": "The meta-transaction." },
|
"params": { "mtx": "The meta-transaction." },
|
||||||
@ -616,6 +579,19 @@
|
|||||||
"targetImpl": "The address of an older implementation of the function."
|
"targetImpl": "The address of an older implementation of the function."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sellToLiquidityProvider(address,address,address,address,uint256,uint256,bytes)": {
|
||||||
|
"details": "Sells `sellAmount` of `takerToken` to the liquidity provider at the given `target`.",
|
||||||
|
"params": {
|
||||||
|
"auxiliaryData": "Auxiliary data supplied to the `target` contract.",
|
||||||
|
"makerToken": "The token being bought.",
|
||||||
|
"minBuyAmount": "The minimum acceptable amount of `makerToken` to buy. Reverts if this amount is not satisfied.",
|
||||||
|
"recipient": "The recipient of the bought tokens. If equal to address(0), `msg.sender` is assumed to be the recipient.",
|
||||||
|
"sellAmount": "The amount of `takerToken` to sell.",
|
||||||
|
"takerToken": "The token being sold.",
|
||||||
|
"target": "The address of the on-chain liquidity provider to trade with."
|
||||||
|
},
|
||||||
|
"returns": { "boughtAmount": "The amount of `makerToken` bought." }
|
||||||
|
},
|
||||||
"sellToUniswap(address[],uint256,uint256,bool)": {
|
"sellToUniswap(address[],uint256,uint256,bool)": {
|
||||||
"details": "Efficiently sell directly to uniswap/sushiswap.",
|
"details": "Efficiently sell directly to uniswap/sushiswap.",
|
||||||
"params": {
|
"params": {
|
||||||
@ -626,14 +602,6 @@
|
|||||||
},
|
},
|
||||||
"returns": { "buyAmount": "Amount of `tokens[-1]` bought." }
|
"returns": { "buyAmount": "Amount of `tokens[-1]` bought." }
|
||||||
},
|
},
|
||||||
"setLiquidityProviderForMarket(address,address,address)": {
|
|
||||||
"details": "Sets address of the liquidity provider for a market given (xAsset, yAsset).",
|
|
||||||
"params": {
|
|
||||||
"providerAddress": "Address of the liquidity provider.",
|
|
||||||
"xAsset": "First asset managed by the liquidity provider.",
|
|
||||||
"yAsset": "Second asset managed by the liquidity provider."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"setQuoteSigner(address)": {
|
"setQuoteSigner(address)": {
|
||||||
"details": "Replace the optional signer for `transformERC20()` calldata. Only callable by the owner.",
|
"details": "Replace the optional signer for `transformERC20()` calldata. Only callable by the owner.",
|
||||||
"params": { "quoteSigner": "The address of the new calldata signer." }
|
"params": { "quoteSigner": "The address of the new calldata signer." }
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"artifacts_copy": "node lib/src/copy.js",
|
"artifacts_copy": "node lib/src/copy.js",
|
||||||
"artifacts_transform": "node lib/src/transform.js ./artifacts && prettier --write ./artifacts/*.json && cp -r ./artifacts/ ../../python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/",
|
"artifacts_transform": "node lib/src/transform.js ./artifacts && prettier --write ./artifacts/*.json",
|
||||||
"artifacts_update": "yarn artifacts_copy && yarn artifacts_transform && yarn build",
|
"artifacts_update": "yarn artifacts_copy && yarn artifacts_transform && yarn build",
|
||||||
"build": "yarn tsc -b",
|
"build": "yarn tsc -b",
|
||||||
"build:ci": "yarn build",
|
"build:ci": "yarn build",
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "13.10.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Update IZeroEx wrapper and remove ILiquidityProviderRegistry wrapper",
|
||||||
|
"pr": 16
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1604385937,
|
"timestamp": 1604385937,
|
||||||
"version": "13.9.5",
|
"version": "13.9.5",
|
||||||
|
@ -1,327 +0,0 @@
|
|||||||
// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma enum-naming
|
|
||||||
// tslint:disable:whitespace no-unbound-method no-trailing-whitespace
|
|
||||||
// tslint:disable:no-unused-variable
|
|
||||||
import {
|
|
||||||
AwaitTransactionSuccessOpts,
|
|
||||||
ContractFunctionObj,
|
|
||||||
ContractTxFunctionObj,
|
|
||||||
SendTransactionOpts,
|
|
||||||
BaseContract,
|
|
||||||
PromiseWithTransactionHash,
|
|
||||||
methodAbiToFunctionSignature,
|
|
||||||
linkLibrariesInBytecode,
|
|
||||||
} from '@0x/base-contract';
|
|
||||||
import { schemas } from '@0x/json-schemas';
|
|
||||||
import {
|
|
||||||
BlockParam,
|
|
||||||
BlockParamLiteral,
|
|
||||||
BlockRange,
|
|
||||||
CallData,
|
|
||||||
ContractAbi,
|
|
||||||
ContractArtifact,
|
|
||||||
DecodedLogArgs,
|
|
||||||
MethodAbi,
|
|
||||||
TransactionReceiptWithDecodedLogs,
|
|
||||||
TxData,
|
|
||||||
TxDataPayable,
|
|
||||||
SupportedProvider,
|
|
||||||
} from 'ethereum-types';
|
|
||||||
import { BigNumber, classUtils, hexUtils, logUtils, providerUtils } from '@0x/utils';
|
|
||||||
import { EventCallback, IndexedFilterValues, SimpleContractArtifact } from '@0x/types';
|
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
|
||||||
import { assert } from '@0x/assert';
|
|
||||||
import * as ethers from 'ethers';
|
|
||||||
// tslint:enable:no-unused-variable
|
|
||||||
|
|
||||||
/* istanbul ignore next */
|
|
||||||
// tslint:disable:array-type
|
|
||||||
// tslint:disable:no-parameter-reassignment
|
|
||||||
// tslint:disable-next-line:class-name
|
|
||||||
export class ILiquidityProviderRegistryContract extends BaseContract {
|
|
||||||
/**
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
public static deployedBytecode: string | undefined;
|
|
||||||
public static contractName = 'ILiquidityProviderRegistry';
|
|
||||||
private readonly _methodABIIndex: { [name: string]: number } = {};
|
|
||||||
public static async deployFrom0xArtifactAsync(
|
|
||||||
artifact: ContractArtifact | SimpleContractArtifact,
|
|
||||||
supportedProvider: SupportedProvider,
|
|
||||||
txDefaults: Partial<TxData>,
|
|
||||||
logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact },
|
|
||||||
): Promise<ILiquidityProviderRegistryContract> {
|
|
||||||
assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [
|
|
||||||
schemas.addressSchema,
|
|
||||||
schemas.numberSchema,
|
|
||||||
schemas.jsNumber,
|
|
||||||
]);
|
|
||||||
if (artifact.compilerOutput === undefined) {
|
|
||||||
throw new Error('Compiler output not found in the artifact file');
|
|
||||||
}
|
|
||||||
const provider = providerUtils.standardizeOrThrow(supportedProvider);
|
|
||||||
const bytecode = artifact.compilerOutput.evm.bytecode.object;
|
|
||||||
const abi = artifact.compilerOutput.abi;
|
|
||||||
const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {};
|
|
||||||
if (Object.keys(logDecodeDependencies) !== undefined) {
|
|
||||||
for (const key of Object.keys(logDecodeDependencies)) {
|
|
||||||
logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ILiquidityProviderRegistryContract.deployAsync(
|
|
||||||
bytecode,
|
|
||||||
abi,
|
|
||||||
provider,
|
|
||||||
txDefaults,
|
|
||||||
logDecodeDependenciesAbiOnly,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async deployWithLibrariesFrom0xArtifactAsync(
|
|
||||||
artifact: ContractArtifact,
|
|
||||||
libraryArtifacts: { [libraryName: string]: ContractArtifact },
|
|
||||||
supportedProvider: SupportedProvider,
|
|
||||||
txDefaults: Partial<TxData>,
|
|
||||||
logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact },
|
|
||||||
): Promise<ILiquidityProviderRegistryContract> {
|
|
||||||
assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [
|
|
||||||
schemas.addressSchema,
|
|
||||||
schemas.numberSchema,
|
|
||||||
schemas.jsNumber,
|
|
||||||
]);
|
|
||||||
if (artifact.compilerOutput === undefined) {
|
|
||||||
throw new Error('Compiler output not found in the artifact file');
|
|
||||||
}
|
|
||||||
const provider = providerUtils.standardizeOrThrow(supportedProvider);
|
|
||||||
const abi = artifact.compilerOutput.abi;
|
|
||||||
const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {};
|
|
||||||
if (Object.keys(logDecodeDependencies) !== undefined) {
|
|
||||||
for (const key of Object.keys(logDecodeDependencies)) {
|
|
||||||
logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const libraryAddresses = await ILiquidityProviderRegistryContract._deployLibrariesAsync(
|
|
||||||
artifact,
|
|
||||||
libraryArtifacts,
|
|
||||||
new Web3Wrapper(provider),
|
|
||||||
txDefaults,
|
|
||||||
);
|
|
||||||
const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses);
|
|
||||||
return ILiquidityProviderRegistryContract.deployAsync(
|
|
||||||
bytecode,
|
|
||||||
abi,
|
|
||||||
provider,
|
|
||||||
txDefaults,
|
|
||||||
logDecodeDependenciesAbiOnly,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async deployAsync(
|
|
||||||
bytecode: string,
|
|
||||||
abi: ContractAbi,
|
|
||||||
supportedProvider: SupportedProvider,
|
|
||||||
txDefaults: Partial<TxData>,
|
|
||||||
logDecodeDependencies: { [contractName: string]: ContractAbi },
|
|
||||||
): Promise<ILiquidityProviderRegistryContract> {
|
|
||||||
assert.isHexString('bytecode', bytecode);
|
|
||||||
assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [
|
|
||||||
schemas.addressSchema,
|
|
||||||
schemas.numberSchema,
|
|
||||||
schemas.jsNumber,
|
|
||||||
]);
|
|
||||||
const provider = providerUtils.standardizeOrThrow(supportedProvider);
|
|
||||||
const constructorAbi = BaseContract._lookupConstructorAbi(abi);
|
|
||||||
[] = BaseContract._formatABIDataItemList(constructorAbi.inputs, [], BaseContract._bigNumberToString);
|
|
||||||
const iface = new ethers.utils.Interface(abi);
|
|
||||||
const deployInfo = iface.deployFunction;
|
|
||||||
const txData = deployInfo.encode(bytecode, []);
|
|
||||||
const web3Wrapper = new Web3Wrapper(provider);
|
|
||||||
const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync(
|
|
||||||
{
|
|
||||||
data: txData,
|
|
||||||
...txDefaults,
|
|
||||||
},
|
|
||||||
web3Wrapper.estimateGasAsync.bind(web3Wrapper),
|
|
||||||
);
|
|
||||||
const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
|
||||||
logUtils.log(`transactionHash: ${txHash}`);
|
|
||||||
const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
|
||||||
logUtils.log(`ILiquidityProviderRegistry successfully deployed at ${txReceipt.contractAddress}`);
|
|
||||||
const contractInstance = new ILiquidityProviderRegistryContract(
|
|
||||||
txReceipt.contractAddress as string,
|
|
||||||
provider,
|
|
||||||
txDefaults,
|
|
||||||
logDecodeDependencies,
|
|
||||||
);
|
|
||||||
contractInstance.constructorArgs = [];
|
|
||||||
return contractInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns The contract ABI
|
|
||||||
*/
|
|
||||||
public static ABI(): ContractAbi {
|
|
||||||
const abi = [
|
|
||||||
{
|
|
||||||
constant: true,
|
|
||||||
inputs: [
|
|
||||||
{
|
|
||||||
name: 'takerToken',
|
|
||||||
type: 'address',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'makerToken',
|
|
||||||
type: 'address',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
name: 'getLiquidityProviderForMarket',
|
|
||||||
outputs: [
|
|
||||||
{
|
|
||||||
name: 'providerAddress',
|
|
||||||
type: 'address',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
payable: false,
|
|
||||||
stateMutability: 'view',
|
|
||||||
type: 'function',
|
|
||||||
},
|
|
||||||
] as ContractAbi;
|
|
||||||
return abi;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static async _deployLibrariesAsync(
|
|
||||||
artifact: ContractArtifact,
|
|
||||||
libraryArtifacts: { [libraryName: string]: ContractArtifact },
|
|
||||||
web3Wrapper: Web3Wrapper,
|
|
||||||
txDefaults: Partial<TxData>,
|
|
||||||
libraryAddresses: { [libraryName: string]: string } = {},
|
|
||||||
): Promise<{ [libraryName: string]: string }> {
|
|
||||||
const links = artifact.compilerOutput.evm.bytecode.linkReferences;
|
|
||||||
// Go through all linked libraries, recursively deploying them if necessary.
|
|
||||||
for (const link of Object.values(links)) {
|
|
||||||
for (const libraryName of Object.keys(link)) {
|
|
||||||
if (!libraryAddresses[libraryName]) {
|
|
||||||
// Library not yet deployed.
|
|
||||||
const libraryArtifact = libraryArtifacts[libraryName];
|
|
||||||
if (!libraryArtifact) {
|
|
||||||
throw new Error(`Missing artifact for linked library "${libraryName}"`);
|
|
||||||
}
|
|
||||||
// Deploy any dependent libraries used by this library.
|
|
||||||
await ILiquidityProviderRegistryContract._deployLibrariesAsync(
|
|
||||||
libraryArtifact,
|
|
||||||
libraryArtifacts,
|
|
||||||
web3Wrapper,
|
|
||||||
txDefaults,
|
|
||||||
libraryAddresses,
|
|
||||||
);
|
|
||||||
// Deploy this library.
|
|
||||||
const linkedLibraryBytecode = linkLibrariesInBytecode(libraryArtifact, libraryAddresses);
|
|
||||||
const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync(
|
|
||||||
{
|
|
||||||
data: linkedLibraryBytecode,
|
|
||||||
...txDefaults,
|
|
||||||
},
|
|
||||||
web3Wrapper.estimateGasAsync.bind(web3Wrapper),
|
|
||||||
);
|
|
||||||
const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
|
||||||
logUtils.log(`transactionHash: ${txHash}`);
|
|
||||||
const { contractAddress } = await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
|
||||||
logUtils.log(`${libraryArtifact.contractName} successfully deployed at ${contractAddress}`);
|
|
||||||
libraryAddresses[libraryArtifact.contractName] = contractAddress as string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return libraryAddresses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getFunctionSignature(methodName: string): string {
|
|
||||||
const index = this._methodABIIndex[methodName];
|
|
||||||
const methodAbi = ILiquidityProviderRegistryContract.ABI()[index] as MethodAbi; // tslint:disable-line:no-unnecessary-type-assertion
|
|
||||||
const functionSignature = methodAbiToFunctionSignature(methodAbi);
|
|
||||||
return functionSignature;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getABIDecodedTransactionData<T>(methodName: string, callData: string): T {
|
|
||||||
const functionSignature = this.getFunctionSignature(methodName);
|
|
||||||
const self = (this as any) as ILiquidityProviderRegistryContract;
|
|
||||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
|
||||||
const abiDecodedCallData = abiEncoder.strictDecode<T>(callData);
|
|
||||||
return abiDecodedCallData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getABIDecodedReturnData<T>(methodName: string, callData: string): T {
|
|
||||||
const functionSignature = this.getFunctionSignature(methodName);
|
|
||||||
const self = (this as any) as ILiquidityProviderRegistryContract;
|
|
||||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
|
||||||
const abiDecodedCallData = abiEncoder.strictDecodeReturnValue<T>(callData);
|
|
||||||
return abiDecodedCallData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getSelector(methodName: string): string {
|
|
||||||
const functionSignature = this.getFunctionSignature(methodName);
|
|
||||||
const self = (this as any) as ILiquidityProviderRegistryContract;
|
|
||||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
|
||||||
return abiEncoder.getSelector();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the address of a liquidity provider for the given market
|
|
||||||
* (takerToken, makerToken), reverting if the pool does not exist.
|
|
||||||
* @param takerToken Taker asset managed by liquidity provider.
|
|
||||||
* @param makerToken Maker asset managed by liquidity provider.
|
|
||||||
* @returns Address of the liquidity provider.
|
|
||||||
*/
|
|
||||||
public getLiquidityProviderForMarket(takerToken: string, makerToken: string): ContractFunctionObj<string> {
|
|
||||||
const self = (this as any) as ILiquidityProviderRegistryContract;
|
|
||||||
assert.isString('takerToken', takerToken);
|
|
||||||
assert.isString('makerToken', makerToken);
|
|
||||||
const functionSignature = 'getLiquidityProviderForMarket(address,address)';
|
|
||||||
|
|
||||||
return {
|
|
||||||
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<string> {
|
|
||||||
BaseContract._assertCallParams(callData, defaultBlock);
|
|
||||||
const rawCallResult = await self._performCallAsync(
|
|
||||||
{ data: this.getABIEncodedTransactionData(), ...callData },
|
|
||||||
defaultBlock,
|
|
||||||
);
|
|
||||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
|
||||||
BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder);
|
|
||||||
return abiEncoder.strictDecodeReturnValue<string>(rawCallResult);
|
|
||||||
},
|
|
||||||
getABIEncodedTransactionData(): string {
|
|
||||||
return self._strictEncodeArguments(functionSignature, [
|
|
||||||
takerToken.toLowerCase(),
|
|
||||||
makerToken.toLowerCase(),
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
address: string,
|
|
||||||
supportedProvider: SupportedProvider,
|
|
||||||
txDefaults?: Partial<TxData>,
|
|
||||||
logDecodeDependencies?: { [contractName: string]: ContractAbi },
|
|
||||||
deployedBytecode: string | undefined = ILiquidityProviderRegistryContract.deployedBytecode,
|
|
||||||
) {
|
|
||||||
super(
|
|
||||||
'ILiquidityProviderRegistry',
|
|
||||||
ILiquidityProviderRegistryContract.ABI(),
|
|
||||||
address,
|
|
||||||
supportedProvider,
|
|
||||||
txDefaults,
|
|
||||||
logDecodeDependencies,
|
|
||||||
deployedBytecode,
|
|
||||||
);
|
|
||||||
classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']);
|
|
||||||
ILiquidityProviderRegistryContract.ABI().forEach((item, index) => {
|
|
||||||
if (item.type === 'function') {
|
|
||||||
const methodAbi = item as MethodAbi;
|
|
||||||
this._methodABIIndex[methodAbi.name] = index;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tslint:disable:max-file-line-count
|
|
||||||
// tslint:enable:no-unbound-method no-parameter-reassignment no-consecutive-blank-lines ordered-imports align
|
|
||||||
// tslint:enable:trailing-comma whitespace no-trailing-whitespace
|
|
@ -36,7 +36,6 @@ import * as ethers from 'ethers';
|
|||||||
// tslint:enable:no-unused-variable
|
// tslint:enable:no-unused-variable
|
||||||
|
|
||||||
export type IZeroExEventArgs =
|
export type IZeroExEventArgs =
|
||||||
| IZeroExLiquidityProviderForMarketUpdatedEventArgs
|
|
||||||
| IZeroExMetaTransactionExecutedEventArgs
|
| IZeroExMetaTransactionExecutedEventArgs
|
||||||
| IZeroExMigratedEventArgs
|
| IZeroExMigratedEventArgs
|
||||||
| IZeroExOwnershipTransferredEventArgs
|
| IZeroExOwnershipTransferredEventArgs
|
||||||
@ -46,7 +45,6 @@ export type IZeroExEventArgs =
|
|||||||
| IZeroExTransformerDeployerUpdatedEventArgs;
|
| IZeroExTransformerDeployerUpdatedEventArgs;
|
||||||
|
|
||||||
export enum IZeroExEvents {
|
export enum IZeroExEvents {
|
||||||
LiquidityProviderForMarketUpdated = 'LiquidityProviderForMarketUpdated',
|
|
||||||
MetaTransactionExecuted = 'MetaTransactionExecuted',
|
MetaTransactionExecuted = 'MetaTransactionExecuted',
|
||||||
Migrated = 'Migrated',
|
Migrated = 'Migrated',
|
||||||
OwnershipTransferred = 'OwnershipTransferred',
|
OwnershipTransferred = 'OwnershipTransferred',
|
||||||
@ -56,12 +54,6 @@ export enum IZeroExEvents {
|
|||||||
TransformerDeployerUpdated = 'TransformerDeployerUpdated',
|
TransformerDeployerUpdated = 'TransformerDeployerUpdated',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IZeroExLiquidityProviderForMarketUpdatedEventArgs extends DecodedLogArgs {
|
|
||||||
xAsset: string;
|
|
||||||
yAsset: string;
|
|
||||||
providerAddress: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IZeroExMetaTransactionExecutedEventArgs extends DecodedLogArgs {
|
export interface IZeroExMetaTransactionExecutedEventArgs extends DecodedLogArgs {
|
||||||
hash: string;
|
hash: string;
|
||||||
selector: string;
|
selector: string;
|
||||||
@ -219,29 +211,6 @@ export class IZeroExContract extends BaseContract {
|
|||||||
*/
|
*/
|
||||||
public static ABI(): ContractAbi {
|
public static ABI(): ContractAbi {
|
||||||
const abi = [
|
const abi = [
|
||||||
{
|
|
||||||
anonymous: false,
|
|
||||||
inputs: [
|
|
||||||
{
|
|
||||||
name: 'xAsset',
|
|
||||||
type: 'address',
|
|
||||||
indexed: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'yAsset',
|
|
||||||
type: 'address',
|
|
||||||
indexed: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'providerAddress',
|
|
||||||
type: 'address',
|
|
||||||
indexed: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
name: 'LiquidityProviderForMarketUpdated',
|
|
||||||
outputs: [],
|
|
||||||
type: 'event',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
anonymous: false,
|
anonymous: false,
|
||||||
inputs: [
|
inputs: [
|
||||||
@ -728,27 +697,6 @@ export class IZeroExContract extends BaseContract {
|
|||||||
stateMutability: 'view',
|
stateMutability: 'view',
|
||||||
type: 'function',
|
type: 'function',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
inputs: [
|
|
||||||
{
|
|
||||||
name: 'xAsset',
|
|
||||||
type: 'address',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'yAsset',
|
|
||||||
type: 'address',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
name: 'getLiquidityProviderForMarket',
|
|
||||||
outputs: [
|
|
||||||
{
|
|
||||||
name: 'providerAddress',
|
|
||||||
type: 'address',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
stateMutability: 'view',
|
|
||||||
type: 'function',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
@ -1062,6 +1010,10 @@ export class IZeroExContract extends BaseContract {
|
|||||||
name: 'takerToken',
|
name: 'takerToken',
|
||||||
type: 'address',
|
type: 'address',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'target',
|
||||||
|
type: 'address',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'recipient',
|
name: 'recipient',
|
||||||
type: 'address',
|
type: 'address',
|
||||||
@ -1074,6 +1026,10 @@ export class IZeroExContract extends BaseContract {
|
|||||||
name: 'minBuyAmount',
|
name: 'minBuyAmount',
|
||||||
type: 'uint256',
|
type: 'uint256',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'auxiliaryData',
|
||||||
|
type: 'bytes',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
name: 'sellToLiquidityProvider',
|
name: 'sellToLiquidityProvider',
|
||||||
outputs: [
|
outputs: [
|
||||||
@ -1114,26 +1070,6 @@ export class IZeroExContract extends BaseContract {
|
|||||||
stateMutability: 'payable',
|
stateMutability: 'payable',
|
||||||
type: 'function',
|
type: 'function',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
inputs: [
|
|
||||||
{
|
|
||||||
name: 'xAsset',
|
|
||||||
type: 'address',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'yAsset',
|
|
||||||
type: 'address',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'providerAddress',
|
|
||||||
type: 'address',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
name: 'setLiquidityProviderForMarket',
|
|
||||||
outputs: [],
|
|
||||||
stateMutability: 'nonpayable',
|
|
||||||
type: 'function',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
@ -1848,60 +1784,6 @@ export class IZeroExContract extends BaseContract {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Returns the address of the liquidity provider for a market given
|
|
||||||
* (xAsset, yAsset), or reverts if pool does not exist.
|
|
||||||
* @param xAsset First asset managed by the liquidity provider.
|
|
||||||
* @param yAsset Second asset managed by the liquidity provider.
|
|
||||||
*/
|
|
||||||
public getLiquidityProviderForMarket(xAsset: string, yAsset: string): ContractTxFunctionObj<string> {
|
|
||||||
const self = (this as any) as IZeroExContract;
|
|
||||||
assert.isString('xAsset', xAsset);
|
|
||||||
assert.isString('yAsset', yAsset);
|
|
||||||
const functionSignature = 'getLiquidityProviderForMarket(address,address)';
|
|
||||||
|
|
||||||
return {
|
|
||||||
async sendTransactionAsync(
|
|
||||||
txData?: Partial<TxData> | undefined,
|
|
||||||
opts: SendTransactionOpts = { shouldValidate: true },
|
|
||||||
): Promise<string> {
|
|
||||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
|
|
||||||
{ data: this.getABIEncodedTransactionData(), ...txData },
|
|
||||||
this.estimateGasAsync.bind(this),
|
|
||||||
);
|
|
||||||
if (opts.shouldValidate !== false) {
|
|
||||||
await this.callAsync(txDataWithDefaults);
|
|
||||||
}
|
|
||||||
return self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
|
||||||
},
|
|
||||||
awaitTransactionSuccessAsync(
|
|
||||||
txData?: Partial<TxData>,
|
|
||||||
opts: AwaitTransactionSuccessOpts = { shouldValidate: true },
|
|
||||||
): PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs> {
|
|
||||||
return self._promiseWithTransactionHash(this.sendTransactionAsync(txData, opts), opts);
|
|
||||||
},
|
|
||||||
async estimateGasAsync(txData?: Partial<TxData> | undefined): Promise<number> {
|
|
||||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({
|
|
||||||
data: this.getABIEncodedTransactionData(),
|
|
||||||
...txData,
|
|
||||||
});
|
|
||||||
return self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
|
|
||||||
},
|
|
||||||
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<string> {
|
|
||||||
BaseContract._assertCallParams(callData, defaultBlock);
|
|
||||||
const rawCallResult = await self._performCallAsync(
|
|
||||||
{ data: this.getABIEncodedTransactionData(), ...callData },
|
|
||||||
defaultBlock,
|
|
||||||
);
|
|
||||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
|
||||||
BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder);
|
|
||||||
return abiEncoder.strictDecodeReturnValue<string>(rawCallResult);
|
|
||||||
},
|
|
||||||
getABIEncodedTransactionData(): string {
|
|
||||||
return self._strictEncodeArguments(functionSignature, [xAsset.toLowerCase(), yAsset.toLowerCase()]);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Get the block at which a meta-transaction has been executed.
|
* Get the block at which a meta-transaction has been executed.
|
||||||
* @param mtx The meta-transaction.
|
* @param mtx The meta-transaction.
|
||||||
@ -2606,20 +2488,38 @@ export class IZeroExContract extends BaseContract {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Sells `sellAmount` of `takerToken` to the liquidity provider
|
||||||
|
* at the given `target`.
|
||||||
|
* @param makerToken The token being bought.
|
||||||
|
* @param takerToken The token being sold.
|
||||||
|
* @param target The address of the on-chain liquidity provider to trade
|
||||||
|
* with.
|
||||||
|
* @param recipient The recipient of the bought tokens. If equal to
|
||||||
|
* address(0), `msg.sender` is assumed to be the recipient.
|
||||||
|
* @param sellAmount The amount of `takerToken` to sell.
|
||||||
|
* @param minBuyAmount The minimum acceptable amount of `makerToken` to
|
||||||
|
* buy. Reverts if this amount is not satisfied.
|
||||||
|
* @param auxiliaryData Auxiliary data supplied to the `target` contract.
|
||||||
|
*/
|
||||||
public sellToLiquidityProvider(
|
public sellToLiquidityProvider(
|
||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
|
target: string,
|
||||||
recipient: string,
|
recipient: string,
|
||||||
sellAmount: BigNumber,
|
sellAmount: BigNumber,
|
||||||
minBuyAmount: BigNumber,
|
minBuyAmount: BigNumber,
|
||||||
|
auxiliaryData: string,
|
||||||
): ContractTxFunctionObj<BigNumber> {
|
): ContractTxFunctionObj<BigNumber> {
|
||||||
const self = (this as any) as IZeroExContract;
|
const self = (this as any) as IZeroExContract;
|
||||||
assert.isString('makerToken', makerToken);
|
assert.isString('makerToken', makerToken);
|
||||||
assert.isString('takerToken', takerToken);
|
assert.isString('takerToken', takerToken);
|
||||||
|
assert.isString('target', target);
|
||||||
assert.isString('recipient', recipient);
|
assert.isString('recipient', recipient);
|
||||||
assert.isBigNumber('sellAmount', sellAmount);
|
assert.isBigNumber('sellAmount', sellAmount);
|
||||||
assert.isBigNumber('minBuyAmount', minBuyAmount);
|
assert.isBigNumber('minBuyAmount', minBuyAmount);
|
||||||
const functionSignature = 'sellToLiquidityProvider(address,address,address,uint256,uint256)';
|
assert.isString('auxiliaryData', auxiliaryData);
|
||||||
|
const functionSignature = 'sellToLiquidityProvider(address,address,address,address,uint256,uint256,bytes)';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async sendTransactionAsync(
|
async sendTransactionAsync(
|
||||||
@ -2662,9 +2562,11 @@ export class IZeroExContract extends BaseContract {
|
|||||||
return self._strictEncodeArguments(functionSignature, [
|
return self._strictEncodeArguments(functionSignature, [
|
||||||
makerToken.toLowerCase(),
|
makerToken.toLowerCase(),
|
||||||
takerToken.toLowerCase(),
|
takerToken.toLowerCase(),
|
||||||
|
target.toLowerCase(),
|
||||||
recipient.toLowerCase(),
|
recipient.toLowerCase(),
|
||||||
sellAmount,
|
sellAmount,
|
||||||
minBuyAmount,
|
minBuyAmount,
|
||||||
|
auxiliaryData,
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -2731,70 +2633,6 @@ export class IZeroExContract extends BaseContract {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Sets address of the liquidity provider for a market given
|
|
||||||
* (xAsset, yAsset).
|
|
||||||
* @param xAsset First asset managed by the liquidity provider.
|
|
||||||
* @param yAsset Second asset managed by the liquidity provider.
|
|
||||||
* @param providerAddress Address of the liquidity provider.
|
|
||||||
*/
|
|
||||||
public setLiquidityProviderForMarket(
|
|
||||||
xAsset: string,
|
|
||||||
yAsset: string,
|
|
||||||
providerAddress: string,
|
|
||||||
): ContractTxFunctionObj<void> {
|
|
||||||
const self = (this as any) as IZeroExContract;
|
|
||||||
assert.isString('xAsset', xAsset);
|
|
||||||
assert.isString('yAsset', yAsset);
|
|
||||||
assert.isString('providerAddress', providerAddress);
|
|
||||||
const functionSignature = 'setLiquidityProviderForMarket(address,address,address)';
|
|
||||||
|
|
||||||
return {
|
|
||||||
async sendTransactionAsync(
|
|
||||||
txData?: Partial<TxData> | undefined,
|
|
||||||
opts: SendTransactionOpts = { shouldValidate: true },
|
|
||||||
): Promise<string> {
|
|
||||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
|
|
||||||
{ data: this.getABIEncodedTransactionData(), ...txData },
|
|
||||||
this.estimateGasAsync.bind(this),
|
|
||||||
);
|
|
||||||
if (opts.shouldValidate !== false) {
|
|
||||||
await this.callAsync(txDataWithDefaults);
|
|
||||||
}
|
|
||||||
return self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
|
||||||
},
|
|
||||||
awaitTransactionSuccessAsync(
|
|
||||||
txData?: Partial<TxData>,
|
|
||||||
opts: AwaitTransactionSuccessOpts = { shouldValidate: true },
|
|
||||||
): PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs> {
|
|
||||||
return self._promiseWithTransactionHash(this.sendTransactionAsync(txData, opts), opts);
|
|
||||||
},
|
|
||||||
async estimateGasAsync(txData?: Partial<TxData> | undefined): Promise<number> {
|
|
||||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({
|
|
||||||
data: this.getABIEncodedTransactionData(),
|
|
||||||
...txData,
|
|
||||||
});
|
|
||||||
return self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
|
|
||||||
},
|
|
||||||
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<void> {
|
|
||||||
BaseContract._assertCallParams(callData, defaultBlock);
|
|
||||||
const rawCallResult = await self._performCallAsync(
|
|
||||||
{ data: this.getABIEncodedTransactionData(), ...callData },
|
|
||||||
defaultBlock,
|
|
||||||
);
|
|
||||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
|
||||||
BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder);
|
|
||||||
return abiEncoder.strictDecodeReturnValue<void>(rawCallResult);
|
|
||||||
},
|
|
||||||
getABIEncodedTransactionData(): string {
|
|
||||||
return self._strictEncodeArguments(functionSignature, [
|
|
||||||
xAsset.toLowerCase(),
|
|
||||||
yAsset.toLowerCase(),
|
|
||||||
providerAddress.toLowerCase(),
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Replace the optional signer for `transformERC20()` calldata.
|
* Replace the optional signer for `transformERC20()` calldata.
|
||||||
* Only callable by the owner.
|
* Only callable by the owner.
|
||||||
|
@ -125,7 +125,6 @@ export {
|
|||||||
IZeroExContract,
|
IZeroExContract,
|
||||||
IZeroExEventArgs,
|
IZeroExEventArgs,
|
||||||
IZeroExEvents,
|
IZeroExEvents,
|
||||||
IZeroExLiquidityProviderForMarketUpdatedEventArgs,
|
|
||||||
IZeroExMetaTransactionExecutedEventArgs,
|
IZeroExMetaTransactionExecutedEventArgs,
|
||||||
IZeroExMigratedEventArgs,
|
IZeroExMigratedEventArgs,
|
||||||
IZeroExOwnershipTransferredEventArgs,
|
IZeroExOwnershipTransferredEventArgs,
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "6.5.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Add `exchangeProxyLiquidityProviderSandbox` address",
|
||||||
|
"pr": 16
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1604385937,
|
"timestamp": 1604385937,
|
||||||
"version": "6.4.7",
|
"version": "6.4.7",
|
||||||
|
@ -402,6 +402,7 @@ export async function runMigrationsAsync(
|
|||||||
exchangeProxyAllowanceTarget: exchangeProxyAllowanceTargetAddress,
|
exchangeProxyAllowanceTarget: exchangeProxyAllowanceTargetAddress,
|
||||||
exchangeProxyTransformerDeployer: txDefaults.from,
|
exchangeProxyTransformerDeployer: txDefaults.from,
|
||||||
exchangeProxyFlashWallet: exchangeProxyFlashWalletAddress,
|
exchangeProxyFlashWallet: exchangeProxyFlashWalletAddress,
|
||||||
|
exchangeProxyLiquidityProviderSandbox: NULL_ADDRESS,
|
||||||
transformers: {
|
transformers: {
|
||||||
wethTransformer: wethTransformer.address,
|
wethTransformer: wethTransformer.address,
|
||||||
payTakerTransformer: payTakerTransformer.address,
|
payTakerTransformer: payTakerTransformer.address,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user