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",
|
||||
"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
|
||||
);
|
||||
}
|
||||
|
||||
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.
|
||||
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(
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
address payable recipient,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address payable provider,
|
||||
address recipient,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
payable
|
||||
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;
|
||||
|
||||
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/LibSafeMathV06.sol";
|
||||
import "../errors/LibLiquidityProviderRichErrors.sol";
|
||||
import "../external/ILiquidityProviderSandbox.sol";
|
||||
import "../external/LiquidityProviderSandbox.sol";
|
||||
import "../fixins/FixinCommon.sol";
|
||||
import "../migrations/LibMigrate.sol";
|
||||
import "../storage/LibLiquidityProviderStorage.sol";
|
||||
import "../vendor/v3/IERC20Bridge.sol";
|
||||
import "./IFeature.sol";
|
||||
import "./ILiquidityProviderFeature.sol";
|
||||
import "./libs/LibTokenSpender.sol";
|
||||
@ -39,7 +37,6 @@ contract LiquidityProviderFeature is
|
||||
ILiquidityProviderFeature,
|
||||
FixinCommon
|
||||
{
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
using LibSafeMathV06 for uint256;
|
||||
using LibRichErrorsV06 for bytes;
|
||||
|
||||
@ -50,16 +47,24 @@ contract LiquidityProviderFeature is
|
||||
|
||||
/// @dev ETH pseudo-token address.
|
||||
address constant internal ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
/// @dev The WETH contract address.
|
||||
IEtherTokenV06 public immutable weth;
|
||||
/// @dev The sandbox contract address.
|
||||
ILiquidityProviderSandbox public immutable sandbox;
|
||||
|
||||
/// @dev Store the WETH address in an immutable.
|
||||
/// @param weth_ The weth token.
|
||||
constructor(IEtherTokenV06 weth_)
|
||||
/// @dev Event for data pipeline.
|
||||
event LiquidityProviderSwap(
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
uint256 inputTokenAmount,
|
||||
uint256 outputTokenAmount,
|
||||
address provider,
|
||||
address recipient
|
||||
);
|
||||
|
||||
constructor(address zeroEx)
|
||||
public
|
||||
FixinCommon()
|
||||
{
|
||||
weth = weth_;
|
||||
sandbox = new LiquidityProviderSandbox(zeroEx);
|
||||
}
|
||||
|
||||
/// @dev Initialize and register this feature.
|
||||
@ -70,131 +75,102 @@ contract LiquidityProviderFeature is
|
||||
returns (bytes4 success)
|
||||
{
|
||||
_registerFeatureFunction(this.sellToLiquidityProvider.selector);
|
||||
_registerFeatureFunction(this.setLiquidityProviderForMarket.selector);
|
||||
_registerFeatureFunction(this.getLiquidityProviderForMarket.selector);
|
||||
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(
|
||||
address makerToken,
|
||||
address takerToken,
|
||||
address payable recipient,
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
address payable provider,
|
||||
address recipient,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
override
|
||||
payable
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
address providerAddress = getLiquidityProviderForMarket(makerToken, takerToken);
|
||||
if (recipient == address(0)) {
|
||||
recipient = msg.sender;
|
||||
}
|
||||
|
||||
if (takerToken == ETH_TOKEN_ADDRESS) {
|
||||
// Wrap ETH.
|
||||
weth.deposit{value: sellAmount}();
|
||||
weth.transfer(providerAddress, sellAmount);
|
||||
if (inputToken == ETH_TOKEN_ADDRESS) {
|
||||
provider.transfer(sellAmount);
|
||||
} else {
|
||||
LibTokenSpender.spendERC20Tokens(
|
||||
IERC20TokenV06(takerToken),
|
||||
IERC20TokenV06(inputToken),
|
||||
msg.sender,
|
||||
providerAddress,
|
||||
provider,
|
||||
sellAmount
|
||||
);
|
||||
}
|
||||
|
||||
if (makerToken == ETH_TOKEN_ADDRESS) {
|
||||
uint256 balanceBefore = weth.balanceOf(address(this));
|
||||
IERC20Bridge(providerAddress).bridgeTransferFrom(
|
||||
address(weth),
|
||||
address(0),
|
||||
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),
|
||||
if (inputToken == ETH_TOKEN_ADDRESS) {
|
||||
uint256 balanceBefore = IERC20TokenV06(outputToken).balanceOf(recipient);
|
||||
sandbox.executeSellEthForToken(
|
||||
provider,
|
||||
outputToken,
|
||||
recipient,
|
||||
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) {
|
||||
LibLiquidityProviderRichErrors.LiquidityProviderIncompleteSellError(
|
||||
providerAddress,
|
||||
makerToken,
|
||||
takerToken,
|
||||
provider,
|
||||
outputToken,
|
||||
inputToken,
|
||||
sellAmount,
|
||||
boughtAmount,
|
||||
minBuyAmount
|
||||
).rrevert();
|
||||
}
|
||||
}
|
||||
|
||||
/// @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
|
||||
override
|
||||
onlyOwner
|
||||
{
|
||||
LibLiquidityProviderStorage.getStorage()
|
||||
.addressBook[xAsset][yAsset] = providerAddress;
|
||||
LibLiquidityProviderStorage.getStorage()
|
||||
.addressBook[yAsset][xAsset] = providerAddress;
|
||||
emit LiquidityProviderForMarketUpdated(
|
||||
xAsset,
|
||||
yAsset,
|
||||
providerAddress
|
||||
emit LiquidityProviderSwap(
|
||||
inputToken,
|
||||
outputToken,
|
||||
sellAmount,
|
||||
boughtAmount,
|
||||
provider,
|
||||
recipient
|
||||
);
|
||||
}
|
||||
|
||||
/// @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.
|
||||
string public constant override FEATURE_NAME = "TransformERC20";
|
||||
/// @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.
|
||||
/// Should be delegatecalled by `Migrate.migrate()`.
|
||||
|
@ -37,7 +37,7 @@ contract UniswapFeature is
|
||||
/// @dev Name of this feature.
|
||||
string public constant override FEATURE_NAME = "UniswapFeature";
|
||||
/// @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.
|
||||
IEtherTokenV06 private immutable WETH;
|
||||
/// @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,
|
||||
TransformERC20,
|
||||
MetaTransactions,
|
||||
ReentrancyGuard,
|
||||
LiquidityProvider
|
||||
ReentrancyGuard
|
||||
}
|
||||
|
||||
/// @dev Get the storage slot given a storage ID. We assign unique, well-spaced
|
||||
|
@ -1,19 +1,15 @@
|
||||
|
||||
/*
|
||||
|
||||
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;
|
||||
|
@ -32,28 +32,26 @@ contract TestFillQuoteTransformerBridge {
|
||||
uint256 amount;
|
||||
}
|
||||
|
||||
bytes4 private constant ERC20_BRIDGE_PROXY_ID = 0xdc1600f3;
|
||||
|
||||
function bridgeTransferFrom(
|
||||
address tokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
function sellTokenForToken(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
address recipient,
|
||||
uint256 minBuyAmount,
|
||||
bytes calldata auxiliaryData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
FillBehavior memory behavior = abi.decode(bridgeData, (FillBehavior));
|
||||
TestMintableERC20Token(tokenAddress).mint(
|
||||
to,
|
||||
LibMathV06.getPartialAmountFloor(
|
||||
FillBehavior memory behavior = abi.decode(auxiliaryData, (FillBehavior));
|
||||
boughtAmount = LibMathV06.getPartialAmountFloor(
|
||||
behavior.makerAssetMintRatio,
|
||||
1e18,
|
||||
behavior.amount
|
||||
)
|
||||
);
|
||||
return ERC20_BRIDGE_PROXY_ID;
|
||||
TestMintableERC20Token(makerToken).mint(
|
||||
recipient,
|
||||
boughtAmount
|
||||
);
|
||||
}
|
||||
|
||||
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"
|
||||
},
|
||||
"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": "./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": {
|
||||
"type": "git",
|
||||
|
@ -12,6 +12,7 @@ import * as FullMigration from '../generated-artifacts/FullMigration.json';
|
||||
import * as IAllowanceTarget from '../generated-artifacts/IAllowanceTarget.json';
|
||||
import * as IERC20Transformer from '../generated-artifacts/IERC20Transformer.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 IOwnableFeature from '../generated-artifacts/IOwnableFeature.json';
|
||||
import * as ISimpleFunctionRegistryFeature from '../generated-artifacts/ISimpleFunctionRegistryFeature.json';
|
||||
@ -54,4 +55,5 @@ export const artifacts = {
|
||||
LogMetadataTransformer: LogMetadataTransformer as ContractArtifact,
|
||||
BridgeAdapter: BridgeAdapter 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_erc20_transformer';
|
||||
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_simple_function_registry_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 ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.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 InitialMigration from '../test/generated-artifacts/InitialMigration.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 LibERC20Transformer from '../test/generated-artifacts/LibERC20Transformer.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 LibMetaTransactionsStorage from '../test/generated-artifacts/LibMetaTransactionsStorage.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 LibWalletRichErrors from '../test/generated-artifacts/LibWalletRichErrors.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 MetaTransactionsFeature from '../test/generated-artifacts/MetaTransactionsFeature.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 TestLibSignature from '../test/generated-artifacts/TestLibSignature.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 TestMigrator from '../test/generated-artifacts/TestMigrator.json';
|
||||
import * as TestMintableERC20Token from '../test/generated-artifacts/TestMintableERC20Token.json';
|
||||
@ -137,6 +139,8 @@ export const artifacts = {
|
||||
FlashWallet: FlashWallet as ContractArtifact,
|
||||
IAllowanceTarget: IAllowanceTarget as ContractArtifact,
|
||||
IFlashWallet: IFlashWallet as ContractArtifact,
|
||||
ILiquidityProviderSandbox: ILiquidityProviderSandbox as ContractArtifact,
|
||||
LiquidityProviderSandbox: LiquidityProviderSandbox as ContractArtifact,
|
||||
TransformerDeployer: TransformerDeployer as ContractArtifact,
|
||||
BootstrapFeature: BootstrapFeature as ContractArtifact,
|
||||
IBootstrapFeature: IBootstrapFeature as ContractArtifact,
|
||||
@ -168,7 +172,6 @@ export const artifacts = {
|
||||
InitialMigration: InitialMigration as ContractArtifact,
|
||||
LibBootstrap: LibBootstrap as ContractArtifact,
|
||||
LibMigrate: LibMigrate as ContractArtifact,
|
||||
LibLiquidityProviderStorage: LibLiquidityProviderStorage as ContractArtifact,
|
||||
LibMetaTransactionsStorage: LibMetaTransactionsStorage as ContractArtifact,
|
||||
LibOwnableStorage: LibOwnableStorage as ContractArtifact,
|
||||
LibProxyStorage: LibProxyStorage as ContractArtifact,
|
||||
@ -217,6 +220,7 @@ export const artifacts = {
|
||||
TestInitialMigration: TestInitialMigration as ContractArtifact,
|
||||
TestLibSignature: TestLibSignature as ContractArtifact,
|
||||
TestLibTokenSpender: TestLibTokenSpender as ContractArtifact,
|
||||
TestLiquidityProvider: TestLiquidityProvider as ContractArtifact,
|
||||
TestMetaTransactionsTransformERC20Feature: TestMetaTransactionsTransformERC20Feature as ContractArtifact,
|
||||
TestMigrator: TestMigrator as ContractArtifact,
|
||||
TestMintTokenERC20Transformer: TestMintTokenERC20Transformer as ContractArtifact,
|
||||
|
@ -1,16 +1,25 @@
|
||||
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 { IOwnableFeatureContract, IZeroExContract, LiquidityProviderFeatureContract } from '../../src/wrappers';
|
||||
import { artifacts } from '../artifacts';
|
||||
import { abis } from '../utils/abis';
|
||||
import { fullMigrateAsync } from '../utils/migration';
|
||||
import { IERC20BridgeEvents, TestBridgeContract, TestWethContract } from '../wrappers';
|
||||
import {
|
||||
LiquidityProviderSandboxContract,
|
||||
TestBridgeContract,
|
||||
TestBridgeEvents,
|
||||
TestLiquidityProviderContract,
|
||||
TestLiquidityProviderEvents,
|
||||
TestWethContract,
|
||||
} from '../wrappers';
|
||||
|
||||
blockchainTests('LiquidityProvider feature', env => {
|
||||
let zeroEx: IZeroExContract;
|
||||
let feature: LiquidityProviderFeatureContract;
|
||||
let sandbox: LiquidityProviderSandboxContract;
|
||||
let liquidityProvider: TestLiquidityProviderContract;
|
||||
let token: DummyERC20TokenContract;
|
||||
let weth: TestWethContract;
|
||||
let owner: string;
|
||||
@ -47,102 +56,112 @@ blockchainTests('LiquidityProvider feature', env => {
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
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)
|
||||
.migrate(featureImpl.address, featureImpl.migrate().getABIEncodedTransactionData(), owner)
|
||||
.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 TestBridgeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestBridge,
|
||||
liquidityProvider = await TestLiquidityProviderContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestLiquidityProvider,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
token.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 () => {
|
||||
const [xAsset, yAsset] = [randomAddress(), randomAddress()];
|
||||
const tx = feature
|
||||
.sellToLiquidityProvider(
|
||||
xAsset,
|
||||
yAsset,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
blockchainTests.resets('Sandbox', () => {
|
||||
it('Cannot call sandbox `executeSellTokenForToken` function directly', async () => {
|
||||
const tx = sandbox
|
||||
.executeSellTokenForToken(
|
||||
liquidityProvider.address,
|
||||
token.address,
|
||||
weth.address,
|
||||
taker,
|
||||
constants.ZERO_AMOUNT,
|
||||
constants.NULL_BYTES,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
return expect(tx).to.revertWith(
|
||||
new ZeroExRevertErrors.LiquidityProvider.NoLiquidityProviderForMarketError(xAsset, yAsset),
|
||||
);
|
||||
return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(taker));
|
||||
});
|
||||
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 () => {
|
||||
const tx = await feature
|
||||
.sellToLiquidityProvider(
|
||||
weth.address,
|
||||
token.address,
|
||||
weth.address,
|
||||
liquidityProvider.address,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
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 });
|
||||
verifyEventsFromLogs(
|
||||
@ -153,22 +172,24 @@ blockchainTests('LiquidityProvider feature', env => {
|
||||
outputToken: weth.address,
|
||||
inputTokenAmount: constants.ONE_ETHER,
|
||||
outputTokenAmount: constants.ZERO_AMOUNT,
|
||||
from: constants.NULL_ADDRESS,
|
||||
from: bridge.address,
|
||||
to: taker,
|
||||
},
|
||||
],
|
||||
IERC20BridgeEvents.ERC20BridgeTransfer,
|
||||
TestBridgeEvents.ERC20BridgeTransfer,
|
||||
);
|
||||
});
|
||||
it('Reverts if cannot fulfill the minimum buy amount', async () => {
|
||||
const minBuyAmount = new BigNumber(1);
|
||||
const tx = feature
|
||||
.sellToLiquidityProvider(
|
||||
weth.address,
|
||||
token.address,
|
||||
weth.address,
|
||||
liquidityProvider.address,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
minBuyAmount,
|
||||
constants.NULL_BYTES,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
return expect(tx).to.revertWith(
|
||||
@ -185,36 +206,38 @@ blockchainTests('LiquidityProvider feature', env => {
|
||||
it('Successfully executes an ETH-ERC20 swap', async () => {
|
||||
const tx = await feature
|
||||
.sellToLiquidityProvider(
|
||||
token.address,
|
||||
ETH_TOKEN_ADDRESS,
|
||||
token.address,
|
||||
liquidityProvider.address,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
constants.ZERO_AMOUNT,
|
||||
constants.NULL_BYTES,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker, value: constants.ONE_ETHER });
|
||||
verifyEventsFromLogs(
|
||||
tx.logs,
|
||||
[
|
||||
{
|
||||
inputToken: weth.address,
|
||||
outputToken: token.address,
|
||||
inputTokenAmount: constants.ONE_ETHER,
|
||||
outputTokenAmount: constants.ZERO_AMOUNT,
|
||||
from: constants.NULL_ADDRESS,
|
||||
to: taker,
|
||||
recipient: taker,
|
||||
minBuyAmount: constants.ZERO_AMOUNT,
|
||||
ethBalance: constants.ONE_ETHER,
|
||||
},
|
||||
],
|
||||
IERC20BridgeEvents.ERC20BridgeTransfer,
|
||||
TestLiquidityProviderEvents.SellEthForToken,
|
||||
);
|
||||
});
|
||||
it('Successfully executes an ERC20-ETH swap', async () => {
|
||||
const tx = await feature
|
||||
.sellToLiquidityProvider(
|
||||
ETH_TOKEN_ADDRESS,
|
||||
token.address,
|
||||
ETH_TOKEN_ADDRESS,
|
||||
liquidityProvider.address,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.ONE_ETHER,
|
||||
constants.ZERO_AMOUNT,
|
||||
constants.NULL_BYTES,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: taker });
|
||||
verifyEventsFromLogs(
|
||||
@ -222,14 +245,12 @@ blockchainTests('LiquidityProvider feature', env => {
|
||||
[
|
||||
{
|
||||
inputToken: token.address,
|
||||
outputToken: weth.address,
|
||||
inputTokenAmount: constants.ONE_ETHER,
|
||||
outputTokenAmount: constants.ZERO_AMOUNT,
|
||||
from: constants.NULL_ADDRESS,
|
||||
to: zeroEx.address,
|
||||
recipient: taker,
|
||||
minBuyAmount: constants.ZERO_AMOUNT,
|
||||
inputTokenBalance: constants.ONE_ETHER,
|
||||
},
|
||||
],
|
||||
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_liquidity_provider';
|
||||
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_ownable_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_erc20_transformer';
|
||||
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_storage';
|
||||
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_wallet_rich_errors';
|
||||
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/meta_transactions_feature';
|
||||
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_lib_signature';
|
||||
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_migrator';
|
||||
export * from '../test/generated-wrappers/test_mint_token_erc20_transformer';
|
||||
|
@ -10,6 +10,7 @@
|
||||
"generated-artifacts/IAllowanceTarget.json",
|
||||
"generated-artifacts/IERC20Transformer.json",
|
||||
"generated-artifacts/IFlashWallet.json",
|
||||
"generated-artifacts/ILiquidityProvider.json",
|
||||
"generated-artifacts/IOwnableFeature.json",
|
||||
"generated-artifacts/ISimpleFunctionRegistryFeature.json",
|
||||
"generated-artifacts/ITokenSpenderFeature.json",
|
||||
@ -50,6 +51,7 @@
|
||||
"test/generated-artifacts/IGasToken.json",
|
||||
"test/generated-artifacts/ILiquidityProvider.json",
|
||||
"test/generated-artifacts/ILiquidityProviderFeature.json",
|
||||
"test/generated-artifacts/ILiquidityProviderSandbox.json",
|
||||
"test/generated-artifacts/IMetaTransactionsFeature.json",
|
||||
"test/generated-artifacts/IOwnableFeature.json",
|
||||
"test/generated-artifacts/ISignatureValidatorFeature.json",
|
||||
@ -65,7 +67,6 @@
|
||||
"test/generated-artifacts/LibCommonRichErrors.json",
|
||||
"test/generated-artifacts/LibERC20Transformer.json",
|
||||
"test/generated-artifacts/LibLiquidityProviderRichErrors.json",
|
||||
"test/generated-artifacts/LibLiquidityProviderStorage.json",
|
||||
"test/generated-artifacts/LibMetaTransactionsRichErrors.json",
|
||||
"test/generated-artifacts/LibMetaTransactionsStorage.json",
|
||||
"test/generated-artifacts/LibMigrate.json",
|
||||
@ -88,6 +89,7 @@
|
||||
"test/generated-artifacts/LibTransformERC20Storage.json",
|
||||
"test/generated-artifacts/LibWalletRichErrors.json",
|
||||
"test/generated-artifacts/LiquidityProviderFeature.json",
|
||||
"test/generated-artifacts/LiquidityProviderSandbox.json",
|
||||
"test/generated-artifacts/LogMetadataTransformer.json",
|
||||
"test/generated-artifacts/MetaTransactionsFeature.json",
|
||||
"test/generated-artifacts/MixinAdapterAddresses.json",
|
||||
@ -117,6 +119,7 @@
|
||||
"test/generated-artifacts/TestInitialMigration.json",
|
||||
"test/generated-artifacts/TestLibSignature.json",
|
||||
"test/generated-artifacts/TestLibTokenSpender.json",
|
||||
"test/generated-artifacts/TestLiquidityProvider.json",
|
||||
"test/generated-artifacts/TestMetaTransactionsTransformERC20Feature.json",
|
||||
"test/generated-artifacts/TestMigrator.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,
|
||||
"version": "5.0.3",
|
||||
|
@ -20,8 +20,7 @@ pragma solidity ^0.6;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
|
||||
import "./interfaces/ILiquidityProvider.sol";
|
||||
import "./interfaces/ILiquidityProviderRegistry.sol";
|
||||
import "@0x/contracts-zero-ex/contracts/src/vendor/ILiquidityProvider.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
@ -34,37 +33,26 @@ contract LiquidityProviderSampler is
|
||||
uint256 constant private DEFAULT_CALL_GAS = 400e3; // 400k
|
||||
|
||||
/// @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 makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromLiquidityProviderRegistry(
|
||||
address registryAddress,
|
||||
function sampleSellsFromLiquidityProvider(
|
||||
address providerAddress,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts, address providerAddress)
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
// Initialize array of maker token amounts.
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
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++) {
|
||||
try
|
||||
ILiquidityProvider(providerAddress).getSellQuote
|
||||
@ -81,68 +69,33 @@ contract LiquidityProviderSampler is
|
||||
}
|
||||
|
||||
/// @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 makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromLiquidityProviderRegistry(
|
||||
address registryAddress,
|
||||
function sampleBuysFromLiquidityProvider(
|
||||
address providerAddress,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts, address providerAddress)
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
providerAddress = _getLiquidityProviderFromRegistry(
|
||||
registryAddress,
|
||||
takerToken,
|
||||
makerToken
|
||||
);
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, registryAddress),
|
||||
takerTokenData: abi.encode(takerToken, registryAddress),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromLiquidityProviderRegistry
|
||||
makerTokenData: abi.encode(makerToken, providerAddress),
|
||||
takerTokenData: abi.encode(takerToken, providerAddress),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromLiquidityProvider
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Returns the address of a liquidity provider for the given market
|
||||
/// (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(
|
||||
function _sampleSellForApproximateBuyFromLiquidityProvider(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory makerTokenData,
|
||||
uint256 sellAmount
|
||||
@ -151,15 +104,15 @@ contract LiquidityProviderSampler is
|
||||
view
|
||||
returns (uint256 buyAmount)
|
||||
{
|
||||
(address takerToken, address plpRegistryAddress) =
|
||||
(address takerToken, address providerAddress) =
|
||||
abi.decode(takerTokenData, (address, address));
|
||||
(address makerToken) =
|
||||
abi.decode(makerTokenData, (address));
|
||||
try
|
||||
this.sampleSellsFromLiquidityProviderRegistry
|
||||
this.sampleSellsFromLiquidityProvider
|
||||
{gas: DEFAULT_CALL_GAS}
|
||||
(plpRegistryAddress, takerToken, makerToken, _toSingleValueArray(sellAmount))
|
||||
returns (uint256[] memory amounts, address)
|
||||
(providerAddress, takerToken, makerToken, _toSingleValueArray(sellAmount))
|
||||
returns (uint256[] memory amounts)
|
||||
{
|
||||
return amounts[0];
|
||||
} 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"
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "ERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider",
|
||||
"publicInterfaceContracts": "ERC20BridgeSampler",
|
||||
"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": {
|
||||
"assets": []
|
||||
}
|
||||
@ -94,6 +94,7 @@
|
||||
"@0x/contracts-gen": "^2.0.18",
|
||||
"@0x/contracts-test-utils": "^5.3.10",
|
||||
"@0x/contracts-utils": "^4.5.7",
|
||||
"@0x/contracts-zero-ex": "^0.8.0",
|
||||
"@0x/mesh-rpc-client": "^9.4.2",
|
||||
"@0x/migrations": "^6.4.7",
|
||||
"@0x/sol-compiler": "^4.2.7",
|
||||
|
@ -5,15 +5,5 @@
|
||||
*/
|
||||
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 ILiquidityProvider from '../generated-artifacts/ILiquidityProvider.json';
|
||||
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,
|
||||
};
|
||||
export const artifacts = { ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact };
|
||||
|
@ -147,10 +147,10 @@ export {
|
||||
GetMarketOrdersRfqtOpts,
|
||||
KyberFillData,
|
||||
LiquidityProviderFillData,
|
||||
LiquidityProviderRegistry,
|
||||
MarketDepth,
|
||||
MarketDepthSide,
|
||||
MooniswapFillData,
|
||||
MultiBridgeFillData,
|
||||
MultiHopFillData,
|
||||
NativeCollapsedFill,
|
||||
NativeFillData,
|
||||
|
@ -34,7 +34,7 @@ import { getSwapMinBuyAmount } from './utils';
|
||||
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
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 {
|
||||
public readonly provider: ZeroExProvider;
|
||||
@ -96,9 +96,16 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
const buyToken = getTokenFromAssetData(quote.makerAssetData);
|
||||
const sellAmount = quote.worstCaseQuoteInfo.totalTakerAssetAmount;
|
||||
let minBuyAmount = getSwapMinBuyAmount(quote);
|
||||
let ethAmount = quote.worstCaseQuoteInfo.protocolFeeInWeiAmount;
|
||||
if (isFromETH) {
|
||||
ethAmount = ethAmount.plus(sellAmount);
|
||||
}
|
||||
const { buyTokenFeeAmount, sellTokenFeeAmount, recipient: feeRecipient } = affiliateFee;
|
||||
|
||||
// VIP routes.
|
||||
if (isDirectUniswapCompatible(quote, optsWithDefaults)) {
|
||||
if (
|
||||
isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap])
|
||||
) {
|
||||
const source = quote.orders[0].fills[0].source;
|
||||
const fillData = quote.orders[0].fills[0].fillData as UniswapV2FillData;
|
||||
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.
|
||||
const transforms = [];
|
||||
if (isFromETH) {
|
||||
@ -198,8 +225,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
}
|
||||
|
||||
// This transformer pays affiliate fees.
|
||||
const { buyTokenFeeAmount, sellTokenFeeAmount, recipient: feeRecipient } = affiliateFee;
|
||||
|
||||
if (buyTokenFeeAmount.isGreaterThan(0) && feeRecipient !== NULL_ADDRESS) {
|
||||
transforms.push({
|
||||
deploymentNonce: this.transformerNonces.affiliateFeeTransformer,
|
||||
@ -216,7 +241,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
// Adjust the minimum buy amount by the fee.
|
||||
minBuyAmount = BigNumber.max(0, minBuyAmount.minus(buyTokenFeeAmount));
|
||||
}
|
||||
|
||||
if (sellTokenFeeAmount.isGreaterThan(0) && feeRecipient !== NULL_ADDRESS) {
|
||||
throw new Error('Affiliate fees denominated in sell token are not yet supported');
|
||||
}
|
||||
@ -240,11 +264,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
|
||||
let ethAmount = quote.worstCaseQuoteInfo.protocolFeeInWeiAmount;
|
||||
if (isFromETH) {
|
||||
ethAmount = ethAmount.plus(sellAmount);
|
||||
}
|
||||
|
||||
return {
|
||||
calldataHexString,
|
||||
ethAmount,
|
||||
@ -266,7 +285,11 @@ function isBuyQuote(quote: SwapQuote): quote is MarketBuySwapQuote {
|
||||
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.
|
||||
if (opts.isMetaTransaction) {
|
||||
return false;
|
||||
@ -285,8 +308,7 @@ function isDirectUniswapCompatible(quote: SwapQuote, opts: ExchangeProxyContract
|
||||
return false;
|
||||
}
|
||||
const fill = order.fills[0];
|
||||
// And that fill must be uniswap v2 or sushiswap.
|
||||
if (![ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap].includes(fill.source)) {
|
||||
if (!directSources.includes(fill.source)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -5,7 +5,7 @@ import { MarketOperation, SwapQuote } from '../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
|
||||
* `worstCaseQuoteInfo.makerAssetAmount` because that does not stop at
|
||||
* maximum slippage.
|
||||
|
@ -165,8 +165,9 @@ export class SwapQuoter {
|
||||
expiryBufferMs,
|
||||
permittedOrderFeeTypes,
|
||||
samplerGasLimit,
|
||||
liquidityProviderRegistryAddress,
|
||||
rfqt,
|
||||
tokenAdjacencyGraph,
|
||||
liquidityProviderRegistry,
|
||||
} = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options);
|
||||
const provider = providerUtils.standardizeOrThrow(supportedProvider);
|
||||
assert.isValidOrderbook('orderbook', orderbook);
|
||||
@ -208,13 +209,21 @@ export class SwapQuoter {
|
||||
},
|
||||
);
|
||||
this._marketOperationUtils = new MarketOperationUtils(
|
||||
new DexOrderSampler(samplerContract, samplerOverrides, provider),
|
||||
new DexOrderSampler(
|
||||
samplerContract,
|
||||
samplerOverrides,
|
||||
provider,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
tokenAdjacencyGraph,
|
||||
liquidityProviderRegistry,
|
||||
),
|
||||
this._contractAddresses,
|
||||
{
|
||||
chainId,
|
||||
exchangeAddress: this._contractAddresses.exchange,
|
||||
},
|
||||
liquidityProviderRegistryAddress,
|
||||
);
|
||||
this._swapQuoteCalculator = new SwapQuoteCalculator(this._marketOperationUtils);
|
||||
}
|
||||
|
@ -4,7 +4,13 @@ import { TakerRequestQueryParams } from '@0x/quote-server';
|
||||
import { SignedOrder } from '@0x/types';
|
||||
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';
|
||||
|
||||
/**
|
||||
@ -310,11 +316,12 @@ export interface SwapQuoterOpts extends OrderPrunerOpts {
|
||||
ethereumRpcUrl?: string;
|
||||
contractAddresses?: AssetSwapperContractAddresses;
|
||||
samplerGasLimit?: number;
|
||||
liquidityProviderRegistryAddress?: string;
|
||||
multiBridgeAddress?: string;
|
||||
ethGasStationUrl?: string;
|
||||
rfqt?: SwapQuoterRfqtOpts;
|
||||
samplerOverrides?: SamplerOverrides;
|
||||
tokenAdjacencyGraph?: TokenAdjacencyGraph;
|
||||
liquidityProviderRegistry?: LiquidityProviderRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
FeeSchedule,
|
||||
FillData,
|
||||
GetMarketOrdersOpts,
|
||||
LiquidityProviderRegistry,
|
||||
MultiHopFillData,
|
||||
SnowSwapFillData,
|
||||
SushiSwapFillData,
|
||||
@ -24,8 +25,7 @@ import {
|
||||
/**
|
||||
* Valid sources for market sell.
|
||||
*/
|
||||
export const SELL_SOURCE_FILTER = new SourceFilters(
|
||||
[
|
||||
export const SELL_SOURCE_FILTER = new SourceFilters([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.Uniswap,
|
||||
ERC20BridgeSource.UniswapV2,
|
||||
@ -44,15 +44,13 @@ export const SELL_SOURCE_FILTER = new SourceFilters(
|
||||
ERC20BridgeSource.MultiHop,
|
||||
ERC20BridgeSource.Dodo,
|
||||
ERC20BridgeSource.Cream,
|
||||
],
|
||||
[ERC20BridgeSource.MultiBridge],
|
||||
);
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
]);
|
||||
|
||||
/**
|
||||
* Valid sources for market buy.
|
||||
*/
|
||||
export const BUY_SOURCE_FILTER = new SourceFilters(
|
||||
[
|
||||
export const BUY_SOURCE_FILTER = new SourceFilters([
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.Uniswap,
|
||||
ERC20BridgeSource.UniswapV2,
|
||||
@ -70,9 +68,8 @@ export const BUY_SOURCE_FILTER = new SourceFilters(
|
||||
ERC20BridgeSource.MultiHop,
|
||||
ERC20BridgeSource.Dodo,
|
||||
ERC20BridgeSource.Cream,
|
||||
],
|
||||
[ERC20BridgeSource.MultiBridge],
|
||||
);
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
]);
|
||||
|
||||
/**
|
||||
* 0x Protocol Fee Multiplier
|
||||
@ -352,6 +349,8 @@ export const MAINNET_KYBER_TOKEN_RESERVE_IDS: { [token: string]: string } = {
|
||||
'0xaa42414e44000000000000000000000000000000000000000000000000000000',
|
||||
};
|
||||
|
||||
export const LIQUIDITY_PROVIDER_REGISTRY: LiquidityProviderRegistry = {};
|
||||
|
||||
export const MAINNET_SUSHI_SWAP_ROUTER = '0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F';
|
||||
|
||||
export const MAINNET_SHELL_POOLS = {
|
||||
@ -544,5 +543,5 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = {
|
||||
exchangeProxyOverhead: () => ZERO_AMOUNT,
|
||||
allowFallback: true,
|
||||
shouldGenerateQuoteReport: false,
|
||||
tokenAdjacencyGraph: {},
|
||||
tokenAdjacencyGraph: { default: [] },
|
||||
};
|
||||
|
@ -78,7 +78,6 @@ export async function getRfqtIndicativeQuotesAsync(
|
||||
|
||||
export class MarketOperationUtils {
|
||||
private readonly _wethAddress: string;
|
||||
private readonly _multiBridge: string;
|
||||
private readonly _sellSources: SourceFilters;
|
||||
private readonly _buySources: SourceFilters;
|
||||
private readonly _feeSources = new SourceFilters(FEE_QUOTE_SOURCES);
|
||||
@ -108,19 +107,10 @@ export class MarketOperationUtils {
|
||||
private readonly _sampler: DexOrderSampler,
|
||||
private readonly contractAddresses: AssetSwapperContractAddresses,
|
||||
private readonly _orderDomain: OrderDomain,
|
||||
private readonly _liquidityProviderRegistry: string = NULL_ADDRESS,
|
||||
) {
|
||||
this._wethAddress = contractAddresses.etherToken.toLowerCase();
|
||||
this._multiBridge = contractAddresses.multiBridge.toLowerCase();
|
||||
const optionalQuoteSources = [];
|
||||
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);
|
||||
this._buySources = BUY_SOURCE_FILTER;
|
||||
this._sellSources = SELL_SOURCE_FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,42 +166,21 @@ export class MarketOperationUtils {
|
||||
// Get native order fillable amounts.
|
||||
this._sampler.getOrderFillableTakerAmounts(nativeOrders, this.contractAddresses.exchange),
|
||||
// Get ETH -> maker token price.
|
||||
this._sampler.getMedianSellRate(
|
||||
feeSourceFilters.sources,
|
||||
makerToken,
|
||||
this._wethAddress,
|
||||
ONE_ETHER,
|
||||
this._liquidityProviderRegistry,
|
||||
this._multiBridge,
|
||||
),
|
||||
this._sampler.getMedianSellRate(feeSourceFilters.sources, makerToken, this._wethAddress, ONE_ETHER),
|
||||
// Get ETH -> taker token price.
|
||||
this._sampler.getMedianSellRate(
|
||||
feeSourceFilters.sources,
|
||||
takerToken,
|
||||
this._wethAddress,
|
||||
ONE_ETHER,
|
||||
this._liquidityProviderRegistry,
|
||||
this._multiBridge,
|
||||
),
|
||||
this._sampler.getMedianSellRate(feeSourceFilters.sources, takerToken, this._wethAddress, ONE_ETHER),
|
||||
// Get sell quotes for taker -> maker.
|
||||
this._sampler.getSellQuotes(
|
||||
quoteSourceFilters.exclude(offChainSources).sources,
|
||||
makerToken,
|
||||
takerToken,
|
||||
sampleAmounts,
|
||||
this._wethAddress,
|
||||
_opts.tokenAdjacencyGraph,
|
||||
this._liquidityProviderRegistry,
|
||||
this._multiBridge,
|
||||
),
|
||||
this._sampler.getTwoHopSellQuotes(
|
||||
quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [],
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerAmount,
|
||||
this._wethAddress,
|
||||
_opts.tokenAdjacencyGraph,
|
||||
this._liquidityProviderRegistry,
|
||||
),
|
||||
);
|
||||
|
||||
@ -327,41 +296,21 @@ export class MarketOperationUtils {
|
||||
// Get native order fillable amounts.
|
||||
this._sampler.getOrderFillableMakerAmounts(nativeOrders, this.contractAddresses.exchange),
|
||||
// Get ETH -> makerToken token price.
|
||||
this._sampler.getMedianSellRate(
|
||||
feeSourceFilters.sources,
|
||||
makerToken,
|
||||
this._wethAddress,
|
||||
ONE_ETHER,
|
||||
this._liquidityProviderRegistry,
|
||||
this._multiBridge,
|
||||
),
|
||||
this._sampler.getMedianSellRate(feeSourceFilters.sources, makerToken, this._wethAddress, ONE_ETHER),
|
||||
// Get ETH -> taker token price.
|
||||
this._sampler.getMedianSellRate(
|
||||
feeSourceFilters.sources,
|
||||
takerToken,
|
||||
this._wethAddress,
|
||||
ONE_ETHER,
|
||||
this._liquidityProviderRegistry,
|
||||
this._multiBridge,
|
||||
),
|
||||
this._sampler.getMedianSellRate(feeSourceFilters.sources, takerToken, this._wethAddress, ONE_ETHER),
|
||||
// Get buy quotes for taker -> maker.
|
||||
this._sampler.getBuyQuotes(
|
||||
quoteSourceFilters.exclude(offChainSources).sources,
|
||||
makerToken,
|
||||
takerToken,
|
||||
sampleAmounts,
|
||||
this._wethAddress,
|
||||
_opts.tokenAdjacencyGraph,
|
||||
this._liquidityProviderRegistry,
|
||||
),
|
||||
this._sampler.getTwoHopBuyQuotes(
|
||||
quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [],
|
||||
makerToken,
|
||||
takerToken,
|
||||
makerAmount,
|
||||
this._wethAddress,
|
||||
_opts.tokenAdjacencyGraph,
|
||||
this._liquidityProviderRegistry,
|
||||
),
|
||||
);
|
||||
const isPriceAwareRfqEnabled =
|
||||
@ -391,10 +340,6 @@ export class MarketOperationUtils {
|
||||
offChainBalancerQuotes,
|
||||
offChainCreamQuotes,
|
||||
] = 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;
|
||||
return {
|
||||
side: MarketOperation.Buy,
|
||||
@ -482,7 +427,6 @@ export class MarketOperationUtils {
|
||||
getNativeOrderTokens(orders[0])[1],
|
||||
this._wethAddress,
|
||||
ONE_ETHER,
|
||||
this._wethAddress,
|
||||
),
|
||||
),
|
||||
...batchNativeOrders.map((orders, i) =>
|
||||
@ -491,8 +435,6 @@ export class MarketOperationUtils {
|
||||
getNativeOrderTokens(orders[0])[0],
|
||||
getNativeOrderTokens(orders[0])[1],
|
||||
[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,
|
||||
takerToken: string,
|
||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
||||
wethAddress: string,
|
||||
): string[] {
|
||||
let intermediateTokens = [];
|
||||
if (makerToken === wethAddress) {
|
||||
intermediateTokens = _.get(tokenAdjacencyGraph, takerToken, [] as string[]);
|
||||
} else if (takerToken === wethAddress) {
|
||||
intermediateTokens = _.get(tokenAdjacencyGraph, makerToken, [] as string[]);
|
||||
} else {
|
||||
intermediateTokens = _.union(
|
||||
_.intersection(_.get(tokenAdjacencyGraph, takerToken, []), _.get(tokenAdjacencyGraph, makerToken, [])),
|
||||
[wethAddress],
|
||||
const intermediateTokens = _.intersection(
|
||||
_.get(tokenAdjacencyGraph, takerToken, tokenAdjacencyGraph.default),
|
||||
_.get(tokenAdjacencyGraph, makerToken, tokenAdjacencyGraph.default),
|
||||
);
|
||||
}
|
||||
return _.uniqBy(intermediateTokens, a => a.toLowerCase()).filter(
|
||||
token => token.toLowerCase() !== makerToken.toLowerCase() && token.toLowerCase() !== takerToken.toLowerCase(),
|
||||
);
|
||||
|
@ -15,7 +15,6 @@ import {
|
||||
WALLET_SIGNATURE,
|
||||
ZERO_AMOUNT,
|
||||
} from './constants';
|
||||
import { getMultiBridgeIntermediateToken } from './multibridge_utils';
|
||||
import {
|
||||
AggregationError,
|
||||
BalancerFillData,
|
||||
@ -28,7 +27,6 @@ import {
|
||||
KyberFillData,
|
||||
LiquidityProviderFillData,
|
||||
MooniswapFillData,
|
||||
MultiBridgeFillData,
|
||||
MultiHopFillData,
|
||||
NativeCollapsedFill,
|
||||
OptimizedMarketOrder,
|
||||
@ -193,8 +191,6 @@ function getBridgeAddressFromFill(fill: CollapsedFill, opts: CreateOrderFromPath
|
||||
return opts.contractAddresses.creamBridge;
|
||||
case ERC20BridgeSource.LiquidityProvider:
|
||||
return (fill.fillData as LiquidityProviderFillData).poolAddress;
|
||||
case ERC20BridgeSource.MultiBridge:
|
||||
return (fill.fillData as MultiBridgeFillData).poolAddress;
|
||||
case ERC20BridgeSource.MStable:
|
||||
return opts.contractAddresses.mStableBridge;
|
||||
case ERC20BridgeSource.Mooniswap:
|
||||
@ -301,13 +297,6 @@ export function createBridgeOrder(
|
||||
createSushiSwapBridgeData(sushiSwapFillData.tokenAddressPath, sushiSwapFillData.router),
|
||||
);
|
||||
break;
|
||||
case ERC20BridgeSource.MultiBridge:
|
||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||
makerToken,
|
||||
bridgeAddress,
|
||||
createMultiBridgeData(takerToken, makerToken),
|
||||
);
|
||||
break;
|
||||
case ERC20BridgeSource.Kyber:
|
||||
const kyberFillData = (fill as CollapsedFill<KyberFillData>).fillData!; // tslint:disable-line:no-non-null-assertion
|
||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||
@ -372,15 +361,6 @@ function createBridgeData(tokenAddress: string): string {
|
||||
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 {
|
||||
const encoder = AbiEncoder.create([
|
||||
{ name: 'takerToken', type: 'address' },
|
||||
|
@ -2,7 +2,7 @@ import { BigNumber } from '@0x/utils';
|
||||
|
||||
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 { getCompleteRate, getRate } from './rate_utils';
|
||||
import {
|
||||
@ -202,7 +202,7 @@ export class Path {
|
||||
}
|
||||
}
|
||||
}
|
||||
return doSourcesConflict(this.sourceFlags);
|
||||
return true;
|
||||
}
|
||||
|
||||
public isValidNextFill(fill: Fill): boolean {
|
||||
@ -215,7 +215,7 @@ export class Path {
|
||||
if (fill.parent) {
|
||||
return false;
|
||||
}
|
||||
return doSourcesConflict(this.sourceFlags | fill.flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
private _collapseFills(): ReadonlyArray<CollapsedFill> {
|
||||
@ -268,9 +268,3 @@ export interface CollapsedPath extends Path {
|
||||
readonly collapsedFills: ReadonlyArray<CollapsedFill>;
|
||||
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 { CreamPoolsCache } from './cream_utils';
|
||||
import { SamplerOperations } from './sampler_operations';
|
||||
import { BatchedOperation } from './types';
|
||||
import { BatchedOperation, LiquidityProviderRegistry, TokenAdjacencyGraph } from './types';
|
||||
|
||||
/**
|
||||
* Generate sample amounts up to `maxFillAmount`.
|
||||
@ -40,8 +40,18 @@ export class DexOrderSampler extends SamplerOperations {
|
||||
balancerPoolsCache?: BalancerPoolsCache,
|
||||
creamPoolsCache?: CreamPoolsCache,
|
||||
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. */
|
||||
|
@ -1,17 +1,17 @@
|
||||
import { SupportedProvider } from '@0x/dev-utils';
|
||||
import { SignedOrder } from '@0x/types';
|
||||
import { BigNumber, NULL_ADDRESS } from '@0x/utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { ERC20BridgeSamplerContract } from '../../wrappers';
|
||||
|
||||
import { BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote } from './balancer_utils';
|
||||
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 { getCurveInfosForPair, getSnowSwapInfosForPair, getSwerveInfosForPair } from './curve_utils';
|
||||
import { getKyberReserveIdsForPair } from './kyber_utils';
|
||||
import { getMultiBridgeIntermediateToken } from './multibridge_utils';
|
||||
import { getLiquidityProvidersForPair } from './liquidity_provider_utils';
|
||||
import { getIntermediateTokens } from './multihop_utils';
|
||||
import { SamplerContractOperation } from './sampler_contract_operation';
|
||||
import { getShellsForPair } from './shell_utils';
|
||||
@ -28,8 +28,8 @@ import {
|
||||
HopInfo,
|
||||
KyberFillData,
|
||||
LiquidityProviderFillData,
|
||||
LiquidityProviderRegistry,
|
||||
MooniswapFillData,
|
||||
MultiBridgeFillData,
|
||||
MultiHopFillData,
|
||||
ShellFillData,
|
||||
SnowSwapFillData,
|
||||
@ -47,7 +47,6 @@ import {
|
||||
*/
|
||||
export const TWO_HOP_SOURCE_FILTERS = SourceFilters.all().exclude([
|
||||
ERC20BridgeSource.MultiHop,
|
||||
ERC20BridgeSource.MultiBridge,
|
||||
ERC20BridgeSource.Native,
|
||||
]);
|
||||
/**
|
||||
@ -80,6 +79,8 @@ export class SamplerOperations {
|
||||
public readonly balancerPoolsCache: BalancerPoolsCache = new BalancerPoolsCache(),
|
||||
public readonly creamPoolsCache: CreamPoolsCache = new CreamPoolsCache(),
|
||||
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> {
|
||||
@ -221,64 +222,32 @@ export class SamplerOperations {
|
||||
}
|
||||
|
||||
public getLiquidityProviderSellQuotes(
|
||||
registryAddress: string,
|
||||
providerAddress: string,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<LiquidityProviderFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.LiquidityProvider,
|
||||
fillData: {} as LiquidityProviderFillData, // tslint:disable-line:no-object-literal-type-assertion
|
||||
fillData: { poolAddress: providerAddress },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromLiquidityProviderRegistry,
|
||||
params: [registryAddress, takerToken, makerToken, takerFillAmounts],
|
||||
callback: (callResults: string, fillData: LiquidityProviderFillData): BigNumber[] => {
|
||||
const [samples, poolAddress] = this._samplerContract.getABIDecodedReturnData<[BigNumber[], string]>(
|
||||
'sampleSellsFromLiquidityProviderRegistry',
|
||||
callResults,
|
||||
);
|
||||
fillData.poolAddress = poolAddress;
|
||||
return samples;
|
||||
},
|
||||
function: this._samplerContract.sampleSellsFromLiquidityProvider,
|
||||
params: [providerAddress, takerToken, makerToken, takerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getLiquidityProviderBuyQuotes(
|
||||
registryAddress: string,
|
||||
providerAddress: string,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<LiquidityProviderFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.LiquidityProvider,
|
||||
fillData: {} as LiquidityProviderFillData, // tslint:disable-line:no-object-literal-type-assertion
|
||||
fillData: { poolAddress: providerAddress },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromLiquidityProviderRegistry,
|
||||
params: [registryAddress, 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],
|
||||
function: this._samplerContract.sampleBuysFromLiquidityProvider,
|
||||
params: [providerAddress, takerToken, makerToken, makerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
@ -669,34 +638,15 @@ export class SamplerOperations {
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
sellAmount: BigNumber,
|
||||
wethAddress: string,
|
||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
||||
liquidityProviderRegistryAddress?: string,
|
||||
): BatchedOperation<Array<DexSample<MultiHopFillData>>> {
|
||||
const _sources = TWO_HOP_SOURCE_FILTERS.getAllowed(sources);
|
||||
if (_sources.length === 0) {
|
||||
return SamplerOperations.constant([]);
|
||||
}
|
||||
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph, wethAddress);
|
||||
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph);
|
||||
const subOps = intermediateTokens.map(intermediateToken => {
|
||||
const firstHopOps = this._getSellQuoteOperations(
|
||||
_sources,
|
||||
intermediateToken,
|
||||
takerToken,
|
||||
[ZERO_AMOUNT],
|
||||
wethAddress,
|
||||
tokenAdjacencyGraph,
|
||||
liquidityProviderRegistryAddress,
|
||||
);
|
||||
const secondHopOps = this._getSellQuoteOperations(
|
||||
_sources,
|
||||
makerToken,
|
||||
intermediateToken,
|
||||
[ZERO_AMOUNT],
|
||||
wethAddress,
|
||||
tokenAdjacencyGraph,
|
||||
liquidityProviderRegistryAddress,
|
||||
);
|
||||
const firstHopOps = this._getSellQuoteOperations(_sources, intermediateToken, takerToken, [ZERO_AMOUNT]);
|
||||
const secondHopOps = this._getSellQuoteOperations(_sources, makerToken, intermediateToken, [ZERO_AMOUNT]);
|
||||
return new SamplerContractOperation({
|
||||
contract: this._samplerContract,
|
||||
source: ERC20BridgeSource.MultiHop,
|
||||
@ -747,34 +697,19 @@ export class SamplerOperations {
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
buyAmount: BigNumber,
|
||||
wethAddress: string,
|
||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
||||
liquidityProviderRegistryAddress?: string,
|
||||
): BatchedOperation<Array<DexSample<MultiHopFillData>>> {
|
||||
const _sources = TWO_HOP_SOURCE_FILTERS.getAllowed(sources);
|
||||
if (_sources.length === 0) {
|
||||
return SamplerOperations.constant([]);
|
||||
}
|
||||
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph, wethAddress);
|
||||
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph);
|
||||
const subOps = intermediateTokens.map(intermediateToken => {
|
||||
const firstHopOps = this._getBuyQuoteOperations(
|
||||
_sources,
|
||||
intermediateToken,
|
||||
takerToken,
|
||||
[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,
|
||||
);
|
||||
const firstHopOps = this._getBuyQuoteOperations(_sources, intermediateToken, takerToken, [
|
||||
new BigNumber(0),
|
||||
]);
|
||||
const secondHopOps = this._getBuyQuoteOperations(_sources, makerToken, intermediateToken, [
|
||||
new BigNumber(0),
|
||||
]);
|
||||
return new SamplerContractOperation({
|
||||
contract: this._samplerContract,
|
||||
source: ERC20BridgeSource.MultiHop,
|
||||
@ -853,17 +788,10 @@ export class SamplerOperations {
|
||||
): SourceQuoteOperation<ShellFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Shell,
|
||||
fillData: { poolAddress },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromShell,
|
||||
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 {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Shell,
|
||||
fillData: { poolAddress },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromShell,
|
||||
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,
|
||||
takerToken: string,
|
||||
takerFillAmount: BigNumber,
|
||||
liquidityProviderRegistryAddress?: string,
|
||||
multiBridgeAddress?: string,
|
||||
): BatchedOperation<BigNumber> {
|
||||
if (makerToken.toLowerCase() === takerToken.toLowerCase()) {
|
||||
return SamplerOperations.constant(new BigNumber(1));
|
||||
}
|
||||
const getSellQuotes = this.getSellQuotes(
|
||||
sources,
|
||||
makerToken,
|
||||
takerToken,
|
||||
[takerFillAmount],
|
||||
NULL_ADDRESS, // weth address
|
||||
{}, // token adjacency
|
||||
liquidityProviderRegistryAddress,
|
||||
multiBridgeAddress,
|
||||
);
|
||||
const subOps = this._getSellQuoteOperations(sources, makerToken, takerToken, [takerFillAmount], {
|
||||
default: [],
|
||||
});
|
||||
return {
|
||||
encodeCall: () => {
|
||||
const encodedCall = getSellQuotes.encodeCall();
|
||||
// All soures were excluded
|
||||
if (encodedCall === NULL_BYTES) {
|
||||
return NULL_BYTES;
|
||||
}
|
||||
return this._samplerContract.batchCall([encodedCall]).getABIEncodedTransactionData();
|
||||
const subCalls = subOps.map(op => op.encodeCall());
|
||||
return this._samplerContract.batchCall(subCalls).getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResults: callResults => {
|
||||
if (callResults === NULL_BYTES) {
|
||||
return ZERO_AMOUNT;
|
||||
}
|
||||
const rawSubCallResults = this._samplerContract.getABIDecodedReturnData<string[]>(
|
||||
'batchCall',
|
||||
callResults,
|
||||
);
|
||||
const samples = getSellQuotes.handleCallResults(rawSubCallResults[0]);
|
||||
const samples = subOps.map((op, i) => op.handleCallResults(rawSubCallResults[i]));
|
||||
if (samples.length === 0) {
|
||||
return ZERO_AMOUNT;
|
||||
}
|
||||
const flatSortedSamples = samples
|
||||
.reduce((acc, v) => acc.concat(...v))
|
||||
.filter(v => !v.output.isZero())
|
||||
.sort((a, b) => a.output.comparedTo(b.output));
|
||||
.filter(v => !v.isZero())
|
||||
.sort((a, b) => a.comparedTo(b));
|
||||
if (flatSortedSamples.length === 0) {
|
||||
return ZERO_AMOUNT;
|
||||
}
|
||||
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,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
wethAddress: string,
|
||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
||||
liquidityProviderRegistryAddress?: string,
|
||||
multiBridgeAddress?: string,
|
||||
): BatchedOperation<DexSample[][]> {
|
||||
const subOps = this._getSellQuoteOperations(
|
||||
sources,
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerFillAmounts,
|
||||
wethAddress,
|
||||
tokenAdjacencyGraph,
|
||||
liquidityProviderRegistryAddress,
|
||||
multiBridgeAddress,
|
||||
);
|
||||
const subOps = this._getSellQuoteOperations(sources, makerToken, takerToken, takerFillAmounts);
|
||||
return {
|
||||
encodeCall: () => {
|
||||
const subCalls = subOps.map(op => op.encodeCall());
|
||||
@ -1034,19 +926,8 @@ export class SamplerOperations {
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
wethAddress: string,
|
||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
||||
liquidityProviderRegistryAddress?: string,
|
||||
): BatchedOperation<DexSample[][]> {
|
||||
const subOps = this._getBuyQuoteOperations(
|
||||
sources,
|
||||
makerToken,
|
||||
takerToken,
|
||||
makerFillAmounts,
|
||||
wethAddress,
|
||||
tokenAdjacencyGraph,
|
||||
liquidityProviderRegistryAddress,
|
||||
);
|
||||
const subOps = this._getBuyQuoteOperations(sources, makerToken, takerToken, makerFillAmounts);
|
||||
return {
|
||||
encodeCall: () => {
|
||||
const subCalls = subOps.map(op => op.encodeCall());
|
||||
@ -1075,21 +956,12 @@ export class SamplerOperations {
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
wethAddress: string,
|
||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
||||
liquidityProviderRegistryAddress?: string,
|
||||
multiBridgeAddress?: string,
|
||||
tokenAdjacencyGraph: TokenAdjacencyGraph = this.tokenAdjacencyGraph,
|
||||
): 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,
|
||||
// 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(
|
||||
_sources.map(
|
||||
(source): SourceQuoteOperation | SourceQuoteOperation[] => {
|
||||
@ -1144,30 +1016,12 @@ export class SamplerOperations {
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.LiquidityProvider:
|
||||
if (liquidityProviderRegistryAddress === undefined) {
|
||||
throw new Error(
|
||||
'Cannot sample liquidity from a LiquidityProvider liquidity pool, if a registry is not provided.',
|
||||
);
|
||||
}
|
||||
return this.getLiquidityProviderSellQuotes(
|
||||
liquidityProviderRegistryAddress,
|
||||
makerToken,
|
||||
return getLiquidityProvidersForPair(
|
||||
this.liquidityProviderRegistry,
|
||||
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,
|
||||
intermediateToken,
|
||||
takerToken,
|
||||
takerFillAmounts,
|
||||
).map(pool =>
|
||||
this.getLiquidityProviderSellQuotes(pool, makerToken, takerToken, takerFillAmounts),
|
||||
);
|
||||
case ERC20BridgeSource.MStable:
|
||||
return this.getMStableSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||
@ -1216,18 +1070,11 @@ export class SamplerOperations {
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
wethAddress: string,
|
||||
tokenAdjacencyGraph: TokenAdjacencyGraph,
|
||||
liquidityProviderRegistryAddress?: string,
|
||||
): SourceQuoteOperation[] {
|
||||
const _sources = BATCH_SOURCE_FILTERS.exclude(
|
||||
liquidityProviderRegistryAddress ? [] : [ERC20BridgeSource.LiquidityProvider],
|
||||
).getAllowed(sources);
|
||||
|
||||
// Find the adjacent tokens in the provided tooken adjacency graph,
|
||||
// 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(
|
||||
_sources.map(
|
||||
(source): SourceQuoteOperation | SourceQuoteOperation[] => {
|
||||
@ -1282,16 +1129,12 @@ export class SamplerOperations {
|
||||
),
|
||||
);
|
||||
case ERC20BridgeSource.LiquidityProvider:
|
||||
if (liquidityProviderRegistryAddress === undefined) {
|
||||
throw new Error(
|
||||
'Cannot sample liquidity from a LiquidityProvider liquidity pool, if a registry is not provided.',
|
||||
);
|
||||
}
|
||||
return this.getLiquidityProviderBuyQuotes(
|
||||
liquidityProviderRegistryAddress,
|
||||
makerToken,
|
||||
return getLiquidityProvidersForPair(
|
||||
this.liquidityProviderRegistry,
|
||||
takerToken,
|
||||
makerFillAmounts,
|
||||
makerToken,
|
||||
).map(pool =>
|
||||
this.getLiquidityProviderBuyQuotes(pool, makerToken, takerToken, makerFillAmounts),
|
||||
);
|
||||
case ERC20BridgeSource.MStable:
|
||||
return this.getMStableBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||
|
@ -132,10 +132,6 @@ export interface LiquidityProviderFillData extends FillData {
|
||||
poolAddress: string;
|
||||
}
|
||||
|
||||
export interface MultiBridgeFillData extends FillData {
|
||||
poolAddress: string;
|
||||
}
|
||||
|
||||
export interface BancorFillData extends FillData {
|
||||
path: string[];
|
||||
networkAddress: string;
|
||||
@ -375,6 +371,11 @@ export interface MarketSideLiquidity {
|
||||
|
||||
export interface TokenAdjacencyGraph {
|
||||
[token: string]: string[];
|
||||
default: string[];
|
||||
}
|
||||
|
||||
export interface LiquidityProviderRegistry {
|
||||
[address: string]: [string, string];
|
||||
}
|
||||
|
||||
export interface GenerateOptimizedOrdersOpts {
|
||||
|
@ -3,8 +3,4 @@
|
||||
* 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/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 DODOSampler from '../test/generated-artifacts/DODOSampler.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 Eth2DaiSampler from '../test/generated-artifacts/Eth2DaiSampler.json';
|
||||
import * as IBalancer from '../test/generated-artifacts/IBalancer.json';
|
||||
import * as ICurve from '../test/generated-artifacts/ICurve.json';
|
||||
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.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 IMStable from '../test/generated-artifacts/IMStable.json';
|
||||
import * as IMultiBridge from '../test/generated-artifacts/IMultiBridge.json';
|
||||
@ -64,8 +61,6 @@ export const artifacts = {
|
||||
ICurve: ICurve as ContractArtifact,
|
||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
||||
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
|
||||
ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
|
||||
IMStable: IMStable as ContractArtifact,
|
||||
IMooniswap: IMooniswap as ContractArtifact,
|
||||
IMultiBridge: IMultiBridge as ContractArtifact,
|
||||
@ -73,7 +68,6 @@ export const artifacts = {
|
||||
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
|
||||
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
|
||||
DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact,
|
||||
DummyLiquidityProviderRegistry: DummyLiquidityProviderRegistry as ContractArtifact,
|
||||
TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
|
||||
TestNativeOrderSampler: TestNativeOrderSampler as ContractArtifact,
|
||||
};
|
||||
|
@ -11,11 +11,7 @@ import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import {
|
||||
DummyLiquidityProviderContract,
|
||||
DummyLiquidityProviderRegistryContract,
|
||||
TestERC20BridgeSamplerContract,
|
||||
} from '../wrappers';
|
||||
import { DummyLiquidityProviderContract, TestERC20BridgeSamplerContract } from '../wrappers';
|
||||
|
||||
// tslint:disable: custom-no-magic-numbers
|
||||
|
||||
@ -817,7 +813,6 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const yAsset = randomAddress();
|
||||
const sampleAmounts = getSampleAmounts(yAsset);
|
||||
let liquidityProvider: DummyLiquidityProviderContract;
|
||||
let registryContract: DummyLiquidityProviderRegistryContract;
|
||||
|
||||
before(async () => {
|
||||
liquidityProvider = await DummyLiquidityProviderContract.deployFrom0xArtifactAsync(
|
||||
@ -826,61 +821,33 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
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 () => {
|
||||
const [quotes, providerAddress] = await testContract
|
||||
.sampleSellsFromLiquidityProviderRegistry(registryContract.address, yAsset, xAsset, sampleAmounts)
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromLiquidityProvider(liquidityProvider.address, yAsset, xAsset, sampleAmounts)
|
||||
.callAsync();
|
||||
quotes.forEach((value, idx) => {
|
||||
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 () => {
|
||||
const [quotes, providerAddress] = await testContract
|
||||
.sampleBuysFromLiquidityProviderRegistry(registryContract.address, yAsset, xAsset, sampleAmounts)
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromLiquidityProvider(liquidityProvider.address, yAsset, xAsset, sampleAmounts)
|
||||
.callAsync();
|
||||
quotes.forEach((value, idx) => {
|
||||
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 () => {
|
||||
const [quotes, providerAddress] = await testContract
|
||||
.sampleBuysFromLiquidityProviderRegistry(
|
||||
registryContract.address,
|
||||
yAsset,
|
||||
randomAddress(),
|
||||
sampleAmounts,
|
||||
)
|
||||
it('should just return zeros if the liquidity provider does not exist', async () => {
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromLiquidityProvider(randomAddress(), yAsset, xAsset, sampleAmounts)
|
||||
.callAsync();
|
||||
quotes.forEach(value => {
|
||||
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 exchangeAddress = getContractAddressesForChainOrThrow(CHAIN_ID).exchange;
|
||||
|
||||
const tokenAdjacencyGraph: TokenAdjacencyGraph = {};
|
||||
const tokenAdjacencyGraph: TokenAdjacencyGraph = { default: [wethAddress] };
|
||||
|
||||
describe('getSampleAmounts()', () => {
|
||||
const FILL_AMOUNT = getRandomInteger(1, 1e18);
|
||||
@ -159,26 +159,31 @@ describe('DexSampler tests', () => {
|
||||
it('getLiquidityProviderSellQuotes()', async () => {
|
||||
const expectedMakerToken = randomAddress();
|
||||
const expectedTakerToken = randomAddress();
|
||||
const registry = randomAddress();
|
||||
const poolAddress = randomAddress();
|
||||
const sampler = new MockSamplerContract({
|
||||
sampleSellsFromLiquidityProviderRegistry: (registryAddress, takerToken, makerToken, _fillAmounts) => {
|
||||
expect(registryAddress).to.eq(registry);
|
||||
sampleSellsFromLiquidityProvider: (providerAddress, takerToken, makerToken, _fillAmounts) => {
|
||||
expect(providerAddress).to.eq(poolAddress);
|
||||
expect(takerToken).to.eq(expectedTakerToken);
|
||||
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(
|
||||
dexOrderSampler.getSellQuotes(
|
||||
[ERC20BridgeSource.LiquidityProvider],
|
||||
expectedMakerToken,
|
||||
expectedTakerToken,
|
||||
[toBaseUnitAmount(1000)],
|
||||
wethAddress,
|
||||
tokenAdjacencyGraph,
|
||||
registry,
|
||||
),
|
||||
);
|
||||
expect(result).to.deep.equal([
|
||||
@ -196,26 +201,31 @@ describe('DexSampler tests', () => {
|
||||
it('getLiquidityProviderBuyQuotes()', async () => {
|
||||
const expectedMakerToken = randomAddress();
|
||||
const expectedTakerToken = randomAddress();
|
||||
const registry = randomAddress();
|
||||
const poolAddress = randomAddress();
|
||||
const sampler = new MockSamplerContract({
|
||||
sampleBuysFromLiquidityProviderRegistry: (registryAddress, takerToken, makerToken, _fillAmounts) => {
|
||||
expect(registryAddress).to.eq(registry);
|
||||
sampleBuysFromLiquidityProvider: (providerAddress, takerToken, makerToken, _fillAmounts) => {
|
||||
expect(providerAddress).to.eq(poolAddress);
|
||||
expect(takerToken).to.eq(expectedTakerToken);
|
||||
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(
|
||||
dexOrderSampler.getBuyQuotes(
|
||||
[ERC20BridgeSource.LiquidityProvider],
|
||||
expectedMakerToken,
|
||||
expectedTakerToken,
|
||||
[toBaseUnitAmount(1000)],
|
||||
wethAddress,
|
||||
tokenAdjacencyGraph,
|
||||
registry,
|
||||
),
|
||||
);
|
||||
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 () => {
|
||||
const expectedTakerToken = randomAddress();
|
||||
const expectedMakerToken = randomAddress();
|
||||
@ -416,15 +382,21 @@ describe('DexSampler tests', () => {
|
||||
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(
|
||||
dexOrderSampler.getSellQuotes(
|
||||
sources,
|
||||
expectedMakerToken,
|
||||
expectedTakerToken,
|
||||
expectedTakerFillAmounts,
|
||||
wethAddress,
|
||||
tokenAdjacencyGraph,
|
||||
),
|
||||
);
|
||||
const expectedQuotes = sources.map(s =>
|
||||
@ -561,16 +533,17 @@ describe('DexSampler tests', () => {
|
||||
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue());
|
||||
},
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(sampler);
|
||||
const [quotes] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getBuyQuotes(
|
||||
sources,
|
||||
expectedMakerToken,
|
||||
expectedTakerToken,
|
||||
expectedMakerFillAmounts,
|
||||
wethAddress,
|
||||
const dexOrderSampler = new DexOrderSampler(
|
||||
sampler,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
tokenAdjacencyGraph,
|
||||
),
|
||||
);
|
||||
const [quotes] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getBuyQuotes(sources, expectedMakerToken, expectedTakerToken, expectedMakerFillAmounts),
|
||||
);
|
||||
const expectedQuotes = sources.map(s =>
|
||||
expectedMakerFillAmounts.map(a => ({
|
||||
|
@ -20,7 +20,7 @@ import { constants } from '../src/constants';
|
||||
import { ExchangeProxySwapQuoteConsumer } from '../src/quote_consumers/exchange_proxy_swap_quote_consumer';
|
||||
import { getSwapMinBuyAmount } from '../src/quote_consumers/utils';
|
||||
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';
|
||||
|
||||
@ -161,7 +161,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
);
|
||||
}
|
||||
|
||||
const callDataEncoder = AbiEncoder.createMethod('transformERC20', [
|
||||
const transformERC20Encoder = AbiEncoder.createMethod('transformERC20', [
|
||||
{ type: 'address', name: 'inputToken' },
|
||||
{ type: 'address', name: 'outputToken' },
|
||||
{ type: 'uint256', name: 'inputTokenAmount' },
|
||||
@ -173,7 +173,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
},
|
||||
]);
|
||||
|
||||
interface CallArgs {
|
||||
interface TransformERC20Args {
|
||||
inputToken: string;
|
||||
outputToken: string;
|
||||
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()', () => {
|
||||
it('can produce a sell quote', async () => {
|
||||
const quote = getRandomSellQuote();
|
||||
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.outputToken).to.eq(MAKER_TOKEN);
|
||||
expect(callArgs.inputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount);
|
||||
@ -217,7 +237,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
it('can produce a buy quote', async () => {
|
||||
const quote = getRandomBuyQuote();
|
||||
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.outputToken).to.eq(MAKER_TOKEN);
|
||||
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 () => {
|
||||
const quote = getRandomSellQuote();
|
||||
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);
|
||||
expect(nonces).to.not.include(consumer.transformerNonces.wethTransformer);
|
||||
});
|
||||
@ -256,7 +276,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
||||
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(
|
||||
consumer.transformerNonces.wethTransformer,
|
||||
);
|
||||
@ -270,7 +290,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
||||
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(
|
||||
consumer.transformerNonces.wethTransformer,
|
||||
);
|
||||
@ -278,7 +298,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
expect(wethTransformerData.amount).to.bignumber.eq(MAX_UINT256);
|
||||
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 affiliateFee = {
|
||||
recipient: randomAddress(),
|
||||
@ -288,7 +308,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
||||
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(
|
||||
consumer.transformerNonces.affiliateFeeTransformer,
|
||||
);
|
||||
@ -315,7 +335,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
||||
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.outputToken).to.eq(MAKER_TOKEN);
|
||||
expect(callArgs.inputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount);
|
||||
@ -357,5 +377,35 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
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';
|
||||
import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
|
||||
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 * as _ from 'lodash';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
@ -63,10 +63,11 @@ const DEFAULT_EXCLUDED = [
|
||||
ERC20BridgeSource.Shell,
|
||||
ERC20BridgeSource.Cream,
|
||||
ERC20BridgeSource.Dodo,
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
];
|
||||
const BUY_SOURCES = BUY_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 = {
|
||||
isFirmPriceAwareEnabled: true,
|
||||
isIndicativePriceAwareEnabled: true,
|
||||
@ -77,7 +78,6 @@ describe('MarketOperationUtils tests', () => {
|
||||
const CHAIN_ID = ChainId.Mainnet;
|
||||
const contractAddresses = {
|
||||
...getContractAddressesForChainOrThrow(CHAIN_ID),
|
||||
multiBridge: NULL_ADDRESS,
|
||||
...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 {
|
||||
return (
|
||||
sources: ERC20BridgeSource[],
|
||||
@ -335,7 +303,6 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.Bancor]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.Curve]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.LiquidityProvider]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.MultiBridge]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.MStable]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.Mooniswap]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.Swerve]: _.times(NUM_SAMPLES, () => 0),
|
||||
@ -480,6 +447,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
},
|
||||
balancerPoolsCache: new BalancerPoolsCache(),
|
||||
creamPoolsCache: new CreamPoolsCache(),
|
||||
liquidityProviderRegistry: {},
|
||||
} as any) as DexOrderSampler;
|
||||
|
||||
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());
|
||||
});
|
||||
|
||||
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 () => {
|
||||
const excludedSources = [ERC20BridgeSource.Uniswap, ERC20BridgeSource.Eth2Dai];
|
||||
let sourcesPolled: ERC20BridgeSource[] = [];
|
||||
@ -1341,41 +1261,28 @@ describe('MarketOperationUtils tests', () => {
|
||||
});
|
||||
|
||||
it('is able to create a order from LiquidityProvider', async () => {
|
||||
const registryAddress = randomAddress();
|
||||
const liquidityProviderAddress = (DEFAULT_FILL_DATA[ERC20BridgeSource.LiquidityProvider] as any)
|
||||
.poolAddress;
|
||||
const xAsset = randomAddress();
|
||||
const yAsset = randomAddress();
|
||||
const toSell = fromTokenUnitAmount(10);
|
||||
|
||||
const [getSellQuotesParams, getSellQuotesFn] = callTradeOperationAndRetainLiquidityProviderParams(
|
||||
createGetMultipleSellQuotesOperationFromRates,
|
||||
{
|
||||
[ERC20BridgeSource.LiquidityProvider]: createDecreasingRates(5),
|
||||
},
|
||||
);
|
||||
|
||||
const rates: RatesBySource = {};
|
||||
rates[ERC20BridgeSource.LiquidityProvider] = [1, 1, 1, 1];
|
||||
MOCK_SAMPLER.liquidityProviderRegistry[liquidityProviderAddress] = [MAKER_TOKEN, TAKER_TOKEN];
|
||||
replaceSamplerOps({
|
||||
getOrderFillableTakerAmounts: () => [constants.ZERO_AMOUNT],
|
||||
getSellQuotes: getSellQuotesFn,
|
||||
getSellQuotes: createGetMultipleSellQuotesOperationFromRates(rates),
|
||||
});
|
||||
|
||||
const sampler = new MarketOperationUtils(
|
||||
MOCK_SAMPLER,
|
||||
contractAddresses,
|
||||
ORDER_DOMAIN,
|
||||
registryAddress,
|
||||
);
|
||||
const sampler = new MarketOperationUtils(MOCK_SAMPLER, contractAddresses, ORDER_DOMAIN);
|
||||
const ordersAndReport = await sampler.getMarketSellOrdersAsync(
|
||||
[
|
||||
createOrder({
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(xAsset),
|
||||
takerAssetData: assetDataUtils.encodeERC20AssetData(yAsset),
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(MAKER_TOKEN),
|
||||
takerAssetData: assetDataUtils.encodeERC20AssetData(TAKER_TOKEN),
|
||||
}),
|
||||
],
|
||||
Web3Wrapper.toBaseUnitAmount(10, 18),
|
||||
FILL_AMOUNT,
|
||||
{
|
||||
excludedSources: SELL_SOURCES.concat(ERC20BridgeSource.Bancor),
|
||||
includedSources: [ERC20BridgeSource.LiquidityProvider],
|
||||
excludedSources: [],
|
||||
numSamples: 4,
|
||||
bridgeSlippage: 0,
|
||||
},
|
||||
@ -1390,9 +1297,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
) as ERC20BridgeAssetData;
|
||||
expect(decodedAssetData.assetProxyId).to.eql(AssetProxyId.ERC20Bridge);
|
||||
expect(decodedAssetData.bridgeAddress).to.eql(liquidityProviderAddress);
|
||||
expect(result[0].takerAssetAmount).to.bignumber.eql(toSell);
|
||||
expect(getSellQuotesParams.sources).contains(ERC20BridgeSource.LiquidityProvider);
|
||||
expect(getSellQuotesParams.liquidityProviderAddress).is.eql(registryAddress);
|
||||
expect(result[0].takerAssetAmount).to.bignumber.eql(FILL_AMOUNT);
|
||||
});
|
||||
|
||||
it('factors in exchange proxy gas overhead', async () => {
|
||||
@ -1403,20 +1308,16 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.Uniswap]: [1, 1, 1, 1],
|
||||
[ERC20BridgeSource.LiquidityProvider]: [0.9999, 0.9999, 0.9999, 0.9999],
|
||||
};
|
||||
MOCK_SAMPLER.liquidityProviderRegistry[randomAddress()] = [MAKER_TOKEN, TAKER_TOKEN];
|
||||
replaceSamplerOps({
|
||||
getSellQuotes: createGetMultipleSellQuotesOperationFromRates(rates),
|
||||
getMedianSellRate: createGetMedianSellRate(ETH_TO_MAKER_RATE),
|
||||
});
|
||||
const optimizer = new MarketOperationUtils(
|
||||
MOCK_SAMPLER,
|
||||
contractAddresses,
|
||||
ORDER_DOMAIN,
|
||||
randomAddress(), // liquidity provider registry
|
||||
);
|
||||
const optimizer = new MarketOperationUtils(MOCK_SAMPLER, contractAddresses, ORDER_DOMAIN);
|
||||
const gasPrice = 100e9; // 100 gwei
|
||||
const exchangeProxyOverhead = (sourceFlags: number) =>
|
||||
sourceFlags === SOURCE_FLAGS.LiquidityProvider
|
||||
? new BigNumber(3e4).times(gasPrice)
|
||||
? constants.ZERO_AMOUNT
|
||||
: new BigNumber(1.3e5).times(gasPrice);
|
||||
const improvedOrdersResponse = await optimizer.getMarketSellOrdersAsync(
|
||||
createOrdersFromSellRates(FILL_AMOUNT, rates[ERC20BridgeSource.Native]),
|
||||
@ -1424,12 +1325,12 @@ describe('MarketOperationUtils tests', () => {
|
||||
{
|
||||
...DEFAULT_OPTS,
|
||||
numSamples: 4,
|
||||
excludedSources: [
|
||||
...(DEFAULT_OPTS.excludedSources as ERC20BridgeSource[]),
|
||||
ERC20BridgeSource.Eth2Dai,
|
||||
ERC20BridgeSource.Kyber,
|
||||
ERC20BridgeSource.Bancor,
|
||||
includedSources: [
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.Uniswap,
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
],
|
||||
excludedSources: [],
|
||||
exchangeProxyOverhead,
|
||||
},
|
||||
);
|
||||
@ -1529,54 +1430,6 @@ describe('MarketOperationUtils tests', () => {
|
||||
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 () => {
|
||||
const excludedSources = [ERC20BridgeSource.Uniswap, ERC20BridgeSource.Eth2Dai];
|
||||
let sourcesPolled: ERC20BridgeSource[] = [];
|
||||
@ -1874,20 +1727,16 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.Uniswap]: [1, 1, 1, 1],
|
||||
[ERC20BridgeSource.LiquidityProvider]: [0.9999, 0.9999, 0.9999, 0.9999],
|
||||
};
|
||||
MOCK_SAMPLER.liquidityProviderRegistry[randomAddress()] = [MAKER_TOKEN, TAKER_TOKEN];
|
||||
replaceSamplerOps({
|
||||
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
|
||||
getMedianSellRate: createGetMedianSellRate(ETH_TO_TAKER_RATE),
|
||||
});
|
||||
const optimizer = new MarketOperationUtils(
|
||||
MOCK_SAMPLER,
|
||||
contractAddresses,
|
||||
ORDER_DOMAIN,
|
||||
randomAddress(), // liquidity provider registry
|
||||
);
|
||||
const optimizer = new MarketOperationUtils(MOCK_SAMPLER, contractAddresses, ORDER_DOMAIN);
|
||||
const gasPrice = 100e9; // 100 gwei
|
||||
const exchangeProxyOverhead = (sourceFlags: number) =>
|
||||
sourceFlags === SOURCE_FLAGS.LiquidityProvider
|
||||
? new BigNumber(3e4).times(gasPrice)
|
||||
? constants.ZERO_AMOUNT
|
||||
: new BigNumber(1.3e5).times(gasPrice);
|
||||
const improvedOrdersResponse = await optimizer.getMarketBuyOrdersAsync(
|
||||
createOrdersFromSellRates(FILL_AMOUNT, rates[ERC20BridgeSource.Native]),
|
||||
@ -1895,11 +1744,12 @@ describe('MarketOperationUtils tests', () => {
|
||||
{
|
||||
...DEFAULT_OPTS,
|
||||
numSamples: 4,
|
||||
excludedSources: [
|
||||
...(DEFAULT_OPTS.excludedSources as ERC20BridgeSource[]),
|
||||
ERC20BridgeSource.Eth2Dai,
|
||||
ERC20BridgeSource.Kyber,
|
||||
includedSources: [
|
||||
ERC20BridgeSource.Native,
|
||||
ERC20BridgeSource.Uniswap,
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
],
|
||||
excludedSources: [],
|
||||
exchangeProxyOverhead,
|
||||
},
|
||||
);
|
||||
|
@ -37,19 +37,12 @@ export type SampleBuysKyberHandler = (
|
||||
) => [string, SampleResults];
|
||||
export type SampleBuysMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
|
||||
export type SampleSellsLPHandler = (
|
||||
registryAddress: string,
|
||||
providerAddress: string,
|
||||
takerToken: string,
|
||||
makerToken: string,
|
||||
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;
|
||||
export type SampleSellsMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
|
||||
|
||||
const DUMMY_PROVIDER = {
|
||||
sendAsync: (..._args: any[]): any => {
|
||||
@ -61,15 +54,14 @@ interface Handlers {
|
||||
getOrderFillableMakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
||||
getOrderFillableTakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
||||
sampleSellsFromKyberNetwork: SampleSellsKyberHandler;
|
||||
sampleSellsFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
||||
sampleSellsFromMultiBridge: SampleSellsMBHandler;
|
||||
sampleSellsFromLiquidityProvider: SampleSellsLPHandler;
|
||||
sampleSellsFromEth2Dai: SampleSellsHandler;
|
||||
sampleSellsFromUniswap: SampleSellsHandler;
|
||||
sampleSellsFromUniswapV2: SampleSellsMultihopHandler;
|
||||
sampleBuysFromEth2Dai: SampleBuysHandler;
|
||||
sampleBuysFromUniswap: SampleBuysHandler;
|
||||
sampleBuysFromUniswapV2: SampleBuysMultihopHandler;
|
||||
sampleBuysFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
||||
sampleBuysFromLiquidityProvider: SampleSellsLPHandler;
|
||||
}
|
||||
|
||||
// tslint:disable: no-unbound-method
|
||||
@ -171,35 +163,17 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract {
|
||||
);
|
||||
}
|
||||
|
||||
public sampleSellsFromLiquidityProviderRegistry(
|
||||
registryAddress: string,
|
||||
public sampleSellsFromLiquidityProvider(
|
||||
providerAddress: string,
|
||||
takerToken: string,
|
||||
makerToken: string,
|
||||
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[]> {
|
||||
return this._wrapCall(
|
||||
super.sampleSellsFromMultiBridge,
|
||||
this._handlers.sampleSellsFromMultiBridge,
|
||||
multiBridgeAddress,
|
||||
super.sampleSellsFromLiquidityProvider,
|
||||
this._handlers.sampleSellsFromLiquidityProvider,
|
||||
providerAddress,
|
||||
takerToken,
|
||||
intermediateToken,
|
||||
makerToken,
|
||||
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/deployment_constants';
|
||||
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/eth2_dai_sampler';
|
||||
export * from '../test/generated-wrappers/i_balancer';
|
||||
export * from '../test/generated-wrappers/i_curve';
|
||||
export * from '../test/generated-wrappers/i_eth2_dai';
|
||||
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_mooniswap';
|
||||
export * from '../test/generated-wrappers/i_multi_bridge';
|
||||
|
@ -3,26 +3,19 @@
|
||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/DummyLiquidityProvider.json",
|
||||
"generated-artifacts/DummyLiquidityProviderRegistry.json",
|
||||
"generated-artifacts/ERC20BridgeSampler.json",
|
||||
"generated-artifacts/ILiquidityProvider.json",
|
||||
"generated-artifacts/ILiquidityProviderRegistry.json",
|
||||
"test/generated-artifacts/ApproximateBuys.json",
|
||||
"test/generated-artifacts/BalancerSampler.json",
|
||||
"test/generated-artifacts/CurveSampler.json",
|
||||
"test/generated-artifacts/DODOSampler.json",
|
||||
"test/generated-artifacts/DeploymentConstants.json",
|
||||
"test/generated-artifacts/DummyLiquidityProvider.json",
|
||||
"test/generated-artifacts/DummyLiquidityProviderRegistry.json",
|
||||
"test/generated-artifacts/ERC20BridgeSampler.json",
|
||||
"test/generated-artifacts/Eth2DaiSampler.json",
|
||||
"test/generated-artifacts/IBalancer.json",
|
||||
"test/generated-artifacts/ICurve.json",
|
||||
"test/generated-artifacts/IEth2Dai.json",
|
||||
"test/generated-artifacts/IKyberNetwork.json",
|
||||
"test/generated-artifacts/ILiquidityProvider.json",
|
||||
"test/generated-artifacts/ILiquidityProviderRegistry.json",
|
||||
"test/generated-artifacts/IMStable.json",
|
||||
"test/generated-artifacts/IMooniswap.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",
|
||||
"changes": [
|
||||
|
@ -32,6 +32,7 @@
|
||||
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
||||
"exchangeProxyTransformerDeployer": "0x39dce47a67ad34344eab877eae3ef1fa2a1d50bb",
|
||||
"exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18",
|
||||
"exchangeProxyLiquidityProviderSandbox": "0xdb971b18ea5075734cec1241732cc1b41031dfc9",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x68c0bb685099dc7cb5c5ce2b26185945b357383e",
|
||||
"payTakerTransformer": "0x49b9df2c58491764cf40cb052dd4243df63622c7",
|
||||
@ -72,6 +73,7 @@
|
||||
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
||||
"exchangeProxyTransformerDeployer": "0x1c9a27658dd303a31205a3b245e8993b92d4d502",
|
||||
"exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18",
|
||||
"exchangeProxyLiquidityProviderSandbox": "0xb8afda68a9834969a69ebd4aab201feff814d170",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437",
|
||||
"payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6",
|
||||
@ -112,6 +114,7 @@
|
||||
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
||||
"exchangeProxyTransformerDeployer": "0x1c9a27658dd303a31205a3b245e8993b92d4d502",
|
||||
"exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18",
|
||||
"exchangeProxyLiquidityProviderSandbox": "0xb8afda68a9834969a69ebd4aab201feff814d170",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437",
|
||||
"payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6",
|
||||
@ -152,6 +155,7 @@
|
||||
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
||||
"exchangeProxyTransformerDeployer": "0x1b62de2dbb5e7aa519e9c442721ecef75702807f",
|
||||
"exchangeProxyFlashWallet": "0x22f9dcf4647084d6c31b2765f6910cd85c178c18",
|
||||
"exchangeProxyLiquidityProviderSandbox": "0x598d7a659d1f163d94abe3628674f8a2569ff344",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x9ce35b5ee9e710535e3988e3f8731d9ca9dba17d",
|
||||
"payTakerTransformer": "0x5a53e7b02a83aa9f60ccf4e424f0442c255bc977",
|
||||
@ -192,6 +196,7 @@
|
||||
"exchangeProxyAllowanceTarget": "0x8362c3ebd90041b30ec45908332e592721642637",
|
||||
"exchangeProxyTransformerDeployer": "0x5409ed021d9299bf6814279a6a1411a7e866a631",
|
||||
"exchangeProxyFlashWallet": "0xb9682a8e7920b431f1d412b8510f0077410c8faa",
|
||||
"exchangeProxyLiquidityProviderSandbox": "0x0000000000000000000000000000000000000000",
|
||||
"transformers": {
|
||||
"wethTransformer": "0xc6b0d3c45a6b5092808196cb00df5c357d55e1d5",
|
||||
"payTakerTransformer": "0x7209185959d7227fb77274e1e88151d7c4c368d3",
|
||||
|
@ -33,6 +33,7 @@ export interface ContractAddresses {
|
||||
exchangeProxyAllowanceTarget: string;
|
||||
exchangeProxyTransformerDeployer: string;
|
||||
exchangeProxyFlashWallet: string;
|
||||
exchangeProxyLiquidityProviderSandbox: string;
|
||||
transformers: {
|
||||
wethTransformer: 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,
|
||||
"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",
|
||||
"compilerOutput": {
|
||||
"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,
|
||||
"inputs": [
|
||||
@ -232,16 +222,6 @@
|
||||
"stateMutability": "view",
|
||||
"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": [
|
||||
{
|
||||
@ -390,9 +370,11 @@
|
||||
"inputs": [
|
||||
{ "internalType": "address", "name": "makerToken", "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": "minBuyAmount", "type": "uint256" }
|
||||
{ "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" },
|
||||
{ "internalType": "bytes", "name": "auxiliaryData", "type": "bytes" }
|
||||
],
|
||||
"name": "sellToLiquidityProvider",
|
||||
"outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }],
|
||||
@ -411,17 +393,6 @@
|
||||
"stateMutability": "payable",
|
||||
"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" }],
|
||||
"name": "setQuoteSigner",
|
||||
@ -536,14 +507,6 @@
|
||||
"params": { "selector": "The function selector." },
|
||||
"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))": {
|
||||
"details": "Get the block at which a meta-transaction has been executed.",
|
||||
"params": { "mtx": "The meta-transaction." },
|
||||
@ -616,6 +579,19 @@
|
||||
"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)": {
|
||||
"details": "Efficiently sell directly to uniswap/sushiswap.",
|
||||
"params": {
|
||||
@ -626,14 +602,6 @@
|
||||
},
|
||||
"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)": {
|
||||
"details": "Replace the optional signer for `transformERC20()` calldata. Only callable by the owner.",
|
||||
"params": { "quoteSigner": "The address of the new calldata signer." }
|
||||
|
@ -11,7 +11,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"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",
|
||||
"build": "yarn tsc -b",
|
||||
"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,
|
||||
"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
|
||||
|
||||
export type IZeroExEventArgs =
|
||||
| IZeroExLiquidityProviderForMarketUpdatedEventArgs
|
||||
| IZeroExMetaTransactionExecutedEventArgs
|
||||
| IZeroExMigratedEventArgs
|
||||
| IZeroExOwnershipTransferredEventArgs
|
||||
@ -46,7 +45,6 @@ export type IZeroExEventArgs =
|
||||
| IZeroExTransformerDeployerUpdatedEventArgs;
|
||||
|
||||
export enum IZeroExEvents {
|
||||
LiquidityProviderForMarketUpdated = 'LiquidityProviderForMarketUpdated',
|
||||
MetaTransactionExecuted = 'MetaTransactionExecuted',
|
||||
Migrated = 'Migrated',
|
||||
OwnershipTransferred = 'OwnershipTransferred',
|
||||
@ -56,12 +54,6 @@ export enum IZeroExEvents {
|
||||
TransformerDeployerUpdated = 'TransformerDeployerUpdated',
|
||||
}
|
||||
|
||||
export interface IZeroExLiquidityProviderForMarketUpdatedEventArgs extends DecodedLogArgs {
|
||||
xAsset: string;
|
||||
yAsset: string;
|
||||
providerAddress: string;
|
||||
}
|
||||
|
||||
export interface IZeroExMetaTransactionExecutedEventArgs extends DecodedLogArgs {
|
||||
hash: string;
|
||||
selector: string;
|
||||
@ -219,29 +211,6 @@ export class IZeroExContract extends BaseContract {
|
||||
*/
|
||||
public static ABI(): ContractAbi {
|
||||
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,
|
||||
inputs: [
|
||||
@ -728,27 +697,6 @@ export class IZeroExContract extends BaseContract {
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
name: 'xAsset',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
name: 'yAsset',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
name: 'getLiquidityProviderForMarket',
|
||||
outputs: [
|
||||
{
|
||||
name: 'providerAddress',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
@ -1062,6 +1010,10 @@ export class IZeroExContract extends BaseContract {
|
||||
name: 'takerToken',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
name: 'target',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
name: 'recipient',
|
||||
type: 'address',
|
||||
@ -1074,6 +1026,10 @@ export class IZeroExContract extends BaseContract {
|
||||
name: 'minBuyAmount',
|
||||
type: 'uint256',
|
||||
},
|
||||
{
|
||||
name: 'auxiliaryData',
|
||||
type: 'bytes',
|
||||
},
|
||||
],
|
||||
name: 'sellToLiquidityProvider',
|
||||
outputs: [
|
||||
@ -1114,26 +1070,6 @@ export class IZeroExContract extends BaseContract {
|
||||
stateMutability: 'payable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
name: 'xAsset',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
name: 'yAsset',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
name: 'providerAddress',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
name: 'setLiquidityProviderForMarket',
|
||||
outputs: [],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
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.
|
||||
* @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(
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
target: string,
|
||||
recipient: string,
|
||||
sellAmount: BigNumber,
|
||||
minBuyAmount: BigNumber,
|
||||
auxiliaryData: string,
|
||||
): ContractTxFunctionObj<BigNumber> {
|
||||
const self = (this as any) as IZeroExContract;
|
||||
assert.isString('makerToken', makerToken);
|
||||
assert.isString('takerToken', takerToken);
|
||||
assert.isString('target', target);
|
||||
assert.isString('recipient', recipient);
|
||||
assert.isBigNumber('sellAmount', sellAmount);
|
||||
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 {
|
||||
async sendTransactionAsync(
|
||||
@ -2662,9 +2562,11 @@ export class IZeroExContract extends BaseContract {
|
||||
return self._strictEncodeArguments(functionSignature, [
|
||||
makerToken.toLowerCase(),
|
||||
takerToken.toLowerCase(),
|
||||
target.toLowerCase(),
|
||||
recipient.toLowerCase(),
|
||||
sellAmount,
|
||||
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.
|
||||
* Only callable by the owner.
|
||||
|
@ -125,7 +125,6 @@ export {
|
||||
IZeroExContract,
|
||||
IZeroExEventArgs,
|
||||
IZeroExEvents,
|
||||
IZeroExLiquidityProviderForMarketUpdatedEventArgs,
|
||||
IZeroExMetaTransactionExecutedEventArgs,
|
||||
IZeroExMigratedEventArgs,
|
||||
IZeroExOwnershipTransferredEventArgs,
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "6.5.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `exchangeProxyLiquidityProviderSandbox` address",
|
||||
"pr": 16
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1604385937,
|
||||
"version": "6.4.7",
|
||||
|
@ -402,6 +402,7 @@ export async function runMigrationsAsync(
|
||||
exchangeProxyAllowanceTarget: exchangeProxyAllowanceTargetAddress,
|
||||
exchangeProxyTransformerDeployer: txDefaults.from,
|
||||
exchangeProxyFlashWallet: exchangeProxyFlashWalletAddress,
|
||||
exchangeProxyLiquidityProviderSandbox: NULL_ADDRESS,
|
||||
transformers: {
|
||||
wethTransformer: wethTransformer.address,
|
||||
payTakerTransformer: payTakerTransformer.address,
|
||||
|
Loading…
x
Reference in New Issue
Block a user