diff --git a/contracts/asset-proxy/CHANGELOG.json b/contracts/asset-proxy/CHANGELOG.json index b7ff41a547..ca27fa23de 100644 --- a/contracts/asset-proxy/CHANGELOG.json +++ b/contracts/asset-proxy/CHANGELOG.json @@ -10,6 +10,10 @@ "note": "Export DexForwarderBridgeContract", "pr": 2656 }, + { + "note": "Add BancorBridge and IBancorNetwork, ", + "pr": 2650 + }, { "note": "Added `MStableBridge`", "pr": 2662 diff --git a/contracts/asset-proxy/contracts/src/bridges/BancorBridge.sol b/contracts/asset-proxy/contracts/src/bridges/BancorBridge.sol new file mode 100644 index 0000000000..b8f1d90e1f --- /dev/null +++ b/contracts/asset-proxy/contracts/src/bridges/BancorBridge.sol @@ -0,0 +1,122 @@ + +/* + + 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/LibERC20Token.sol"; +import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; +import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol"; +import "../interfaces/IERC20Bridge.sol"; +import "../interfaces/IBancorNetwork.sol"; + + +contract BancorBridge is + IERC20Bridge, + IWallet, + DeploymentConstants +{ + struct TransferState { + address bancorNetworkAddress; + address[] path; + } + + /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of + /// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress` + /// token encoded in the bridge data, then transfers the bought + /// tokens to `to`. + /// @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 conversion path addresses and Bancor network address + /// @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. + ( + state.path, + state.bancorNetworkAddress + // solhint-disable indent + ) = abi.decode(bridgeData, (address[], address)); + // solhint-enable indent + + require(state.path.length > 0, "BancorBridge/PATH_MUST_EXIST"); + // Just transfer the tokens if they're the same. + if (state.path[0] == toTokenAddress) { + LibERC20Token.transfer(state.path[0], to, amount); + return BRIDGE_SUCCESS; + } + + // Otherwise use Bancor to convert + require(state.path.length > 2, "BancorBridge/PATH_LENGTH_MUST_BE_GREATER_THAN_TWO"); + require(state.path[state.path.length - 1] == toTokenAddress, "BancorBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"); + + // // Grant an allowance to the Bancor Network to spend `fromTokenAddress` token. + uint256 fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this)); + LibERC20Token.approveIfBelow(state.path[0], state.bancorNetworkAddress, fromTokenBalance); + + // Convert the tokens + uint256 boughtAmount = IBancorNetwork(state.bancorNetworkAddress).convertByPath( + state.path, // path originating with source token and terminating in destination token + fromTokenBalance, // amount of source token to trade + amount, // minimum amount of destination token expected to receive + to, // beneficiary + address(0), // affiliateAccount; no fee paid + 0 // affiliateFee; no fee paid + ); + + emit ERC20BridgeTransfer( + state.path[0], // fromTokenAddress + toTokenAddress, + fromTokenBalance, + boughtAmount, + 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 Magic success bytes, always. + function isValidSignature( + bytes32, + bytes calldata + ) + external + view + returns (bytes4 magicValue) + { + return LEGACY_WALLET_MAGIC_VALUE; + } + +} diff --git a/contracts/asset-proxy/contracts/src/interfaces/IBancorNetwork.sol b/contracts/asset-proxy/contracts/src/interfaces/IBancorNetwork.sol new file mode 100644 index 0000000000..7c1dfb6346 --- /dev/null +++ b/contracts/asset-proxy/contracts/src/interfaces/IBancorNetwork.sol @@ -0,0 +1,38 @@ +/* + + 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; + + +contract IContractRegistry { + function addressOf( + bytes32 contractName + ) external returns(address); +} + + +contract IBancorNetwork { + function convertByPath( + address[] calldata _path, + uint256 _amount, + uint256 _minReturn, + address _beneficiary, + address _affiliateAccount, + uint256 _affiliateFee + ) external payable returns (uint256); +} diff --git a/contracts/asset-proxy/contracts/test/TestBancorBridge.sol b/contracts/asset-proxy/contracts/test/TestBancorBridge.sol new file mode 100644 index 0000000000..aa0175eea5 --- /dev/null +++ b/contracts/asset-proxy/contracts/test/TestBancorBridge.sol @@ -0,0 +1,247 @@ +/* + + Copyright 2019 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.5.9; +pragma experimental ABIEncoderV2; + +import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; +import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; +import "@0x/contracts-utils/contracts/src/LibAddressArray.sol"; +import "../src/bridges/BancorBridge.sol"; +import "../src/interfaces/IBancorNetwork.sol"; + + +contract TestEventsRaiser { + + event TokenTransfer( + address token, + address from, + address to, + uint256 amount + ); + + event TokenApprove( + address spender, + uint256 allowance + ); + + event ConvertByPathInput( + uint amountIn, + uint amountOutMin, + address toTokenAddress, + address to, + address feeRecipient, + uint256 feeAmount + ); + + function raiseTokenTransfer( + address from, + address to, + uint256 amount + ) + external + { + emit TokenTransfer( + msg.sender, + from, + to, + amount + ); + } + + function raiseTokenApprove(address spender, uint256 allowance) external { + emit TokenApprove(spender, allowance); + } + + function raiseConvertByPathInput( + uint amountIn, + uint amountOutMin, + address toTokenAddress, + address to, + address feeRecipient, + uint256 feeAmount + ) external + { + emit ConvertByPathInput( + amountIn, + amountOutMin, + toTokenAddress, + to, + feeRecipient, + feeAmount + ); + } +} + + +/// @dev A minimalist ERC20 token. +contract TestToken { + + using LibSafeMath for uint256; + + mapping (address => uint256) public balances; + string private _nextRevertReason; + + /// @dev Set the balance for `owner`. + function setBalance(address owner, uint256 balance) + external + payable + { + balances[owner] = balance; + } + + /// @dev Just emits a TokenTransfer event on the caller + function transfer(address to, uint256 amount) + external + returns (bool) + { + TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount); + return true; + } + + /// @dev Just emits a TokenApprove event on the caller + function approve(address spender, uint256 allowance) + external + returns (bool) + { + TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance); + return true; + } + + function allowance(address, address) external view returns (uint256) { + return 0; + } + + /// @dev Retrieve the balance for `owner`. + function balanceOf(address owner) + external + view + returns (uint256) + { + return balances[owner]; + } +} + + +/// @dev Mock the BancorNetwork contract +contract TestBancorNetwork is + IBancorNetwork +{ + string private _nextRevertReason; + + /// @dev Set the revert reason for `swapExactTokensForTokens`. + function setRevertReason(string calldata reason) + external + { + _nextRevertReason = reason; + } + + function convertByPath( + address[] calldata _path, + uint256 _amount, + uint256 _minReturn, + address _beneficiary, + address _affiliateAccount, + uint256 _affiliateFee + ) external payable returns (uint256) + { + _revertIfReasonExists(); + + TestEventsRaiser(msg.sender).raiseConvertByPathInput( + // tokens sold + _amount, + // tokens bought + _minReturn, + // output token + _path[_path.length - 1], + // recipient + _beneficiary, + // fee recipient + _affiliateAccount, + // fee amount + _affiliateFee + ); + } + + function _revertIfReasonExists() + private + view + { + if (bytes(_nextRevertReason).length != 0) { + revert(_nextRevertReason); + } + } + +} + + +/// @dev BancorBridge overridden to mock tokens and BancorNetwork +contract TestBancorBridge is + BancorBridge, + TestEventsRaiser +{ + + // Token address to TestToken instance. + mapping (address => TestToken) private _testTokens; + // TestRouter instance. + TestBancorNetwork private _testNetwork; + + constructor() public { + _testNetwork = new TestBancorNetwork(); + } + + function setNetworkRevertReason(string calldata revertReason) + external + { + _testNetwork.setRevertReason(revertReason); + } + + /// @dev Sets the balance of this contract for an existing token. + function setTokenBalance(address tokenAddress, uint256 balance) + external + { + TestToken token = _testTokens[tokenAddress]; + token.setBalance(address(this), balance); + } + + /// @dev Create a new token + /// @param tokenAddress The token address. If zero, one will be created. + function createToken( + address tokenAddress + ) + external + returns (TestToken token) + { + token = TestToken(tokenAddress); + if (tokenAddress == address(0)) { + token = new TestToken(); + } + _testTokens[address(token)] = token; + + return token; + } + + function getNetworkAddress() + external + view + returns (address) + { + return address(_testNetwork); + } + +} diff --git a/contracts/asset-proxy/package.json b/contracts/asset-proxy/package.json index b797642d00..b274e4ff3f 100644 --- a/contracts/asset-proxy/package.json +++ b/contracts/asset-proxy/package.json @@ -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|ChaiBridge|CurveBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json", + "abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CurveBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MultiAssetProxy|Ownable|StaticCallProxy|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": { diff --git a/contracts/asset-proxy/src/artifacts.ts b/contracts/asset-proxy/src/artifacts.ts index 86f387af6f..2578197d61 100644 --- a/contracts/asset-proxy/src/artifacts.ts +++ b/contracts/asset-proxy/src/artifacts.ts @@ -6,6 +6,7 @@ import { ContractArtifact } from 'ethereum-types'; 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 CurveBridge from '../generated-artifacts/CurveBridge.json'; import * as DexForwarderBridge from '../generated-artifacts/DexForwarderBridge.json'; @@ -20,6 +21,7 @@ import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json'; import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json'; import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json'; import * as IBalancerPool from '../generated-artifacts/IBalancerPool.json'; +import * as IBancorNetwork from '../generated-artifacts/IBancorNetwork.json'; import * as IChai from '../generated-artifacts/IChai.json'; import * as ICurve from '../generated-artifacts/ICurve.json'; import * as IDydx from '../generated-artifacts/IDydx.json'; @@ -40,6 +42,7 @@ import * as MStableBridge from '../generated-artifacts/MStableBridge.json'; import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json'; import * as Ownable from '../generated-artifacts/Ownable.json'; import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json'; +import * as TestBancorBridge from '../generated-artifacts/TestBancorBridge.json'; import * as TestChaiBridge from '../generated-artifacts/TestChaiBridge.json'; import * as TestDexForwarderBridge from '../generated-artifacts/TestDexForwarderBridge.json'; import * as TestDydxBridge from '../generated-artifacts/TestDydxBridge.json'; @@ -62,6 +65,7 @@ export const artifacts = { MultiAssetProxy: MultiAssetProxy as ContractArtifact, StaticCallProxy: StaticCallProxy as ContractArtifact, BalancerBridge: BalancerBridge as ContractArtifact, + BancorBridge: BancorBridge as ContractArtifact, ChaiBridge: ChaiBridge as ContractArtifact, CurveBridge: CurveBridge as ContractArtifact, DexForwarderBridge: DexForwarderBridge as ContractArtifact, @@ -77,6 +81,7 @@ export const artifacts = { IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, IAuthorizable: IAuthorizable as ContractArtifact, IBalancerPool: IBalancerPool as ContractArtifact, + IBancorNetwork: IBancorNetwork as ContractArtifact, IChai: IChai as ContractArtifact, ICurve: ICurve as ContractArtifact, IDydx: IDydx as ContractArtifact, @@ -89,6 +94,7 @@ export const artifacts = { IUniswapExchange: IUniswapExchange as ContractArtifact, IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact, IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact, + TestBancorBridge: TestBancorBridge as ContractArtifact, TestChaiBridge: TestChaiBridge as ContractArtifact, TestDexForwarderBridge: TestDexForwarderBridge as ContractArtifact, TestDydxBridge: TestDydxBridge as ContractArtifact, diff --git a/contracts/asset-proxy/src/wrappers.ts b/contracts/asset-proxy/src/wrappers.ts index 3660a3e0f6..b1f6905913 100644 --- a/contracts/asset-proxy/src/wrappers.ts +++ b/contracts/asset-proxy/src/wrappers.ts @@ -4,6 +4,7 @@ * ----------------------------------------------------------------------------- */ export * from '../generated-wrappers/balancer_bridge'; +export * from '../generated-wrappers/bancor_bridge'; export * from '../generated-wrappers/chai_bridge'; export * from '../generated-wrappers/curve_bridge'; export * from '../generated-wrappers/dex_forwarder_bridge'; @@ -18,6 +19,7 @@ export * from '../generated-wrappers/i_asset_proxy'; export * from '../generated-wrappers/i_asset_proxy_dispatcher'; export * from '../generated-wrappers/i_authorizable'; export * from '../generated-wrappers/i_balancer_pool'; +export * from '../generated-wrappers/i_bancor_network'; export * from '../generated-wrappers/i_chai'; export * from '../generated-wrappers/i_curve'; export * from '../generated-wrappers/i_dydx'; @@ -38,6 +40,7 @@ export * from '../generated-wrappers/mixin_gas_token'; export * from '../generated-wrappers/multi_asset_proxy'; export * from '../generated-wrappers/ownable'; export * from '../generated-wrappers/static_call_proxy'; +export * from '../generated-wrappers/test_bancor_bridge'; export * from '../generated-wrappers/test_chai_bridge'; export * from '../generated-wrappers/test_dex_forwarder_bridge'; export * from '../generated-wrappers/test_dydx_bridge'; diff --git a/contracts/asset-proxy/test/artifacts.ts b/contracts/asset-proxy/test/artifacts.ts index 4168957c27..2cacee3e89 100644 --- a/contracts/asset-proxy/test/artifacts.ts +++ b/contracts/asset-proxy/test/artifacts.ts @@ -6,6 +6,7 @@ import { ContractArtifact } from 'ethereum-types'; 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 CurveBridge from '../test/generated-artifacts/CurveBridge.json'; import * as DexForwarderBridge from '../test/generated-artifacts/DexForwarderBridge.json'; @@ -20,6 +21,7 @@ import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json'; import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json'; import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json'; import * as IBalancerPool from '../test/generated-artifacts/IBalancerPool.json'; +import * as IBancorNetwork from '../test/generated-artifacts/IBancorNetwork.json'; import * as IChai from '../test/generated-artifacts/IChai.json'; import * as ICurve from '../test/generated-artifacts/ICurve.json'; import * as IDydx from '../test/generated-artifacts/IDydx.json'; @@ -40,6 +42,7 @@ import * as MStableBridge from '../test/generated-artifacts/MStableBridge.json'; import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json'; import * as Ownable from '../test/generated-artifacts/Ownable.json'; import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json'; +import * as TestBancorBridge from '../test/generated-artifacts/TestBancorBridge.json'; import * as TestChaiBridge from '../test/generated-artifacts/TestChaiBridge.json'; import * as TestDexForwarderBridge from '../test/generated-artifacts/TestDexForwarderBridge.json'; import * as TestDydxBridge from '../test/generated-artifacts/TestDydxBridge.json'; @@ -62,6 +65,7 @@ export const artifacts = { MultiAssetProxy: MultiAssetProxy as ContractArtifact, StaticCallProxy: StaticCallProxy as ContractArtifact, BalancerBridge: BalancerBridge as ContractArtifact, + BancorBridge: BancorBridge as ContractArtifact, ChaiBridge: ChaiBridge as ContractArtifact, CurveBridge: CurveBridge as ContractArtifact, DexForwarderBridge: DexForwarderBridge as ContractArtifact, @@ -77,6 +81,7 @@ export const artifacts = { IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact, IAuthorizable: IAuthorizable as ContractArtifact, IBalancerPool: IBalancerPool as ContractArtifact, + IBancorNetwork: IBancorNetwork as ContractArtifact, IChai: IChai as ContractArtifact, ICurve: ICurve as ContractArtifact, IDydx: IDydx as ContractArtifact, @@ -89,6 +94,7 @@ export const artifacts = { IUniswapExchange: IUniswapExchange as ContractArtifact, IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact, IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact, + TestBancorBridge: TestBancorBridge as ContractArtifact, TestChaiBridge: TestChaiBridge as ContractArtifact, TestDexForwarderBridge: TestDexForwarderBridge as ContractArtifact, TestDydxBridge: TestDydxBridge as ContractArtifact, diff --git a/contracts/asset-proxy/test/bancor_bridge.ts b/contracts/asset-proxy/test/bancor_bridge.ts new file mode 100644 index 0000000000..9514904082 --- /dev/null +++ b/contracts/asset-proxy/test/bancor_bridge.ts @@ -0,0 +1,205 @@ +import { + blockchainTests, + constants, + expect, + filterLogsToArguments, + getRandomInteger, + randomAddress, +} from '@0x/contracts-test-utils'; +import { AssetProxyId } from '@0x/types'; +import { AbiEncoder, BigNumber, hexUtils } from '@0x/utils'; +import { DecodedLogs } from 'ethereum-types'; +import * as _ from 'lodash'; + +import { artifacts } from './artifacts'; + +import { TestBancorBridgeContract } from './generated-wrappers/test_bancor_bridge'; +import { + TestBancorBridgeConvertByPathInputEventArgs as ConvertByPathArgs, + TestBancorBridgeEvents as ContractEvents, + TestBancorBridgeTokenApproveEventArgs as TokenApproveArgs, + TestBancorBridgeTokenTransferEventArgs as TokenTransferArgs, +} from './wrappers'; + +blockchainTests.resets('Bancor unit tests', env => { + const FROM_TOKEN_DECIMALS = 6; + const TO_TOKEN_DECIMALS = 18; + const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS); + const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS); + let testContract: TestBancorBridgeContract; + + before(async () => { + testContract = await TestBancorBridgeContract.deployFrom0xArtifactAsync( + artifacts.TestBancorBridge, + env.provider, + env.txDefaults, + artifacts, + ); + }); + + describe('isValidSignature()', () => { + it('returns success bytes', async () => { + const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381'; + const result = await testContract + .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32))) + .callAsync(); + expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE); + }); + }); + + describe('bridgeTransferFrom()', () => { + interface TransferFromOpts { + tokenAddressesPath: string[]; + toAddress: string; + // Amount to pass into `bridgeTransferFrom()` + amount: BigNumber; + // Token balance of the bridge. + fromTokenBalance: BigNumber; + // Router reverts with this reason + routerRevertReason: string; + } + + interface TransferFromResult { + opts: TransferFromOpts; + result: string; + logs: DecodedLogs; + blocktime: number; + } + + function createTransferFromOpts(opts?: Partial): TransferFromOpts { + const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100)); + return { + tokenAddressesPath: Array(3).fill(constants.NULL_ADDRESS), + amount, + toAddress: randomAddress(), + fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)), + routerRevertReason: '', + ...opts, + }; + } + + const bridgeDataEncoder = AbiEncoder.create('(address[], address)'); + + async function transferFromAsync(opts?: Partial): Promise { + const _opts = createTransferFromOpts(opts); + + for (let i = 0; i < _opts.tokenAddressesPath.length; i++) { + const createFromTokenFn = testContract.createToken(_opts.tokenAddressesPath[i]); + _opts.tokenAddressesPath[i] = await createFromTokenFn.callAsync(); + await createFromTokenFn.awaitTransactionSuccessAsync(); + } + + // Set the token balance for the token we're converting from. + await testContract + .setTokenBalance(_opts.tokenAddressesPath[0], _opts.fromTokenBalance) + .awaitTransactionSuccessAsync(); + + // Set revert reason for the router. + await testContract.setNetworkRevertReason(_opts.routerRevertReason).awaitTransactionSuccessAsync(); + + // Call bridgeTransferFrom(). + const bridgeTransferFromFn = testContract.bridgeTransferFrom( + // Output token + _opts.tokenAddressesPath[_opts.tokenAddressesPath.length - 1], + // Random maker address. + randomAddress(), + // Recipient address. + _opts.toAddress, + // Transfer amount. + _opts.amount, + // ABI-encode the input token address as the bridge data. + bridgeDataEncoder.encode([ + _opts.tokenAddressesPath, + await testContract.getNetworkAddress().callAsync(), + ]), + ); + const result = await bridgeTransferFromFn.callAsync(); + const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync(); + return { + opts: _opts, + result, + logs: (receipt.logs as any) as DecodedLogs, + blocktime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber), + }; + } + + it('returns magic bytes on success', async () => { + const { result } = await transferFromAsync(); + expect(result).to.eq(AssetProxyId.ERC20Bridge); + }); + + it('performs transfer when both tokens are the same', async () => { + const createTokenFn = testContract.createToken(constants.NULL_ADDRESS); + const tokenAddress = await createTokenFn.callAsync(); + await createTokenFn.awaitTransactionSuccessAsync(); + + const { opts, result, logs } = await transferFromAsync({ + tokenAddressesPath: [tokenAddress, tokenAddress], + }); + expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id'); + const transfers = filterLogsToArguments(logs, ContractEvents.TokenTransfer); + + expect(transfers.length).to.eq(1); + expect(transfers[0].token).to.eq(tokenAddress, 'input token address'); + expect(transfers[0].from).to.eq(testContract.address); + expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address'); + expect(transfers[0].amount).to.bignumber.eq(opts.amount, 'amount'); + }); + + describe('token -> token', async () => { + it('calls BancorNetwork.convertByPath()', async () => { + const { opts, result, logs } = await transferFromAsync(); + expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id'); + const transfers = filterLogsToArguments(logs, ContractEvents.ConvertByPathInput); + + expect(transfers.length).to.eq(1); + expect(transfers[0].toTokenAddress).to.eq( + opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1], + 'output token address', + ); + expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address'); + expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount'); + expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount'); + expect(transfers[0].feeRecipient).to.eq(constants.NULL_ADDRESS); + expect(transfers[0].feeAmount).to.bignumber.eq(new BigNumber(0)); + }); + + it('sets allowance for "from" token', async () => { + const { logs } = await transferFromAsync(); + const approvals = filterLogsToArguments(logs, ContractEvents.TokenApprove); + const networkAddress = await testContract.getNetworkAddress().callAsync(); + expect(approvals.length).to.eq(1); + expect(approvals[0].spender).to.eq(networkAddress); + expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256); + }); + + it('fails if the router fails', async () => { + const revertReason = 'FOOBAR'; + const tx = transferFromAsync({ + routerRevertReason: revertReason, + }); + return expect(tx).to.eventually.be.rejectedWith(revertReason); + }); + }); + describe('token -> token -> token', async () => { + it('calls BancorNetwork.convertByPath()', async () => { + const { opts, result, logs } = await transferFromAsync({ + tokenAddressesPath: Array(5).fill(constants.NULL_ADDRESS), + }); + expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id'); + const transfers = filterLogsToArguments(logs, ContractEvents.ConvertByPathInput); + + expect(transfers.length).to.eq(1); + expect(transfers[0].toTokenAddress).to.eq( + opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1], + 'output token address', + ); + expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address'); + expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount'); + expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount'); + expect(transfers[0].feeRecipient).to.eq(constants.NULL_ADDRESS); + expect(transfers[0].feeAmount).to.bignumber.eq(new BigNumber(0)); + }); + }); + }); +}); diff --git a/contracts/asset-proxy/test/wrappers.ts b/contracts/asset-proxy/test/wrappers.ts index f37871cfda..814197df86 100644 --- a/contracts/asset-proxy/test/wrappers.ts +++ b/contracts/asset-proxy/test/wrappers.ts @@ -4,6 +4,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/curve_bridge'; export * from '../test/generated-wrappers/dex_forwarder_bridge'; @@ -18,6 +19,7 @@ export * from '../test/generated-wrappers/i_asset_proxy'; export * from '../test/generated-wrappers/i_asset_proxy_dispatcher'; export * from '../test/generated-wrappers/i_authorizable'; export * from '../test/generated-wrappers/i_balancer_pool'; +export * from '../test/generated-wrappers/i_bancor_network'; export * from '../test/generated-wrappers/i_chai'; export * from '../test/generated-wrappers/i_curve'; export * from '../test/generated-wrappers/i_dydx'; @@ -38,6 +40,7 @@ export * from '../test/generated-wrappers/mixin_gas_token'; export * from '../test/generated-wrappers/multi_asset_proxy'; export * from '../test/generated-wrappers/ownable'; export * from '../test/generated-wrappers/static_call_proxy'; +export * from '../test/generated-wrappers/test_bancor_bridge'; export * from '../test/generated-wrappers/test_chai_bridge'; export * from '../test/generated-wrappers/test_dex_forwarder_bridge'; export * from '../test/generated-wrappers/test_dydx_bridge'; diff --git a/contracts/asset-proxy/tsconfig.json b/contracts/asset-proxy/tsconfig.json index 5b7ac59664..3fb54954f9 100644 --- a/contracts/asset-proxy/tsconfig.json +++ b/contracts/asset-proxy/tsconfig.json @@ -4,6 +4,7 @@ "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], "files": [ "generated-artifacts/BalancerBridge.json", + "generated-artifacts/BancorBridge.json", "generated-artifacts/ChaiBridge.json", "generated-artifacts/CurveBridge.json", "generated-artifacts/DexForwarderBridge.json", @@ -18,6 +19,7 @@ "generated-artifacts/IAssetProxyDispatcher.json", "generated-artifacts/IAuthorizable.json", "generated-artifacts/IBalancerPool.json", + "generated-artifacts/IBancorNetwork.json", "generated-artifacts/IChai.json", "generated-artifacts/ICurve.json", "generated-artifacts/IDydx.json", @@ -38,6 +40,7 @@ "generated-artifacts/MultiAssetProxy.json", "generated-artifacts/Ownable.json", "generated-artifacts/StaticCallProxy.json", + "generated-artifacts/TestBancorBridge.json", "generated-artifacts/TestChaiBridge.json", "generated-artifacts/TestDexForwarderBridge.json", "generated-artifacts/TestDydxBridge.json", @@ -50,6 +53,7 @@ "generated-artifacts/UniswapBridge.json", "generated-artifacts/UniswapV2Bridge.json", "test/generated-artifacts/BalancerBridge.json", + "test/generated-artifacts/BancorBridge.json", "test/generated-artifacts/ChaiBridge.json", "test/generated-artifacts/CurveBridge.json", "test/generated-artifacts/DexForwarderBridge.json", @@ -64,6 +68,7 @@ "test/generated-artifacts/IAssetProxyDispatcher.json", "test/generated-artifacts/IAuthorizable.json", "test/generated-artifacts/IBalancerPool.json", + "test/generated-artifacts/IBancorNetwork.json", "test/generated-artifacts/IChai.json", "test/generated-artifacts/ICurve.json", "test/generated-artifacts/IDydx.json", @@ -84,6 +89,7 @@ "test/generated-artifacts/MultiAssetProxy.json", "test/generated-artifacts/Ownable.json", "test/generated-artifacts/StaticCallProxy.json", + "test/generated-artifacts/TestBancorBridge.json", "test/generated-artifacts/TestChaiBridge.json", "test/generated-artifacts/TestDexForwarderBridge.json", "test/generated-artifacts/TestDydxBridge.json", diff --git a/package.json b/package.json index 3f92b673bb..fcf7510698 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "wsrun": "wsrun", "lerna": "lerna", "build": "lerna link && wsrun build $PKG -r --stages --fast-exit --exclude-missing", - "build:ci": "lerna link && wsrun build:ci $PKG --fast-exit -r --stages --exclude-missing", + "build:ci": "lerna link && wsrun build:ci $PKG --fast-exit -r --stages --exclude-missing --exclude @0x/instant", "build:contracts": "lerna link && wsrun build -p ${npm_package_config_contractsPackages} -c --fast-exit -r --stages --exclude-missing", "build:monorepo_scripts": "PKG=@0x/monorepo-scripts yarn build", "build:ts": "tsc -b", @@ -39,7 +39,7 @@ "contracts:watch": "wsrun watch $PKG --parallel --exclude-missing", "remove_node_modules": "lerna clean --yes; rm -rf node_modules", "rebuild": "run-s clean build", - "test": "wsrun test $PKG --fast-exit --serial --exclude-missing --exclude @0x/asset-swapper --exclude @0x/orderbook", + "test": "wsrun test $PKG --fast-exit --serial --exclude-missing --exclude @0x/orderbook", "test:contracts": "wsrun test -p ${npm_package_config_contractsPackages} -c --fast-exit --exclude-missing", "generate_doc": "node ./packages/monorepo-scripts/lib/doc_generate.js", "upload_md_docs": "aws s3 rm --recursive s3://docs-markdown; wsrun s3:sync_md_docs --exclude-missing", @@ -62,10 +62,6 @@ { "path": "packages/0x.js/_bundles/index.min.js", "maxSize": "1300kB" - }, - { - "path": "packages/instant/umd/v3/instant.js", - "maxSize": "2100kB" } ], "ci": { diff --git a/packages/asset-swapper/CHANGELOG.json b/packages/asset-swapper/CHANGELOG.json index 42f5f8e0eb..044d6138ba 100644 --- a/packages/asset-swapper/CHANGELOG.json +++ b/packages/asset-swapper/CHANGELOG.json @@ -46,6 +46,10 @@ "note": "Adjust fill by ethToInputRate when ethToOutputRate is 0", "pr": 2660 }, + { + "note": "Add Bancor as liquidity source", + "pr": 2650 + }, { "note": "Added `mStable`", "pr": 2662 diff --git a/packages/asset-swapper/package.json b/packages/asset-swapper/package.json index 1654119a4c..228de61dfc 100644 --- a/packages/asset-swapper/package.json +++ b/packages/asset-swapper/package.json @@ -68,6 +68,7 @@ "@0x/utils": "^5.5.1", "@0x/web3-wrapper": "^7.2.0", "@balancer-labs/sor": "0.3.2", + "@bancor/sdk": "^0.2.5", "axios": "^0.19.2", "axios-mock-adapter": "^1.18.1", "decimal.js": "^10.2.0", diff --git a/packages/asset-swapper/src/index.ts b/packages/asset-swapper/src/index.ts index 4012a53bff..0d259c7cd9 100644 --- a/packages/asset-swapper/src/index.ts +++ b/packages/asset-swapper/src/index.ts @@ -108,6 +108,7 @@ export { } from './types'; export { affiliateFeeUtils } from './utils/affiliate_fee_utils'; export { + BancorFillData, BalancerFillData, CollapsedFill, CurveFillData, diff --git a/packages/asset-swapper/src/swap_quoter.ts b/packages/asset-swapper/src/swap_quoter.ts index 333fef93e5..fbe96ed95c 100644 --- a/packages/asset-swapper/src/swap_quoter.ts +++ b/packages/asset-swapper/src/swap_quoter.ts @@ -25,6 +25,7 @@ import { import { assert } from './utils/assert'; import { calculateLiquidity } from './utils/calculate_liquidity'; import { MarketOperationUtils } from './utils/market_operation_utils'; +import { BancorService } from './utils/market_operation_utils/bancor_service'; import { createDummyOrderForSampler } from './utils/market_operation_utils/orders'; import { DexOrderSampler } from './utils/market_operation_utils/sampler'; import { @@ -202,7 +203,7 @@ export class SwapQuoter { }, ); this._marketOperationUtils = new MarketOperationUtils( - new DexOrderSampler(samplerContract, samplerOverrides), + new DexOrderSampler(samplerContract, samplerOverrides, new BancorService(provider)), this._contractAddresses, { chainId, diff --git a/packages/asset-swapper/src/types.ts b/packages/asset-swapper/src/types.ts index bd193ef406..bc7c175908 100644 --- a/packages/asset-swapper/src/types.ts +++ b/packages/asset-swapper/src/types.ts @@ -264,6 +264,7 @@ export interface SwapQuoterOpts extends OrderPrunerOpts { chainId: number; orderRefreshIntervalMs: number; expiryBufferMs: number; + ethereumRpcUrl?: string; contractAddresses?: ContractAddresses; samplerGasLimit?: number; liquidityProviderRegistryAddress?: string; diff --git a/packages/asset-swapper/src/utils/market_operation_utils/bancor_service.ts b/packages/asset-swapper/src/utils/market_operation_utils/bancor_service.ts new file mode 100644 index 0000000000..e4101850b1 --- /dev/null +++ b/packages/asset-swapper/src/utils/market_operation_utils/bancor_service.ts @@ -0,0 +1,63 @@ +import { SupportedProvider } from '@0x/dev-utils'; +import { BigNumber } from '@0x/utils'; +import { SDK } from '@bancor/sdk'; +import { Ethereum, getDecimals } from '@bancor/sdk/dist/blockchains/ethereum'; +import { fromWei, toWei } from '@bancor/sdk/dist/helpers'; +import { BlockchainType, Token } from '@bancor/sdk/dist/types'; + +import { BancorFillData, Quote } from './types'; + +/** + * Converts an address to a Bancor Token type + */ +export function token(address: string, blockchainType: BlockchainType = BlockchainType.Ethereum): Token { + return { + blockchainType, + blockchainId: address, + }; +} + +export class BancorService { + // Bancor recommends setting this value to 2% under the expected return amount + public minReturnAmountBufferPercentage = 0.99; + private _sdk?: SDK; + + constructor(public provider: SupportedProvider) {} + + public async getSDKAsync(): Promise { + if (!this._sdk) { + this._sdk = await SDK.create({ ethereumNodeEndpoint: this.provider }); + } + return this._sdk; + } + + public async getQuoteAsync( + fromToken: string, + toToken: string, + amount: BigNumber = new BigNumber(1), + ): Promise> { + const sdk = await this.getSDKAsync(); + const blockchain = sdk._core.blockchains[BlockchainType.Ethereum] as Ethereum; + const sourceDecimals = await getDecimals(blockchain, fromToken); + const { path, rate } = await sdk.pricing.getPathAndRate( + token(fromToken), + token(toToken), + fromWei(amount.toString(), sourceDecimals), + ); + const targetDecimals = await getDecimals(blockchain, toToken); + const output = toWei(rate, targetDecimals); + return { + amount: new BigNumber(output).multipliedBy(this.minReturnAmountBufferPercentage).dp(0), + fillData: { + path: path.map(p => p.blockchainId), + networkAddress: await this.getBancorNetworkAddressAsync(), + }, + }; + } + + public async getBancorNetworkAddressAsync(): Promise { + const sdk = await this.getSDKAsync(); + const blockchain = sdk._core.blockchains[BlockchainType.Ethereum] as Ethereum; + return blockchain.bancorNetwork._address; + } +} diff --git a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts index 8a98b6acba..12350564dc 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/constants.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/constants.ts @@ -14,6 +14,7 @@ export const SELL_SOURCES = [ ERC20BridgeSource.Kyber, ERC20BridgeSource.Curve, ERC20BridgeSource.Balancer, + // ERC20BridgeSource.Bancor, // FIXME: Disabled until Bancor SDK supports batch requests ERC20BridgeSource.MStable, ]; @@ -27,6 +28,7 @@ export const BUY_SOURCES = [ ERC20BridgeSource.Kyber, ERC20BridgeSource.Curve, ERC20BridgeSource.Balancer, + // ERC20BridgeSource.Bancor, // FIXME: Disabled until Bancor SDK supports buy quotes ERC20BridgeSource.MStable, ]; diff --git a/packages/asset-swapper/src/utils/market_operation_utils/fills.ts b/packages/asset-swapper/src/utils/market_operation_utils/fills.ts index f06445c091..e7fbf7bf6e 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/fills.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/fills.ts @@ -256,6 +256,7 @@ export function collapsePath(path: Fill[]): CollapsedFill[] { if (prevFill.sourcePathId === fill.sourcePathId) { prevFill.input = prevFill.input.plus(fill.input); prevFill.output = prevFill.output.plus(fill.output); + prevFill.fillData = fill.fillData; prevFill.subFills.push(fill); continue; } diff --git a/packages/asset-swapper/src/utils/market_operation_utils/index.ts b/packages/asset-swapper/src/utils/market_operation_utils/index.ts index 1fae744529..fbbd192fcc 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/index.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/index.ts @@ -114,6 +114,7 @@ export class MarketOperationUtils { this._sampler.balancerPoolsCache, this._liquidityProviderRegistry, this._multiBridge, + this._sampler.bancorService, ), // Get ETH -> taker token price. await DexOrderSampler.ops.getMedianSellRateAsync( @@ -139,6 +140,7 @@ export class MarketOperationUtils { this._sampler.balancerPoolsCache, this._liquidityProviderRegistry, this._multiBridge, + this._sampler.bancorService, ), ); @@ -160,6 +162,7 @@ export class MarketOperationUtils { this._sampler.balancerPoolsCache, this._liquidityProviderRegistry, this._multiBridge, + this._sampler.bancorService, ) .then(async r => this._sampler.executeAsync(r)); @@ -241,6 +244,7 @@ export class MarketOperationUtils { this._sampler.balancerPoolsCache, this._liquidityProviderRegistry, this._multiBridge, + this._sampler.bancorService, ), // Get buy quotes for taker -> maker. await DexOrderSampler.ops.getBuyQuotesAsync( @@ -248,7 +252,7 @@ export class MarketOperationUtils { BUY_SOURCES.concat( this._liquidityProviderRegistry !== NULL_ADDRESS ? [ERC20BridgeSource.LiquidityProvider] : [], ), - _opts.excludedSources.concat(ERC20BridgeSource.Balancer), + _opts.excludedSources.concat([ERC20BridgeSource.Balancer]), ), makerToken, takerToken, @@ -256,6 +260,7 @@ export class MarketOperationUtils { this._wethAddress, this._sampler.balancerPoolsCache, this._liquidityProviderRegistry, + this._sampler.bancorService, ), ); @@ -268,6 +273,7 @@ export class MarketOperationUtils { this._wethAddress, this._sampler.balancerPoolsCache, this._liquidityProviderRegistry, + this._sampler.bancorService, ), ); diff --git a/packages/asset-swapper/src/utils/market_operation_utils/orders.ts b/packages/asset-swapper/src/utils/market_operation_utils/orders.ts index 2e639c9ef3..446cd11387 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/orders.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/orders.ts @@ -20,6 +20,7 @@ import { getMultiBridgeIntermediateToken } from './multibridge_utils'; import { AggregationError, BalancerFillData, + BancorFillData, CollapsedFill, CurveFillData, ERC20BridgeSource, @@ -190,6 +191,8 @@ function getBridgeAddressFromFill(fill: CollapsedFill, opts: CreateOrderFromPath return opts.contractAddresses.uniswapV2Bridge; case ERC20BridgeSource.Curve: return opts.contractAddresses.curveBridge; + case ERC20BridgeSource.Bancor: + return opts.contractAddresses.bancorBridge; case ERC20BridgeSource.Balancer: return opts.contractAddresses.balancerBridge; case ERC20BridgeSource.LiquidityProvider: @@ -232,6 +235,14 @@ function createBridgeOrder(fill: CollapsedFill, opts: CreateOrderFromPathOpts): createBalancerBridgeData(takerToken, balancerFillData.poolAddress), ); break; + case ERC20BridgeSource.Bancor: + const bancorFillData = (fill as CollapsedFill).fillData!; // tslint:disable-line:no-non-null-assertion + makerAssetData = assetDataUtils.encodeERC20BridgeAssetData( + makerToken, + bridgeAddress, + createBancorBridgeData(bancorFillData.path, bancorFillData.networkAddress), + ); + break; case ERC20BridgeSource.UniswapV2: const uniswapV2FillData = (fill as CollapsedFill).fillData!; // tslint:disable-line:no-non-null-assertion makerAssetData = assetDataUtils.encodeERC20BridgeAssetData( @@ -337,6 +348,14 @@ function createBalancerBridgeData(takerToken: string, poolAddress: string): stri return encoder.encode({ takerToken, poolAddress }); } +function createBancorBridgeData(path: string[], networkAddress: string): string { + const encoder = AbiEncoder.create([ + { name: 'path', type: 'address[]' }, + { name: 'networkAddress', type: 'address' }, + ]); + return encoder.encode({ path, networkAddress }); +} + function createCurveBridgeData( curveAddress: string, exchangeFunctionSelector: string, diff --git a/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts b/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts index f9855cc22d..eb65fef5bf 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts @@ -4,6 +4,7 @@ import { SamplerOverrides } from '../../types'; import { ERC20BridgeSamplerContract } from '../../wrappers'; import { BalancerPoolsCache } from './balancer_utils'; +import { BancorService } from './bancor_service'; import { samplerOperations } from './sampler_operations'; import { BatchedOperation } from './types'; @@ -39,6 +40,7 @@ export class DexOrderSampler { constructor( private readonly _samplerContract: ERC20BridgeSamplerContract, private readonly _samplerOverrides?: SamplerOverrides, + public bancorService?: BancorService, public balancerPoolsCache: BalancerPoolsCache = new BalancerPoolsCache(), ) {} diff --git a/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts index c48424984e..8813327fb7 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts @@ -3,15 +3,19 @@ import * as _ from 'lodash'; import { BigNumber, ERC20BridgeSource, SignedOrder } from '../..'; import { BalancerPool, BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote } from './balancer_utils'; +import { BancorService } from './bancor_service'; import { NULL_BYTES, ZERO_AMOUNT } from './constants'; import { getCurveInfosForPair } from './curve_utils'; import { getMultiBridgeIntermediateToken } from './multibridge_utils'; import { BalancerFillData, + BancorFillData, BatchedOperation, CurveFillData, CurveInfo, DexSample, + FillData, + Quote, SourceQuoteOperation, UniswapV2FillData, } from './types'; @@ -54,7 +58,9 @@ export const samplerOperations = { .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleSellsFromKyberNetwork', callResults); + return contract + .getABIDecodedReturnData('sampleSellsFromKyberNetwork', callResults) + .map(amount => ({ amount })); }, }; }, @@ -67,7 +73,9 @@ export const samplerOperations = { .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleBuysFromKyberNetwork', callResults); + return contract + .getABIDecodedReturnData('sampleBuysFromKyberNetwork', callResults) + .map(amount => ({ amount })); }, }; }, @@ -80,7 +88,9 @@ export const samplerOperations = { .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleSellsFromUniswap', callResults); + return contract + .getABIDecodedReturnData('sampleSellsFromUniswap', callResults) + .map(amount => ({ amount })); }, }; }, @@ -93,7 +103,9 @@ export const samplerOperations = { .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleBuysFromUniswap', callResults); + return contract + .getABIDecodedReturnData('sampleBuysFromUniswap', callResults) + .map(amount => ({ amount })); }, }; }, @@ -103,14 +115,18 @@ export const samplerOperations = { ): SourceQuoteOperation { return { source: ERC20BridgeSource.UniswapV2, - fillData: { tokenAddressPath }, encodeCall: contract => { return contract .sampleSellsFromUniswapV2(tokenAddressPath, takerFillAmounts) .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleSellsFromUniswapV2', callResults); + return contract + .getABIDecodedReturnData('sampleSellsFromUniswapV2', callResults) + .map(amount => ({ + amount, + fillData: { tokenAddressPath }, + })); }, }; }, @@ -120,14 +136,18 @@ export const samplerOperations = { ): SourceQuoteOperation { return { source: ERC20BridgeSource.UniswapV2, - fillData: { tokenAddressPath }, encodeCall: contract => { return contract .sampleBuysFromUniswapV2(tokenAddressPath, makerFillAmounts) .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleBuysFromUniswapV2', callResults); + return contract + .getABIDecodedReturnData('sampleBuysFromUniswapV2', callResults) + .map(amount => ({ + amount, + fillData: { tokenAddressPath }, + })); }, }; }, @@ -145,10 +165,9 @@ export const samplerOperations = { .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData( - 'sampleSellsFromLiquidityProviderRegistry', - callResults, - ); + return contract + .getABIDecodedReturnData('sampleSellsFromLiquidityProviderRegistry', callResults) + .map(amount => ({ amount })); }, }; }, @@ -166,10 +185,9 @@ export const samplerOperations = { .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData( - 'sampleBuysFromLiquidityProviderRegistry', - callResults, - ); + return contract + .getABIDecodedReturnData('sampleBuysFromLiquidityProviderRegistry', callResults) + .map(amount => ({ amount })); }, }; }, @@ -194,7 +212,9 @@ export const samplerOperations = { .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleSellsFromMultiBridge', callResults); + return contract + .getABIDecodedReturnData('sampleSellsFromMultiBridge', callResults) + .map(amount => ({ amount })); }, }; }, @@ -207,7 +227,9 @@ export const samplerOperations = { .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleSellsFromEth2Dai', callResults); + return contract + .getABIDecodedReturnData('sampleSellsFromEth2Dai', callResults) + .map(amount => ({ amount })); }, }; }, @@ -220,7 +242,9 @@ export const samplerOperations = { .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleBuysFromEth2Dai', callResults); + return contract + .getABIDecodedReturnData('sampleBuysFromEth2Dai', callResults) + .map(amount => ({ amount })); }, }; }, @@ -232,11 +256,6 @@ export const samplerOperations = { ): SourceQuoteOperation { return { source: ERC20BridgeSource.Curve, - fillData: { - curve, - fromTokenIdx, - toTokenIdx, - }, encodeCall: contract => { return contract .sampleSellsFromCurve( @@ -252,7 +271,16 @@ export const samplerOperations = { .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleSellsFromCurve', callResults); + return contract + .getABIDecodedReturnData('sampleSellsFromCurve', callResults) + .map(amount => ({ + amount, + fillData: { + curve, + fromTokenIdx, + toTokenIdx, + }, + })); }, }; }, @@ -264,11 +292,6 @@ export const samplerOperations = { ): SourceQuoteOperation { return { source: ERC20BridgeSource.Curve, - fillData: { - curve, - fromTokenIdx, - toTokenIdx, - }, encodeCall: contract => { return contract .sampleBuysFromCurve( @@ -284,22 +307,57 @@ export const samplerOperations = { .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleBuysFromCurve', callResults); + return contract + .getABIDecodedReturnData('sampleBuysFromCurve', callResults) + .map(amount => ({ + amount, + fillData: { + curve, + fromTokenIdx, + toTokenIdx, + }, + })); + }, + }; + }, + getBancorSellQuotes( + makerToken: string, + takerToken: string, + takerFillAmounts: BigNumber[], + bancorService: BancorService, + ): SourceQuoteOperation { + return { + source: ERC20BridgeSource.Bancor, + encodeCall: _contract => { + return '0x'; + }, + handleCallResultsAsync: async (_contract, _callResults) => { + return Promise.all( + takerFillAmounts.map(async amt => bancorService.getQuoteAsync(takerToken, makerToken, amt)), + ); }, }; }, getBalancerSellQuotes(pool: BalancerPool, takerFillAmounts: BigNumber[]): SourceQuoteOperation { return { source: ERC20BridgeSource.Balancer, - fillData: { poolAddress: pool.id }, - ...samplerOperations.constant(takerFillAmounts.map(amount => computeBalancerSellQuote(pool, amount))), + ...samplerOperations.constant( + takerFillAmounts.map(amount => ({ + amount: computeBalancerSellQuote(pool, amount), + fillData: { poolAddress: pool.id }, + })), + ), }; }, getBalancerBuyQuotes(pool: BalancerPool, makerFillAmounts: BigNumber[]): SourceQuoteOperation { return { source: ERC20BridgeSource.Balancer, - fillData: { poolAddress: pool.id }, - ...samplerOperations.constant(makerFillAmounts.map(amount => computeBalancerBuyQuote(pool, amount))), + ...samplerOperations.constant( + makerFillAmounts.map(amount => ({ + amount: computeBalancerBuyQuote(pool, amount), + fillData: { poolAddress: pool.id }, + })), + ), }; }, getMStableSellQuotes(makerToken: string, takerToken: string, takerFillAmounts: BigNumber[]): SourceQuoteOperation { @@ -311,7 +369,9 @@ export const samplerOperations = { .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleSellsFromMStable', callResults); + return contract + .getABIDecodedReturnData('sampleSellsFromMStable', callResults) + .map(amount => ({ amount })); }, }; }, @@ -324,7 +384,9 @@ export const samplerOperations = { .getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleBuysFromMStable', callResults); + return contract + .getABIDecodedReturnData('sampleBuysFromMStable', callResults) + .map(amount => ({ amount })); }, }; }, @@ -337,6 +399,7 @@ export const samplerOperations = { balancerPoolsCache?: BalancerPoolsCache, liquidityProviderRegistryAddress?: string, multiBridgeAddress?: string, + bancorService?: BancorService, ): Promise> => { if (makerToken.toLowerCase() === takerToken.toLowerCase()) { return samplerOperations.constant(new BigNumber(1)); @@ -350,6 +413,7 @@ export const samplerOperations = { balancerPoolsCache, liquidityProviderRegistryAddress, multiBridgeAddress, + bancorService, ); return { encodeCall: contract => { @@ -417,11 +481,12 @@ export const samplerOperations = { balancerPoolsCache?: BalancerPoolsCache, liquidityProviderRegistryAddress?: string, multiBridgeAddress?: string, + bancorService?: BancorService, ): Promise> => { const subOps = _.flatten( await Promise.all( sources.map( - async (source): Promise => { + async (source): Promise | Array>> => { switch (source) { case ERC20BridgeSource.Eth2Dai: return samplerOperations.getEth2DaiSellQuotes(makerToken, takerToken, takerFillAmounts); @@ -491,6 +556,18 @@ export const samplerOperations = { return pools.map(pool => samplerOperations.getBalancerSellQuotes(pool, takerFillAmounts), ); + case ERC20BridgeSource.Bancor: + if (bancorService === undefined) { + throw new Error( + 'Cannot sample liquidity from Bancor; no Bancor service instantiated.', + ); + } + return samplerOperations.getBancorSellQuotes( + makerToken, + takerToken, + takerFillAmounts, + bancorService, + ); case ERC20BridgeSource.MStable: return samplerOperations.getMStableSellQuotes(makerToken, takerToken, takerFillAmounts); default: @@ -500,8 +577,16 @@ export const samplerOperations = { ), ), ); - const samplerOps = subOps.filter(op => op.source !== ERC20BridgeSource.Balancer); - const nonSamplerOps = subOps.filter(op => op.source === ERC20BridgeSource.Balancer); + const nonSamplerSources = [ERC20BridgeSource.Balancer, ERC20BridgeSource.Bancor]; + const samplerOps: Array> = []; + const nonSamplerOps: Array> = []; + subOps.forEach(op => { + if (nonSamplerSources.includes(op.source)) { + nonSamplerOps.push(op); + } else { + samplerOps.push(op); + } + }); return { encodeCall: contract => { // All operations are NOOPs @@ -512,7 +597,7 @@ export const samplerOperations = { return contract.batchCall(subCalls).getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - let samples: BigNumber[][]; + let samples: Array>>; // If all operations were NOOPs then just call the handle result callback if (callResults === NULL_BYTES && samplerOps.length === 0) { samples = await Promise.all(nonSamplerOps.map(async op => op.handleCallResultsAsync(contract, ''))); @@ -528,9 +613,9 @@ export const samplerOperations = { return [...samplerOps, ...nonSamplerOps].map((op, i) => { return samples[i].map((output, j) => ({ source: op.source, - output, + output: output.amount, input: takerFillAmounts[j], - fillData: op.fillData, + fillData: output.fillData, })); }); }, @@ -544,11 +629,12 @@ export const samplerOperations = { wethAddress: string, balancerPoolsCache?: BalancerPoolsCache, liquidityProviderRegistryAddress?: string, + bancorService?: BancorService, ): Promise> => { const subOps = _.flatten( await Promise.all( sources.map( - async (source): Promise => { + async (source): Promise | Array>> => { switch (source) { case ERC20BridgeSource.Eth2Dai: return samplerOperations.getEth2DaiBuyQuotes(makerToken, takerToken, makerFillAmounts); @@ -600,6 +686,8 @@ export const samplerOperations = { return pools.map(pool => samplerOperations.getBalancerBuyQuotes(pool, makerFillAmounts), ); + case ERC20BridgeSource.Bancor: + return []; // FIXME: Waiting for Bancor SDK to support buy quotes, but don't throw an error here case ERC20BridgeSource.MStable: return samplerOperations.getMStableBuyQuotes(makerToken, takerToken, makerFillAmounts); default: @@ -609,8 +697,16 @@ export const samplerOperations = { ), ), ); - const samplerOps = subOps.filter(op => op.source !== ERC20BridgeSource.Balancer); - const nonSamplerOps = subOps.filter(op => op.source === ERC20BridgeSource.Balancer); + const nonSamplerSources = [ERC20BridgeSource.Balancer, ERC20BridgeSource.Bancor]; + const samplerOps: Array> = []; + const nonSamplerOps: Array> = []; + subOps.forEach(op => { + if (nonSamplerSources.find(s => s === op.source) !== undefined) { + nonSamplerOps.push(op); + } else { + samplerOps.push(op); + } + }); return { encodeCall: contract => { // All operations are NOOPs @@ -621,7 +717,7 @@ export const samplerOperations = { return contract.batchCall(subCalls).getABIEncodedTransactionData(); }, handleCallResultsAsync: async (contract, callResults) => { - let samples: BigNumber[][]; + let samples: Array>>; if (callResults === NULL_BYTES && samplerOps.length === 0) { samples = await Promise.all(nonSamplerOps.map(async op => op.handleCallResultsAsync(contract, ''))); } else { @@ -636,9 +732,9 @@ export const samplerOperations = { return [...samplerOps, ...nonSamplerOps].map((op, i) => { return samples[i].map((output, j) => ({ source: op.source, - output, + output: output.amount, input: makerFillAmounts[j], - fillData: op.fillData, + fillData: output.fillData, })); }); }, diff --git a/packages/asset-swapper/src/utils/market_operation_utils/types.ts b/packages/asset-swapper/src/utils/market_operation_utils/types.ts index 5ad501693b..0856813fed 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/types.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/types.ts @@ -38,6 +38,7 @@ export enum ERC20BridgeSource { LiquidityProvider = 'LiquidityProvider', MultiBridge = 'MultiBridge', Balancer = 'Balancer', + Bancor = 'Bancor', MStable = 'mStable', } @@ -96,6 +97,15 @@ export interface LiquidityProviderFillData extends FillData { export interface MultiBridgeFillData extends FillData { poolAddress: string; } +export interface BancorFillData extends FillData { + path: string[]; + networkAddress: string; +} + +export interface Quote { + amount: BigNumber; + fillData?: TFillData; +} /** * Represents an individual DEX sample from the sampler contract. @@ -266,9 +276,9 @@ export interface BatchedOperation { handleCallResultsAsync(contract: ERC20BridgeSamplerContract, callResults: string): Promise; } -export interface SourceQuoteOperation extends BatchedOperation { +export interface SourceQuoteOperation + extends BatchedOperation>> { source: ERC20BridgeSource; - fillData?: TFillData; } export interface OptimizedOrdersAndQuoteReport { diff --git a/packages/asset-swapper/test/bancor_service_test.ts b/packages/asset-swapper/test/bancor_service_test.ts new file mode 100644 index 0000000000..3c4af4450a --- /dev/null +++ b/packages/asset-swapper/test/bancor_service_test.ts @@ -0,0 +1,61 @@ +import { web3Factory, Web3ProviderEngine } from '@0x/dev-utils'; +import * as chai from 'chai'; +import * as _ from 'lodash'; +import 'mocha'; + +import { BancorFillData, BigNumber } from '../src'; +import { BancorService, token } from '../src/utils/market_operation_utils/bancor_service'; + +import { chaiSetup } from './utils/chai_setup'; + +chaiSetup.configure(); +const expect = chai.expect; + +const ADDRESS_REGEX = /^(0x)?[0-9a-f]{40}$/i; +const RPC_URL = `https://mainnet.infura.io/v3/${process.env.INFURA_PROJECT_ID}`; + +const provider: Web3ProviderEngine = web3Factory.getRpcProvider({ rpcUrl: RPC_URL }); +// tslint:disable:custom-no-magic-numbers + +// These tests test the bancor SDK against mainnet +// TODO (xianny): After we move asset-swapper out of the monorepo, we should add an env variable to circle CI to run this test +describe.skip('Bancor Service', () => { + const bancorService = new BancorService(provider); + const eth = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; + const bnt = '0x1f573d6fb3f13d689ff844b4ce37794d79a7ff1c'; + it('should retrieve the bancor network address', async () => { + const networkAddress = await bancorService.getBancorNetworkAddressAsync(); + expect(networkAddress).to.match(ADDRESS_REGEX); + }); + it('should retrieve a quote', async () => { + const amt = new BigNumber(2); + const quote = await bancorService.getQuoteAsync(eth, bnt, amt); + const fillData = quote.fillData as BancorFillData; + + // get rate from the bancor sdk + const sdk = await bancorService.getSDKAsync(); + const expectedAmt = await sdk.pricing.getRateByPath(fillData.path.map(s => token(s)), amt.toString()); + + expect(fillData.networkAddress).to.match(ADDRESS_REGEX); + expect(fillData.path).to.be.an.instanceOf(Array); + expect(fillData.path).to.have.lengthOf(3); + expect(quote.amount.dp(0)).to.bignumber.eq( + new BigNumber(expectedAmt).multipliedBy(bancorService.minReturnAmountBufferPercentage).dp(0), + ); + }); + // HACK (xianny): for exploring SDK results + it('should retrieve multiple quotes', async () => { + const amts = [1, 10, 100, 1000].map(a => new BigNumber(a).multipliedBy(10e18)); + const quotes = await Promise.all(amts.map(async amount => bancorService.getQuoteAsync(eth, bnt, amount))); + quotes.map((q, i) => { + // tslint:disable:no-console + const fillData = q.fillData as BancorFillData; + console.log( + `Input ${amts[i].toExponential()}; Output: ${q.amount}; Path: ${ + fillData.path.length + }\nPath: ${JSON.stringify(fillData.path)}`, + ); + // tslint:enable:no-console + }); + }); +}); diff --git a/packages/asset-swapper/test/dex_sampler_test.ts b/packages/asset-swapper/test/dex_sampler_test.ts index ad655d3857..9bc5465235 100644 --- a/packages/asset-swapper/test/dex_sampler_test.ts +++ b/packages/asset-swapper/test/dex_sampler_test.ts @@ -21,7 +21,9 @@ import { DexOrderSampler, getSampleAmounts } from '../src/utils/market_operation import { ERC20BridgeSource, FillData } from '../src/utils/market_operation_utils/types'; import { MockBalancerPoolsCache } from './utils/mock_balancer_pools_cache'; +import { MockBancorService } from './utils/mock_bancor_service'; import { MockSamplerContract } from './utils/mock_sampler_contract'; +import { provider } from './utils/web3_wrapper'; const CHAIN_ID = 1; // tslint:disable: custom-no-magic-numbers @@ -148,7 +150,7 @@ describe('DexSampler tests', () => { expectedTakerFillAmounts, ), ); - expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts); + expect(fillableAmounts.map(q => q.amount)).to.deep.eq(expectedMakerFillAmounts); }); it('getLiquidityProviderSellQuotes()', async () => { @@ -288,7 +290,7 @@ describe('DexSampler tests', () => { expectedTakerFillAmounts, ), ); - expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts); + expect(fillableAmounts.map(q => q.amount)).to.deep.eq(expectedMakerFillAmounts); }); it('getUniswapSellQuotes()', async () => { @@ -312,7 +314,7 @@ describe('DexSampler tests', () => { expectedTakerFillAmounts, ), ); - expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts); + expect(fillableAmounts.map(q => q.amount)).to.deep.eq(expectedMakerFillAmounts); }); it('getUniswapV2SellQuotes()', async () => { @@ -334,7 +336,7 @@ describe('DexSampler tests', () => { expectedTakerFillAmounts, ), ); - expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts); + expect(fillableAmounts.map(q => q.amount)).to.deep.eq(expectedMakerFillAmounts); }); it('getEth2DaiBuyQuotes()', async () => { @@ -358,7 +360,7 @@ describe('DexSampler tests', () => { expectedMakerFillAmounts, ), ); - expect(fillableAmounts).to.deep.eq(expectedTakerFillAmounts); + expect(fillableAmounts.map(q => q.amount)).to.deep.eq(expectedTakerFillAmounts); }); it('getUniswapBuyQuotes()', async () => { @@ -382,7 +384,7 @@ describe('DexSampler tests', () => { expectedMakerFillAmounts, ), ); - expect(fillableAmounts).to.deep.eq(expectedTakerFillAmounts); + expect(fillableAmounts.map(q => q.amount)).to.deep.eq(expectedTakerFillAmounts); }); interface RatesBySource { @@ -484,7 +486,12 @@ describe('DexSampler tests', () => { return Promise.resolve(pools); }, }); - const dexOrderSampler = new DexOrderSampler(new MockSamplerContract({}), undefined, balancerPoolsCache); + const dexOrderSampler = new DexOrderSampler( + new MockSamplerContract({}), + undefined, // sampler overrides + undefined, // bancor service + balancerPoolsCache, + ); const [quotes] = await dexOrderSampler.executeAsync( await DexOrderSampler.ops.getSellQuotesAsync( [ERC20BridgeSource.Balancer], @@ -506,7 +513,52 @@ describe('DexSampler tests', () => { expect(quotes).to.have.lengthOf(2); // one array per pool expect(quotes).to.deep.eq(expectedQuotes); }); - + it('getSellQuotes() uses samples from Bancor', async () => { + const expectedTakerToken = randomAddress(); + const expectedMakerToken = randomAddress(); + const networkAddress = randomAddress(); + const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3); + const rate = getRandomFloat(0, 100); + const bancorService = new MockBancorService(provider, { + getQuoteAsync: async (fromToken: string, toToken: string, amount: BigNumber) => { + expect(fromToken).equal(expectedTakerToken); + expect(toToken).equal(expectedMakerToken); + return Promise.resolve({ + fillData: { path: [fromToken, toToken], networkAddress }, + amount: amount.multipliedBy(rate), + }); + }, + }); + const dexOrderSampler = new DexOrderSampler( + new MockSamplerContract({}), + undefined, // sampler overrides + bancorService, + undefined, // balancer cache + ); + const [quotes] = await dexOrderSampler.executeAsync( + await DexOrderSampler.ops.getSellQuotesAsync( + [ERC20BridgeSource.Bancor], + expectedMakerToken, + expectedTakerToken, + expectedTakerFillAmounts, + wethAddress, + undefined, // balancer pools cache + undefined, // liquidity provider registry address + undefined, // multibridge address + bancorService, + ), + ); + const expectedQuotes = [ + expectedTakerFillAmounts.map(a => ({ + source: ERC20BridgeSource.Bancor, + input: a, + output: a.multipliedBy(rate), + fillData: { path: [expectedTakerToken, expectedMakerToken], networkAddress }, + })), + ]; + expect(quotes).to.have.lengthOf(1); // one set per pool + expect(quotes).to.deep.eq(expectedQuotes); + }); it('getBuyQuotes()', async () => { const expectedTakerToken = randomAddress(); const expectedMakerToken = randomAddress(); @@ -590,7 +642,12 @@ describe('DexSampler tests', () => { return Promise.resolve(pools); }, }); - const dexOrderSampler = new DexOrderSampler(new MockSamplerContract({}), undefined, balancerPoolsCache); + const dexOrderSampler = new DexOrderSampler( + new MockSamplerContract({}), + undefined, // sampler overrides + undefined, // bancor service + balancerPoolsCache, + ); const [quotes] = await dexOrderSampler.executeAsync( await DexOrderSampler.ops.getBuyQuotesAsync( [ERC20BridgeSource.Balancer], diff --git a/packages/asset-swapper/test/market_operation_utils_test.ts b/packages/asset-swapper/test/market_operation_utils_test.ts index efba5220e7..7ed3d87255 100644 --- a/packages/asset-swapper/test/market_operation_utils_test.ts +++ b/packages/asset-swapper/test/market_operation_utils_test.ts @@ -288,6 +288,7 @@ describe('MarketOperationUtils tests', () => { [ERC20BridgeSource.Uniswap]: createDecreasingRates(NUM_SAMPLES), [ERC20BridgeSource.UniswapV2]: _.times(NUM_SAMPLES, () => 0), [ERC20BridgeSource.Balancer]: _.times(NUM_SAMPLES, () => 0), + [ERC20BridgeSource.Bancor]: _.times(NUM_SAMPLES, () => 0), [ERC20BridgeSource.Curve]: _.times(NUM_SAMPLES, () => 0), [ERC20BridgeSource.LiquidityProvider]: _.times(NUM_SAMPLES, () => 0), [ERC20BridgeSource.MultiBridge]: _.times(NUM_SAMPLES, () => 0), @@ -301,6 +302,7 @@ describe('MarketOperationUtils tests', () => { const DEFAULT_FILL_DATA: FillDataBySource = { [ERC20BridgeSource.UniswapV2]: { tokenAddressPath: [] }, [ERC20BridgeSource.Balancer]: { poolAddress: randomAddress() }, + [ERC20BridgeSource.Bancor]: { path: [], networkAddress: randomAddress() }, [ERC20BridgeSource.Curve]: { curve: { poolAddress: randomAddress(), diff --git a/packages/asset-swapper/test/utils/mock_bancor_service.ts b/packages/asset-swapper/test/utils/mock_bancor_service.ts new file mode 100644 index 0000000000..5952301190 --- /dev/null +++ b/packages/asset-swapper/test/utils/mock_bancor_service.ts @@ -0,0 +1,24 @@ +import { BigNumber } from '@0x/utils'; + +import { SupportedProvider } from '../../src'; +import { BancorService } from '../../src/utils/market_operation_utils/bancor_service'; +import { BancorFillData, Quote } from '../../src/utils/market_operation_utils/types'; + +export interface Handlers { + getQuoteAsync: (fromToken: string, toToken: string, amount: BigNumber) => Promise>; +} + +export class MockBancorService extends BancorService { + // Bancor recommends setting this value to 2% under the expected return amount + public minReturnAmountBufferPercentage = 0.98; + + constructor(provider: SupportedProvider, public handlers: Partial) { + super(provider); + } + + public async getQuoteAsync(fromToken: string, toToken: string, amount: BigNumber): Promise> { + return this.handlers.getQuoteAsync + ? this.handlers.getQuoteAsync(fromToken, toToken, amount) + : super.getQuoteAsync(fromToken, toToken, amount); + } +} diff --git a/packages/contract-addresses/CHANGELOG.json b/packages/contract-addresses/CHANGELOG.json index 1e751cf678..ee3c6944aa 100644 --- a/packages/contract-addresses/CHANGELOG.json +++ b/packages/contract-addresses/CHANGELOG.json @@ -18,6 +18,10 @@ "note": "Redeploy previously unverified contracts on testnets", "pr": 2656 }, + { + "note": "Deploy `BancorBridge` on Mainnet", + "pr": 2650 + }, { "note": "Deploy FQT", "pr": 2667 diff --git a/packages/contract-addresses/addresses.json b/packages/contract-addresses/addresses.json index c4ecda434f..621afcfa12 100644 --- a/packages/contract-addresses/addresses.json +++ b/packages/contract-addresses/addresses.json @@ -34,6 +34,7 @@ "dexForwarderBridge": "0xc47b7094f378e54347e281aab170e8cca69d880a", "multiBridge": "0xc03117a8c9bde203f70aa911cb64a7a0df5ba1e1", "balancerBridge": "0xfe01821ca163844203220cd08e4f2b2fb43ae4e4", + "bancorBridge": "0x0000000000000000000000000000000000000000", "exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e", "exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff", "exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb", @@ -82,6 +83,7 @@ "dexForwarderBridge": "0x3261ea1411a1a840aed708896f779e1b837c917e", "multiBridge": "0x0000000000000000000000000000000000000000", "balancerBridge": "0x47697b44bd89051e93b4d5857ba8e024800a74ac", + "bancorBridge": "0x0000000000000000000000000000000000000000", "exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e", "exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff", "exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb", @@ -130,6 +132,7 @@ "dexForwarderBridge": "0x0000000000000000000000000000000000000000", "multiBridge": "0x0000000000000000000000000000000000000000", "balancerBridge": "0x5d8c9ba74607d2cbc4176882a42d4ace891c1c00", + "bancorBridge": "0x0000000000000000000000000000000000000000", "exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e", "exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff", "exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb", @@ -178,6 +181,7 @@ "dexForwarderBridge": "0x985d1a95c6a86a3bf85c4d425af984abceaf01de", "multiBridge": "0x0000000000000000000000000000000000000000", "balancerBridge": "0x407b4128e9ecad8769b2332312a9f655cb9f5f3a", + "bancorBridge": "0x0000000000000000000000000000000000000000", "exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e", "exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff", "exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb", @@ -226,6 +230,7 @@ "dexForwarderBridge": "0x0000000000000000000000000000000000000000", "multiBridge": "0x0000000000000000000000000000000000000000", "balancerBridge": "0x0000000000000000000000000000000000000000", + "bancorBridge": "0x0000000000000000000000000000000000000000", "exchangeProxyGovernor": "0x0000000000000000000000000000000000000000", "exchangeProxy": "0x5315e44798395d4a952530d131249fe00f554565", "exchangeProxyAllowanceTarget": "0x8362c3ebd90041b30ec45908332e592721642637", diff --git a/packages/contract-addresses/src/index.ts b/packages/contract-addresses/src/index.ts index d2593d04a0..68e99dc4d4 100644 --- a/packages/contract-addresses/src/index.ts +++ b/packages/contract-addresses/src/index.ts @@ -35,6 +35,7 @@ export interface ContractAddresses { dexForwarderBridge: string; multiBridge: string; balancerBridge: string; + bancorBridge: string; exchangeProxyGovernor: string; exchangeProxy: string; exchangeProxyAllowanceTarget: string; diff --git a/packages/migrations/CHANGELOG.json b/packages/migrations/CHANGELOG.json index e2b39f9841..7430065450 100644 --- a/packages/migrations/CHANGELOG.json +++ b/packages/migrations/CHANGELOG.json @@ -9,6 +9,10 @@ { "note": "Refactor `migration.ts` a little", "pr": 2656 + }, + { + "note": "Add bancorBridge to addresses", + "pr": 2650 } ] }, diff --git a/packages/migrations/src/migration.ts b/packages/migrations/src/migration.ts index 9ffb30af57..9d7014266f 100644 --- a/packages/migrations/src/migration.ts +++ b/packages/migrations/src/migration.ts @@ -405,6 +405,7 @@ export async function runMigrationsAsync( dexForwarderBridge: NULL_ADDRESS, multiBridge: NULL_ADDRESS, balancerBridge: NULL_ADDRESS, + bancorBridge: NULL_ADDRESS, exchangeProxyGovernor: NULL_ADDRESS, mStableBridge: NULL_ADDRESS, exchangeProxy: exchangeProxy.address, diff --git a/yarn.lock b/yarn.lock index 00129a7803..113f56f24e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -751,7 +751,6 @@ "@0x/quote-server@^2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@0x/quote-server/-/quote-server-2.0.2.tgz#60d0665c1cad378c9abb89b5491bdc55b4c8412c" - integrity sha512-ScK8lHj2AN0RaEjSYplnxsABGy30j6bATG3GjmGMWOx5Bmj2X6UGHpD2ZJ0UH+oJqyDHyZ31vgpMbCSlBLFlzQ== dependencies: "@0x/json-schemas" "^5.0.7" "@0x/order-utils" "^10.2.4" @@ -1003,6 +1002,12 @@ dependencies: regenerator-runtime "^0.12.0" +"@babel/runtime@7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.0.tgz#4fc1d642a9fd0299754e8b5de62c631cf5568205" + dependencies: + regenerator-runtime "^0.13.2" + "@babel/runtime@^7.1.5", "@babel/runtime@^7.3.1": version "7.5.5" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132" @@ -1050,13 +1055,23 @@ "@balancer-labs/sor@0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-0.3.2.tgz#b05c63a07031c2ea13ed0d2670f5105cfaa40523" - integrity sha512-wmYmTm/zhnRPd/OaqzJJGo9mRIp4PvNNS/AG0EVWJmLmZvYkm2sl6/dBL3KC88rub9duVQr2M8BHCosseFuGLw== dependencies: bignumber.js "^9.0.0" ethers "^4.0.39" isomorphic-fetch "^2.2.1" typescript "^3.8.3" +"@bancor/sdk@^0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@bancor/sdk/-/sdk-0.2.5.tgz#dda2d6a91bc130684d83e5d395c00677cd0fdd71" + dependencies: + "@types/text-encoding" "0.0.35" + decimal.js "^10.2.0" + eosjs "^20.0.3" + node-fetch "^2.6.0" + web3 "1.2.1" + web3-typescript-typings "^0.10.2" + "@cnakazawa/watch@^1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef" @@ -1997,7 +2012,6 @@ "@types/bignumber.js@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@types/bignumber.js/-/bignumber.js-5.0.0.tgz#d9f1a378509f3010a3255e9cc822ad0eeb4ab969" - integrity sha512-0DH7aPGCClywOFaxxjE6UwpN2kQYe9LwuDQMv+zYA97j5GkOMo8e66LYT+a8JYU7jfmUFRZLa9KycxHDsKXJCA== dependencies: bignumber.js "*" @@ -2022,7 +2036,6 @@ "@types/body-parser@*": version "1.19.0" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" - integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ== dependencies: "@types/connect" "*" "@types/node" "*" @@ -2034,7 +2047,6 @@ "@types/connect@*": version "3.4.33" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" - integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== dependencies: "@types/node" "*" @@ -2079,7 +2091,6 @@ "@types/express-serve-static-core@*": version "4.17.7" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.7.tgz#dfe61f870eb549dc6d7e12050901847c7d7e915b" - integrity sha512-EMgTj/DF9qpgLXyc+Btimg+XoH7A2liE8uKul8qSmMTHCeNYzydDKFdsJskDvw42UsesCnhO63dO0Grbj8J4Dw== dependencies: "@types/node" "*" "@types/qs" "*" @@ -2088,7 +2099,6 @@ "@types/express@^4.17.3": version "4.17.6" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.6.tgz#6bce49e49570507b86ea1b07b806f04697fac45e" - integrity sha512-n/mr9tZI83kd4azlPG5y997C/M4DNABK9yErhFM6hKdym4kkmd9j0vtsJyjFIwfRBxtrxZtAfGZCNRIBMFLK5w== dependencies: "@types/body-parser" "*" "@types/express-serve-static-core" "*" @@ -2187,7 +2197,6 @@ "@types/mime@*": version "2.0.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.2.tgz#857a118d8634c84bba7ae14088e4508490cd5da5" - integrity sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q== "@types/minimatch@*", "@types/minimatch@3.0.3", "@types/minimatch@^3.0.3": version "3.0.3" @@ -2238,7 +2247,6 @@ "@types/qs@*": version "6.9.3" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.3.tgz#b755a0934564a200d3efdf88546ec93c369abd03" - integrity sha512-7s9EQWupR1fTc2pSMtXRQ9w9gLOcrJn+h7HOXw4evxyvVqMi4f+q7d2tnFe3ng3SNHjtK+0EzGMGFUQX4/AQRA== "@types/query-string@^5.1.0": version "5.1.0" @@ -2247,7 +2255,6 @@ "@types/range-parser@*": version "1.2.3" resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" - integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== "@types/react-dom@16.0.6": version "16.0.6" @@ -2298,7 +2305,6 @@ "@types/serve-static@*": version "1.13.4" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.4.tgz#6662a93583e5a6cabca1b23592eb91e12fa80e7c" - integrity sha512-jTDt0o/YbpNwZbQmE/+2e+lfjJEJJR0I3OFaKQKPWkASkCoW3i6fsUnqudSMcNAfbtmADGu8f4MV4q+GqULmug== dependencies: "@types/express-serve-static-core" "*" "@types/mime" "*" @@ -2323,6 +2329,10 @@ "@types/react" "*" csstype "^2.2.0" +"@types/text-encoding@0.0.35": + version "0.0.35" + resolved "https://registry.yarnpkg.com/@types/text-encoding/-/text-encoding-0.0.35.tgz#6f14474e0b232bc70c59677aadc65dcc5a99c3a9" + "@types/tmp@^0.0.33": version "0.0.33" resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.0.33.tgz#1073c4bc824754ae3d10cfab88ab0237ba964e4d" @@ -2375,7 +2385,6 @@ "@web3-js/scrypt-shim@^0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@web3-js/scrypt-shim/-/scrypt-shim-0.1.0.tgz#0bf7529ab6788311d3e07586f7d89107c3bea2cc" - integrity sha512-ZtZeWCc/s0nMcdx/+rZwY1EcuRdemOK9ag21ty9UsHkFxsNb/AaoucUz0iPuyGe0Ku+PFuRmWZG7Z7462p9xPw== dependencies: scryptsy "^2.1.0" semver "^6.3.0" @@ -2383,7 +2392,6 @@ "@web3-js/websocket@^1.0.29": version "1.0.30" resolved "https://registry.yarnpkg.com/@web3-js/websocket/-/websocket-1.0.30.tgz#9ea15b7b582cf3bf3e8bc1f4d3d54c0731a87f87" - integrity sha512-fDwrD47MiDrzcJdSeTLF75aCcxVVt8B1N74rA+vh2XCAvFy4tEWJjtnUtj2QG7/zlQ6g9cQ88bZFBxwd9/FmtA== dependencies: debug "^2.2.0" es5-ext "^0.10.50" @@ -2588,7 +2596,6 @@ accepts@~1.3.4, accepts@~1.3.5: accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== dependencies: mime-types "~2.1.24" negotiator "0.6.2" @@ -3787,7 +3794,7 @@ babel-register@^6.26.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: +babel-runtime@6.26.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: @@ -3916,6 +3923,10 @@ big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" +bigi@1.4.2, bigi@^1.1.0: + version "1.4.2" + resolved "https://registry.yarnpkg.com/bigi/-/bigi-1.4.2.tgz#9c665a95f88b8b08fc05cfd731f561859d725825" + bignumber.js@*, bignumber.js@^9.0.0, bignumber.js@~9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075" @@ -4171,6 +4182,16 @@ browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" +browserify-aes@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a" + dependencies: + buffer-xor "^1.0.2" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + inherits "^2.0.1" + browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.0.6: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" @@ -4249,16 +4270,16 @@ bs-logger@0.x: dependencies: fast-json-stable-stringify "^2.0.0" -bs58@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-2.0.1.tgz#55908d58f1982aba2008fa1bed8f91998a29bf8d" - -bs58@^4.0.0: +bs58@4.0.1, bs58@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" dependencies: base-x "^3.0.2" +bs58@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-2.0.1.tgz#55908d58f1982aba2008fa1bed8f91998a29bf8d" + bs58check@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" @@ -4301,7 +4322,7 @@ buffer-to-arraybuffer@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" -buffer-xor@^1.0.3: +buffer-xor@^1.0.2, buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" @@ -4373,6 +4394,12 @@ byte-size@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-5.0.1.tgz#4b651039a5ecd96767e71a3d7ed380e48bed4191" +bytebuffer@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/bytebuffer/-/bytebuffer-5.0.1.tgz#582eea4b1a873b6d020a48d58df85f0bba6cfddd" + dependencies: + long "~3" + bytes@3.0.0, bytes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -5198,7 +5225,6 @@ content-disposition@0.5.2: content-disposition@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" - integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== dependencies: safe-buffer "5.1.2" @@ -5379,7 +5405,6 @@ cookie@0.3.1: cookie@0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" - integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== cookiejar@^2.1.1: version "2.1.2" @@ -5498,6 +5523,15 @@ create-error-class@^3.0.0: dependencies: capture-stack-trace "^1.0.0" +create-hash@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + ripemd160 "^2.0.0" + sha.js "^2.4.0" + create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" @@ -5508,6 +5542,17 @@ create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2: ripemd160 "^2.0.1" sha.js "^2.4.0" +create-hmac@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: version "1.1.7" resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" @@ -6264,6 +6309,12 @@ ecc-jsbn@~0.1.1: dependencies: jsbn "~0.1.0" +ecurve@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/ecurve/-/ecurve-1.0.5.tgz#d148e8fe50a674f983bb5bae09da0ea23e10535e" + dependencies: + bigi "^1.1.0" + editor@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" @@ -6296,7 +6347,6 @@ elliptic@6.3.3: elliptic@6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" - integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw== dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -6426,6 +6476,28 @@ enzyme@^3.6.0: rst-selector-parser "^2.2.3" string.prototype.trim "^1.1.2" +eosjs-ecc@4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eosjs-ecc/-/eosjs-ecc-4.0.7.tgz#f5246da3b84839fcc237204768ef6e5ea56cc814" + dependencies: + "@babel/runtime" "7.6.0" + bigi "1.4.2" + browserify-aes "1.0.6" + bs58 "4.0.1" + bytebuffer "5.0.1" + create-hash "1.1.3" + create-hmac "1.1.6" + ecurve "1.0.5" + randombytes "2.0.5" + +eosjs@^20.0.3: + version "20.0.3" + resolved "https://registry.yarnpkg.com/eosjs/-/eosjs-20.0.3.tgz#f3ac1fa119b76dd07bf2825ad27342f6502a533b" + dependencies: + babel-runtime "6.26.0" + eosjs-ecc "4.0.7" + text-encoding "0.7.0" + err-code@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" @@ -6833,7 +6905,6 @@ ethashjs@~0.0.7: ethereum-bloom-filters@^1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.7.tgz#b7b80735e385dbb7f944ce6b4533e24511306060" - integrity sha512-cDcJJSJ9GMAcURiAWO3DxIEhTL/uWqlQnvgKpuYQzYPrt/izuGU+1ntQmHt0IRq6ADoSYHFnB+aCEFIldjhkMQ== dependencies: js-sha3 "^0.8.0" @@ -6898,7 +6969,6 @@ ethereumjs-account@^2.0.3: ethereumjs-block@2.2.2, ethereumjs-block@^2.2.2, ethereumjs-block@~2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz#c7654be7e22df489fda206139ecd63e2e9c04965" - integrity sha512-2p49ifhek3h2zeg/+da6XpdFR3GlqY3BIEiqxGF8j9aSRIgkb7M1Ky+yULBKJOu8PAZxfhsYA+HxUk2aCQp3vg== dependencies: async "^2.0.1" ethereumjs-common "^1.5.0" @@ -6944,7 +7014,6 @@ ethereumjs-blockchain@^4.0.1: ethereumjs-blockchain@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/ethereumjs-blockchain/-/ethereumjs-blockchain-4.0.3.tgz#e013034633a30ad2006728e8e2b21956b267b773" - integrity sha512-0nJWbyA+Gu0ZKZr/cywMtB/77aS/4lOVsIKbgUN2sFQYscXO5rPbUfrEe7G2Zhjp86/a0VqLllemDSTHvx3vZA== dependencies: async "^2.6.1" ethashjs "~0.0.7" @@ -6980,7 +7049,6 @@ ethereumjs-common@^1.3.0: ethereumjs-tx@2.1.2, ethereumjs-tx@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed" - integrity sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw== dependencies: ethereumjs-common "^1.5.0" ethereumjs-util "^6.0.0" @@ -7055,7 +7123,6 @@ ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereum ethereumjs-vm@4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-4.1.3.tgz#dc8eb45f47d775da9f0b2437d5e20896fdf66f37" - integrity sha512-RTrD0y7My4O6Qr1P2ZIsMfD6RzL6kU/RhBZ0a5XrPzAeR61crBS7or66ohDrvxDI/rDBxMi+6SnsELih6fzalw== dependencies: async "^2.1.2" async-eventemitter "^0.2.2" @@ -7141,7 +7208,6 @@ ethers@4.0.0-beta.3: ethers@^4.0.39: version "4.0.47" resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.47.tgz#91b9cd80473b1136dd547095ff9171bd1fc68c85" - integrity sha512-hssRYhngV4hiDNeZmVU/k5/E8xmLG8UpcNUzg6mb7lqhgpFPH/t7nuv20RjRrEf0gblzvi2XwR5Te+V3ZFc9pQ== dependencies: aes-js "3.0.0" bn.js "^4.4.0" @@ -7455,7 +7521,6 @@ express@^4.16.3: express@^4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" - integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== dependencies: accepts "~1.3.7" array-flatten "1.1.1" @@ -7774,7 +7839,6 @@ finalhandler@1.1.1: finalhandler@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== dependencies: debug "2.6.9" encodeurl "~1.0.2" @@ -8159,7 +8223,6 @@ ganache-cli@6.8.0-istanbul.0: ganache-core@^2.10.2: version "2.10.2" resolved "https://registry.yarnpkg.com/ganache-core/-/ganache-core-2.10.2.tgz#17c171c6c0195b6734a0dd741a9d2afd4f74e292" - integrity sha512-4XEO0VsqQ1+OW7Za5fQs9/Kk7o8M0T1sRfFSF8h9NeJ2ABaqMO5waqxf567ZMcSkRKaTjUucBSz83xNfZv1HDg== dependencies: abstract-leveldown "3.0.0" async "2.6.2" @@ -9026,7 +9089,6 @@ http-errors@1.7.2: http-errors@~1.7.2: version "1.7.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" - integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== dependencies: depd "~1.1.2" inherits "2.0.4" @@ -9088,7 +9150,6 @@ http-status-codes@^1.3.0, http-status-codes@^1.3.2: http-status-codes@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-1.4.0.tgz#6e4c15d16ff3a9e2df03b89f3a55e1aae05fb477" - integrity sha512-JrT3ua+WgH8zBD3HEJYbeEgnuQaAnUeRRko/YojPAJjGmIfGD3KPU/asLdsLwKjfxOmQe5nXMQ0pt/7MyapVbQ== https-browserify@^1.0.0: version "1.0.0" @@ -9369,7 +9430,6 @@ ipaddr.js@1.8.0: ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== ipaddr.js@^1.5.2: version "1.8.1" @@ -10648,7 +10708,6 @@ js-sha3@^0.7.0: js-sha3@^0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" @@ -11467,6 +11526,10 @@ lolex@^2.2.0, lolex@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/lolex/-/lolex-2.3.2.tgz#85f9450425103bf9e7a60668ea25dc43274ca807" +long@~3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" + looper@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/looper/-/looper-2.0.0.tgz#66cd0c774af3d4fedac53794f742db56da8f09ec" @@ -12267,7 +12330,6 @@ negotiator@0.6.1: negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== neo-async@^2.5.0: version "2.5.1" @@ -12347,7 +12409,7 @@ node-fetch@^1.0.1, node-fetch@^1.3.3, node-fetch@~1.7.1: encoding "^0.1.11" is-stream "^1.0.1" -node-fetch@^2.3.0, node-fetch@^2.5.0: +node-fetch@^2.3.0, node-fetch@^2.5.0, node-fetch@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" @@ -13365,7 +13427,6 @@ parseurl@~1.3.2: parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== pascal-case@^2.0.0: version "2.0.1" @@ -13859,7 +13920,6 @@ proxy-addr@~2.0.4: proxy-addr@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" - integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== dependencies: forwarded "~0.1.2" ipaddr.js "1.9.1" @@ -14097,6 +14157,12 @@ randomatic@^1.1.3: is-number "^3.0.0" kind-of "^4.0.0" +randombytes@2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79" + dependencies: + safe-buffer "^5.1.0" + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" @@ -14127,7 +14193,6 @@ range-parser@^1.0.3, range-parser@~1.2.0: range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== raw-body@2.3.2: version "2.3.2" @@ -15047,17 +15112,16 @@ scrypt@^6.0.2: dependencies: nan "^2.0.8" +scryptsy@2.1.0, scryptsy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790" + scryptsy@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" dependencies: pbkdf2 "^3.0.3" -scryptsy@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790" - integrity sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w== - secp256k1@^3.0.1: version "3.5.0" resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.5.0.tgz#677d3b8a8e04e1a5fa381a1ae437c54207b738d0" @@ -15138,6 +15202,10 @@ semver-sort@0.0.4: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" +semver@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" + semver@^5.5.1: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" @@ -15175,7 +15243,6 @@ send@0.16.2: send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" - integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== dependencies: debug "2.6.9" depd "~1.1.2" @@ -15230,7 +15297,6 @@ serve-static@1.13.2: serve-static@1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" - integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" @@ -16349,6 +16415,10 @@ test-exclude@^5.2.3: read-pkg-up "^4.0.0" require-main-filename "^2.0.0" +text-encoding@0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.7.0.tgz#f895e836e45990624086601798ea98e8f36ee643" + text-encoding@^0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19" @@ -16843,7 +16913,6 @@ typescript@3.5.x: typescript@^3.8.3: version "3.9.6" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.6.tgz#8f3e0198a34c3ae17091b35571d3afd31999365a" - integrity sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw== typewise-core@^1.2, typewise-core@^1.2.0: version "1.2.0" @@ -17362,10 +17431,17 @@ wcwidth@^1.0.0: dependencies: defaults "^1.0.3" +web3-bzz@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.1.tgz#c3bd1e8f0c02a13cd6d4e3c3e9e1713f144f6f0d" + dependencies: + got "9.6.0" + swarm-js "0.1.39" + underscore "1.9.1" + web3-bzz@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.4.tgz#a4adb7a8cba3d260de649bdb1f14ed359bfb3821" - integrity sha512-MqhAo/+0iQSMBtt3/QI1rU83uvF08sYq8r25+OUZ+4VtihnYsmkkca+rdU0QbRyrXY2/yGIpI46PFdh0khD53A== dependencies: "@types/node" "^10.12.18" got "9.6.0" @@ -17380,10 +17456,17 @@ web3-core-helpers@1.0.0-beta.34: web3-eth-iban "1.0.0-beta.34" web3-utils "1.0.0-beta.34" +web3-core-helpers@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz#f5f32d71c60a4a3bd14786118e633ce7ca6d5d0d" + dependencies: + underscore "1.9.1" + web3-eth-iban "1.2.1" + web3-utils "1.2.1" + web3-core-helpers@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.4.tgz#ffd425861f4d66b3f38df032afdb39ea0971fc0f" - integrity sha512-U7wbsK8IbZvF3B7S+QMSNP0tni/6VipnJkB0tZVEpHEIV2WWeBHYmZDnULWcsS/x/jn9yKhJlXIxWGsEAMkjiw== dependencies: underscore "1.9.1" web3-eth-iban "1.2.4" @@ -17399,10 +17482,19 @@ web3-core-helpers@2.0.0-alpha: web3-eth-iban "2.0.0-alpha" web3-utils "2.0.0-alpha" +web3-core-method@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.1.tgz#9df1bafa2cd8be9d9937e01c6a47fc768d15d90a" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.1" + web3-core-promievent "1.2.1" + web3-core-subscriptions "1.2.1" + web3-utils "1.2.1" + web3-core-method@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.4.tgz#a0fbc50b8ff5fd214021435cc2c6d1e115807aed" - integrity sha512-8p9kpL7di2qOVPWgcM08kb+yKom0rxRCMv6m/K+H+yLSxev9TgMbCgMSbPWAHlyiF3SJHw7APFKahK5Z+8XT5A== dependencies: underscore "1.9.1" web3-core-helpers "1.2.4" @@ -17423,18 +17515,33 @@ web3-core-method@2.0.0-alpha: web3-core-subscriptions "2.0.0-alpha" web3-utils "2.0.0-alpha" -web3-core-promievent@1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.4.tgz#75e5c0f2940028722cdd21ba503ebd65272df6cb" - integrity sha512-gEUlm27DewUsfUgC3T8AxkKi8Ecx+e+ZCaunB7X4Qk3i9F4C+5PSMGguolrShZ7Zb6717k79Y86f3A00O0VAZw== +web3-core-promievent@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.1.tgz#003e8a3eb82fb27b6164a6d5b9cad04acf733838" dependencies: any-promise "1.3.0" eventemitter3 "3.1.2" +web3-core-promievent@1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.4.tgz#75e5c0f2940028722cdd21ba503ebd65272df6cb" + dependencies: + any-promise "1.3.0" + eventemitter3 "3.1.2" + +web3-core-requestmanager@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.1.tgz#fa2e2206c3d738db38db7c8fe9c107006f5c6e3d" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.1" + web3-providers-http "1.2.1" + web3-providers-ipc "1.2.1" + web3-providers-ws "1.2.1" + web3-core-requestmanager@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.4.tgz#0a7020a23fb91c6913c611dfd3d8c398d1e4b4a8" - integrity sha512-eZJDjyNTDtmSmzd3S488nR/SMJtNnn/GuwxnMh3AzYCqG3ZMfOylqTad2eYJPvc2PM5/Gj1wAMQcRpwOjjLuPg== dependencies: underscore "1.9.1" web3-core-helpers "1.2.4" @@ -17442,10 +17549,17 @@ web3-core-requestmanager@1.2.4: web3-providers-ipc "1.2.4" web3-providers-ws "1.2.4" +web3-core-subscriptions@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.1.tgz#8c2368a839d4eec1c01a4b5650bbeb82d0e4a099" + dependencies: + eventemitter3 "3.1.2" + underscore "1.9.1" + web3-core-helpers "1.2.1" + web3-core-subscriptions@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.4.tgz#0dc095b5cfd82baa527a39796e3515a846b21b99" - integrity sha512-3D607J2M8ymY9V+/WZq4MLlBulwCkwEjjC2U+cXqgVO1rCyVqbxZNCmHyNYHjDDCxSEbks9Ju5xqJxDSxnyXEw== dependencies: eventemitter3 "3.1.2" underscore "1.9.1" @@ -17459,10 +17573,18 @@ web3-core-subscriptions@2.0.0-alpha: eventemitter3 "^3.1.0" lodash "^4.17.11" +web3-core@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.1.tgz#7278b58fb6495065e73a77efbbce781a7fddf1a9" + dependencies: + web3-core-helpers "1.2.1" + web3-core-method "1.2.1" + web3-core-requestmanager "1.2.1" + web3-utils "1.2.1" + web3-core@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.4.tgz#2df13b978dcfc59c2abaa887d27f88f21ad9a9d6" - integrity sha512-CHc27sMuET2cs1IKrkz7xzmTdMfZpYswe7f0HcuyneTwS1yTlTnHyqjAaTy0ZygAb/x4iaVox+Gvr4oSAqSI+A== dependencies: "@types/bignumber.js" "^5.0.0" "@types/bn.js" "^4.11.4" @@ -17484,10 +17606,17 @@ web3-core@2.0.0-alpha: web3-providers "2.0.0-alpha" web3-utils "2.0.0-alpha" +web3-eth-abi@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.1.tgz#9b915b1c9ebf82f70cca631147035d5419064689" + dependencies: + ethers "4.0.0-beta.3" + underscore "1.9.1" + web3-utils "1.2.1" + web3-eth-abi@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.4.tgz#5b73e5ef70b03999227066d5d1310b168845e2b8" - integrity sha512-8eLIY4xZKoU3DSVu1pORluAw9Ru0/v4CGdw5so31nn+7fR8zgHMgwbFe0aOqWQ5VU42PzMMXeIJwt4AEi2buFg== dependencies: ethers "4.0.0-beta.3" underscore "1.9.1" @@ -17502,10 +17631,25 @@ web3-eth-abi@^1.0.0-beta.24: web3-core-helpers "1.0.0-beta.34" web3-utils "1.0.0-beta.34" +web3-eth-accounts@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.1.tgz#2741a8ef337a7219d57959ac8bd118b9d68d63cf" + dependencies: + any-promise "1.3.0" + crypto-browserify "3.12.0" + eth-lib "0.2.7" + scryptsy "2.1.0" + semver "6.2.0" + underscore "1.9.1" + uuid "3.3.2" + web3-core "1.2.1" + web3-core-helpers "1.2.1" + web3-core-method "1.2.1" + web3-utils "1.2.1" + web3-eth-accounts@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.4.tgz#ada6edc49542354328a85cafab067acd7f88c288" - integrity sha512-04LzT/UtWmRFmi4hHRewP5Zz43fWhuHiK5XimP86sUQodk/ByOkXQ3RoXyGXFMNoRxdcAeRNxSfA2DpIBc9xUw== dependencies: "@web3-js/scrypt-shim" "^0.1.0" any-promise "1.3.0" @@ -17520,10 +17664,22 @@ web3-eth-accounts@1.2.4: web3-core-method "1.2.4" web3-utils "1.2.4" +web3-eth-contract@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.1.tgz#3542424f3d341386fd9ff65e78060b85ac0ea8c4" + dependencies: + underscore "1.9.1" + web3-core "1.2.1" + web3-core-helpers "1.2.1" + web3-core-method "1.2.1" + web3-core-promievent "1.2.1" + web3-core-subscriptions "1.2.1" + web3-eth-abi "1.2.1" + web3-utils "1.2.1" + web3-eth-contract@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.4.tgz#68ef7cc633232779b0a2c506a810fbe903575886" - integrity sha512-b/9zC0qjVetEYnzRA1oZ8gF1OSSUkwSYi5LGr4GeckLkzXP7osEnp9lkO/AQcE4GpG+l+STnKPnASXJGZPgBRQ== dependencies: "@types/bn.js" "^4.11.4" underscore "1.9.1" @@ -17535,10 +17691,22 @@ web3-eth-contract@1.2.4: web3-eth-abi "1.2.4" web3-utils "1.2.4" +web3-eth-ens@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.1.tgz#a0e52eee68c42a8b9865ceb04e5fb022c2d971d5" + dependencies: + eth-ens-namehash "2.0.8" + underscore "1.9.1" + web3-core "1.2.1" + web3-core-helpers "1.2.1" + web3-core-promievent "1.2.1" + web3-eth-abi "1.2.1" + web3-eth-contract "1.2.1" + web3-utils "1.2.1" + web3-eth-ens@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.4.tgz#b95b3aa99fb1e35c802b9e02a44c3046a3fa065e" - integrity sha512-g8+JxnZlhdsCzCS38Zm6R/ngXhXzvc3h7bXlxgKU4coTzLLoMpgOAEz71GxyIJinWTFbLXk/WjNY0dazi9NwVw== dependencies: eth-ens-namehash "2.0.8" underscore "1.9.1" @@ -17556,10 +17724,16 @@ web3-eth-iban@1.0.0-beta.34: bn.js "4.11.6" web3-utils "1.0.0-beta.34" +web3-eth-iban@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.1.tgz#2c3801718946bea24e9296993a975c80b5acf880" + dependencies: + bn.js "4.11.8" + web3-utils "1.2.1" + web3-eth-iban@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.4.tgz#8e0550fd3fd8e47a39357d87fe27dee9483ee476" - integrity sha512-D9HIyctru/FLRpXakRwmwdjb5bWU2O6UE/3AXvRm6DCOf2e+7Ve11qQrPtaubHfpdW3KWjDKvlxV9iaFv/oTMQ== dependencies: bn.js "4.11.8" web3-utils "1.2.4" @@ -17572,10 +17746,19 @@ web3-eth-iban@2.0.0-alpha: bn.js "4.11.8" web3-utils "2.0.0-alpha" +web3-eth-personal@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.1.tgz#244e9911b7b482dc17c02f23a061a627c6e47faf" + dependencies: + web3-core "1.2.1" + web3-core-helpers "1.2.1" + web3-core-method "1.2.1" + web3-net "1.2.1" + web3-utils "1.2.1" + web3-eth-personal@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.4.tgz#3224cca6851c96347d9799b12c1b67b2a6eb232b" - integrity sha512-5Russ7ZECwHaZXcN3DLuLS7390Vzgrzepl4D87SD6Sn1DHsCZtvfdPIYwoTmKNp69LG3mORl7U23Ga5YxqkICw== dependencies: "@types/node" "^12.6.1" web3-core "1.2.4" @@ -17584,10 +17767,27 @@ web3-eth-personal@1.2.4: web3-net "1.2.4" web3-utils "1.2.4" +web3-eth@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.1.tgz#b9989e2557c73a9e8ffdc107c6dafbe72c79c1b0" + dependencies: + underscore "1.9.1" + web3-core "1.2.1" + web3-core-helpers "1.2.1" + web3-core-method "1.2.1" + web3-core-subscriptions "1.2.1" + web3-eth-abi "1.2.1" + web3-eth-accounts "1.2.1" + web3-eth-contract "1.2.1" + web3-eth-ens "1.2.1" + web3-eth-iban "1.2.1" + web3-eth-personal "1.2.1" + web3-net "1.2.1" + web3-utils "1.2.1" + web3-eth@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.4.tgz#24c3b1f1ac79351bbfb808b2ab5c585fa57cdd00" - integrity sha512-+j+kbfmZsbc3+KJpvHM16j1xRFHe2jBAniMo1BHKc3lho6A8Sn9Buyut6odubguX2AxoRArCdIDCkT9hjUERpA== dependencies: underscore "1.9.1" web3-core "1.2.4" @@ -17603,10 +17803,17 @@ web3-eth@1.2.4: web3-net "1.2.4" web3-utils "1.2.4" +web3-net@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.1.tgz#edd249503315dd5ab4fa00220f6509d95bb7ab10" + dependencies: + web3-core "1.2.1" + web3-core-method "1.2.1" + web3-utils "1.2.1" + web3-net@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.4.tgz#1d246406d3aaffbf39c030e4e98bce0ca5f25458" - integrity sha512-wKOsqhyXWPSYTGbp7ofVvni17yfRptpqoUdp3SC8RAhDmGkX6irsiT9pON79m6b3HUHfLoBilFQyt/fTUZOf7A== dependencies: web3-core "1.2.4" web3-core-method "1.2.4" @@ -17687,27 +17894,47 @@ web3-provider-engine@^13.3.2: xhr "^2.2.0" xtend "^4.0.1" +web3-providers-http@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.1.tgz#c93ea003a42e7b894556f7e19dd3540f947f5013" + dependencies: + web3-core-helpers "1.2.1" + xhr2-cookies "1.1.0" + web3-providers-http@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.4.tgz#514fcad71ae77832c2c15574296282fbbc5f4a67" - integrity sha512-dzVCkRrR/cqlIrcrWNiPt9gyt0AZTE0J+MfAu9rR6CyIgtnm1wFUVVGaxYRxuTGQRO4Dlo49gtoGwaGcyxqiTw== dependencies: web3-core-helpers "1.2.4" xhr2-cookies "1.1.0" +web3-providers-ipc@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.1.tgz#017bfc687a8fc5398df2241eb98f135e3edd672c" + dependencies: + oboe "2.1.4" + underscore "1.9.1" + web3-core-helpers "1.2.1" + web3-providers-ipc@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.4.tgz#9d6659f8d44943fb369b739f48df09092be459bd" - integrity sha512-8J3Dguffin51gckTaNrO3oMBo7g+j0UNk6hXmdmQMMNEtrYqw4ctT6t06YOf9GgtOMjSAc1YEh3LPrvgIsR7og== dependencies: oboe "2.1.4" underscore "1.9.1" web3-core-helpers "1.2.4" +web3-providers-ws@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.1.tgz#2d941eaf3d5a8caa3214eff8dc16d96252b842cb" + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.1" + websocket "github:web3-js/WebSocket-Node#polyfill/globalThis" + web3-providers-ws@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.4.tgz#099ee271ee03f6ea4f5df9cfe969e83f4ce0e36f" - integrity sha512-F/vQpDzeK+++oeeNROl1IVTufFCwCR2hpWe5yRXN0ApLwHqXrMI7UwQNdJ9iyibcWjJf/ECbauEEQ8CHgE+MYQ== dependencies: "@web3-js/websocket" "^1.0.29" underscore "1.9.1" @@ -17729,10 +17956,18 @@ web3-providers@2.0.0-alpha: websocket "^1.0.28" xhr2-cookies "1.1.0" +web3-shh@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.1.tgz#4460e3c1e07faf73ddec24ccd00da46f89152b0c" + dependencies: + web3-core "1.2.1" + web3-core-method "1.2.1" + web3-core-subscriptions "1.2.1" + web3-net "1.2.1" + web3-shh@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.4.tgz#5c8ff5ab624a3b14f08af0d24d2b16c10e9f70dd" - integrity sha512-z+9SCw0dE+69Z/Hv8809XDbLj7lTfEv9Sgu8eKEIdGntZf4v7ewj5rzN5bZZSz8aCvfK7Y6ovz1PBAu4QzS4IQ== dependencies: web3-core "1.2.4" web3-core-method "1.2.4" @@ -17757,10 +17992,21 @@ web3-utils@1.0.0-beta.34: underscore "1.8.3" utf8 "2.1.1" +web3-utils@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.1.tgz#21466e38291551de0ab34558de21512ac4274534" + dependencies: + bn.js "4.11.8" + eth-lib "0.2.7" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randomhex "0.1.5" + underscore "1.9.1" + utf8 "3.0.0" + web3-utils@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.4.tgz#96832a39a66b05bf8862a5b0bdad2799d709d951" - integrity sha512-+S86Ip+jqfIPQWvw2N/xBQq5JNqCO0dyvukGdJm8fEWHZbckT4WxSpHbx+9KLEWY4H4x9pUwnoRkK87pYyHfgQ== dependencies: bn.js "4.11.8" eth-lib "0.2.7" @@ -17786,10 +18032,21 @@ web3-utils@2.0.0-alpha: randombytes "^2.1.0" utf8 "2.1.1" +web3@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.1.tgz#5d8158bcca47838ab8c2b784a2dee4c3ceb4179b" + dependencies: + web3-bzz "1.2.1" + web3-core "1.2.1" + web3-eth "1.2.1" + web3-eth-personal "1.2.1" + web3-net "1.2.1" + web3-shh "1.2.1" + web3-utils "1.2.1" + web3@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.4.tgz#6e7ab799eefc9b4648c2dab63003f704a1d5e7d9" - integrity sha512-xPXGe+w0x0t88Wj+s/dmAdASr3O9wmA9mpZRtixGZxmBexAF0MjfqYM+MS4tVl5s11hMTN3AZb8cDD4VLfC57A== dependencies: "@types/node" "^12.6.1" web3-bzz "1.2.4" @@ -17957,6 +18214,16 @@ websocket@^1.0.26: typedarray-to-buffer "^3.1.5" yaeti "^0.0.6" +"websocket@github:web3-js/WebSocket-Node#polyfill/globalThis": + version "1.0.29" + resolved "https://codeload.github.com/web3-js/WebSocket-Node/tar.gz/ef5ea2f41daf4a2113b80c9223df884b4d56c400" + dependencies: + debug "^2.2.0" + es5-ext "^0.10.50" + nan "^2.14.0" + typedarray-to-buffer "^3.1.5" + yaeti "^0.0.6" + whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: version "1.0.5" resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"