feat: [asset-swapper] Add Crypto.com as a source (#43)
* feat: [asset-swapper] Add Crypto.com as a source * Exclude in tests * Disable hop sources to avoid excess inaccuracy * Added CryptoCom Bridge and FQT rollup * update test * Deploy CryptoCom bridge * Update package.json * CHANGELOGs
This commit is contained in:
parent
0c08353b2c
commit
f698721484
136
contracts/asset-proxy/contracts/src/bridges/CryptoComBridge.sol
Normal file
136
contracts/asset-proxy/contracts/src/bridges/CryptoComBridge.sol
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
|
||||
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.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IUniswapV2Router01.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
// solhint-disable not-rely-on-time
|
||||
contract CryptoComBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
struct TransferState {
|
||||
address[] path;
|
||||
address router;
|
||||
uint256 fromTokenBalance;
|
||||
}
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// hold variables to get around stack depth limitations
|
||||
TransferState memory state;
|
||||
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
// solhint-disable indent
|
||||
(state.path, state.router) = abi.decode(bridgeData, (address[], address));
|
||||
// solhint-enable indent
|
||||
|
||||
require(state.path.length >= 2, "CryptoComBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
|
||||
require(state.path[state.path.length - 1] == toTokenAddress, "CryptoComBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
|
||||
|
||||
// Just transfer the tokens if they're the same.
|
||||
if (state.path[0] == toTokenAddress) {
|
||||
LibERC20Token.transfer(state.path[0], to, amount);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
// Get our balance of `fromTokenAddress` token.
|
||||
state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
|
||||
|
||||
// Grant the SushiSwap router an allowance.
|
||||
LibERC20Token.approveIfBelow(
|
||||
state.path[0],
|
||||
state.router,
|
||||
state.fromTokenBalance
|
||||
);
|
||||
|
||||
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
|
||||
// and transfer it to `to`.
|
||||
IUniswapV2Router01 router = IUniswapV2Router01(state.router);
|
||||
uint[] memory amounts = router.swapExactTokensForTokens(
|
||||
// Sell all tokens we hold.
|
||||
state.fromTokenBalance,
|
||||
// Minimum buy amount.
|
||||
amount,
|
||||
// Convert `fromTokenAddress` to `toTokenAddress`.
|
||||
state.path,
|
||||
// Recipient is `to`.
|
||||
to,
|
||||
// Expires after this block.
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
// input token
|
||||
state.path[0],
|
||||
// output token
|
||||
toTokenAddress,
|
||||
// input token amount
|
||||
state.fromTokenBalance,
|
||||
// output token amount
|
||||
amounts[amounts.length - 1],
|
||||
from,
|
||||
to
|
||||
);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
@ -38,7 +38,7 @@
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CreamBridge|CurveBridge|DODOBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IShell|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|ShellBridge|SnowSwapBridge|StaticCallProxy|SushiSwapBridge|SwerveBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json",
|
||||
"abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CreamBridge|CryptoComBridge|CurveBridge|DODOBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IShell|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|ShellBridge|SnowSwapBridge|StaticCallProxy|SushiSwapBridge|SwerveBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
|
@ -9,6 +9,7 @@ import * as BalancerBridge from '../generated-artifacts/BalancerBridge.json';
|
||||
import * as BancorBridge from '../generated-artifacts/BancorBridge.json';
|
||||
import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json';
|
||||
import * as CreamBridge from '../generated-artifacts/CreamBridge.json';
|
||||
import * as CryptoComBridge from '../generated-artifacts/CryptoComBridge.json';
|
||||
import * as CurveBridge from '../generated-artifacts/CurveBridge.json';
|
||||
import * as DexForwarderBridge from '../generated-artifacts/DexForwarderBridge.json';
|
||||
import * as DODOBridge from '../generated-artifacts/DODOBridge.json';
|
||||
@ -77,6 +78,7 @@ export const artifacts = {
|
||||
BancorBridge: BancorBridge as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
CreamBridge: CreamBridge as ContractArtifact,
|
||||
CryptoComBridge: CryptoComBridge as ContractArtifact,
|
||||
CurveBridge: CurveBridge as ContractArtifact,
|
||||
DODOBridge: DODOBridge as ContractArtifact,
|
||||
DexForwarderBridge: DexForwarderBridge as ContractArtifact,
|
||||
|
@ -7,6 +7,7 @@ export * from '../generated-wrappers/balancer_bridge';
|
||||
export * from '../generated-wrappers/bancor_bridge';
|
||||
export * from '../generated-wrappers/chai_bridge';
|
||||
export * from '../generated-wrappers/cream_bridge';
|
||||
export * from '../generated-wrappers/crypto_com_bridge';
|
||||
export * from '../generated-wrappers/curve_bridge';
|
||||
export * from '../generated-wrappers/d_o_d_o_bridge';
|
||||
export * from '../generated-wrappers/dex_forwarder_bridge';
|
||||
|
@ -9,6 +9,7 @@ import * as BalancerBridge from '../test/generated-artifacts/BalancerBridge.json
|
||||
import * as BancorBridge from '../test/generated-artifacts/BancorBridge.json';
|
||||
import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json';
|
||||
import * as CreamBridge from '../test/generated-artifacts/CreamBridge.json';
|
||||
import * as CryptoComBridge from '../test/generated-artifacts/CryptoComBridge.json';
|
||||
import * as CurveBridge from '../test/generated-artifacts/CurveBridge.json';
|
||||
import * as DexForwarderBridge from '../test/generated-artifacts/DexForwarderBridge.json';
|
||||
import * as DODOBridge from '../test/generated-artifacts/DODOBridge.json';
|
||||
@ -77,6 +78,7 @@ export const artifacts = {
|
||||
BancorBridge: BancorBridge as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
CreamBridge: CreamBridge as ContractArtifact,
|
||||
CryptoComBridge: CryptoComBridge as ContractArtifact,
|
||||
CurveBridge: CurveBridge as ContractArtifact,
|
||||
DODOBridge: DODOBridge as ContractArtifact,
|
||||
DexForwarderBridge: DexForwarderBridge as ContractArtifact,
|
||||
|
@ -7,6 +7,7 @@ export * from '../test/generated-wrappers/balancer_bridge';
|
||||
export * from '../test/generated-wrappers/bancor_bridge';
|
||||
export * from '../test/generated-wrappers/chai_bridge';
|
||||
export * from '../test/generated-wrappers/cream_bridge';
|
||||
export * from '../test/generated-wrappers/crypto_com_bridge';
|
||||
export * from '../test/generated-wrappers/curve_bridge';
|
||||
export * from '../test/generated-wrappers/d_o_d_o_bridge';
|
||||
export * from '../test/generated-wrappers/dex_forwarder_bridge';
|
||||
|
@ -7,6 +7,7 @@
|
||||
"generated-artifacts/BancorBridge.json",
|
||||
"generated-artifacts/ChaiBridge.json",
|
||||
"generated-artifacts/CreamBridge.json",
|
||||
"generated-artifacts/CryptoComBridge.json",
|
||||
"generated-artifacts/CurveBridge.json",
|
||||
"generated-artifacts/DODOBridge.json",
|
||||
"generated-artifacts/DexForwarderBridge.json",
|
||||
@ -65,6 +66,7 @@
|
||||
"test/generated-artifacts/BancorBridge.json",
|
||||
"test/generated-artifacts/ChaiBridge.json",
|
||||
"test/generated-artifacts/CreamBridge.json",
|
||||
"test/generated-artifacts/CryptoComBridge.json",
|
||||
"test/generated-artifacts/CurveBridge.json",
|
||||
"test/generated-artifacts/DODOBridge.json",
|
||||
"test/generated-artifacts/DexForwarderBridge.json",
|
||||
|
@ -53,6 +53,10 @@
|
||||
{
|
||||
"note": "Add a permissionless transformer deployer",
|
||||
"pr": 55
|
||||
},
|
||||
{
|
||||
"note": "Add Crypto.com to `BridgeAdapter`",
|
||||
"pr": 43
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
|
||||
import "./mixins/MixinAdapterAddresses.sol";
|
||||
import "./mixins/MixinBalancer.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinCryptoCom.sol";
|
||||
import "./mixins/MixinDodo.sol";
|
||||
import "./mixins/MixinKyber.sol";
|
||||
import "./mixins/MixinMooniswap.sol";
|
||||
@ -37,6 +38,7 @@ contract BridgeAdapter is
|
||||
MixinAdapterAddresses,
|
||||
MixinBalancer,
|
||||
MixinCurve,
|
||||
MixinCryptoCom,
|
||||
MixinDodo,
|
||||
MixinKyber,
|
||||
MixinMooniswap,
|
||||
@ -52,6 +54,7 @@ contract BridgeAdapter is
|
||||
address private immutable BALANCER_BRIDGE_ADDRESS;
|
||||
address private immutable CREAM_BRIDGE_ADDRESS;
|
||||
address private immutable CURVE_BRIDGE_ADDRESS;
|
||||
address private immutable CRYPTO_COM_BRIDGE_ADDRESS;
|
||||
address private immutable DODO_BRIDGE_ADDRESS;
|
||||
address private immutable KYBER_BRIDGE_ADDRESS;
|
||||
address private immutable MOONISWAP_BRIDGE_ADDRESS;
|
||||
@ -68,6 +71,7 @@ contract BridgeAdapter is
|
||||
public
|
||||
MixinBalancer()
|
||||
MixinCurve()
|
||||
MixinCryptoCom(addresses)
|
||||
MixinDodo(addresses)
|
||||
MixinKyber(addresses)
|
||||
MixinMooniswap(addresses)
|
||||
@ -81,6 +85,7 @@ contract BridgeAdapter is
|
||||
{
|
||||
BALANCER_BRIDGE_ADDRESS = addresses.balancerBridge;
|
||||
CURVE_BRIDGE_ADDRESS = addresses.curveBridge;
|
||||
CRYPTO_COM_BRIDGE_ADDRESS = addresses.cryptoComBridge;
|
||||
KYBER_BRIDGE_ADDRESS = addresses.kyberBridge;
|
||||
MOONISWAP_BRIDGE_ADDRESS = addresses.mooniswapBridge;
|
||||
MSTABLE_BRIDGE_ADDRESS = addresses.mStableBridge;
|
||||
@ -185,6 +190,12 @@ contract BridgeAdapter is
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else if (bridgeAddress == CRYPTO_COM_BRIDGE_ADDRESS) {
|
||||
boughtAmount = _tradeCryptoCom(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else {
|
||||
boughtAmount = _tradeZeroExBridge(
|
||||
bridgeAddress,
|
||||
|
@ -26,6 +26,7 @@ contract MixinAdapterAddresses
|
||||
address balancerBridge;
|
||||
address creamBridge;
|
||||
address curveBridge;
|
||||
address cryptoComBridge;
|
||||
address dodoBridge;
|
||||
address kyberBridge;
|
||||
address mooniswapBridge;
|
||||
|
@ -0,0 +1,79 @@
|
||||
|
||||
/*
|
||||
|
||||
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/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "./MixinAdapterAddresses.sol";
|
||||
import "./MixinUniswapV2.sol";
|
||||
|
||||
contract MixinCryptoCom is
|
||||
MixinAdapterAddresses
|
||||
{
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
/// @dev Mainnet address of the `CryptoComRouter` contract.
|
||||
IUniswapV2Router02 private immutable CRYPTOCOM_ROUTER;
|
||||
|
||||
constructor(AdapterAddresses memory addresses)
|
||||
public
|
||||
{
|
||||
CRYPTOCOM_ROUTER = IUniswapV2Router02(addresses.cryptoComBridge);
|
||||
}
|
||||
|
||||
function _tradeCryptoCom(
|
||||
IERC20TokenV06 buyToken,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// solhint-disable indent
|
||||
address[] memory path = abi.decode(bridgeData, (address[]));
|
||||
// solhint-enable indent
|
||||
|
||||
require(path.length >= 2, "CryptoComBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
|
||||
require(
|
||||
path[path.length - 1] == address(buyToken),
|
||||
"CryptoComBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
|
||||
);
|
||||
// Grant the Uniswap router an allowance to sell the first token.
|
||||
IERC20TokenV06(path[0]).approveIfBelow(
|
||||
address(CRYPTOCOM_ROUTER),
|
||||
sellAmount
|
||||
);
|
||||
|
||||
uint[] memory amounts = CRYPTOCOM_ROUTER.swapExactTokensForTokens(
|
||||
// Sell all tokens we hold.
|
||||
sellAmount,
|
||||
// Minimum buy amount.
|
||||
1,
|
||||
// Convert to `buyToken` along this path.
|
||||
path,
|
||||
// Recipient is `this`.
|
||||
address(this),
|
||||
// Expires after this block.
|
||||
block.timestamp
|
||||
);
|
||||
return amounts[amounts.length-1];
|
||||
}
|
||||
}
|
@ -42,7 +42,7 @@
|
||||
"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,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature",
|
||||
"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|FixinTokenSpender|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|INativeOrdersFeature|IOwnableFeature|ISignatureValidatorFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOrderHash|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAdapterAddresses|MixinBalancer|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|PermissionlessTransformerDeployer|SignatureValidatorFeature|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|FeeCollector|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|INativeOrdersFeature|IOwnableFeature|ISignatureValidatorFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOrderHash|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAdapterAddresses|MixinBalancer|MixinCryptoCom|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|PermissionlessTransformerDeployer|SignatureValidatorFeature|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -74,6 +74,7 @@ import * as LogMetadataTransformer from '../test/generated-artifacts/LogMetadata
|
||||
import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransactionsFeature.json';
|
||||
import * as MixinAdapterAddresses from '../test/generated-artifacts/MixinAdapterAddresses.json';
|
||||
import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json';
|
||||
import * as MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json';
|
||||
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
|
||||
import * as MixinDodo from '../test/generated-artifacts/MixinDodo.json';
|
||||
import * as MixinKyber from '../test/generated-artifacts/MixinKyber.json';
|
||||
@ -210,6 +211,7 @@ export const artifacts = {
|
||||
IBridgeAdapter: IBridgeAdapter as ContractArtifact,
|
||||
MixinAdapterAddresses: MixinAdapterAddresses as ContractArtifact,
|
||||
MixinBalancer: MixinBalancer as ContractArtifact,
|
||||
MixinCryptoCom: MixinCryptoCom as ContractArtifact,
|
||||
MixinCurve: MixinCurve as ContractArtifact,
|
||||
MixinDodo: MixinDodo as ContractArtifact,
|
||||
MixinKyber: MixinKyber as ContractArtifact,
|
||||
|
@ -81,6 +81,7 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
||||
dodoBridge: NULL_ADDRESS,
|
||||
dodoHelper: NULL_ADDRESS,
|
||||
snowSwapBridge: NULL_ADDRESS,
|
||||
cryptoComBridge: NULL_ADDRESS,
|
||||
},
|
||||
);
|
||||
transformer = await FillQuoteTransformerContract.deployFrom0xArtifactAsync(
|
||||
|
@ -72,6 +72,7 @@ export * from '../test/generated-wrappers/log_metadata_transformer';
|
||||
export * from '../test/generated-wrappers/meta_transactions_feature';
|
||||
export * from '../test/generated-wrappers/mixin_adapter_addresses';
|
||||
export * from '../test/generated-wrappers/mixin_balancer';
|
||||
export * from '../test/generated-wrappers/mixin_crypto_com';
|
||||
export * from '../test/generated-wrappers/mixin_curve';
|
||||
export * from '../test/generated-wrappers/mixin_dodo';
|
||||
export * from '../test/generated-wrappers/mixin_kyber';
|
||||
|
@ -99,6 +99,7 @@
|
||||
"test/generated-artifacts/MetaTransactionsFeature.json",
|
||||
"test/generated-artifacts/MixinAdapterAddresses.json",
|
||||
"test/generated-artifacts/MixinBalancer.json",
|
||||
"test/generated-artifacts/MixinCryptoCom.json",
|
||||
"test/generated-artifacts/MixinCurve.json",
|
||||
"test/generated-artifacts/MixinDodo.json",
|
||||
"test/generated-artifacts/MixinKyber.json",
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "5.3.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added Crypto.com",
|
||||
"pr": 43
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "5.2.0",
|
||||
"changes": [
|
||||
|
@ -426,4 +426,5 @@ export interface BridgeContractAddresses {
|
||||
creamBridge: string;
|
||||
swerveBridge: string;
|
||||
snowswapBridge: string;
|
||||
cryptoComBridge: string;
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ export const SELL_SOURCE_FILTER = new SourceFilters([
|
||||
ERC20BridgeSource.Dodo,
|
||||
ERC20BridgeSource.Cream,
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
]);
|
||||
|
||||
/**
|
||||
@ -69,6 +70,7 @@ export const BUY_SOURCE_FILTER = new SourceFilters([
|
||||
ERC20BridgeSource.Dodo,
|
||||
ERC20BridgeSource.Cream,
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
]);
|
||||
|
||||
/**
|
||||
@ -352,6 +354,7 @@ export const MAINNET_KYBER_TOKEN_RESERVE_IDS: { [token: string]: string } = {
|
||||
export const LIQUIDITY_PROVIDER_REGISTRY: LiquidityProviderRegistry = {};
|
||||
|
||||
export const MAINNET_SUSHI_SWAP_ROUTER = '0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F';
|
||||
export const MAINNET_CRYPTO_COM_ROUTER = '0xCeB90E4C17d626BE0fACd78b79c9c87d7ca181b3';
|
||||
|
||||
export const MAINNET_SHELL_POOLS = {
|
||||
StableCoins: {
|
||||
@ -394,6 +397,7 @@ const EMPTY_BRIDGE_ADDRESSES: BridgeContractAddresses = {
|
||||
creamBridge: NULL_ADDRESS,
|
||||
snowswapBridge: NULL_ADDRESS,
|
||||
swerveBridge: NULL_ADDRESS,
|
||||
cryptoComBridge: NULL_ADDRESS,
|
||||
};
|
||||
|
||||
export const BRIDGE_ADDRESSES_BY_CHAIN: { [chainId in ChainId]: BridgeContractAddresses } = {
|
||||
@ -414,6 +418,7 @@ export const BRIDGE_ADDRESSES_BY_CHAIN: { [chainId in ChainId]: BridgeContractAd
|
||||
creamBridge: '0xb9d4bf2c8dab828f4ffb656acdb6c2b497d44f25',
|
||||
swerveBridge: '0xf9786d5eb1de47fa56a8f7bb387653c6d410bfee',
|
||||
snowswapBridge: '0xb1dbe83d15236ec10fdb214c6b89774b454754fd',
|
||||
cryptoComBridge: '0x015850307f6aab4ac6631923ceefe71b57492c9b',
|
||||
},
|
||||
[ChainId.Kovan]: {
|
||||
...EMPTY_BRIDGE_ADDRESSES,
|
||||
@ -483,7 +488,16 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
|
||||
},
|
||||
[ERC20BridgeSource.SushiSwap]: (fillData?: FillData) => {
|
||||
// TODO: Different base cost if to/from ETH.
|
||||
let gas = 95e3;
|
||||
let gas = 90e3;
|
||||
const path = (fillData as SushiSwapFillData).tokenAddressPath;
|
||||
if (path.length > 2) {
|
||||
gas += (path.length - 2) * 60e3; // +60k for each hop.
|
||||
}
|
||||
return gas;
|
||||
},
|
||||
[ERC20BridgeSource.CryptoCom]: (fillData?: FillData) => {
|
||||
// TODO: Different base cost if to/from ETH.
|
||||
let gas = 90e3 + 20e3 + 60e3; // temporary allowance diff, unrolled FQT
|
||||
const path = (fillData as SushiSwapFillData).tokenAddressPath;
|
||||
if (path.length > 2) {
|
||||
gas += (path.length - 2) * 60e3; // +60k for each hop.
|
||||
|
@ -199,6 +199,8 @@ function getBridgeAddressFromFill(fill: CollapsedFill, opts: CreateOrderFromPath
|
||||
return opts.contractAddresses.shellBridge;
|
||||
case ERC20BridgeSource.Dodo:
|
||||
return opts.contractAddresses.dodoBridge;
|
||||
case ERC20BridgeSource.CryptoCom:
|
||||
return opts.contractAddresses.cryptoComBridge;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -297,6 +299,14 @@ export function createBridgeOrder(
|
||||
createSushiSwapBridgeData(sushiSwapFillData.tokenAddressPath, sushiSwapFillData.router),
|
||||
);
|
||||
break;
|
||||
case ERC20BridgeSource.CryptoCom:
|
||||
const cryptoComFillData = (fill as CollapsedFill<SushiSwapFillData>).fillData!; // tslint:disable-line:no-non-null-assertion
|
||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||
makerToken,
|
||||
bridgeAddress,
|
||||
createSushiSwapBridgeData(cryptoComFillData.tokenAddressPath, cryptoComFillData.router),
|
||||
);
|
||||
break;
|
||||
case ERC20BridgeSource.Kyber:
|
||||
const kyberFillData = (fill as CollapsedFill<KyberFillData>).fillData!; // tslint:disable-line:no-non-null-assertion
|
||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||
|
@ -7,7 +7,13 @@ import { ERC20BridgeSamplerContract } from '../../wrappers';
|
||||
|
||||
import { BalancerPoolsCache } from './balancer_utils';
|
||||
import { BancorService } from './bancor_service';
|
||||
import { LIQUIDITY_PROVIDER_REGISTRY, MAINNET_SUSHI_SWAP_ROUTER, MAX_UINT256, ZERO_AMOUNT } from './constants';
|
||||
import {
|
||||
LIQUIDITY_PROVIDER_REGISTRY,
|
||||
MAINNET_CRYPTO_COM_ROUTER,
|
||||
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';
|
||||
@ -789,6 +795,32 @@ export class SamplerOperations {
|
||||
});
|
||||
}
|
||||
|
||||
public getCryptoComSellQuotes(
|
||||
tokenAddressPath: string[],
|
||||
takerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<SushiSwapFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.CryptoCom,
|
||||
fillData: { tokenAddressPath, router: MAINNET_CRYPTO_COM_ROUTER },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromSushiSwap,
|
||||
params: [MAINNET_CRYPTO_COM_ROUTER, tokenAddressPath, takerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getCryptoComBuyQuotes(
|
||||
tokenAddressPath: string[],
|
||||
makerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<SushiSwapFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.CryptoCom,
|
||||
fillData: { tokenAddressPath, router: MAINNET_CRYPTO_COM_ROUTER },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromSushiSwap,
|
||||
params: [MAINNET_CRYPTO_COM_ROUTER, tokenAddressPath, makerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getShellSellQuotes(
|
||||
poolAddress: string,
|
||||
makerToken: string,
|
||||
@ -993,6 +1025,16 @@ export class SamplerOperations {
|
||||
);
|
||||
});
|
||||
return sushiOps;
|
||||
case ERC20BridgeSource.CryptoCom:
|
||||
const cryptoComOps = [
|
||||
this.getCryptoComSellQuotes([takerToken, makerToken], takerFillAmounts),
|
||||
];
|
||||
intermediateTokens.forEach(t => {
|
||||
cryptoComOps.push(
|
||||
this.getCryptoComSellQuotes([takerToken, t, makerToken], takerFillAmounts),
|
||||
);
|
||||
});
|
||||
return cryptoComOps;
|
||||
case ERC20BridgeSource.Kyber:
|
||||
return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId =>
|
||||
this.getKyberSellQuotes(reserveId, makerToken, takerToken, takerFillAmounts),
|
||||
@ -1106,6 +1148,16 @@ export class SamplerOperations {
|
||||
);
|
||||
});
|
||||
return sushiOps;
|
||||
case ERC20BridgeSource.CryptoCom:
|
||||
const cryptoComOps = [
|
||||
this.getCryptoComBuyQuotes([takerToken, makerToken], makerFillAmounts),
|
||||
];
|
||||
intermediateTokens.forEach(t => {
|
||||
cryptoComOps.push(
|
||||
this.getCryptoComBuyQuotes([takerToken, t, makerToken], makerFillAmounts),
|
||||
);
|
||||
});
|
||||
return cryptoComOps;
|
||||
case ERC20BridgeSource.Kyber:
|
||||
return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId =>
|
||||
this.getKyberBuyQuotes(reserveId, makerToken, takerToken, makerFillAmounts),
|
||||
|
@ -49,6 +49,7 @@ export enum ERC20BridgeSource {
|
||||
SnowSwap = 'SnowSwap',
|
||||
SushiSwap = 'SushiSwap',
|
||||
Dodo = 'DODO',
|
||||
CryptoCom = 'CryptoCom',
|
||||
}
|
||||
|
||||
// tslint:disable: enum-naming
|
||||
|
@ -64,6 +64,7 @@ const DEFAULT_EXCLUDED = [
|
||||
ERC20BridgeSource.Cream,
|
||||
ERC20BridgeSource.Dodo,
|
||||
ERC20BridgeSource.LiquidityProvider,
|
||||
ERC20BridgeSource.CryptoCom,
|
||||
];
|
||||
const BUY_SOURCES = BUY_SOURCE_FILTER.sources;
|
||||
const SELL_SOURCES = SELL_SOURCE_FILTER.sources;
|
||||
@ -312,6 +313,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.Shell]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.Cream]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.Dodo]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.CryptoCom]: _.times(NUM_SAMPLES, () => 0),
|
||||
};
|
||||
|
||||
const DEFAULT_RATES: RatesBySource = {
|
||||
@ -371,6 +373,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.Shell]: { poolAddress: randomAddress() },
|
||||
[ERC20BridgeSource.Cream]: { poolAddress: randomAddress() },
|
||||
[ERC20BridgeSource.Dodo]: {},
|
||||
[ERC20BridgeSource.CryptoCom]: { tokenAddressPath: [] },
|
||||
};
|
||||
|
||||
const DEFAULT_OPS = {
|
||||
|
@ -332,6 +332,7 @@ export async function runMigrationsAsync(
|
||||
dodoBridge: NULL_ADDRESS,
|
||||
dodoHelper: NULL_ADDRESS,
|
||||
snowSwapBridge: NULL_ADDRESS,
|
||||
cryptoComBridge: NULL_ADDRESS,
|
||||
weth: etherToken.address,
|
||||
},
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user