diff --git a/.prettierignore b/.prettierignore index 7ef0f6735f..db389bdb91 100644 --- a/.prettierignore +++ b/.prettierignore @@ -6,6 +6,7 @@ lib /packages/contract-artifacts/artifacts /python-packages/order_utils/src/zero_ex/contract_artifacts/artifacts /packages/json-schemas/schemas +/python-packages/order_utils/src/zero_ex/json_schemas/schemas /packages/metacoin/src/contract_wrappers /packages/metacoin/artifacts /packages/sra-spec/public/ diff --git a/package.json b/package.json index e598ac2d3d..96c18a2c80 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "packages/*" ], "scripts": { - "ganache": "ganache-cli -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"", + "ganache": "ganache-cli -p 8545 --gasLimit 10000000 --networkId 50 -m \"${npm_package_config_mnemonic}\"", "prettier": "prettier --write '**/*.{ts,tsx,json,md}' --config .prettierrc", "prettier:ci": "prettier --list-different '**/*.{ts,tsx,json,md}' --config .prettierrc", "report_coverage": "lcov-result-merger './{packages/*/coverage/lcov.info,python-packages/*/.coverage}' | coveralls", diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json index 7d9cb83122..0321ee200c 100644 --- a/packages/0x.js/CHANGELOG.json +++ b/packages/0x.js/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "2.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "2.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "2.0.2", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.1", "changes": [ diff --git a/packages/0x.js/CHANGELOG.md b/packages/0x.js/CHANGELOG.md index d312b2c9b1..2467311bfb 100644 --- a/packages/0x.js/CHANGELOG.md +++ b/packages/0x.js/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.4 - _November 14, 2018_ + + * Dependencies updated + +## v2.0.3 - _November 13, 2018_ + + * Dependencies updated + +## v2.0.2 - _November 12, 2018_ + + * Dependencies updated + ## v2.0.1 - _November 9, 2018_ * Dependencies updated diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index 38478980f7..755ff75126 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -1,6 +1,6 @@ { "name": "0x.js", - "version": "2.0.1", + "version": "2.0.4", "engines": { "node": ">=6.12" }, @@ -42,11 +42,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@0x/abi-gen": "^1.0.15", - "@0x/abi-gen-wrappers": "^1.0.2", + "@0x/abi-gen": "^1.0.16", + "@0x/abi-gen-wrappers": "^1.0.5", "@0x/contract-addresses": "^1.1.0", - "@0x/dev-utils": "^1.0.14", - "@0x/migrations": "^2.0.1", + "@0x/dev-utils": "^1.0.17", + "@0x/migrations": "^2.0.4", "@0x/tslint-config": "^1.0.10", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", @@ -73,16 +73,16 @@ "webpack": "^4.20.2" }, "dependencies": { - "@0x/assert": "^1.0.15", - "@0x/base-contract": "^3.0.3", - "@0x/contract-wrappers": "^3.0.1", - "@0x/order-utils": "^2.0.1", - "@0x/order-watcher": "^2.2.1", - "@0x/subproviders": "^2.1.1", + "@0x/assert": "^1.0.17", + "@0x/base-contract": "^3.0.6", + "@0x/contract-wrappers": "^4.0.2", + "@0x/order-utils": "^3.0.2", + "@0x/order-watcher": "^2.2.4", + "@0x/subproviders": "^2.1.4", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "@types/web3-provider-engine": "^14.0.0", "ethereum-types": "^1.1.2", "ethers": "~4.0.4", diff --git a/packages/abi-gen-wrappers/CHANGELOG.json b/packages/abi-gen-wrappers/CHANGELOG.json index c3273536b5..fff2bc41ea 100644 --- a/packages/abi-gen-wrappers/CHANGELOG.json +++ b/packages/abi-gen-wrappers/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "1.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "1.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "1.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.2", "changes": [ diff --git a/packages/abi-gen-wrappers/CHANGELOG.md b/packages/abi-gen-wrappers/CHANGELOG.md index 18bd28cb8d..4dea965f13 100644 --- a/packages/abi-gen-wrappers/CHANGELOG.md +++ b/packages/abi-gen-wrappers/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.5 - _November 14, 2018_ + + * Dependencies updated + +## v1.0.4 - _November 13, 2018_ + + * Dependencies updated + +## v1.0.3 - _November 12, 2018_ + + * Dependencies updated + ## v1.0.2 - _November 9, 2018_ * Dependencies updated diff --git a/packages/abi-gen-wrappers/package.json b/packages/abi-gen-wrappers/package.json index a4316449f7..7236cf6ffd 100644 --- a/packages/abi-gen-wrappers/package.json +++ b/packages/abi-gen-wrappers/package.json @@ -1,6 +1,6 @@ { "name": "@0x/abi-gen-wrappers", - "version": "1.0.2", + "version": "1.0.5", "engines": { "node": ">=6.12" }, @@ -30,17 +30,17 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen-wrappers/README.md", "devDependencies": { - "@0x/abi-gen": "^1.0.15", + "@0x/abi-gen": "^1.0.16", "@0x/tslint-config": "^1.0.10", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "ethereum-types": "^1.1.2", "ethers": "~4.0.4", "lodash": "^4.17.5", "shx": "^0.2.2" }, "dependencies": { - "@0x/base-contract": "^3.0.3" + "@0x/base-contract": "^3.0.6" }, "publishConfig": { "access": "public" diff --git a/packages/abi-gen/CHANGELOG.json b/packages/abi-gen/CHANGELOG.json index 658a997f45..1735c6b530 100644 --- a/packages/abi-gen/CHANGELOG.json +++ b/packages/abi-gen/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1542208198, + "version": "1.0.16", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.15", "changes": [ diff --git a/packages/abi-gen/CHANGELOG.md b/packages/abi-gen/CHANGELOG.md index 21fda1656f..23e2f8914f 100644 --- a/packages/abi-gen/CHANGELOG.md +++ b/packages/abi-gen/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.16 - _November 14, 2018_ + + * Dependencies updated + ## v1.0.15 - _November 9, 2018_ * Dependencies updated diff --git a/packages/abi-gen/package.json b/packages/abi-gen/package.json index 5367c9c298..f69d24116d 100644 --- a/packages/abi-gen/package.json +++ b/packages/abi-gen/package.json @@ -1,6 +1,6 @@ { "name": "@0x/abi-gen", - "version": "1.0.15", + "version": "1.0.16", "engines": { "node": ">=6.12" }, @@ -32,7 +32,7 @@ "homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md", "dependencies": { "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", + "@0x/utils": "^2.0.5", "chalk": "^2.3.0", "ethereum-types": "^1.1.2", "glob": "^7.1.2", diff --git a/packages/assert/CHANGELOG.json b/packages/assert/CHANGELOG.json index 82c0938cf9..2b4a3e7a16 100644 --- a/packages/assert/CHANGELOG.json +++ b/packages/assert/CHANGELOG.json @@ -1,4 +1,22 @@ [ + { + "timestamp": 1542208198, + "version": "1.0.17", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "1.0.16", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.15", "changes": [ diff --git a/packages/assert/CHANGELOG.md b/packages/assert/CHANGELOG.md index 7d0895eca5..66f0971c15 100644 --- a/packages/assert/CHANGELOG.md +++ b/packages/assert/CHANGELOG.md @@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.17 - _November 14, 2018_ + + * Dependencies updated + +## v1.0.16 - _November 12, 2018_ + + * Dependencies updated + ## v1.0.15 - _November 9, 2018_ * Dependencies updated diff --git a/packages/assert/package.json b/packages/assert/package.json index cc2fdaae97..ec093a5beb 100644 --- a/packages/assert/package.json +++ b/packages/assert/package.json @@ -1,6 +1,6 @@ { "name": "@0x/assert", - "version": "1.0.15", + "version": "1.0.17", "engines": { "node": ">=6.12" }, @@ -44,9 +44,9 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/json-schemas": "^2.0.1", + "@0x/json-schemas": "^2.1.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", + "@0x/utils": "^2.0.5", "lodash": "^4.17.5", "valid-url": "^1.0.9" }, diff --git a/packages/asset-buyer/CHANGELOG.json b/packages/asset-buyer/CHANGELOG.json index df4531063c..0e4623d05d 100644 --- a/packages/asset-buyer/CHANGELOG.json +++ b/packages/asset-buyer/CHANGELOG.json @@ -1,4 +1,32 @@ [ + { + "version": "3.0.0", + "changes": [ + { + "note": "update `getBuyQuoteAsync` to return eth spent on assets instead of per unit amount", + "pr": 1252 + } + ], + "timestamp": 1542208198 + }, + { + "timestamp": 1542134075, + "version": "2.2.2", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "2.2.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.2.0", "changes": [ diff --git a/packages/asset-buyer/CHANGELOG.md b/packages/asset-buyer/CHANGELOG.md index d6220767ea..d6013e53e6 100644 --- a/packages/asset-buyer/CHANGELOG.md +++ b/packages/asset-buyer/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.0 - _November 14, 2018_ + + * update `getBuyQuoteAsync` to return eth spent on assets instead of per unit amount (#1252) + +## v2.2.2 - _November 13, 2018_ + + * Dependencies updated + +## v2.2.1 - _November 12, 2018_ + + * Dependencies updated + ## v2.2.0 - _November 9, 2018_ * `getAssetBuyerForProvidedOrders` factory function now takes 3 args instead of 4 (#1187) diff --git a/packages/asset-buyer/package.json b/packages/asset-buyer/package.json index fc24149527..fad33476b8 100644 --- a/packages/asset-buyer/package.json +++ b/packages/asset-buyer/package.json @@ -1,6 +1,6 @@ { "name": "@0x/asset-buyer", - "version": "2.2.0", + "version": "3.0.0", "engines": { "node": ">=6.12" }, @@ -36,16 +36,16 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/asset-buyer/README.md", "dependencies": { - "@0x/assert": "^1.0.15", - "@0x/connect": "^3.0.3", - "@0x/contract-wrappers": "^3.0.1", - "@0x/json-schemas": "^2.0.1", - "@0x/order-utils": "^2.0.1", - "@0x/subproviders": "^2.1.1", + "@0x/assert": "^1.0.17", + "@0x/connect": "^3.0.6", + "@0x/contract-wrappers": "^4.0.2", + "@0x/json-schemas": "^2.1.1", + "@0x/order-utils": "^3.0.2", + "@0x/subproviders": "^2.1.4", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "ethereum-types": "^1.1.2", "lodash": "^4.17.10" }, diff --git a/packages/asset-buyer/src/types.ts b/packages/asset-buyer/src/types.ts index 3f1e6ff212..3b573edca1 100644 --- a/packages/asset-buyer/src/types.ts +++ b/packages/asset-buyer/src/types.ts @@ -54,12 +54,12 @@ export interface BuyQuote { } /** - * ethPerAssetPrice: The price of one unit of the desired asset in ETH + * assetEthAmount: The amount of eth required to pay for the requested asset. * feeEthAmount: The amount of eth required to pay the affiliate fee. - * totalEthAmount: the total amount of eth required to complete the buy. (Filling orders, feeOrders, and paying affiliate fee) + * totalEthAmount: The total amount of eth required to complete the buy (filling orders, feeOrders, and paying affiliate fee). */ export interface BuyQuoteInfo { - ethPerAssetPrice: BigNumber; + assetEthAmount: BigNumber; feeEthAmount: BigNumber; totalEthAmount: BigNumber; } diff --git a/packages/asset-buyer/src/utils/assert.ts b/packages/asset-buyer/src/utils/assert.ts index 2466f53a41..fcf9b0d0e3 100644 --- a/packages/asset-buyer/src/utils/assert.ts +++ b/packages/asset-buyer/src/utils/assert.ts @@ -18,7 +18,7 @@ export const assert = { } }, isValidBuyQuoteInfo(variableName: string, buyQuoteInfo: BuyQuoteInfo): void { - sharedAssert.isBigNumber(`${variableName}.ethPerAssetPrice`, buyQuoteInfo.ethPerAssetPrice); + sharedAssert.isBigNumber(`${variableName}.assetEthAmount`, buyQuoteInfo.assetEthAmount); sharedAssert.isBigNumber(`${variableName}.feeEthAmount`, buyQuoteInfo.feeEthAmount); sharedAssert.isBigNumber(`${variableName}.totalEthAmount`, buyQuoteInfo.totalEthAmount); }, diff --git a/packages/asset-buyer/src/utils/buy_quote_calculator.ts b/packages/asset-buyer/src/utils/buy_quote_calculator.ts index 6a67ed1ed5..b15b880c2e 100644 --- a/packages/asset-buyer/src/utils/buy_quote_calculator.ts +++ b/packages/asset-buyer/src/utils/buy_quote_calculator.ts @@ -106,28 +106,28 @@ function calculateQuoteInfo( isMakerAssetZrxToken: boolean, ): BuyQuoteInfo { // find the total eth and zrx needed to buy assetAmount from the resultOrders from left to right - let ethAmountToBuyAsset = constants.ZERO_AMOUNT; - let ethAmountToBuyZrx = constants.ZERO_AMOUNT; + let assetEthAmount = constants.ZERO_AMOUNT; + let zrxEthAmount = constants.ZERO_AMOUNT; if (isMakerAssetZrxToken) { - ethAmountToBuyAsset = findEthAmountNeededToBuyZrx(ordersAndFillableAmounts, assetBuyAmount); + assetEthAmount = findEthAmountNeededToBuyZrx(ordersAndFillableAmounts, assetBuyAmount); } else { // find eth and zrx amounts needed to buy const ethAndZrxAmountToBuyAsset = findEthAndZrxAmountNeededToBuyAsset(ordersAndFillableAmounts, assetBuyAmount); - ethAmountToBuyAsset = ethAndZrxAmountToBuyAsset[0]; + assetEthAmount = ethAndZrxAmountToBuyAsset[0]; const zrxAmountToBuyAsset = ethAndZrxAmountToBuyAsset[1]; // find eth amount needed to buy zrx - ethAmountToBuyZrx = findEthAmountNeededToBuyZrx(feeOrdersAndFillableAmounts, zrxAmountToBuyAsset); + zrxEthAmount = findEthAmountNeededToBuyZrx(feeOrdersAndFillableAmounts, zrxAmountToBuyAsset); } - /// find the eth amount needed to buy the affiliate fee - const ethAmountToBuyAffiliateFee = ethAmountToBuyAsset.mul(feePercentage).ceil(); - const totalEthAmountWithoutAffiliateFee = ethAmountToBuyAsset.plus(ethAmountToBuyZrx); - const ethAmountTotal = totalEthAmountWithoutAffiliateFee.plus(ethAmountToBuyAffiliateFee); - // divide into the assetBuyAmount in order to find rate of makerAsset / WETH - const ethPerAssetPrice = totalEthAmountWithoutAffiliateFee.div(assetBuyAmount); + // eth amount needed to buy the affiliate fee + const affiliateFeeEthAmount = assetEthAmount.mul(feePercentage).ceil(); + // eth amount needed for fees is the sum of affiliate fee and zrx fee + const feeEthAmount = affiliateFeeEthAmount.plus(zrxEthAmount); + // eth amount needed in total is the sum of the amount needed for the asset and the amount needed for fees + const totalEthAmount = assetEthAmount.plus(feeEthAmount); return { - totalEthAmount: ethAmountTotal, - feeEthAmount: ethAmountToBuyAffiliateFee, - ethPerAssetPrice, + assetEthAmount, + feeEthAmount, + totalEthAmount, }; } diff --git a/packages/asset-buyer/src/utils/order_provider_response_processor.ts b/packages/asset-buyer/src/utils/order_provider_response_processor.ts index 28f684f3c9..25e85b2cc9 100644 --- a/packages/asset-buyer/src/utils/order_provider_response_processor.ts +++ b/packages/asset-buyer/src/utils/order_provider_response_processor.ts @@ -44,19 +44,24 @@ export const orderProviderResponseProcessor = { let unsortedOrders = filteredOrders; // if an orderValidator is provided, use on chain information to calculate remaining fillable makerAsset amounts if (!_.isUndefined(orderValidator)) { - // TODO(bmillman): improvement - // try/catch this request and throw a more domain specific error const takerAddresses = _.map(filteredOrders, () => constants.NULL_ADDRESS); - const ordersAndTradersInfo = await orderValidator.getOrdersAndTradersInfoAsync( - filteredOrders, - takerAddresses, - ); - // take orders + on chain information and find the valid orders and remaining fillable maker asset amounts - unsortedOrders = getValidOrdersWithRemainingFillableMakerAssetAmountsFromOnChain( - filteredOrders, - ordersAndTradersInfo, - isMakerAssetZrxToken, - ); + try { + const ordersAndTradersInfo = await orderValidator.getOrdersAndTradersInfoAsync( + filteredOrders, + takerAddresses, + ); + // take orders + on chain information and find the valid orders and remaining fillable maker asset amounts + unsortedOrders = getValidOrdersWithRemainingFillableMakerAssetAmountsFromOnChain( + filteredOrders, + ordersAndTradersInfo, + isMakerAssetZrxToken, + ); + } catch (err) { + // Sometimes we observe this call to orderValidator fail with response `0x` + // Because of differences in Parity / Geth implementations, its very hard to tell if this response is a "system error" + // or a revert. In this case we just swallow these errors and fallback to partial fill information from the SRA. + // TODO(bmillman): report these errors so we have an idea of how often we're getting these failures. + } } // sort orders by rate // TODO(bmillman): optimization diff --git a/packages/asset-buyer/test/buy_quote_calculator_test.ts b/packages/asset-buyer/test/buy_quote_calculator_test.ts index 0ea3719821..a30017b729 100644 --- a/packages/asset-buyer/test/buy_quote_calculator_test.ts +++ b/packages/asset-buyer/test/buy_quote_calculator_test.ts @@ -108,17 +108,17 @@ describe('buyQuoteCalculator', () => { // 50 eth to fill the first order + 100 eth for fees const expectedEthAmountForAsset = new BigNumber(50); const expectedEthAmountForZrxFees = new BigNumber(100); - const expectedFillEthAmount = expectedEthAmountForAsset.plus(expectedEthAmountForZrxFees); - const expectedFeeEthAmount = expectedEthAmountForAsset.mul(feePercentage); + const expectedFillEthAmount = expectedEthAmountForAsset; + const expectedAffiliateFeeEthAmount = expectedEthAmountForAsset.mul(feePercentage); + const expectedFeeEthAmount = expectedAffiliateFeeEthAmount.plus(expectedEthAmountForZrxFees); const expectedTotalEthAmount = expectedFillEthAmount.plus(expectedFeeEthAmount); - const expectedEthPerAssetPrice = expectedFillEthAmount.div(assetBuyAmount); + expect(buyQuote.bestCaseQuoteInfo.assetEthAmount).to.bignumber.equal(expectedFillEthAmount); expect(buyQuote.bestCaseQuoteInfo.feeEthAmount).to.bignumber.equal(expectedFeeEthAmount); expect(buyQuote.bestCaseQuoteInfo.totalEthAmount).to.bignumber.equal(expectedTotalEthAmount); - expect(buyQuote.bestCaseQuoteInfo.ethPerAssetPrice).to.bignumber.equal(expectedEthPerAssetPrice); // because we have no slippage protection, minRate is equal to maxRate + expect(buyQuote.worstCaseQuoteInfo.assetEthAmount).to.bignumber.equal(expectedFillEthAmount); expect(buyQuote.worstCaseQuoteInfo.feeEthAmount).to.bignumber.equal(expectedFeeEthAmount); expect(buyQuote.worstCaseQuoteInfo.totalEthAmount).to.bignumber.equal(expectedTotalEthAmount); - expect(buyQuote.worstCaseQuoteInfo.ethPerAssetPrice).to.bignumber.equal(expectedEthPerAssetPrice); // test if feePercentage gets passed through expect(buyQuote.feePercentage).to.equal(feePercentage); }); @@ -146,23 +146,23 @@ describe('buyQuoteCalculator', () => { // 50 eth to fill the first order + 100 eth for fees const expectedEthAmountForAsset = new BigNumber(50); const expectedEthAmountForZrxFees = new BigNumber(100); - const expectedFillEthAmount = expectedEthAmountForAsset.plus(expectedEthAmountForZrxFees); - const expectedFeeEthAmount = expectedEthAmountForAsset.mul(feePercentage); + const expectedFillEthAmount = expectedEthAmountForAsset; + const expectedAffiliateFeeEthAmount = expectedEthAmountForAsset.mul(feePercentage); + const expectedFeeEthAmount = expectedAffiliateFeeEthAmount.plus(expectedEthAmountForZrxFees); const expectedTotalEthAmount = expectedFillEthAmount.plus(expectedFeeEthAmount); - const expectedEthPerAssetPrice = expectedFillEthAmount.div(assetBuyAmount); + expect(buyQuote.bestCaseQuoteInfo.assetEthAmount).to.bignumber.equal(expectedFillEthAmount); expect(buyQuote.bestCaseQuoteInfo.feeEthAmount).to.bignumber.equal(expectedFeeEthAmount); expect(buyQuote.bestCaseQuoteInfo.totalEthAmount).to.bignumber.equal(expectedTotalEthAmount); - expect(buyQuote.bestCaseQuoteInfo.ethPerAssetPrice).to.bignumber.equal(expectedEthPerAssetPrice); // 100 eth to fill the first order + 208 eth for fees const expectedWorstEthAmountForAsset = new BigNumber(100); const expectedWorstEthAmountForZrxFees = new BigNumber(208); - const expectedWorstFillEthAmount = expectedWorstEthAmountForAsset.plus(expectedWorstEthAmountForZrxFees); - const expectedWorstFeeEthAmount = expectedWorstEthAmountForAsset.mul(feePercentage); + const expectedWorstFillEthAmount = expectedWorstEthAmountForAsset; + const expectedWorstAffiliateFeeEthAmount = expectedWorstEthAmountForAsset.mul(feePercentage); + const expectedWorstFeeEthAmount = expectedWorstAffiliateFeeEthAmount.plus(expectedWorstEthAmountForZrxFees); const expectedWorstTotalEthAmount = expectedWorstFillEthAmount.plus(expectedWorstFeeEthAmount); - const expectedWorstEthPerAssetPrice = expectedWorstFillEthAmount.div(assetBuyAmount); + expect(buyQuote.worstCaseQuoteInfo.assetEthAmount).to.bignumber.equal(expectedWorstFillEthAmount); expect(buyQuote.worstCaseQuoteInfo.feeEthAmount).to.bignumber.equal(expectedWorstFeeEthAmount); expect(buyQuote.worstCaseQuoteInfo.totalEthAmount).to.bignumber.equal(expectedWorstTotalEthAmount); - expect(buyQuote.worstCaseQuoteInfo.ethPerAssetPrice).to.bignumber.equal(expectedWorstEthPerAssetPrice); // test if feePercentage gets passed through expect(buyQuote.feePercentage).to.equal(feePercentage); }); diff --git a/packages/base-contract/CHANGELOG.json b/packages/base-contract/CHANGELOG.json index f8a1051d62..dc30ac0762 100644 --- a/packages/base-contract/CHANGELOG.json +++ b/packages/base-contract/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "3.0.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "3.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "3.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "3.0.3", "changes": [ diff --git a/packages/base-contract/CHANGELOG.md b/packages/base-contract/CHANGELOG.md index d544f4f99c..cf1b80b6dc 100644 --- a/packages/base-contract/CHANGELOG.md +++ b/packages/base-contract/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.6 - _November 14, 2018_ + + * Dependencies updated + +## v3.0.5 - _November 13, 2018_ + + * Dependencies updated + +## v3.0.4 - _November 12, 2018_ + + * Dependencies updated + ## v3.0.3 - _November 9, 2018_ * Dependencies updated diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json index efa4a5c812..b1cdc3cc6e 100644 --- a/packages/base-contract/package.json +++ b/packages/base-contract/package.json @@ -1,6 +1,6 @@ { "name": "@0x/base-contract", - "version": "3.0.3", + "version": "3.0.6", "engines": { "node": ">=6.12" }, @@ -41,8 +41,8 @@ }, "dependencies": { "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "ethereum-types": "^1.1.2", "ethers": "~4.0.4", "lodash": "^4.17.5" diff --git a/packages/connect/CHANGELOG.json b/packages/connect/CHANGELOG.json index 52ad9d5753..6960e1d979 100644 --- a/packages/connect/CHANGELOG.json +++ b/packages/connect/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "3.0.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "3.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "3.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "3.0.3", "changes": [ diff --git a/packages/connect/CHANGELOG.md b/packages/connect/CHANGELOG.md index 8e38e16de3..13afad09bc 100644 --- a/packages/connect/CHANGELOG.md +++ b/packages/connect/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.6 - _November 14, 2018_ + + * Dependencies updated + +## v3.0.5 - _November 13, 2018_ + + * Dependencies updated + +## v3.0.4 - _November 12, 2018_ + + * Dependencies updated + ## v3.0.3 - _November 9, 2018_ * Dependencies updated diff --git a/packages/connect/package.json b/packages/connect/package.json index 527ac5bdc9..8e3f3ac8f0 100644 --- a/packages/connect/package.json +++ b/packages/connect/package.json @@ -1,6 +1,6 @@ { "name": "@0x/connect", - "version": "3.0.3", + "version": "3.0.6", "engines": { "node": ">=6.12" }, @@ -44,12 +44,12 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/connect/README.md", "dependencies": { - "@0x/assert": "^1.0.15", - "@0x/json-schemas": "^2.0.1", - "@0x/order-utils": "^2.0.1", + "@0x/assert": "^1.0.17", + "@0x/json-schemas": "^2.1.1", + "@0x/order-utils": "^3.0.2", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", + "@0x/utils": "^2.0.5", "lodash": "^4.17.5", "query-string": "^5.0.1", "sinon": "^4.0.0", diff --git a/packages/connect/src/http_client.ts b/packages/connect/src/http_client.ts index b6c031fa83..c52425431b 100644 --- a/packages/connect/src/http_client.ts +++ b/packages/connect/src/http_client.ts @@ -19,7 +19,6 @@ import { fetchAsync } from '@0x/utils'; import * as _ from 'lodash'; import * as queryString from 'query-string'; -import { schemas as clientSchemas } from './schemas/schemas'; import { Client, HttpRequestOptions, HttpRequestType } from './types'; import { relayerResponseJsonParsers } from './utils/relayer_response_json_parsers'; @@ -61,9 +60,9 @@ export class HttpClient implements Client { requestOpts?: RequestOpts & AssetPairsRequestOpts & PagedRequestOpts, ): Promise { if (!_.isUndefined(requestOpts)) { - assert.doesConformToSchema('requestOpts', requestOpts, clientSchemas.assetPairsRequestOptsSchema); - assert.doesConformToSchema('requestOpts', requestOpts, clientSchemas.pagedRequestOptsSchema); - assert.doesConformToSchema('requestOpts', requestOpts, clientSchemas.requestOptsSchema); + assert.doesConformToSchema('requestOpts', requestOpts, schemas.assetPairsRequestOptsSchema); + assert.doesConformToSchema('requestOpts', requestOpts, schemas.pagedRequestOptsSchema); + assert.doesConformToSchema('requestOpts', requestOpts, schemas.requestOptsSchema); } const httpRequestOpts = { params: requestOpts, @@ -81,9 +80,9 @@ export class HttpClient implements Client { requestOpts?: RequestOpts & OrdersRequestOpts & PagedRequestOpts, ): Promise { if (!_.isUndefined(requestOpts)) { - assert.doesConformToSchema('requestOpts', requestOpts, clientSchemas.ordersRequestOptsSchema); - assert.doesConformToSchema('requestOpts', requestOpts, clientSchemas.pagedRequestOptsSchema); - assert.doesConformToSchema('requestOpts', requestOpts, clientSchemas.requestOptsSchema); + assert.doesConformToSchema('requestOpts', requestOpts, schemas.ordersRequestOptsSchema); + assert.doesConformToSchema('requestOpts', requestOpts, schemas.pagedRequestOptsSchema); + assert.doesConformToSchema('requestOpts', requestOpts, schemas.requestOptsSchema); } const httpRequestOpts = { params: requestOpts, @@ -99,7 +98,7 @@ export class HttpClient implements Client { */ public async getOrderAsync(orderHash: string, requestOpts?: RequestOpts): Promise { if (!_.isUndefined(requestOpts)) { - assert.doesConformToSchema('requestOpts', requestOpts, clientSchemas.requestOptsSchema); + assert.doesConformToSchema('requestOpts', requestOpts, schemas.requestOptsSchema); } assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema); const httpRequestOpts = { @@ -119,10 +118,10 @@ export class HttpClient implements Client { request: OrderbookRequest, requestOpts?: RequestOpts & PagedRequestOpts, ): Promise { - assert.doesConformToSchema('request', request, clientSchemas.orderBookRequestSchema); + assert.doesConformToSchema('request', request, schemas.orderBookRequestSchema); if (!_.isUndefined(requestOpts)) { - assert.doesConformToSchema('requestOpts', requestOpts, clientSchemas.pagedRequestOptsSchema); - assert.doesConformToSchema('requestOpts', requestOpts, clientSchemas.requestOptsSchema); + assert.doesConformToSchema('requestOpts', requestOpts, schemas.pagedRequestOptsSchema); + assert.doesConformToSchema('requestOpts', requestOpts, schemas.requestOptsSchema); } const httpRequestOpts = { params: _.defaults({}, request, requestOpts), @@ -142,9 +141,9 @@ export class HttpClient implements Client { requestOpts?: RequestOpts, ): Promise { if (!_.isUndefined(requestOpts)) { - assert.doesConformToSchema('requestOpts', requestOpts, clientSchemas.requestOptsSchema); + assert.doesConformToSchema('requestOpts', requestOpts, schemas.requestOptsSchema); } - assert.doesConformToSchema('request', request, clientSchemas.orderConfigRequestSchema); + assert.doesConformToSchema('request', request, schemas.orderConfigRequestSchema); const httpRequestOpts = { params: requestOpts, payload: request, @@ -160,8 +159,8 @@ export class HttpClient implements Client { */ public async getFeeRecipientsAsync(requestOpts?: RequestOpts & PagedRequestOpts): Promise { if (!_.isUndefined(requestOpts)) { - assert.doesConformToSchema('requestOpts', requestOpts, clientSchemas.pagedRequestOptsSchema); - assert.doesConformToSchema('requestOpts', requestOpts, clientSchemas.requestOptsSchema); + assert.doesConformToSchema('requestOpts', requestOpts, schemas.pagedRequestOptsSchema); + assert.doesConformToSchema('requestOpts', requestOpts, schemas.requestOptsSchema); } const httpRequestOpts = { params: requestOpts, diff --git a/packages/connect/src/schemas/asset_pairs_request_opts_schema.ts b/packages/connect/src/schemas/asset_pairs_request_opts_schema.ts deleted file mode 100644 index a9e3942a44..0000000000 --- a/packages/connect/src/schemas/asset_pairs_request_opts_schema.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const assetPairsRequestOptsSchema = { - id: '/AssetPairsRequestOpts', - type: 'object', - properties: { - assetDataA: { $ref: '/hexSchema' }, - assetDataB: { $ref: '/hexSchema' }, - }, -}; diff --git a/packages/connect/src/schemas/order_config_request_schema.ts b/packages/connect/src/schemas/order_config_request_schema.ts deleted file mode 100644 index 0eda430e89..0000000000 --- a/packages/connect/src/schemas/order_config_request_schema.ts +++ /dev/null @@ -1,24 +0,0 @@ -export const orderConfigRequestSchema = { - id: '/OrderConfigRequest', - type: 'object', - properties: { - makerAddress: { $ref: '/addressSchema' }, - takerAddress: { $ref: '/addressSchema' }, - makerAssetAmount: { $ref: '/numberSchema' }, - takerAssetAmount: { $ref: '/numberSchema' }, - makerAssetData: { $ref: '/hexSchema' }, - takerAssetData: { $ref: '/hexSchema' }, - exchangeAddress: { $ref: '/addressSchema' }, - expirationTimeSeconds: { $ref: '/numberSchema' }, - }, - required: [ - 'makerAddress', - 'takerAddress', - 'makerAssetAmount', - 'takerAssetAmount', - 'makerAssetData', - 'takerAssetData', - 'exchangeAddress', - 'expirationTimeSeconds', - ], -}; diff --git a/packages/connect/src/schemas/orderbook_request_schema.ts b/packages/connect/src/schemas/orderbook_request_schema.ts deleted file mode 100644 index 0c9389d509..0000000000 --- a/packages/connect/src/schemas/orderbook_request_schema.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const orderBookRequestSchema = { - id: '/OrderBookRequest', - type: 'object', - properties: { - baseAssetData: { $ref: '/hexSchema' }, - quoteAssetData: { $ref: '/hexSchema' }, - }, - required: ['baseAssetData', 'quoteAssetData'], -}; diff --git a/packages/connect/src/schemas/orders_request_opts_schema.ts b/packages/connect/src/schemas/orders_request_opts_schema.ts deleted file mode 100644 index 71ce3d06f4..0000000000 --- a/packages/connect/src/schemas/orders_request_opts_schema.ts +++ /dev/null @@ -1,19 +0,0 @@ -export const ordersRequestOptsSchema = { - id: '/OrdersRequestOpts', - type: 'object', - properties: { - makerAssetProxyId: { $ref: '/hexSchema' }, - takerAssetProxyId: { $ref: '/hexSchema' }, - makerAssetAddress: { $ref: '/addressSchema' }, - takerAssetAddress: { $ref: '/addressSchema' }, - exchangeAddress: { $ref: '/addressSchema' }, - senderAddress: { $ref: '/addressSchema' }, - makerAssetData: { $ref: '/hexSchema' }, - takerAssetData: { $ref: '/hexSchema' }, - traderAssetData: { $ref: '/hexSchema' }, - makerAddress: { $ref: '/addressSchema' }, - takerAddress: { $ref: '/addressSchema' }, - traderAddress: { $ref: '/addressSchema' }, - feeRecipientAddress: { $ref: '/addressSchema' }, - }, -}; diff --git a/packages/connect/src/schemas/paged_request_opts_schema.ts b/packages/connect/src/schemas/paged_request_opts_schema.ts deleted file mode 100644 index eb2e521004..0000000000 --- a/packages/connect/src/schemas/paged_request_opts_schema.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const pagedRequestOptsSchema = { - id: '/PagedRequestOpts', - type: 'object', - properties: { - page: { type: 'number' }, - perPage: { type: 'number' }, - }, -}; diff --git a/packages/connect/src/schemas/request_opts_schema.ts b/packages/connect/src/schemas/request_opts_schema.ts deleted file mode 100644 index a51e980692..0000000000 --- a/packages/connect/src/schemas/request_opts_schema.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const requestOptsSchema = { - id: '/RequestOpts', - type: 'object', - properties: { - networkId: { type: 'number' }, - }, -}; diff --git a/packages/connect/src/schemas/schemas.ts b/packages/connect/src/schemas/schemas.ts deleted file mode 100644 index 8d101ed6fa..0000000000 --- a/packages/connect/src/schemas/schemas.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { assetPairsRequestOptsSchema } from './asset_pairs_request_opts_schema'; -import { orderConfigRequestSchema } from './order_config_request_schema'; -import { orderBookRequestSchema } from './orderbook_request_schema'; -import { ordersRequestOptsSchema } from './orders_request_opts_schema'; -import { pagedRequestOptsSchema } from './paged_request_opts_schema'; -import { requestOptsSchema } from './request_opts_schema'; - -export const schemas = { - orderConfigRequestSchema, - orderBookRequestSchema, - ordersRequestOptsSchema, - pagedRequestOptsSchema, - requestOptsSchema, - assetPairsRequestOptsSchema, -}; diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index 0ab5e5d087..fbf3972a98 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -1,4 +1,22 @@ [ + { + "timestamp": 1542208198, + "version": "4.0.2", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "4.0.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "4.0.0", "changes": [ @@ -17,7 +35,8 @@ "Throw previously swallowed network errors when calling `validateOrderFillableOrThrowAsync` (see issue: #1218)", "pr": 1235 } - ] + ], + "timestamp": 1542028948 }, { "version": "3.0.1", diff --git a/packages/contract-wrappers/CHANGELOG.md b/packages/contract-wrappers/CHANGELOG.md index 1fe903dd98..eca1b46334 100644 --- a/packages/contract-wrappers/CHANGELOG.md +++ b/packages/contract-wrappers/CHANGELOG.md @@ -5,6 +5,20 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v4.0.2 - _November 14, 2018_ + + * Dependencies updated + +## v4.0.1 - _November 13, 2018_ + + * Dependencies updated + +## v4.0.0 - _November 12, 2018_ + + * Add signature validation, regular cancellation and `cancelledUpTo` checks to `validateOrderFillableOrThrowAsync` (#1235) + * Improved the errors thrown by `validateOrderFillableOrThrowAsync` by making them more descriptive (#1235) + * Throw previously swallowed network errors when calling `validateOrderFillableOrThrowAsync` (see issue: #1218) (#1235) + ## v3.0.1 - _November 9, 2018_ * Fix bug in `ForwarderWrapper` where `feeRecipientAddress` was not correctly normalized. (#1178) diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index cb69bbd333..2d6b4e3f84 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contract-wrappers", - "version": "3.0.1", + "version": "4.0.2", "description": "Smart TS wrappers for 0x smart contracts", "keywords": [ "0xproject", @@ -37,9 +37,9 @@ "node": ">=6.0.0" }, "devDependencies": { - "@0x/dev-utils": "^1.0.14", - "@0x/migrations": "^2.0.1", - "@0x/subproviders": "^2.1.1", + "@0x/dev-utils": "^1.0.17", + "@0x/migrations": "^2.0.4", + "@0x/subproviders": "^2.1.4", "@0x/tslint-config": "^1.0.10", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", @@ -65,17 +65,17 @@ "web3-provider-engine": "14.0.6" }, "dependencies": { - "@0x/abi-gen-wrappers": "^1.0.2", - "@0x/assert": "^1.0.15", + "@0x/abi-gen-wrappers": "^1.0.5", + "@0x/assert": "^1.0.17", "@0x/contract-addresses": "^1.1.0", "@0x/contract-artifacts": "^1.1.0", - "@0x/fill-scenarios": "^1.0.9", - "@0x/json-schemas": "^2.0.1", - "@0x/order-utils": "^2.0.1", + "@0x/fill-scenarios": "^1.0.12", + "@0x/json-schemas": "^2.1.1", + "@0x/order-utils": "^3.0.2", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "ethereum-types": "^1.1.2", "ethereumjs-blockstream": "6.0.0", "ethereumjs-util": "^5.1.1", diff --git a/packages/contracts/package.json b/packages/contracts/package.json index bf9bb4826a..c87e2e95b2 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "contracts", - "version": "2.1.51", + "version": "2.1.54", "engines": { "node": ">=6.12" }, @@ -45,11 +45,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md", "devDependencies": { - "@0x/abi-gen": "^1.0.15", - "@0x/dev-utils": "^1.0.14", - "@0x/sol-compiler": "^1.1.9", - "@0x/sol-cov": "^2.1.9", - "@0x/subproviders": "^2.1.1", + "@0x/abi-gen": "^1.0.16", + "@0x/dev-utils": "^1.0.17", + "@0x/sol-compiler": "^1.1.12", + "@0x/sol-cov": "^2.1.12", + "@0x/subproviders": "^2.1.4", "@0x/tslint-config": "^1.0.10", "@types/bn.js": "^4.11.0", "@types/ethereumjs-abi": "^0.6.0", @@ -71,12 +71,12 @@ "yargs": "^10.0.3" }, "dependencies": { - "@0x/base-contract": "^3.0.3", - "@0x/order-utils": "^2.0.1", + "@0x/base-contract": "^3.0.6", + "@0x/order-utils": "^3.0.2", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "@types/js-combinatorics": "^0.5.29", "bn.js": "^4.11.8", "ethereum-types": "^1.1.2", diff --git a/packages/dev-tools-pages/package.json b/packages/dev-tools-pages/package.json index b1b89ac995..e6d954f156 100644 --- a/packages/dev-tools-pages/package.json +++ b/packages/dev-tools-pages/package.json @@ -1,6 +1,6 @@ { "name": "@0x/dev-tools-pages", - "version": "0.0.3", + "version": "0.0.6", "engines": { "node": ">=6.12" }, @@ -16,7 +16,7 @@ }, "license": "Apache-2.0", "dependencies": { - "@0x/react-shared": "^1.0.18", + "@0x/react-shared": "^1.0.21", "basscss": "^8.0.3", "bowser": "^1.9.3", "less": "^2.7.2", diff --git a/packages/dev-utils/CHANGELOG.json b/packages/dev-utils/CHANGELOG.json index 269cdc9346..d6cdd1c5a2 100644 --- a/packages/dev-utils/CHANGELOG.json +++ b/packages/dev-utils/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "1.0.17", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "1.0.16", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "1.0.15", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.14", "changes": [ diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index ee614a9048..4becadf813 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.17 - _November 14, 2018_ + + * Dependencies updated + +## v1.0.16 - _November 13, 2018_ + + * Dependencies updated + +## v1.0.15 - _November 12, 2018_ + + * Dependencies updated + ## v1.0.14 - _November 9, 2018_ * Dependencies updated diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index e1b3201d30..3db3911310 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/dev-utils", - "version": "1.0.14", + "version": "1.0.17", "engines": { "node": ">=6.12" }, @@ -41,11 +41,11 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/subproviders": "^2.1.1", + "@0x/subproviders": "^2.1.4", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "@types/web3-provider-engine": "^14.0.0", "chai": "^4.0.1", "ethereum-types": "^1.1.2", diff --git a/packages/fill-scenarios/CHANGELOG.json b/packages/fill-scenarios/CHANGELOG.json index 8aa4e78d36..deeae5f5dc 100644 --- a/packages/fill-scenarios/CHANGELOG.json +++ b/packages/fill-scenarios/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "1.0.12", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "1.0.11", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "1.0.10", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.9", "changes": [ diff --git a/packages/fill-scenarios/CHANGELOG.md b/packages/fill-scenarios/CHANGELOG.md index 4ff28f82fa..c8bd402de6 100644 --- a/packages/fill-scenarios/CHANGELOG.md +++ b/packages/fill-scenarios/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.12 - _November 14, 2018_ + + * Dependencies updated + +## v1.0.11 - _November 13, 2018_ + + * Dependencies updated + +## v1.0.10 - _November 12, 2018_ + + * Dependencies updated + ## v1.0.9 - _November 9, 2018_ * Dependencies updated diff --git a/packages/fill-scenarios/package.json b/packages/fill-scenarios/package.json index e9ca077fb1..2d9bff0e72 100644 --- a/packages/fill-scenarios/package.json +++ b/packages/fill-scenarios/package.json @@ -1,6 +1,6 @@ { "name": "@0x/fill-scenarios", - "version": "1.0.9", + "version": "1.0.12", "description": "0x order fill scenario generator", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -28,14 +28,14 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/abi-gen-wrappers": "^1.0.2", - "@0x/base-contract": "^3.0.3", + "@0x/abi-gen-wrappers": "^1.0.5", + "@0x/base-contract": "^3.0.6", "@0x/contract-artifacts": "^1.1.0", - "@0x/order-utils": "^2.0.1", + "@0x/order-utils": "^3.0.2", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "ethereum-types": "^1.1.2", "ethers": "~4.0.4", "lodash": "^4.17.5" diff --git a/packages/instant/package.json b/packages/instant/package.json index 3c87743c14..6caa3902be 100644 --- a/packages/instant/package.json +++ b/packages/instant/package.json @@ -1,6 +1,6 @@ { "name": "@0x/instant", - "version": "0.0.4", + "version": "0.0.7", "engines": { "node": ">=6.12" }, @@ -45,15 +45,16 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/instant/README.md", "dependencies": { - "@0x/assert": "^1.0.15", - "@0x/asset-buyer": "^2.2.0", - "@0x/json-schemas": "^2.0.1", - "@0x/order-utils": "^2.0.1", - "@0x/subproviders": "^2.1.1", + "@0x/assert": "^1.0.17", + "@0x/asset-buyer": "^3.0.0", + "@0x/json-schemas": "^2.1.1", + "@0x/order-utils": "^3.0.2", + "@0x/subproviders": "^2.1.4", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", + "bowser": "^1.9.4", "copy-to-clipboard": "^3.0.8", "ethereum-types": "^1.1.2", "lodash": "^4.17.10", @@ -82,6 +83,7 @@ "awesome-typescript-loader": "^5.2.1", "enzyme": "^3.6.0", "enzyme-adapter-react-16": "^1.5.0", + "ip": "^1.1.5", "jest": "^23.6.0", "make-promises-safe": "^1.1.0", "npm-run-all": "^4.1.2", diff --git a/packages/instant/src/components/animations/slide_animation.tsx b/packages/instant/src/components/animations/slide_animation.tsx index 9adb1c6743..5992bcba78 100644 --- a/packages/instant/src/components/animations/slide_animation.tsx +++ b/packages/instant/src/components/animations/slide_animation.tsx @@ -1,10 +1,10 @@ import * as React from 'react'; import { OptionallyScreenSpecific } from '../../style/media'; +import { SlideAnimationState } from '../../types'; import { PositionAnimation, PositionAnimationSettings } from './position_animation'; -export type SlideAnimationState = 'slidIn' | 'slidOut' | 'none'; export interface SlideAnimationProps { animationState: SlideAnimationState; slideInSettings: OptionallyScreenSpecific; diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 877ab275c8..8b6121e43d 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -43,7 +43,6 @@ export class BuyButton extends React.Component { onClick={this._handleClick} isDisabled={shouldDisableButton} fontColor={ColorOption.white} - fontSize="20px" > Buy diff --git a/packages/instant/src/components/buy_order_progress.tsx b/packages/instant/src/components/buy_order_progress.tsx index bc73194231..6568de91b2 100644 --- a/packages/instant/src/components/buy_order_progress.tsx +++ b/packages/instant/src/components/buy_order_progress.tsx @@ -12,7 +12,6 @@ export interface BuyOrderProgressProps { export const BuyOrderProgress: React.StatelessComponent = props => { const { buyOrderState } = props; - if ( buyOrderState.processState === OrderProcessState.Processing || buyOrderState.processState === OrderProcessState.Success || @@ -30,6 +29,5 @@ export const BuyOrderProgress: React.StatelessComponent = ); } - return null; }; diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx index 6041bf4f5e..e563bec73d 100644 --- a/packages/instant/src/components/buy_order_state_buttons.tsx +++ b/packages/instant/src/components/buy_order_state_buttons.tsx @@ -35,7 +35,7 @@ export const BuyOrderStateButtons: React.StatelessComponent - diff --git a/packages/instant/src/components/coinbase_wallet_logo.tsx b/packages/instant/src/components/coinbase_wallet_logo.tsx new file mode 100644 index 0000000000..845b96d732 --- /dev/null +++ b/packages/instant/src/components/coinbase_wallet_logo.tsx @@ -0,0 +1,23 @@ +import * as React from 'react'; + +export interface CoinbaseWalletLogoProps { + width?: number; +} + +export const CoinbaseWalletLogo: React.StatelessComponent = ({ width }) => ( + + + + +); + +CoinbaseWalletLogo.displayName = 'CoinbaseWalletLogo'; + +CoinbaseWalletLogo.defaultProps = { + width: 164, +}; diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index 3503ff31af..e4d8749a91 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -29,13 +29,19 @@ export class ERC20TokenSelector extends React.Component const { tokens, onTokenSelect } = this.props; return ( + + + Select Token + + - + {_.map(tokens, token => { if (!this._isTokenQueryMatch(token)) { return null; @@ -57,8 +63,10 @@ export class ERC20TokenSelector extends React.Component if (_.isUndefined(searchQuery)) { return true; } - const stringToSearch = `${token.metaData.name} ${token.metaData.symbol}`; - return _.includes(stringToSearch.toLowerCase(), searchQuery.toLowerCase()); + const searchQueryLowerCase = searchQuery.toLowerCase(); + const tokenName = token.metaData.name.toLowerCase(); + const tokenSymbol = token.metaData.symbol.toLowerCase(); + return _.startsWith(tokenSymbol, searchQueryLowerCase) || _.startsWith(tokenName, searchQueryLowerCase); }; } diff --git a/packages/instant/src/components/install_wallet_panel_content.tsx b/packages/instant/src/components/install_wallet_panel_content.tsx new file mode 100644 index 0000000000..88c26f59cf --- /dev/null +++ b/packages/instant/src/components/install_wallet_panel_content.tsx @@ -0,0 +1,68 @@ +import * as React from 'react'; + +import { + META_MASK_CHROME_STORE_URL, + META_MASK_FIREFOX_STORE_URL, + META_MASK_OPERA_STORE_URL, + META_MASK_SITE_URL, +} from '../constants'; +import { ColorOption } from '../style/theme'; +import { Browser } from '../types'; +import { envUtil } from '../util/env'; + +import { MetaMaskLogo } from './meta_mask_logo'; +import { StandardPanelContent, StandardPanelContentProps } from './standard_panel_content'; +import { Button } from './ui/button'; + +export interface InstallWalletPanelContentProps {} + +export class InstallWalletPanelContent extends React.Component { + public render(): React.ReactNode { + const panelProps = this._getStandardPanelContentProps(); + return ; + } + private readonly _getStandardPanelContentProps = (): StandardPanelContentProps => { + const browser = envUtil.getBrowser(); + let description = 'Please install the MetaMask wallet browser extension.'; + let actionText = 'Learn More'; + let actionUrl = META_MASK_SITE_URL; + switch (browser) { + case Browser.Chrome: + description = 'Please install the MetaMask wallet browser extension from the Chrome Store.'; + actionText = 'Get Chrome Extension'; + actionUrl = META_MASK_CHROME_STORE_URL; + break; + case Browser.Firefox: + description = 'Please install the MetaMask wallet browser extension from the Firefox Store.'; + actionText = 'Get Firefox Extension'; + actionUrl = META_MASK_FIREFOX_STORE_URL; + break; + case Browser.Opera: + description = 'Please install the MetaMask wallet browser extension from the Opera Store.'; + actionText = 'Get Opera Add-on'; + actionUrl = META_MASK_OPERA_STORE_URL; + break; + default: + break; + } + return { + image: , + title: 'Install MetaMask', + description, + moreInfoSettings: { + href: META_MASK_SITE_URL, + text: 'What is MetaMask?', + }, + action: ( + + ), + }; + }; +} diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index b07776b2c7..0026952693 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -15,8 +15,8 @@ import { Spinner } from './ui/spinner'; import { Text } from './ui/text'; export interface InstantHeadingProps { - selectedAssetAmount?: BigNumber; - totalEthBaseAmount?: BigNumber; + selectedAssetUnitAmount?: BigNumber; + totalEthBaseUnitAmount?: BigNumber; ethUsdPrice?: BigNumber; quoteRequestState: AsyncProcessState; buyOrderState: OrderState; @@ -32,12 +32,7 @@ export class InstantHeading extends React.Component { public render(): React.ReactNode { const iconOrAmounts = this._renderIcon() || this._renderAmountsSection(); return ( - + { if (this.props.quoteRequestState === AsyncProcessState.Pending) { return ; } - if (_.isUndefined(this.props.selectedAssetAmount)) { + if (_.isUndefined(this.props.selectedAssetUnitAmount)) { return ; } return amountFunction(); @@ -113,8 +108,8 @@ export class InstantHeading extends React.Component { private readonly _renderEthAmount = (): React.ReactNode => { return ( - {format.ethBaseAmount( - this.props.totalEthBaseAmount, + {format.ethBaseUnitAmount( + this.props.totalEthBaseUnitAmount, 4, , )} @@ -125,8 +120,8 @@ export class InstantHeading extends React.Component { private readonly _renderDollarAmount = (): React.ReactNode => { return ( - {format.ethBaseAmountInUsd( - this.props.totalEthBaseAmount, + {format.ethBaseUnitAmountInUsd( + this.props.totalEthBaseUnitAmount, this.props.ethUsdPrice, 2, , diff --git a/packages/instant/src/components/meta_mask_logo.tsx b/packages/instant/src/components/meta_mask_logo.tsx new file mode 100644 index 0000000000..bfbc67270f --- /dev/null +++ b/packages/instant/src/components/meta_mask_logo.tsx @@ -0,0 +1,80 @@ +import * as React from 'react'; + +export interface MetaMaskLogoProps { + width?: number; + height?: number; +} + +export const MetaMaskLogo: React.StatelessComponent = ({ width, height }) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); + +MetaMaskLogo.displayName = 'MetaMaskLogo'; + +MetaMaskLogo.defaultProps = { + width: 85, + height: 80, +}; diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx index 9abd7137e5..5fc956e1cf 100644 --- a/packages/instant/src/components/order_details.tsx +++ b/packages/instant/src/components/order_details.tsx @@ -4,6 +4,7 @@ import * as _ from 'lodash'; import * as React from 'react'; import { oc } from 'ts-optchain'; +import { BIG_NUMBER_ZERO } from '../constants'; import { ColorOption } from '../style/theme'; import { format } from '../util/format'; @@ -15,16 +16,23 @@ import { Text } from './ui/text'; export interface OrderDetailsProps { buyQuoteInfo?: BuyQuoteInfo; + selectedAssetUnitAmount?: BigNumber; ethUsdPrice?: BigNumber; isLoading: boolean; } export class OrderDetails extends React.Component { public render(): React.ReactNode { - const { buyQuoteInfo, ethUsdPrice } = this.props; + const { buyQuoteInfo, ethUsdPrice, selectedAssetUnitAmount } = this.props; const buyQuoteAccessor = oc(buyQuoteInfo); - const ethAssetPrice = buyQuoteAccessor.ethPerAssetPrice(); - const ethTokenFee = buyQuoteAccessor.feeEthAmount(); - const totalEthAmount = buyQuoteAccessor.totalEthAmount(); + const assetEthBaseUnitAmount = buyQuoteAccessor.assetEthAmount(); + const feeEthBaseUnitAmount = buyQuoteAccessor.feeEthAmount(); + const totalEthBaseUnitAmount = buyQuoteAccessor.totalEthAmount(); + const pricePerTokenEth = + !_.isUndefined(assetEthBaseUnitAmount) && + !_.isUndefined(selectedAssetUnitAmount) && + !selectedAssetUnitAmount.eq(BIG_NUMBER_ZERO) + ? assetEthBaseUnitAmount.div(selectedAssetUnitAmount).ceil() + : undefined; return ( @@ -40,20 +48,19 @@ export class OrderDetails extends React.Component { { const { rowLabel, ethAmount, isEthAmountInBaseUnits, shouldEmphasize, isLoading } = this.props; const fontWeight = shouldEmphasize ? 700 : 400; - const ethFormatter = isEthAmountInBaseUnits ? format.ethBaseAmount : format.ethUnitAmount; + const ethFormatter = isEthAmountInBaseUnits ? format.ethBaseUnitAmount : format.ethUnitAmount; return ( @@ -105,7 +112,9 @@ export class EthAmountRow extends React.Component { ); } private _renderUsdSection(): React.ReactNode { - const usdFormatter = this.props.isEthAmountInBaseUnits ? format.ethBaseAmountInUsd : format.ethUnitAmountInUsd; + const usdFormatter = this.props.isEthAmountInBaseUnits + ? format.ethBaseUnitAmountInUsd + : format.ethUnitAmountInUsd; const shouldHideUsdPriceSection = _.isUndefined(this.props.ethUsdPrice) || _.isUndefined(this.props.ethAmount); return shouldHideUsdPriceSection ? null : ( diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx index 8c0b47d726..ebcd62f35b 100644 --- a/packages/instant/src/components/payment_method.tsx +++ b/packages/instant/src/components/payment_method.tsx @@ -1,45 +1,114 @@ -import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; import { ColorOption } from '../style/theme'; -import { Network } from '../types'; +import { Account, AccountState, Network } from '../types'; +import { envUtil } from '../util/env'; +import { CoinbaseWalletLogo } from './coinbase_wallet_logo'; +import { MetaMaskLogo } from './meta_mask_logo'; import { PaymentMethodDropdown } from './payment_method_dropdown'; import { Circle } from './ui/circle'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; +import { Icon } from './ui/icon'; import { Text } from './ui/text'; +import { WalletPrompt } from './wallet_prompt'; -export interface PaymentMethodProps {} +export interface PaymentMethodProps { + account: Account; + network: Network; + walletName: string; + onInstallWalletClick: () => void; + onUnlockWalletClick: () => void; +} -export const PaymentMethod: React.StatelessComponent = () => ( - - - - - Payment Method - +export class PaymentMethod extends React.Component { + public render(): React.ReactNode { + return ( + + + + + {this._renderTitleText()} + + {this._renderTitleLabel()} + + + {this._renderMainContent()} + + ); + } + private readonly _renderTitleText = (): string => { + const { account } = this.props; + switch (account.state) { + case AccountState.Loading: + return 'loading...'; + case AccountState.Locked: + case AccountState.None: + return 'connect your wallet'; + case AccountState.Ready: + return 'payment method'; + } + }; + private readonly _renderTitleLabel = (): React.ReactNode => { + const { account } = this.props; + if (account.state === AccountState.Ready || account.state === AccountState.Locked) { + const circleColor: ColorOption = account.state === AccountState.Ready ? ColorOption.green : ColorOption.red; + return ( - + - MetaMask + {this.props.walletName} - - - - -); + ); + } + return null; + }; + private readonly _renderMainContent = (): React.ReactNode => { + const { account, network } = this.props; + const isMobile = envUtil.isMobileOperatingSystem(); + const logo = isMobile ? : ; + const primaryColor = isMobile ? ColorOption.darkBlue : ColorOption.darkOrange; + const secondaryColor = isMobile ? ColorOption.lightBlue : ColorOption.lightOrange; + const colors = { primaryColor, secondaryColor }; + switch (account.state) { + case AccountState.Loading: + // Just take up the same amount of space as the other states. + return ; + case AccountState.Locked: + return ( + } + {...colors} + > + Please Unlock {this.props.walletName} + + ); + case AccountState.None: + return ( + + {isMobile ? 'Install Coinbase Wallet' : 'Install MetaMask'} + + ); + case AccountState.Ready: + return ( + + ); + } + }; +} diff --git a/packages/instant/src/components/payment_method_dropdown.tsx b/packages/instant/src/components/payment_method_dropdown.tsx index bdce2a49d2..b330dbcd69 100644 --- a/packages/instant/src/components/payment_method_dropdown.tsx +++ b/packages/instant/src/components/payment_method_dropdown.tsx @@ -3,6 +3,7 @@ import copy from 'copy-to-clipboard'; import * as React from 'react'; import { Network } from '../types'; +import { envUtil } from '../util/env'; import { etherscanUtil } from '../util/etherscan'; import { format } from '../util/format'; @@ -18,10 +19,13 @@ export class PaymentMethodDropdown extends React.Component; } private readonly _getDropdownItemConfigs = (): DropdownItemConfig[] => { + if (envUtil.isMobileOperatingSystem()) { + return []; + } const viewOnEtherscan = { text: 'View on Etherscan', onClick: this._handleEtherscanClick, diff --git a/packages/instant/src/components/placing_order_button.tsx b/packages/instant/src/components/placing_order_button.tsx index d774d7d275..2516b90b12 100644 --- a/packages/instant/src/components/placing_order_button.tsx +++ b/packages/instant/src/components/placing_order_button.tsx @@ -7,9 +7,9 @@ import { Container } from './ui/container'; import { Spinner } from './ui/spinner'; export const PlacingOrderButton: React.StatelessComponent<{}> = props => ( - diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index 1abadb78b1..e1599a3168 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -156,8 +156,6 @@ export class ScalingInput extends React.Component { diff --git a/packages/instant/src/components/secondary_button.tsx b/packages/instant/src/components/secondary_button.tsx index df05396065..705390e283 100644 --- a/packages/instant/src/components/secondary_button.tsx +++ b/packages/instant/src/components/secondary_button.tsx @@ -15,8 +15,6 @@ export const SecondaryButton: React.StatelessComponent = p borderColor={ColorOption.lightGrey} width={props.width} onClick={props.onClick} - fontColor={ColorOption.primaryColor} - fontSize="16px" {...buttonProps} > {props.children} diff --git a/packages/instant/src/components/sliding_error.tsx b/packages/instant/src/components/sliding_error.tsx index a8d4e391c3..b59e2a905c 100644 --- a/packages/instant/src/components/sliding_error.tsx +++ b/packages/instant/src/components/sliding_error.tsx @@ -3,9 +3,10 @@ import * as React from 'react'; import { ScreenSpecification } from '../style/media'; import { ColorOption } from '../style/theme'; import { zIndex } from '../style/z_index'; +import { SlideAnimationState } from '../types'; import { PositionAnimationSettings } from './animations/position_animation'; -import { SlideAnimation, SlideAnimationState } from './animations/slide_animation'; +import { SlideAnimation } from './animations/slide_animation'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; diff --git a/packages/instant/src/components/sliding_panel.tsx b/packages/instant/src/components/sliding_panel.tsx index 9d16f95606..7f90370499 100644 --- a/packages/instant/src/components/sliding_panel.tsx +++ b/packages/instant/src/components/sliding_panel.tsx @@ -2,35 +2,25 @@ import * as React from 'react'; import { ColorOption } from '../style/theme'; import { zIndex } from '../style/z_index'; +import { SlideAnimationState } from '../types'; import { PositionAnimationSettings } from './animations/position_animation'; -import { SlideAnimation, SlideAnimationState } from './animations/slide_animation'; +import { SlideAnimation } from './animations/slide_animation'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; import { Icon } from './ui/icon'; -import { Text } from './ui/text'; export interface PanelProps { - title?: string; onClose?: () => void; } -export const Panel: React.StatelessComponent = ({ title, children, onClose }) => ( +export const Panel: React.StatelessComponent = ({ children, onClose }) => ( - - {title && ( - - - {title} - - - )} - - - + + - + {children} diff --git a/packages/instant/src/components/standard_panel_content.tsx b/packages/instant/src/components/standard_panel_content.tsx new file mode 100644 index 0000000000..582b3318e0 --- /dev/null +++ b/packages/instant/src/components/standard_panel_content.tsx @@ -0,0 +1,62 @@ +import * as React from 'react'; + +import { ColorOption } from '../style/theme'; + +import { Container } from './ui/container'; +import { Flex } from './ui/flex'; +import { Text } from './ui/text'; + +export interface MoreInfoSettings { + text: string; + href: string; +} + +export interface StandardPanelContentProps { + image: React.ReactNode; + title?: string; + description: string; + moreInfoSettings?: MoreInfoSettings; + action: React.ReactNode; +} + +const SPACING_BETWEEN_PX = '20px'; + +export const StandardPanelContent: React.StatelessComponent = ({ + image, + title, + description, + moreInfoSettings, + action, +}) => ( + + + {image} + {title && ( + + + {title} + + + )} + + + {description} + + + + {moreInfoSettings && ( + + {moreInfoSettings.text} + + )} + + + {action} + +); diff --git a/packages/instant/src/components/standard_sliding_panel.tsx b/packages/instant/src/components/standard_sliding_panel.tsx new file mode 100644 index 0000000000..f587ff79a9 --- /dev/null +++ b/packages/instant/src/components/standard_sliding_panel.tsx @@ -0,0 +1,29 @@ +import * as React from 'react'; + +import { SlideAnimationState, StandardSlidingPanelContent, StandardSlidingPanelSettings } from '../types'; + +import { InstallWalletPanelContent } from './install_wallet_panel_content'; +import { SlidingPanel } from './sliding_panel'; + +export interface StandardSlidingPanelProps extends StandardSlidingPanelSettings { + onClose: () => void; +} + +export class StandardSlidingPanel extends React.Component { + public render(): React.ReactNode { + const { animationState, content, onClose } = this.props; + return ( + + {this._getNodeForContent(content)} + + ); + } + private readonly _getNodeForContent = (content: StandardSlidingPanelContent): React.ReactNode => { + switch (content) { + case StandardSlidingPanelContent.InstallWallet: + return ; + case StandardSlidingPanelContent.None: + return null; + } + }; +} diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx index 59aaa33a14..8465b9cd0a 100644 --- a/packages/instant/src/components/timed_progress_bar.tsx +++ b/packages/instant/src/components/timed_progress_bar.tsx @@ -2,7 +2,7 @@ import * as _ from 'lodash'; import * as React from 'react'; import { PROGRESS_FINISH_ANIMATION_TIME_MS, PROGRESS_STALL_AT_WIDTH } from '../constants'; -import { ColorOption, keyframes, styled } from '../style/theme'; +import { ColorOption, css, keyframes, styled } from '../style/theme'; import { Container } from './ui/container'; @@ -20,15 +20,11 @@ export class TimedProgressBar extends React.Component private readonly _barRef = React.createRef(); public render(): React.ReactNode { - const timedProgressProps = this._calculateTimedProgressProps(); - return ( - - - - ); + const widthAnimationSettings = this._calculateWidthAnimationSettings(); + return ; } - private _calculateTimedProgressProps(): TimedProgressProps { + private _calculateWidthAnimationSettings(): WidthAnimationSettings { if (this.props.hasEnded) { if (!this._barRef.current) { throw new Error('ended but no reference'); @@ -60,21 +56,45 @@ const expandingWidthKeyframes = (fromWidth: string, toWidth: string) => { `; }; -interface TimedProgressProps { +export interface WidthAnimationSettings { timeMs: number; fromWidth: string; toWidth: string; } -export const TimedProgress = +interface ProgressProps { + width?: string; + animationSettings?: WidthAnimationSettings; +} + +export const Progress = styled.div < - TimedProgressProps > + ProgressProps > ` && { background-color: ${props => props.theme[ColorOption.primaryColor]}; border-radius: 6px; height: 6px; - animation: ${props => expandingWidthKeyframes(props.fromWidth, props.toWidth)} - ${props => props.timeMs}ms linear 1 forwards; + ${props => (props.width ? `width: ${props.width};` : '')} + ${props => + props.animationSettings + ? css` + animation: ${expandingWidthKeyframes( + props.animationSettings.fromWidth, + props.animationSettings.toWidth, + )} + ${props.animationSettings.timeMs}ms linear 1 forwards; + ` + : ''} } `; + +export interface ProgressBarProps extends ProgressProps {} + +export const ProgressBar: React.ComponentType> = React.forwardRef( + (props, ref) => ( + + + + ), +); diff --git a/packages/instant/src/components/ui/button.tsx b/packages/instant/src/components/ui/button.tsx index b90221bf4e..e77b1b5d19 100644 --- a/packages/instant/src/components/ui/button.tsx +++ b/packages/instant/src/components/ui/button.tsx @@ -2,6 +2,9 @@ import { darken, saturate } from 'polished'; import * as React from 'react'; import { ColorOption, styled } from '../../style/theme'; +import { util } from '../../util/util'; + +export type ButtonOnClickHandler = (event: React.MouseEvent) => void; export interface ButtonProps { backgroundColor?: ColorOption; @@ -12,15 +15,26 @@ export interface ButtonProps { padding?: string; type?: string; isDisabled?: boolean; - onClick?: (event: React.MouseEvent) => void; + href?: string; + onClick?: ButtonOnClickHandler; className?: string; } -const PlainButton: React.StatelessComponent = ({ children, isDisabled, onClick, type, className }) => ( - -); +const PlainButton: React.StatelessComponent = ({ + children, + isDisabled, + onClick, + href, + type, + className, +}) => { + const computedOnClick = isDisabled ? undefined : href ? util.createOpenUrlInNewWindow(href) : onClick; + return ( + + ); +}; const darkenOnHoverAmount = 0.1; const darkenOnActiveAmount = 0.2; @@ -31,7 +45,7 @@ export const Button = styled(PlainButton)` box-sizing: border-box; font-size: ${props => props.fontSize}; font-family: 'Inter UI', sans-serif; - font-weight: 600; + font-weight: 500; color: ${props => props.fontColor && props.theme[props.fontColor]}; cursor: ${props => (props.isDisabled ? 'default' : 'pointer')}; transition: background-color, opacity 0.5s ease; @@ -64,11 +78,10 @@ export const Button = styled(PlainButton)` Button.defaultProps = { backgroundColor: ColorOption.primaryColor, - borderColor: ColorOption.primaryColor, width: 'auto', isDisabled: false, - padding: '.6em 1.2em', - fontSize: '15px', + padding: '.82em 1.2em', + fontSize: '16px', }; Button.displayName = 'Button'; diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index 8aa5db9e52..4dafe13862 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -20,7 +20,7 @@ export interface ContainerProps { marginBottom?: string; marginLeft?: string; padding?: string; - borderRadius?: string; + borderRadius?: MediaChoice; border?: string; borderColor?: ColorOption; borderTop?: string; @@ -57,7 +57,6 @@ export const Container = ${props => cssRuleIfExists(props, 'margin-bottom')} ${props => cssRuleIfExists(props, 'margin-left')} ${props => cssRuleIfExists(props, 'padding')} - ${props => cssRuleIfExists(props, 'border-radius')} ${props => cssRuleIfExists(props, 'border')} ${props => cssRuleIfExists(props, 'border-top')} ${props => cssRuleIfExists(props, 'border-bottom')} @@ -70,6 +69,7 @@ export const Container = ${props => props.display && stylesForMedia('display', props.display)} ${props => props.width && stylesForMedia('width', props.width)} ${props => props.height && stylesForMedia('height', props.height)} + ${props => props.borderRadius && stylesForMedia('border-radius', props.borderRadius)} background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')}; &:hover { diff --git a/packages/instant/src/components/ui/icon.tsx b/packages/instant/src/components/ui/icon.tsx index a88fa87ddb..811142b5b3 100644 --- a/packages/instant/src/components/ui/icon.tsx +++ b/packages/instant/src/components/ui/icon.tsx @@ -20,6 +20,7 @@ interface IconInfoMapping { success: IconInfo; chevron: IconInfo; search: IconInfo; + lock: IconInfo; } const ICONS: IconInfoMapping = { closeX: { @@ -58,6 +59,11 @@ const ICONS: IconInfoMapping = { path: 'M8.39404 5.19727C8.39404 6.96289 6.96265 8.39453 5.19702 8.39453C3.4314 8.39453 2 6.96289 2 5.19727C2 3.43164 3.4314 2 5.19702 2C6.96265 2 8.39404 3.43164 8.39404 5.19727ZM8.09668 9.51074C7.26855 10.0684 6.27075 10.3945 5.19702 10.3945C2.3269 10.3945 0 8.06738 0 5.19727C0 2.32715 2.3269 0 5.19702 0C8.06738 0 10.394 2.32715 10.394 5.19727C10.394 6.27051 10.0686 7.26855 9.51074 8.09668L13.6997 12.2861L12.2854 13.7002L8.09668 9.51074Z', }, + lock: { + viewBox: '0 0 13 16', + path: + 'M6.47619 0C3.79509 0 1.60489 2.21216 1.60489 4.92014V6.33135C0.717479 6.33135 0 7.05602 0 7.95232V14.379C0 15.2753 0.717479 16 1.60489 16H11.3475C12.2349 16 12.9524 15.2753 12.9524 14.379V7.95232C12.9524 7.05602 12.2349 6.33135 11.3475 6.33135V4.92014C11.3475 2.21216 9.1573 0 6.47619 0ZM9.6482 6.33135H3.30418V4.92014C3.30418 3.16567 4.72026 1.71633 6.47619 1.71633C8.23213 1.71633 9.6482 3.16567 9.6482 4.92014V6.33135Z', + }, }; export interface IconProps { diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx index 2fb408db4a..1ea5d8fe16 100644 --- a/packages/instant/src/components/ui/input.tsx +++ b/packages/instant/src/components/ui/input.tsx @@ -3,6 +3,7 @@ import * as React from 'react'; import { ColorOption, styled } from '../../style/theme'; export interface InputProps { + tabIndex?: number; className?: string; value?: string; width?: string; diff --git a/packages/instant/src/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx index 4fe429d25a..fd14cc4d1d 100644 --- a/packages/instant/src/components/ui/text.tsx +++ b/packages/instant/src/components/ui/text.tsx @@ -2,6 +2,7 @@ import { darken } from 'polished'; import * as React from 'react'; import { ColorOption, styled } from '../../style/theme'; +import { util } from '../../util/util'; export interface TextProps { fontColor?: ColorOption; @@ -20,10 +21,16 @@ export interface TextProps { onClick?: (event: React.MouseEvent) => void; noWrap?: boolean; display?: string; + href?: string; } +export const Text: React.StatelessComponent = ({ href, onClick, ...rest }) => { + const computedOnClick = href ? util.createOpenUrlInNewWindow(href) : onClick; + return ; +}; + const darkenOnHoverAmount = 0.3; -export const Text = +export const StyledText = styled.div < TextProps > ` diff --git a/packages/instant/src/components/wallet_prompt.tsx b/packages/instant/src/components/wallet_prompt.tsx new file mode 100644 index 0000000000..a0b3ae457e --- /dev/null +++ b/packages/instant/src/components/wallet_prompt.tsx @@ -0,0 +1,47 @@ +import * as React from 'react'; + +import { ColorOption } from '../style/theme'; + +import { Container } from './ui/container'; +import { Flex } from './ui/flex'; +import { Text } from './ui/text'; + +export interface WalletPromptProps { + image: React.ReactNode; + onClick?: () => void; + primaryColor: ColorOption; + secondaryColor: ColorOption; +} + +export const WalletPrompt: React.StatelessComponent = ({ + onClick, + image, + children, + secondaryColor, + primaryColor, +}) => ( + + + {image} + + + {children} + + + + +); + +WalletPrompt.defaultProps = { + primaryColor: ColorOption.darkOrange, + secondaryColor: ColorOption.lightOrange, +}; diff --git a/packages/instant/src/components/zero_ex_instant.tsx b/packages/instant/src/components/zero_ex_instant.tsx index b945f99088..2267b4dbf2 100644 --- a/packages/instant/src/components/zero_ex_instant.tsx +++ b/packages/instant/src/components/zero_ex_instant.tsx @@ -1,8 +1,9 @@ import * as React from 'react'; +import { ZeroExInstantContainer } from '../components/zero_ex_instant_container'; + import { INJECTED_DIV_CLASS } from '../constants'; -import { ZeroExInstantContainer } from './zero_ex_instant_container'; import { ZeroExInstantProvider, ZeroExInstantProviderProps } from './zero_ex_instant_provider'; export type ZeroExInstantProps = ZeroExInstantProviderProps; diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 5748e064ed..698bfef17c 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -1,26 +1,29 @@ import * as React from 'react'; import { AvailableERC20TokenSelector } from '../containers/available_erc20_token_selector'; +import { ConnectedBuyOrderProgressOrPaymentMethod } from '../containers/connected_buy_order_progress_or_payment_method'; +import { CurrentStandardSlidingPanel } from '../containers/current_standard_sliding_panel'; import { LatestBuyQuoteOrderDetails } from '../containers/latest_buy_quote_order_details'; import { LatestError } from '../containers/latest_error'; -import { SelectedAssetBuyOrderProgress } from '../containers/selected_asset_buy_order_progress'; import { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_buy_order_state_buttons'; import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading'; import { ColorOption } from '../style/theme'; import { zIndex } from '../style/z_index'; +import { OrderProcessState, SlideAnimationState } from '../types'; -import { SlideAnimationState } from './animations/slide_animation'; import { CSSReset } from './css_reset'; import { SlidingPanel } from './sliding_panel'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; -export interface ZeroExInstantContainerProps {} +export interface ZeroExInstantContainerProps { + orderProcessState: OrderProcessState; +} export interface ZeroExInstantContainerState { tokenSelectionPanelAnimationState: SlideAnimationState; } -export class ZeroExInstantContainer extends React.Component { +export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantContainerState> { public state = { tokenSelectionPanelAnimationState: 'none' as SlideAnimationState, }; @@ -40,26 +43,26 @@ export class ZeroExInstantContainer extends React.Component - + + diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx index 10438ab7a5..2856ea3e33 100644 --- a/packages/instant/src/components/zero_ex_instant_overlay.tsx +++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx @@ -1,12 +1,12 @@ import * as React from 'react'; +import { ZeroExInstantContainer } from '../components/zero_ex_instant_container'; import { ColorOption } from '../style/theme'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; import { Icon } from './ui/icon'; import { Overlay } from './ui/overlay'; -import { ZeroExInstantContainer } from './zero_ex_instant_container'; import { ZeroExInstantProvider, ZeroExInstantProviderProps } from './zero_ex_instant_provider'; export interface ZeroExInstantOverlayProps extends ZeroExInstantProviderProps { diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 411f118cc2..8be53ee20b 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -73,7 +73,7 @@ export class ZeroExInstantProvider extends React.Component void; + unlockWalletAndDispatchToStore: (providerState: ProviderState) => void; +} + +type ConnectedProps = Omit; + +type FinalProps = ConnectedProps & ConnectedAccountPaymentMethodProps; + +const mapStateToProps = (state: State, _ownProps: ConnectedAccountPaymentMethodProps): ConnectedState => ({ + network: state.network, + providerState: state.providerState, +}); + +const mapDispatchToProps = ( + dispatch: Dispatch, + ownProps: ConnectedAccountPaymentMethodProps, +): ConnectedDispatch => ({ + openInstallWalletPanel: () => dispatch(actions.openStandardSlidingPanel(StandardSlidingPanelContent.InstallWallet)), + unlockWalletAndDispatchToStore: async (providerState: ProviderState) => + asyncData.fetchAccountInfoAndDispatchToStore(providerState, dispatch, true), +}); + +const mergeProps = ( + connectedState: ConnectedState, + connectedDispatch: ConnectedDispatch, + ownProps: ConnectedAccountPaymentMethodProps, +): FinalProps => ({ + ...ownProps, + network: connectedState.network, + account: connectedState.providerState.account, + walletName: connectedState.providerState.name, + onUnlockWalletClick: () => connectedDispatch.unlockWalletAndDispatchToStore(connectedState.providerState), + onInstallWalletClick: () => { + const isMobile = envUtil.isMobileOperatingSystem(); + if (!isMobile) { + connectedDispatch.openInstallWalletPanel(); + return; + } + const operatingSystem = envUtil.getOperatingSystem(); + let url = COINBASE_WALLET_SITE_URL; + switch (operatingSystem) { + case OperatingSystem.Android: + url = COINBASE_WALLET_ANDROID_APP_STORE_URL; + break; + case OperatingSystem.iOS: + url = COINBASE_WALLET_IOS_APP_STORE_URL; + break; + default: + break; + } + window.open(url, '_blank'); + }, +}); + +export const ConnectedAccountPaymentMethod: React.ComponentClass = connect( + mapStateToProps, + mapDispatchToProps, + mergeProps, +)(PaymentMethod); diff --git a/packages/instant/src/containers/connected_buy_order_progress_or_payment_method.tsx b/packages/instant/src/containers/connected_buy_order_progress_or_payment_method.tsx new file mode 100644 index 0000000000..cace18e7ec --- /dev/null +++ b/packages/instant/src/containers/connected_buy_order_progress_or_payment_method.tsx @@ -0,0 +1,35 @@ +import * as React from 'react'; +import { connect } from 'react-redux'; + +import { State } from '../redux/reducer'; +import { OrderProcessState } from '../types'; + +import { ConnectedAccountPaymentMethod } from './connected_account_payment_method'; +import { SelectedAssetBuyOrderProgress } from './selected_asset_buy_order_progress'; + +interface BuyOrderProgressOrPaymentMethodProps { + orderProcessState: OrderProcessState; +} +export const BuyOrderProgressOrPaymentMethod = (props: BuyOrderProgressOrPaymentMethodProps) => { + const { orderProcessState } = props; + if ( + orderProcessState === OrderProcessState.Processing || + orderProcessState === OrderProcessState.Success || + orderProcessState === OrderProcessState.Failure + ) { + return ; + } else { + return ; + } + return null; +}; + +interface ConnectedState extends BuyOrderProgressOrPaymentMethodProps {} + +export interface ConnectedBuyOrderProgressOrPaymentMethodProps {} +const mapStateToProps = (state: State, _ownProps: ConnectedBuyOrderProgressOrPaymentMethodProps): ConnectedState => ({ + orderProcessState: state.buyOrderState.processState, +}); +export const ConnectedBuyOrderProgressOrPaymentMethod: React.ComponentClass< + ConnectedBuyOrderProgressOrPaymentMethodProps +> = connect(mapStateToProps)(BuyOrderProgressOrPaymentMethod); diff --git a/packages/instant/src/containers/current_standard_sliding_panel.ts b/packages/instant/src/containers/current_standard_sliding_panel.ts new file mode 100644 index 0000000000..82ac7fa1ba --- /dev/null +++ b/packages/instant/src/containers/current_standard_sliding_panel.ts @@ -0,0 +1,31 @@ +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; + +import { StandardSlidingPanel } from '../components/standard_sliding_panel'; +import { Action, actions } from '../redux/actions'; +import { State } from '../redux/reducer'; +import { StandardSlidingPanelSettings } from '../types'; + +export interface CurrentStandardSlidingPanelProps {} + +interface ConnectedState extends StandardSlidingPanelSettings {} + +interface ConnectedDispatch { + onClose: () => void; +} + +const mapStateToProps = (state: State, _ownProps: CurrentStandardSlidingPanelProps): ConnectedState => + state.standardSlidingPanelSettings; + +const mapDispatchToProps = ( + dispatch: Dispatch, + ownProps: CurrentStandardSlidingPanelProps, +): ConnectedDispatch => ({ + onClose: () => dispatch(actions.closeStandardSlidingPanel()), +}); + +export const CurrentStandardSlidingPanel: React.ComponentClass = connect( + mapStateToProps, + mapDispatchToProps, +)(StandardSlidingPanel); diff --git a/packages/instant/src/containers/latest_buy_quote_order_details.ts b/packages/instant/src/containers/latest_buy_quote_order_details.ts index 2b59ed3aec..5dfe535e74 100644 --- a/packages/instant/src/containers/latest_buy_quote_order_details.ts +++ b/packages/instant/src/containers/latest_buy_quote_order_details.ts @@ -14,6 +14,7 @@ export interface LatestBuyQuoteOrderDetailsProps {} interface ConnectedState { buyQuoteInfo?: BuyQuoteInfo; + selectedAssetUnitAmount?: BigNumber; ethUsdPrice?: BigNumber; isLoading: boolean; } @@ -21,6 +22,7 @@ interface ConnectedState { const mapStateToProps = (state: State, _ownProps: LatestBuyQuoteOrderDetailsProps): ConnectedState => ({ // use the worst case quote info buyQuoteInfo: oc(state).latestBuyQuote.worstCaseQuoteInfo(), + selectedAssetUnitAmount: state.selectedAssetUnitAmount, ethUsdPrice: state.ethUsdPrice, isLoading: state.quoteRequestState === AsyncProcessState.Pending, }); diff --git a/packages/instant/src/containers/latest_error.tsx b/packages/instant/src/containers/latest_error.tsx index c0da181f19..b7cfdb5044 100644 --- a/packages/instant/src/containers/latest_error.tsx +++ b/packages/instant/src/containers/latest_error.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { Dispatch } from 'redux'; -import { SlideAnimationState } from '../components/animations/slide_animation'; import { SlidingError } from '../components/sliding_error'; import { Overlay } from '../components/ui/overlay'; import { Action } from '../redux/actions'; @@ -11,7 +10,7 @@ import { State } from '../redux/reducer'; import { ScreenWidths } from '../style/media'; import { generateOverlayBlack } from '../style/theme'; import { zIndex } from '../style/z_index'; -import { Asset, DisplayStatus, Omit } from '../types'; +import { Asset, DisplayStatus, Omit, SlideAnimationState } from '../types'; import { errorFlasher } from '../util/error_flasher'; export interface LatestErrorComponentProps { diff --git a/packages/instant/src/containers/selected_asset_instant_heading.ts b/packages/instant/src/containers/selected_asset_instant_heading.ts index a407279e60..8dc127e1d7 100644 --- a/packages/instant/src/containers/selected_asset_instant_heading.ts +++ b/packages/instant/src/containers/selected_asset_instant_heading.ts @@ -14,16 +14,16 @@ export interface InstantHeadingProps { } interface ConnectedState { - selectedAssetAmount?: BigNumber; - totalEthBaseAmount?: BigNumber; + selectedAssetUnitAmount?: BigNumber; + totalEthBaseUnitAmount?: BigNumber; ethUsdPrice?: BigNumber; quoteRequestState: AsyncProcessState; buyOrderState: OrderState; } const mapStateToProps = (state: State, _ownProps: InstantHeadingProps): ConnectedState => ({ - selectedAssetAmount: state.selectedAssetAmount, - totalEthBaseAmount: oc(state).latestBuyQuote.worstCaseQuoteInfo.totalEthAmount(), + selectedAssetUnitAmount: state.selectedAssetUnitAmount, + totalEthBaseUnitAmount: oc(state).latestBuyQuote.worstCaseQuoteInfo.totalEthAmount(), ethUsdPrice: state.ethUsdPrice, quoteRequestState: state.quoteRequestState, buyOrderState: state.buyOrderState, diff --git a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts index 93ff3db705..2c2661e1af 100644 --- a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts +++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts @@ -6,11 +6,11 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { Dispatch } from 'redux'; -import { ERC20AssetAmountInput } from '../components/erc20_asset_amount_input'; +import { ERC20AssetAmountInput, ERC20AssetAmountInputProps } from '../components/erc20_asset_amount_input'; import { Action, actions } from '../redux/actions'; import { State } from '../redux/reducer'; import { ColorOption } from '../style/theme'; -import { AffiliateInfo, ERC20Asset, OrderProcessState } from '../types'; +import { AffiliateInfo, ERC20Asset, Omit, OrderProcessState } from '../types'; import { buyQuoteUpdater } from '../util/buy_quote_updater'; export interface SelectedERC20AssetAmountInputProps { @@ -37,13 +37,7 @@ interface ConnectedDispatch { ) => void; } -interface ConnectedProps { - value?: BigNumber; - asset?: ERC20Asset; - onChange: (value?: BigNumber, asset?: ERC20Asset) => void; - isDisabled: boolean; - numberOfAssetsAvailable?: number; -} +type ConnectedProps = Omit; type FinalProps = ConnectedProps & SelectedERC20AssetAmountInputProps; @@ -59,7 +53,7 @@ const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputP const assetBuyer = state.providerState.assetBuyer; return { assetBuyer, - value: state.selectedAssetAmount, + value: state.selectedAssetUnitAmount, asset: selectedAsset, isDisabled, numberOfAssetsAvailable, @@ -87,7 +81,11 @@ const mapDispatchToProps = ( // even if it's debounced, give them the illusion it's loading dispatch(actions.setQuoteRequestStatePending()); // tslint:disable-next-line:no-floating-promises - debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value, true, affiliateInfo); + debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value, { + setPending: true, + dispatchErrors: true, + affiliateInfo, + }); } }, }); diff --git a/packages/instant/src/data/asset_meta_data_map.ts b/packages/instant/src/data/asset_meta_data_map.ts index 970b6c383c..6ecb9af857 100644 --- a/packages/instant/src/data/asset_meta_data_map.ts +++ b/packages/instant/src/data/asset_meta_data_map.ts @@ -8,42 +8,42 @@ export const assetMetaDataMap: ObjectMap = { '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498': { assetProxyId: AssetProxyId.ERC20, decimals: 18, - primaryColor: 'rgb(54, 50, 60)', + primaryColor: '#333333', symbol: 'zrx', name: '0x', }, '0xf47261b000000000000000000000000042d6622dece394b54999fbd73d108123806f6a18': { assetProxyId: AssetProxyId.ERC20, decimals: 18, - primaryColor: '#ec3e6c', + primaryColor: '#EC4F81', symbol: 'spank', name: 'Spank', }, '0xf47261b0000000000000000000000000d26114cd6ee289accf82350c8d8487fedb8a0c07': { assetProxyId: AssetProxyId.ERC20, decimals: 18, - primaryColor: '#2e61ea', + primaryColor: '#2458E7', symbol: 'omg', name: 'OmiseGo', }, '0xf47261b00000000000000000000000009f8f72aa9304c8b593d555f12ef6589cc3a579a2': { assetProxyId: AssetProxyId.ERC20, decimals: 18, - primaryColor: '#87e4ca', + primaryColor: '#68CCBB', symbol: 'mkr', name: 'Maker', }, '0xf47261b00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef': { assetProxyId: AssetProxyId.ERC20, decimals: 18, - primaryColor: '#9c326c', + primaryColor: '#FF5000', symbol: 'bat', name: 'Basic Attention Token', }, '0xf47261b0000000000000000000000000744d70fdbe2ba4cf95131626614a1763df805b9e': { assetProxyId: AssetProxyId.ERC20, decimals: 18, - primaryColor: '#5663b0', + primaryColor: '#4763D7', symbol: 'snt', name: 'Status', }, @@ -54,27 +54,6 @@ export const assetMetaDataMap: ObjectMap = { symbol: 'mana', name: 'Decentraland', }, - '0xf47261b0000000000000000000000000a74476443119a942de498590fe1f2454d7d4ac0d': { - assetProxyId: AssetProxyId.ERC20, - decimals: 18, - primaryColor: '#263469', - symbol: 'gnt', - name: 'Golem', - }, - '0xf47261b000000000000000000000000012480e24eb5bec1a9d4369cab6a80cad3c0a377a': { - assetProxyId: AssetProxyId.ERC20, - decimals: 18, - primaryColor: '#de5445', - symbol: 'sub', - name: 'Substratum', - }, - '0xf47261b000000000000000000000000008d32b0da63e2C3bcF8019c9c5d849d7a9d791e6': { - assetProxyId: AssetProxyId.ERC20, - decimals: 18, - primaryColor: '#000', - symbol: 'dentacoin', - name: 'Dentacoin', - }, '0xf47261b00000000000000000000000001985365e9f78359a9b6ad760e32412f4a445e862': { assetProxyId: AssetProxyId.ERC20, decimals: 18, @@ -82,4 +61,144 @@ export const assetMetaDataMap: ObjectMap = { symbol: 'rep', name: 'Augur', }, + '0xf47261b00000000000000000000000000abdace70d3790235af448c88547603b945604ea': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#2c3c8c', + symbol: 'dnt', + name: 'district0x', + }, + '0xf47261b000000000000000000000000005f4a42e251f2d52b8ed15e9fedaacfcef1fad27': { + assetProxyId: AssetProxyId.ERC20, + decimals: 12, + primaryColor: '#048998', + symbol: 'zil', + name: 'Zilliqa', + }, + '0xf47261b00000000000000000000000008f8221afbb33998d8584a2b05749ba73c37a938a': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#58BFD6', + symbol: 'req', + name: 'Request Network', + }, + '0xf47261b0000000000000000000000000e0b7927c4af23765cb51314a0e0521a9645f0e2a': { + assetProxyId: AssetProxyId.ERC20, + decimals: 9, + primaryColor: '#BC9952', + symbol: 'dgd', + name: 'DigixDao', + }, + '0xf47261b00000000000000000000000004f3afec4e5a3f2a6a1a411def7d7dfe50ee057bf': { + assetProxyId: AssetProxyId.ERC20, + decimals: 9, + primaryColor: '#DEB564', + symbol: 'dgx', + name: 'Digix Gold Token', + }, + '0xf47261b0000000000000000000000000419d0d8bdd9af5e606ae2232ed285aff190e711b': { + assetProxyId: AssetProxyId.ERC20, + decimals: 8, + primaryColor: '#E40057', + symbol: 'fun', + name: 'FunFair', + }, + '0xf47261b000000000000000000000000041e5560054824ea6b0732e656e3ad64e20e94e45': { + assetProxyId: AssetProxyId.ERC20, + decimals: 8, + primaryColor: '#04bc24', + symbol: 'cvc', + name: 'Civic', + }, + '0xf47261b00000000000000000000000005ca9a71b1d01849c0a95490cc00559717fcf0d1d': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#F7296E', + symbol: 'ae', + name: 'Aeternity', + }, + '0xf47261b0000000000000000000000000408e41876cccdc0f92210600ef50372656052a38': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#233C5A', + symbol: 'ren', + name: 'Republic Protocol', + }, + '0xf47261b0000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#325CD2', + symbol: 'link', + name: 'ChainLink', + }, + '0xf47261b00000000000000000000000006810e776880c02933d47db1b9fc05908e5386b96': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#48A4C0', + symbol: 'gno', + name: 'Gnosis', + }, + '0xf47261b0000000000000000000000000960b236a07cf122663c4303350609a66a7b288c0': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#04a29e', + symbol: 'ant', + name: 'Aragon', + }, + '0xf47261b00000000000000000000000004156d3342d5c385a87d264f90653733592000581': { + assetProxyId: AssetProxyId.ERC20, + decimals: 8, + primaryColor: '#4CABA7', + symbol: 'salt', + name: 'Salt', + }, + '0xf47261b0000000000000000000000000595832f8fc6bf59c85c527fec3740a1b7a361269': { + assetProxyId: AssetProxyId.ERC20, + decimals: 6, + primaryColor: '#5BC9D4', + symbol: 'powr', + name: 'PowerLedger', + }, + '0xf47261b00000000000000000000000008eb24319393716668d768dcec29356ae9cffe285': { + assetProxyId: AssetProxyId.ERC20, + decimals: 8, + primaryColor: '#523CE8', + symbol: 'agi', + name: 'SingularityNET', + }, + '0xf47261b000000000000000000000000039bb259f66e1c59d5abef88375979b4d20d98022': { + assetProxyId: AssetProxyId.ERC20, + decimals: 8, + primaryColor: '#EDB740', + symbol: 'wax', + name: 'WAX', + }, + '0xf47261b0000000000000000000000000beb9ef514a379b997e0798fdcc901ee474b6d9a1': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#333333', + symbol: 'mln', + name: 'Melon', + }, + '0xf47261b000000000000000000000000058b6a8a3302369daec383334672404ee733ab239': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#232D37', + symbol: 'lpt', + name: 'Livepeer', + }, + '0xf47261b000000000000000000000000027054b13b1b798b345b591a4d22e6562d47ea75a': { + assetProxyId: AssetProxyId.ERC20, + decimals: 4, + primaryColor: '#3A74F6', + symbol: 'ast', + name: 'AirSwap', + }, + '0xf47261b000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#F2B350', + symbol: 'dai', + name: 'Dai Stablecoin', + }, }; diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index 8947c6c975..77e3dec124 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -2,7 +2,7 @@ import { BuyQuote } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; -import { ActionsUnion, AddressAndEthBalanceInWei, Asset } from '../types'; +import { ActionsUnion, AddressAndEthBalanceInWei, Asset, StandardSlidingPanelContent } from '../types'; export interface PlainAction { type: T; @@ -26,7 +26,7 @@ export enum ActionTypes { SET_ACCOUNT_STATE_READY = 'SET_ACCOUNT_STATE_READY', UPDATE_ACCOUNT_ETH_BALANCE = 'UPDATE_ACCOUNT_ETH_BALANCE', UPDATE_ETH_USD_PRICE = 'UPDATE_ETH_USD_PRICE', - UPDATE_SELECTED_ASSET_AMOUNT = 'UPDATE_SELECTED_ASSET_AMOUNT', + UPDATE_SELECTED_ASSET_UNIT_AMOUNT = 'UPDATE_SELECTED_ASSET_UNIT_AMOUNT', SET_BUY_ORDER_STATE_NONE = 'SET_BUY_ORDER_STATE_NONE', SET_BUY_ORDER_STATE_VALIDATING = 'SET_BUY_ORDER_STATE_VALIDATING', SET_BUY_ORDER_STATE_PROCESSING = 'SET_BUY_ORDER_STATE_PROCESSING', @@ -41,6 +41,8 @@ export enum ActionTypes { HIDE_ERROR = 'HIDE_ERROR', CLEAR_ERROR = 'CLEAR_ERROR', RESET_AMOUNT = 'RESET_AMOUNT', + OPEN_STANDARD_SLIDING_PANEL = 'OPEN_STANDARD_SLIDING_PANEL', + CLOSE_STANDARD_SLIDING_PANEL = 'CLOSE_STANDARD_SLIDING_PANEL', } export const actions = { @@ -50,7 +52,8 @@ export const actions = { updateAccountEthBalance: (addressAndBalance: AddressAndEthBalanceInWei) => createAction(ActionTypes.UPDATE_ACCOUNT_ETH_BALANCE, addressAndBalance), updateEthUsdPrice: (price?: BigNumber) => createAction(ActionTypes.UPDATE_ETH_USD_PRICE, price), - updateSelectedAssetAmount: (amount?: BigNumber) => createAction(ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT, amount), + updateSelectedAssetAmount: (amount?: BigNumber) => + createAction(ActionTypes.UPDATE_SELECTED_ASSET_UNIT_AMOUNT, amount), setBuyOrderStateNone: () => createAction(ActionTypes.SET_BUY_ORDER_STATE_NONE), setBuyOrderStateValidating: () => createAction(ActionTypes.SET_BUY_ORDER_STATE_VALIDATING), setBuyOrderStateProcessing: (txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => @@ -66,4 +69,7 @@ export const actions = { hideError: () => createAction(ActionTypes.HIDE_ERROR), clearError: () => createAction(ActionTypes.CLEAR_ERROR), resetAmount: () => createAction(ActionTypes.RESET_AMOUNT), + openStandardSlidingPanel: (content: StandardSlidingPanelContent) => + createAction(ActionTypes.OPEN_STANDARD_SLIDING_PANEL, content), + closeStandardSlidingPanel: () => createAction(ActionTypes.CLOSE_STANDARD_SLIDING_PANEL), }; diff --git a/packages/instant/src/redux/async_data.ts b/packages/instant/src/redux/async_data.ts index b920ac9141..5d30388b85 100644 --- a/packages/instant/src/redux/async_data.ts +++ b/packages/instant/src/redux/async_data.ts @@ -1,102 +1,103 @@ import { AssetProxyId } from '@0x/types'; +import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; +import { Dispatch } from 'redux'; import { BIG_NUMBER_ZERO } from '../constants'; -import { AccountState, ERC20Asset, OrderProcessState } from '../types'; +import { AccountState, ERC20Asset, OrderProcessState, ProviderState } from '../types'; import { assetUtils } from '../util/asset'; import { buyQuoteUpdater } from '../util/buy_quote_updater'; import { coinbaseApi } from '../util/coinbase_api'; import { errorFlasher } from '../util/error_flasher'; import { actions } from './actions'; -import { Store } from './store'; +import { State } from './reducer'; export const asyncData = { - fetchEthPriceAndDispatchToStore: async (store: Store) => { + fetchEthPriceAndDispatchToStore: async (dispatch: Dispatch) => { try { const ethUsdPrice = await coinbaseApi.getEthUsdPrice(); - store.dispatch(actions.updateEthUsdPrice(ethUsdPrice)); + dispatch(actions.updateEthUsdPrice(ethUsdPrice)); } catch (e) { const errorMessage = 'Error fetching ETH/USD price'; - errorFlasher.flashNewErrorMessage(store.dispatch, errorMessage); - store.dispatch(actions.updateEthUsdPrice(BIG_NUMBER_ZERO)); + errorFlasher.flashNewErrorMessage(dispatch, errorMessage); + dispatch(actions.updateEthUsdPrice(BIG_NUMBER_ZERO)); } }, - fetchAvailableAssetDatasAndDispatchToStore: async (store: Store) => { - const { providerState, assetMetaDataMap, network } = store.getState(); + fetchAvailableAssetDatasAndDispatchToStore: async (state: State, dispatch: Dispatch) => { + const { providerState, assetMetaDataMap, network } = state; const assetBuyer = providerState.assetBuyer; try { const assetDatas = await assetBuyer.getAvailableAssetDatasAsync(); const assets = assetUtils.createAssetsFromAssetDatas(assetDatas, assetMetaDataMap, network); - store.dispatch(actions.setAvailableAssets(assets)); + dispatch(actions.setAvailableAssets(assets)); } catch (e) { const errorMessage = 'Could not find any assets'; - errorFlasher.flashNewErrorMessage(store.dispatch, errorMessage); + errorFlasher.flashNewErrorMessage(dispatch, errorMessage); // On error, just specify that none are available - store.dispatch(actions.setAvailableAssets([])); + dispatch(actions.setAvailableAssets([])); } }, - fetchAccountInfoAndDispatchToStore: async (options: { store: Store; shouldSetToLoading: boolean }) => { - const { store, shouldSetToLoading } = options; - const { providerState } = store.getState(); + fetchAccountInfoAndDispatchToStore: async ( + providerState: ProviderState, + dispatch: Dispatch, + shouldAttemptUnlock: boolean = false, + shouldSetToLoading: boolean = false, + ) => { const web3Wrapper = providerState.web3Wrapper; const provider = providerState.provider; if (shouldSetToLoading && providerState.account.state !== AccountState.Loading) { - store.dispatch(actions.setAccountStateLoading()); + dispatch(actions.setAccountStateLoading()); } let availableAddresses: string[]; try { // TODO(bmillman): Add support at the web3Wrapper level for calling `eth_requestAccounts` instead of calling enable here const isPrivacyModeEnabled = !_.isUndefined((provider as any).enable); - availableAddresses = isPrivacyModeEnabled - ? await (provider as any).enable() - : await web3Wrapper.getAvailableAddressesAsync(); + availableAddresses = + isPrivacyModeEnabled && shouldAttemptUnlock + ? await (provider as any).enable() + : await web3Wrapper.getAvailableAddressesAsync(); } catch (e) { - store.dispatch(actions.setAccountStateLocked()); + dispatch(actions.setAccountStateLocked()); return; } if (!_.isEmpty(availableAddresses)) { const activeAddress = availableAddresses[0]; - store.dispatch(actions.setAccountStateReady(activeAddress)); + dispatch(actions.setAccountStateReady(activeAddress)); // tslint:disable-next-line:no-floating-promises - asyncData.fetchAccountBalanceAndDispatchToStore(store); + asyncData.fetchAccountBalanceAndDispatchToStore(activeAddress, providerState.web3Wrapper, dispatch); } else { - store.dispatch(actions.setAccountStateLocked()); + dispatch(actions.setAccountStateLocked()); } }, - fetchAccountBalanceAndDispatchToStore: async (store: Store) => { - const { providerState } = store.getState(); - const web3Wrapper = providerState.web3Wrapper; - const account = providerState.account; - if (account.state !== AccountState.Ready) { - return; - } + fetchAccountBalanceAndDispatchToStore: async (address: string, web3Wrapper: Web3Wrapper, dispatch: Dispatch) => { try { - const address = account.address; const ethBalanceInWei = await web3Wrapper.getBalanceInWeiAsync(address); - store.dispatch(actions.updateAccountEthBalance({ address, ethBalanceInWei })); + dispatch(actions.updateAccountEthBalance({ address, ethBalanceInWei })); } catch (e) { // leave balance as is return; } }, - fetchCurrentBuyQuoteAndDispatchToStore: async (options: { store: Store; shouldSetPending: boolean }) => { - const { store, shouldSetPending } = options; - const { buyOrderState, providerState, selectedAsset, selectedAssetAmount, affiliateInfo } = store.getState(); + fetchCurrentBuyQuoteAndDispatchToStore: async ( + state: State, + dispatch: Dispatch, + options: { updateSilently: boolean }, + ) => { + const { buyOrderState, providerState, selectedAsset, selectedAssetUnitAmount, affiliateInfo } = state; const assetBuyer = providerState.assetBuyer; if ( - !_.isUndefined(selectedAssetAmount) && + !_.isUndefined(selectedAssetUnitAmount) && !_.isUndefined(selectedAsset) && buyOrderState.processState === OrderProcessState.None && selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20 ) { await buyQuoteUpdater.updateBuyQuoteAsync( assetBuyer, - store.dispatch, + dispatch, selectedAsset as ERC20Asset, - selectedAssetAmount, - shouldSetPending, - affiliateInfo, + selectedAssetUnitAmount, + { setPending: !options.updateSilently, dispatchErrors: !options.updateSilently, affiliateInfo }, ); } }, diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index ef46fdd9d9..dfc2b89f30 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -19,6 +19,8 @@ import { OrderProcessState, OrderState, ProviderState, + StandardSlidingPanelContent, + StandardSlidingPanelSettings, } from '../types'; import { Action, ActionTypes } from './actions'; @@ -30,6 +32,7 @@ export interface DefaultState { buyOrderState: OrderState; latestErrorDisplayStatus: DisplayStatus; quoteRequestState: AsyncProcessState; + standardSlidingPanelSettings: StandardSlidingPanelSettings; } // State that is required but needs to be derived from the props @@ -41,7 +44,7 @@ interface PropsDerivedState { interface OptionalState { selectedAsset: Asset; availableAssets: Asset[]; - selectedAssetAmount: BigNumber; + selectedAssetUnitAmount: BigNumber; ethUsdPrice: BigNumber; latestBuyQuote: BuyQuote; latestErrorMessage: string; @@ -56,6 +59,10 @@ export const DEFAULT_STATE: DefaultState = { buyOrderState: { processState: OrderProcessState.None }, latestErrorDisplayStatus: DisplayStatus.Hidden, quoteRequestState: AsyncProcessState.None, + standardSlidingPanelSettings: { + animationState: 'none', + content: StandardSlidingPanelContent.None, + }, }; export const createReducer = (initialState: State) => { @@ -66,11 +73,19 @@ export const createReducer = (initialState: State) => { case ActionTypes.SET_ACCOUNT_STATE_LOCKED: return reduceStateWithAccount(state, LOCKED_ACCOUNT); case ActionTypes.SET_ACCOUNT_STATE_READY: { - const account: AccountReady = { + const address = action.data; + let newAccount: AccountReady = { state: AccountState.Ready, - address: action.data, + address, }; - return reduceStateWithAccount(state, account); + const currentAccount = state.providerState.account; + if (currentAccount.state === AccountState.Ready && currentAccount.address === address) { + newAccount = { + ...newAccount, + ethBalanceInWei: currentAccount.ethBalanceInWei, + }; + } + return reduceStateWithAccount(state, newAccount); } case ActionTypes.UPDATE_ACCOUNT_ETH_BALANCE: { const { address, ethBalanceInWei } = action.data; @@ -90,10 +105,10 @@ export const createReducer = (initialState: State) => { ...state, ethUsdPrice: action.data, }; - case ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT: + case ActionTypes.UPDATE_SELECTED_ASSET_UNIT_AMOUNT: return { ...state, - selectedAssetAmount: action.data, + selectedAssetUnitAmount: action.data, }; case ActionTypes.UPDATE_LATEST_BUY_QUOTE: const newBuyQuoteIfExists = action.data; @@ -204,13 +219,29 @@ export const createReducer = (initialState: State) => { latestBuyQuote: undefined, quoteRequestState: AsyncProcessState.None, buyOrderState: { processState: OrderProcessState.None }, - selectedAssetAmount: undefined, + selectedAssetUnitAmount: undefined, }; case ActionTypes.SET_AVAILABLE_ASSETS: return { ...state, availableAssets: action.data, }; + case ActionTypes.OPEN_STANDARD_SLIDING_PANEL: + return { + ...state, + standardSlidingPanelSettings: { + content: action.data, + animationState: 'slidIn', + }, + }; + case ActionTypes.CLOSE_STANDARD_SLIDING_PANEL: + return { + ...state, + standardSlidingPanelSettings: { + content: state.standardSlidingPanelSettings.content, + animationState: 'slidOut', + }, + }; default: return state; } @@ -232,9 +263,9 @@ const reduceStateWithAccount = (state: State, account: Account) => { const doesBuyQuoteMatchState = (buyQuote: BuyQuote, state: State): boolean => { const selectedAssetIfExists = state.selectedAsset; - const selectedAssetAmountIfExists = state.selectedAssetAmount; + const selectedAssetUnitAmountIfExists = state.selectedAssetUnitAmount; // if no selectedAsset or selectedAssetAmount exists on the current state, return false - if (_.isUndefined(selectedAssetIfExists) || _.isUndefined(selectedAssetAmountIfExists)) { + if (_.isUndefined(selectedAssetIfExists) || _.isUndefined(selectedAssetUnitAmountIfExists)) { return false; } // if buyQuote's assetData does not match that of the current selected asset, return false @@ -246,7 +277,7 @@ const doesBuyQuoteMatchState = (buyQuote: BuyQuote, state: State): boolean => { const selectedAssetMetaData = selectedAssetIfExists.metaData; if (selectedAssetMetaData.assetProxyId === AssetProxyId.ERC20) { const selectedAssetAmountBaseUnits = Web3Wrapper.toBaseUnitAmount( - selectedAssetAmountIfExists, + selectedAssetUnitAmountIfExists, selectedAssetMetaData.decimals, ); const doesAssetAmountMatch = selectedAssetAmountBaseUnits.eq(buyQuote.assetBuyAmount); diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts index 1e9f55e000..a0751286b8 100644 --- a/packages/instant/src/style/theme.ts +++ b/packages/instant/src/style/theme.ts @@ -17,6 +17,8 @@ export enum ColorOption { darkOrange = 'darkOrange', green = 'green', red = 'red', + darkBlue = 'darkBlue', + lightBlue = 'lightBlue', } export const theme: Theme = { @@ -32,6 +34,8 @@ export const theme: Theme = { darkOrange: '#F2994C', green: '#3CB34F', red: '#D00000', + darkBlue: '#135df6', + lightBlue: '#F2F7FF', }; export const transparentWhite = 'rgba(255,255,255,0.3)'; diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index b43a82d460..67f21a3960 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -95,6 +95,7 @@ export interface AffiliateInfo { } export interface ProviderState { + name: string; provider: Provider; assetBuyer: AssetBuyer; web3Wrapper: Web3Wrapper; @@ -125,3 +126,42 @@ export interface AddressAndEthBalanceInWei { address: string; ethBalanceInWei: BigNumber; } + +export type SlideAnimationState = 'slidIn' | 'slidOut' | 'none'; + +export enum StandardSlidingPanelContent { + None = 'NONE', + InstallWallet = 'INSTALL_WALLET', +} + +export interface StandardSlidingPanelSettings { + animationState: SlideAnimationState; + content: StandardSlidingPanelContent; +} + +export enum Browser { + Chrome = 'CHROME', + Firefox = 'FIREFOX', + Opera = 'OPERA', + Safari = 'SAFARI', + Edge = 'EDGE', + Other = 'OTHER', +} + +export enum OperatingSystem { + Android = 'ANDROID', + iOS = 'IOS', + Mac = 'MAC', + Windows = 'WINDOWS', + WindowsPhone = 'WINDOWS_PHONE', + Linux = 'LINUX', + Other = 'OTHER', +} + +export enum ProviderType { + Parity = 'PARITY', + MetaMask = 'META_MASK', + Mist = 'MIST', + CoinbaseWallet = 'COINBASE_WALLET', + Cipher = 'CIPHER', +} diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index fbfbb19f3a..40560d3eb1 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -80,8 +80,6 @@ export const assetUtils = { return metaData.symbol.toUpperCase(); case AssetProxyId.ERC721: return metaData.name; - default: - return defaultName; } }, formattedSymbolForAsset: (asset?: ERC20Asset, defaultName: string = '???'): string => { diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts index c33e28f1c5..2fd16d7818 100644 --- a/packages/instant/src/util/buy_quote_updater.ts +++ b/packages/instant/src/util/buy_quote_updater.ts @@ -15,40 +15,43 @@ export const buyQuoteUpdater = { assetBuyer: AssetBuyer, dispatch: Dispatch, asset: ERC20Asset, - assetAmount: BigNumber, - setPending = true, - affiliateInfo?: AffiliateInfo, + assetUnitAmount: BigNumber, + options: { setPending: boolean; dispatchErrors: boolean; affiliateInfo?: AffiliateInfo }, ): Promise => { // get a new buy quote. - const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, asset.metaData.decimals); - if (setPending) { + const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetUnitAmount, asset.metaData.decimals); + if (options.setPending) { // mark quote as pending dispatch(actions.setQuoteRequestStatePending()); } - const feePercentage = oc(affiliateInfo).feePercentage(); + const feePercentage = oc(options.affiliateInfo).feePercentage(); let newBuyQuote: BuyQuote | undefined; try { newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue, { feePercentage }); } catch (error) { - dispatch(actions.setQuoteRequestStateFailure()); - let errorMessage; - if (error.message === AssetBuyerError.InsufficientAssetLiquidity) { - const assetName = assetUtils.bestNameForAsset(asset, 'of this asset'); - errorMessage = `Not enough ${assetName} available`; - } else if (error.message === AssetBuyerError.InsufficientZrxLiquidity) { - errorMessage = 'Not enough ZRX available'; - } else if ( - error.message === AssetBuyerError.StandardRelayerApiError || - error.message.startsWith(AssetBuyerError.AssetUnavailable) - ) { - const assetName = assetUtils.bestNameForAsset(asset, 'This asset'); - errorMessage = `${assetName} is currently unavailable`; - } - if (!_.isUndefined(errorMessage)) { - errorFlasher.flashNewErrorMessage(dispatch, errorMessage); - } else { - throw error; + if (options.dispatchErrors) { + dispatch(actions.setQuoteRequestStateFailure()); + let errorMessage; + if (error.message === AssetBuyerError.InsufficientAssetLiquidity) { + const assetName = assetUtils.bestNameForAsset(asset, 'of this asset'); + errorMessage = `Not enough ${assetName} available`; + } else if (error.message === AssetBuyerError.InsufficientZrxLiquidity) { + errorMessage = 'Not enough ZRX available'; + } else if ( + error.message === AssetBuyerError.StandardRelayerApiError || + error.message.startsWith(AssetBuyerError.AssetUnavailable) + ) { + const assetName = assetUtils.bestNameForAsset(asset, 'This asset'); + errorMessage = `${assetName} is currently unavailable`; + } + if (!_.isUndefined(errorMessage)) { + errorFlasher.flashNewErrorMessage(dispatch, errorMessage); + } else { + throw error; + } } + // TODO: report to error reporter on else + return; } // We have a successful new buy quote diff --git a/packages/instant/src/util/env.ts b/packages/instant/src/util/env.ts new file mode 100644 index 0000000000..4a32f9cb11 --- /dev/null +++ b/packages/instant/src/util/env.ts @@ -0,0 +1,65 @@ +import * as bowser from 'bowser'; +import { Provider } from 'ethereum-types'; +import * as _ from 'lodash'; + +import { PROVIDER_TYPE_TO_NAME } from '../constants'; +import { Browser, OperatingSystem, ProviderType } from '../types'; + +export const envUtil = { + getBrowser(): Browser { + if (bowser.chrome) { + return Browser.Chrome; + } else if (bowser.firefox) { + return Browser.Firefox; + } else if (bowser.opera) { + return Browser.Opera; + } else if (bowser.msedge) { + return Browser.Edge; + } else if (bowser.safari) { + return Browser.Safari; + } else { + return Browser.Other; + } + }, + isMobileOperatingSystem(): boolean { + return bowser.mobile; + }, + getOperatingSystem(): OperatingSystem { + if (bowser.android) { + return OperatingSystem.Android; + } else if (bowser.ios) { + return OperatingSystem.iOS; + } else if (bowser.mac) { + return OperatingSystem.Mac; + } else if (bowser.windows) { + return OperatingSystem.Windows; + } else if (bowser.windowsphone) { + return OperatingSystem.WindowsPhone; + } else if (bowser.linux) { + return OperatingSystem.Linux; + } else { + return OperatingSystem.Other; + } + }, + getProviderType(provider: Provider): ProviderType | undefined { + if (provider.constructor.name === 'EthereumProvider') { + return ProviderType.Mist; + } else if ((provider as any).isParity) { + return ProviderType.Parity; + } else if ((provider as any).isMetaMask) { + return ProviderType.MetaMask; + } else if (!_.isUndefined(_.get(window, 'SOFA'))) { + return ProviderType.CoinbaseWallet; + } else if (!_.isUndefined(_.get(window, '__CIPHER__'))) { + return ProviderType.Cipher; + } + return; + }, + getProviderName(provider: Provider): string { + const providerTypeIfExists = envUtil.getProviderType(provider); + if (_.isUndefined(providerTypeIfExists)) { + return provider.constructor.name; + } + return PROVIDER_TYPE_TO_NAME[providerTypeIfExists]; + }, +}; diff --git a/packages/instant/src/util/etherscan.ts b/packages/instant/src/util/etherscan.ts index 4d62c4d9f0..f9bf828272 100644 --- a/packages/instant/src/util/etherscan.ts +++ b/packages/instant/src/util/etherscan.ts @@ -8,9 +8,8 @@ const etherscanPrefix = (networkId: number): string | undefined => { return 'kovan.'; case Network.Mainnet: return ''; - default: - return undefined; } + return ''; }; export const etherscanUtil = { diff --git a/packages/instant/src/util/format.ts b/packages/instant/src/util/format.ts index 44661d6974..e9c432b2f8 100644 --- a/packages/instant/src/util/format.ts +++ b/packages/instant/src/util/format.ts @@ -5,15 +5,15 @@ import * as _ from 'lodash'; import { ETH_DECIMALS } from '../constants'; export const format = { - ethBaseAmount: ( - ethBaseAmount?: BigNumber, + ethBaseUnitAmount: ( + ethBaseUnitAmount?: BigNumber, decimalPlaces: number = 4, defaultText: React.ReactNode = '0 ETH', ): React.ReactNode => { - if (_.isUndefined(ethBaseAmount)) { + if (_.isUndefined(ethBaseUnitAmount)) { return defaultText; } - const ethUnitAmount = Web3Wrapper.toUnitAmount(ethBaseAmount, ETH_DECIMALS); + const ethUnitAmount = Web3Wrapper.toUnitAmount(ethBaseUnitAmount, ETH_DECIMALS); return format.ethUnitAmount(ethUnitAmount, decimalPlaces); }, ethUnitAmount: ( @@ -27,16 +27,16 @@ export const format = { const roundedAmount = ethUnitAmount.round(decimalPlaces).toDigits(decimalPlaces); return `${roundedAmount} ETH`; }, - ethBaseAmountInUsd: ( - ethBaseAmount?: BigNumber, + ethBaseUnitAmountInUsd: ( + ethBaseUnitAmount?: BigNumber, ethUsdPrice?: BigNumber, decimalPlaces: number = 2, defaultText: React.ReactNode = '$0.00', ): React.ReactNode => { - if (_.isUndefined(ethBaseAmount) || _.isUndefined(ethUsdPrice)) { + if (_.isUndefined(ethBaseUnitAmount) || _.isUndefined(ethUsdPrice)) { return defaultText; } - const ethUnitAmount = Web3Wrapper.toUnitAmount(ethBaseAmount, ETH_DECIMALS); + const ethUnitAmount = Web3Wrapper.toUnitAmount(ethBaseUnitAmount, ETH_DECIMALS); return format.ethUnitAmountInUsd(ethUnitAmount, ethUsdPrice, decimalPlaces); }, ethUnitAmountInUsd: ( diff --git a/packages/instant/src/util/heartbeater_factory.ts b/packages/instant/src/util/heartbeater_factory.ts index 96a8ac4e6e..2b852fb0d5 100644 --- a/packages/instant/src/util/heartbeater_factory.ts +++ b/packages/instant/src/util/heartbeater_factory.ts @@ -10,13 +10,15 @@ export interface HeartbeatFactoryOptions { export const generateAccountHeartbeater = (options: HeartbeatFactoryOptions): Heartbeater => { const { store, shouldPerformImmediatelyOnStart } = options; return new Heartbeater(async () => { - await asyncData.fetchAccountInfoAndDispatchToStore({ store, shouldSetToLoading: false }); + await asyncData.fetchAccountInfoAndDispatchToStore(store.getState().providerState, store.dispatch, false); }, shouldPerformImmediatelyOnStart); }; export const generateBuyQuoteHeartbeater = (options: HeartbeatFactoryOptions): Heartbeater => { const { store, shouldPerformImmediatelyOnStart } = options; return new Heartbeater(async () => { - await asyncData.fetchCurrentBuyQuoteAndDispatchToStore({ store, shouldSetPending: false }); + await asyncData.fetchCurrentBuyQuoteAndDispatchToStore(store.getState(), store.dispatch, { + updateSilently: true, + }); }, shouldPerformImmediatelyOnStart); }; diff --git a/packages/instant/src/util/provider_state_factory.ts b/packages/instant/src/util/provider_state_factory.ts index 3281f6bfba..452a71460d 100644 --- a/packages/instant/src/util/provider_state_factory.ts +++ b/packages/instant/src/util/provider_state_factory.ts @@ -4,6 +4,7 @@ import * as _ from 'lodash'; import { LOADING_ACCOUNT, NO_ACCOUNT } from '../constants'; import { Maybe, Network, OrderSource, ProviderState } from '../types'; +import { envUtil } from '../util/env'; import { assetBuyerFactory } from './asset_buyer_factory'; import { providerFactory } from './provider_factory'; @@ -29,6 +30,7 @@ export const providerStateFactory = { provider: Provider, ): ProviderState => { const providerState: ProviderState = { + name: envUtil.getProviderName(provider), provider, web3Wrapper: new Web3Wrapper(provider), assetBuyer: assetBuyerFactory.getAssetBuyer(provider, orderSource, network), @@ -40,6 +42,7 @@ export const providerStateFactory = { const injectedProviderIfExists = providerFactory.getInjectedProviderIfExists(); if (!_.isUndefined(injectedProviderIfExists)) { const providerState: ProviderState = { + name: envUtil.getProviderName(injectedProviderIfExists), provider: injectedProviderIfExists, web3Wrapper: new Web3Wrapper(injectedProviderIfExists), assetBuyer: assetBuyerFactory.getAssetBuyer(injectedProviderIfExists, orderSource, network), @@ -53,6 +56,7 @@ export const providerStateFactory = { getInitialProviderStateFallback: (orderSource: OrderSource, network: Network): ProviderState => { const provider = providerFactory.getFallbackNoSigningProvider(network); const providerState: ProviderState = { + name: envUtil.getProviderName(provider), provider, web3Wrapper: new Web3Wrapper(provider), assetBuyer: assetBuyerFactory.getAssetBuyer(provider, orderSource, network), diff --git a/packages/instant/src/util/util.ts b/packages/instant/src/util/util.ts index 232a868503..29b6b1d2bf 100644 --- a/packages/instant/src/util/util.ts +++ b/packages/instant/src/util/util.ts @@ -2,4 +2,5 @@ import * as _ from 'lodash'; export const util = { boundNoop: _.noop.bind(_), + createOpenUrlInNewWindow: (href: string) => () => window.open(href, '_blank'), }; diff --git a/packages/instant/test/util/format.test.ts b/packages/instant/test/util/format.test.ts index c346b76045..fe0a63e6e8 100644 --- a/packages/instant/test/util/format.test.ts +++ b/packages/instant/test/util/format.test.ts @@ -15,20 +15,20 @@ const BIG_NUMBER_FAKE_ETH_USD_PRICE = new BigNumber(2.534); describe('format', () => { describe('ethBaseAmount', () => { it('converts 1 ETH in base units to the string `1 ETH`', () => { - expect(format.ethBaseAmount(ONE_ETH_IN_BASE_UNITS)).toBe('1 ETH'); + expect(format.ethBaseUnitAmount(ONE_ETH_IN_BASE_UNITS)).toBe('1 ETH'); }); it('converts .432414 ETH in base units to the string `.4324 ETH`', () => { - expect(format.ethBaseAmount(DECIMAL_ETH_IN_BASE_UNITS)).toBe('0.4324 ETH'); + expect(format.ethBaseUnitAmount(DECIMAL_ETH_IN_BASE_UNITS)).toBe('0.4324 ETH'); }); it('converts 5.3014059295032 ETH in base units to the string `5.301 ETH`', () => { - expect(format.ethBaseAmount(IRRATIONAL_ETH_IN_BASE_UNITS)).toBe('5.301 ETH'); + expect(format.ethBaseUnitAmount(IRRATIONAL_ETH_IN_BASE_UNITS)).toBe('5.301 ETH'); }); it('returns defaultText param when ethBaseAmount is not defined', () => { const defaultText = 'defaultText'; - expect(format.ethBaseAmount(undefined, 4, defaultText)).toBe(defaultText); + expect(format.ethBaseUnitAmount(undefined, 4, defaultText)).toBe(defaultText); }); it('it allows for configurable decimal places', () => { - expect(format.ethBaseAmount(DECIMAL_ETH_IN_BASE_UNITS, 2)).toBe('0.43 ETH'); + expect(format.ethBaseUnitAmount(DECIMAL_ETH_IN_BASE_UNITS, 2)).toBe('0.43 ETH'); }); }); describe('ethUnitAmount', () => { @@ -52,24 +52,26 @@ describe('format', () => { }); describe('ethBaseAmountInUsd', () => { it('correctly formats 1 ETH to usd according to some price', () => { - expect(format.ethBaseAmountInUsd(ONE_ETH_IN_BASE_UNITS, BIG_NUMBER_FAKE_ETH_USD_PRICE)).toBe('$2.53'); + expect(format.ethBaseUnitAmountInUsd(ONE_ETH_IN_BASE_UNITS, BIG_NUMBER_FAKE_ETH_USD_PRICE)).toBe('$2.53'); }); it('correctly formats .432414 ETH to usd according to some price', () => { - expect(format.ethBaseAmountInUsd(DECIMAL_ETH_IN_BASE_UNITS, BIG_NUMBER_FAKE_ETH_USD_PRICE)).toBe('$1.10'); + expect(format.ethBaseUnitAmountInUsd(DECIMAL_ETH_IN_BASE_UNITS, BIG_NUMBER_FAKE_ETH_USD_PRICE)).toBe( + '$1.10', + ); }); it('correctly formats 5.3014059295032 ETH to usd according to some price', () => { - expect(format.ethBaseAmountInUsd(IRRATIONAL_ETH_IN_BASE_UNITS, BIG_NUMBER_FAKE_ETH_USD_PRICE)).toBe( + expect(format.ethBaseUnitAmountInUsd(IRRATIONAL_ETH_IN_BASE_UNITS, BIG_NUMBER_FAKE_ETH_USD_PRICE)).toBe( '$13.43', ); }); it('returns defaultText param when ethBaseAmountInUsd or ethUsdPrice is not defined', () => { const defaultText = 'defaultText'; - expect(format.ethBaseAmountInUsd(undefined, undefined, 2, defaultText)).toBe(defaultText); - expect(format.ethBaseAmountInUsd(BIG_NUMBER_ONE, undefined, 2, defaultText)).toBe(defaultText); - expect(format.ethBaseAmountInUsd(undefined, BIG_NUMBER_ONE, 2, defaultText)).toBe(defaultText); + expect(format.ethBaseUnitAmountInUsd(undefined, undefined, 2, defaultText)).toBe(defaultText); + expect(format.ethBaseUnitAmountInUsd(BIG_NUMBER_ONE, undefined, 2, defaultText)).toBe(defaultText); + expect(format.ethBaseUnitAmountInUsd(undefined, BIG_NUMBER_ONE, 2, defaultText)).toBe(defaultText); }); it('it allows for configurable decimal places', () => { - expect(format.ethBaseAmountInUsd(DECIMAL_ETH_IN_BASE_UNITS, BIG_NUMBER_FAKE_ETH_USD_PRICE, 4)).toBe( + expect(format.ethBaseUnitAmountInUsd(DECIMAL_ETH_IN_BASE_UNITS, BIG_NUMBER_FAKE_ETH_USD_PRICE, 4)).toBe( '$1.0957', ); }); diff --git a/packages/instant/tslint.json b/packages/instant/tslint.json index 08b76be97d..d43ee8da7e 100644 --- a/packages/instant/tslint.json +++ b/packages/instant/tslint.json @@ -3,6 +3,7 @@ "rules": { "custom-no-magic-numbers": false, "semicolon": [true, "always", "ignore-bound-class-methods"], - "max-classes-per-file": false + "max-classes-per-file": false, + "switch-default": false } } diff --git a/packages/instant/webpack.config.js b/packages/instant/webpack.config.js index 78a33ce904..3129e13a67 100644 --- a/packages/instant/webpack.config.js +++ b/packages/instant/webpack.config.js @@ -1,7 +1,8 @@ const path = require('path'); +const ip = require('ip'); // The common js bundle (not this one) is built using tsc. // The umd bundle (this one) has a different entrypoint. -module.exports = { +const config = { entry: './src/index.umd.ts', output: { filename: '[name].bundle.js', @@ -24,5 +25,15 @@ module.exports = { devServer: { contentBase: path.join(__dirname, 'public'), port: 5000, + host: '0.0.0.0', + after: () => { + if (config.devServer.host === '0.0.0.0') { + console.log( + `webpack-dev-server can be accessed externally at: http://${ip.address()}:${config.devServer.port}`, + ); + } + }, }, }; + +module.exports = config; diff --git a/packages/json-schemas/CHANGELOG.json b/packages/json-schemas/CHANGELOG.json index f25a487b83..bf815e5231 100644 --- a/packages/json-schemas/CHANGELOG.json +++ b/packages/json-schemas/CHANGELOG.json @@ -1,14 +1,27 @@ [ { - "version": "2.0.1", + "timestamp": 1542208198, + "version": "2.1.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "2.1.0", "changes": [ { "note": "Improve schemas by enforcing that amounts that must be whole numbers (e.g Order asset amounts) no longer allow decimal amounts", "pr": 1173 + }, + { + "note": "Add schemas from @0x/connect", + "pr": 1250 } ], - "timestamp": 1541740904 + "timestamp": 1542028948 }, { "version": "2.0.0", diff --git a/packages/json-schemas/CHANGELOG.md b/packages/json-schemas/CHANGELOG.md index a1c784640b..dc412bded8 100644 --- a/packages/json-schemas/CHANGELOG.md +++ b/packages/json-schemas/CHANGELOG.md @@ -5,9 +5,14 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v2.0.1 - _November 9, 2018_ +## v2.1.1 - _November 14, 2018_ + + * Dependencies updated + +## v2.1.0 - _November 12, 2018_ * Improve schemas by enforcing that amounts that must be whole numbers (e.g Order asset amounts) no longer allow decimal amounts (#1173) + * Add schemas from @0x/connect (#1250) ## v2.0.0 - _October 18, 2018_ diff --git a/packages/json-schemas/package.json b/packages/json-schemas/package.json index c87cbb65ab..fb89a2d5b1 100644 --- a/packages/json-schemas/package.json +++ b/packages/json-schemas/package.json @@ -1,6 +1,6 @@ { "name": "@0x/json-schemas", - "version": "2.0.1", + "version": "2.1.1", "engines": { "node": ">=6.12" }, @@ -46,7 +46,7 @@ }, "devDependencies": { "@0x/tslint-config": "^1.0.10", - "@0x/utils": "^2.0.4", + "@0x/utils": "^2.0.5", "@types/lodash.foreach": "^4.5.3", "@types/lodash.values": "^4.3.3", "@types/mocha": "^2.2.42", diff --git a/packages/json-schemas/schemas/asset_pairs_request_opts_schema.json b/packages/json-schemas/schemas/asset_pairs_request_opts_schema.json new file mode 100644 index 0000000000..174a8fdc32 --- /dev/null +++ b/packages/json-schemas/schemas/asset_pairs_request_opts_schema.json @@ -0,0 +1,8 @@ +{ + "id": "/AssetPairsRequestOpts", + "type": "object", + "properties": { + "assetDataA": { "$ref": "/hexSchema" }, + "assetDataB": { "$ref": "/hexSchema" } + } +} diff --git a/packages/json-schemas/schemas/order_config_request_schema.json b/packages/json-schemas/schemas/order_config_request_schema.json new file mode 100644 index 0000000000..ca9b2e30ee --- /dev/null +++ b/packages/json-schemas/schemas/order_config_request_schema.json @@ -0,0 +1,24 @@ +{ + "id": "/OrderConfigRequest", + "type": "object", + "properties": { + "makerAddress": { "$ref": "/addressSchema" }, + "takerAddress": { "$ref": "/addressSchema" }, + "makerAssetAmount": { "$ref": "/wholeNumberSchema" }, + "takerAssetAmount": { "$ref": "/wholeNumberSchema" }, + "makerAssetData": { "$ref": "/hexSchema" }, + "takerAssetData": { "$ref": "/hexSchema" }, + "exchangeAddress": { "$ref": "/addressSchema" }, + "expirationTimeSeconds": { "$ref": "/wholeNumberSchema" } + }, + "required": [ + "makerAddress", + "takerAddress", + "makerAssetAmount", + "takerAssetAmount", + "makerAssetData", + "takerAssetData", + "exchangeAddress", + "expirationTimeSeconds" + ] +} diff --git a/packages/json-schemas/schemas/orderbook_request_schema.json b/packages/json-schemas/schemas/orderbook_request_schema.json new file mode 100644 index 0000000000..27848bdcb1 --- /dev/null +++ b/packages/json-schemas/schemas/orderbook_request_schema.json @@ -0,0 +1,9 @@ +{ + "id": "/OrderBookRequest", + "type": "object", + "properties": { + "baseAssetData": { "$ref": "/hexSchema" }, + "quoteAssetData": { "$ref": "/hexSchema" } + }, + "required": ["baseAssetData", "quoteAssetData"] +} \ No newline at end of file diff --git a/packages/json-schemas/schemas/orders_request_opts_schema.json b/packages/json-schemas/schemas/orders_request_opts_schema.json new file mode 100644 index 0000000000..10da510607 --- /dev/null +++ b/packages/json-schemas/schemas/orders_request_opts_schema.json @@ -0,0 +1,19 @@ +{ + "id": "/OrdersRequestOpts", + "type": "object", + "properties": { + "makerAssetProxyId": { "$ref": "/hexSchema" }, + "takerAssetProxyId": { "$ref": "/hexSchema" }, + "makerAssetAddress": { "$ref": "/addressSchema" }, + "takerAssetAddress": { "$ref": "/addressSchema" }, + "exchangeAddress": { "$ref": "/addressSchema" }, + "senderAddress": { "$ref": "/addressSchema" }, + "makerAssetData": { "$ref": "/hexSchema" }, + "takerAssetData": { "$ref": "/hexSchema" }, + "traderAssetData": { "$ref": "/hexSchema" }, + "makerAddress": { "$ref": "/addressSchema" }, + "takerAddress": { "$ref": "/addressSchema" }, + "traderAddress": { "$ref": "/addressSchema" }, + "feeRecipientAddress": { "$ref": "/addressSchema" } + } +} diff --git a/packages/json-schemas/schemas/paged_request_opts_schema.json b/packages/json-schemas/schemas/paged_request_opts_schema.json new file mode 100644 index 0000000000..7cfc73947b --- /dev/null +++ b/packages/json-schemas/schemas/paged_request_opts_schema.json @@ -0,0 +1,8 @@ +{ + "id": "/PagedRequestOpts", + "type": "object", + "properties": { + "page": { "type": "number" }, + "perPage": { "type": "number" } + } +} diff --git a/packages/json-schemas/schemas/request_opts_schema.json b/packages/json-schemas/schemas/request_opts_schema.json new file mode 100644 index 0000000000..b50547d180 --- /dev/null +++ b/packages/json-schemas/schemas/request_opts_schema.json @@ -0,0 +1,7 @@ +{ + "id": "/RequestOpts", + "type": "object", + "properties": { + "networkId": { "type": "number" } + } +} diff --git a/packages/json-schemas/src/schemas.ts b/packages/json-schemas/src/schemas.ts index 8ece5de758..21a6f424ca 100644 --- a/packages/json-schemas/src/schemas.ts +++ b/packages/json-schemas/src/schemas.ts @@ -1,4 +1,5 @@ import * as addressSchema from '../schemas/address_schema.json'; +import * as assetPairsRequestOptsSchema from '../schemas/asset_pairs_request_opts_schema.json'; import * as blockParamSchema from '../schemas/block_param_schema.json'; import * as blockRangeSchema from '../schemas/block_range_schema.json'; import * as callDataSchema from '../schemas/call_data_schema.json'; @@ -10,11 +11,15 @@ import * as indexFilterValuesSchema from '../schemas/index_filter_values_schema. import * as jsNumber from '../schemas/js_number.json'; import * as numberSchema from '../schemas/number_schema.json'; import * as orderCancellationRequestsSchema from '../schemas/order_cancel_schema.json'; +import * as orderConfigRequestSchema from '../schemas/order_config_request_schema.json'; import * as orderFillOrKillRequestsSchema from '../schemas/order_fill_or_kill_requests_schema.json'; import * as orderFillRequestsSchema from '../schemas/order_fill_requests_schema.json'; import * as orderHashSchema from '../schemas/order_hash_schema.json'; import * as orderSchema from '../schemas/order_schema.json'; +import * as orderBookRequestSchema from '../schemas/orderbook_request_schema.json'; +import * as ordersRequestOptsSchema from '../schemas/orders_request_opts_schema.json'; import * as ordersSchema from '../schemas/orders_schema.json'; +import * as pagedRequestOptsSchema from '../schemas/paged_request_opts_schema.json'; import * as paginatedCollectionSchema from '../schemas/paginated_collection_schema.json'; import * as relayerApiAssetDataPairsResponseSchema from '../schemas/relayer_api_asset_data_pairs_response_schema.json'; import * as relayerApiAssetDataPairsSchema from '../schemas/relayer_api_asset_data_pairs_schema.json'; @@ -30,6 +35,7 @@ import * as relayerApiOrdersChannelSubscribeSchema from '../schemas/relayer_api_ import * as relayerApiOrdersChannelUpdateSchema from '../schemas/relayer_api_orders_channel_update_response_schema.json'; import * as relayerApiOrdersResponseSchema from '../schemas/relayer_api_orders_response_schema.json'; import * as relayerApiOrdersSchema from '../schemas/relayer_api_orders_schema.json'; +import * as requestOptsSchema from '../schemas/request_opts_schema.json'; import * as signedOrderSchema from '../schemas/signed_order_schema.json'; import * as signedOrdersSchema from '../schemas/signed_orders_schema.json'; import * as tokenSchema from '../schemas/token_schema.json'; @@ -58,6 +64,12 @@ export const schemas = { blockRangeSchema, tokenSchema, jsNumber, + requestOptsSchema, + pagedRequestOptsSchema, + ordersRequestOptsSchema, + orderBookRequestSchema, + orderConfigRequestSchema, + assetPairsRequestOptsSchema, txDataSchema, paginatedCollectionSchema, relayerApiErrorResponseSchema, diff --git a/packages/json-schemas/tsconfig.json b/packages/json-schemas/tsconfig.json index 7b14166c0e..a79d543850 100644 --- a/packages/json-schemas/tsconfig.json +++ b/packages/json-schemas/tsconfig.json @@ -44,6 +44,12 @@ "./schemas/zero_ex_transaction_schema.json", "./schemas/tx_data_schema.json", "./schemas/index_filter_values_schema.json", - "./schemas/whole_number_schema.json" + "./schemas/whole_number_schema.json", + "./schemas/asset_pairs_request_opts_schema.json", + "./schemas/orderbook_request_schema.json", + "./schemas/orders_request_opts_schema.json", + "./schemas/paged_request_opts_schema.json", + "./schemas/request_opts_schema.json", + "./schemas/order_config_request_schema.json" ] } diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json index 35a0834f2f..f990db6b0c 100644 --- a/packages/metacoin/package.json +++ b/packages/metacoin/package.json @@ -1,6 +1,6 @@ { "name": "@0x/metacoin", - "version": "0.0.25", + "version": "0.0.28", "engines": { "node": ">=6.12" }, @@ -29,15 +29,15 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "@0x/abi-gen": "^1.0.15", - "@0x/base-contract": "^3.0.3", - "@0x/sol-cov": "^2.1.9", - "@0x/subproviders": "^2.1.1", + "@0x/abi-gen": "^1.0.16", + "@0x/base-contract": "^3.0.6", + "@0x/sol-cov": "^2.1.12", + "@0x/subproviders": "^2.1.4", "@0x/tslint-config": "^1.0.10", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "@types/mocha": "^5.2.2", "copyfiles": "^2.0.0", "ethereum-types": "^1.1.2", @@ -46,8 +46,8 @@ "run-s": "^0.0.0" }, "devDependencies": { - "@0x/dev-utils": "^1.0.14", - "@0x/sol-compiler": "^1.1.9", + "@0x/dev-utils": "^1.0.17", + "@0x/sol-compiler": "^1.1.12", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^2.0.1", diff --git a/packages/migrations/CHANGELOG.json b/packages/migrations/CHANGELOG.json index b7128f8e1c..5b0d589096 100644 --- a/packages/migrations/CHANGELOG.json +++ b/packages/migrations/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "2.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "2.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "2.0.2", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.1", "changes": [ diff --git a/packages/migrations/CHANGELOG.md b/packages/migrations/CHANGELOG.md index 387ae0abb6..87d0b25ca8 100644 --- a/packages/migrations/CHANGELOG.md +++ b/packages/migrations/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.4 - _November 14, 2018_ + + * Dependencies updated + +## v2.0.3 - _November 13, 2018_ + + * Dependencies updated + +## v2.0.2 - _November 12, 2018_ + + * Dependencies updated + ## v2.0.1 - _November 9, 2018_ * Dependencies updated diff --git a/packages/migrations/package.json b/packages/migrations/package.json index d8c5fb6c27..8eaae96ba7 100644 --- a/packages/migrations/package.json +++ b/packages/migrations/package.json @@ -1,6 +1,6 @@ { "name": "@0x/migrations", - "version": "2.0.1", + "version": "2.0.4", "engines": { "node": ">=6.12" }, @@ -17,7 +17,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@0x/dev-utils": "^1.0.14", + "@0x/dev-utils": "^1.0.17", "@0x/tslint-config": "^1.0.10", "@0x/types": "^1.2.1", "@types/yargs": "^10.0.0", @@ -29,16 +29,16 @@ "yargs": "^10.0.3" }, "dependencies": { - "@0x/abi-gen-wrappers": "^1.0.2", - "@0x/base-contract": "^3.0.3", + "@0x/abi-gen-wrappers": "^1.0.5", + "@0x/base-contract": "^3.0.6", "@0x/contract-addresses": "^1.1.0", "@0x/contract-artifacts": "^1.1.0", - "@0x/order-utils": "^2.0.1", - "@0x/sol-compiler": "^1.1.9", - "@0x/subproviders": "^2.1.1", + "@0x/order-utils": "^3.0.2", + "@0x/sol-compiler": "^1.1.12", + "@0x/subproviders": "^2.1.4", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "@ledgerhq/hw-app-eth": "^4.3.0", "ethereum-types": "^1.1.2", "ethers": "~4.0.4", diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index 0ed6117dfc..55e7defda7 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -1,4 +1,22 @@ [ + { + "timestamp": 1542208198, + "version": "3.0.2", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "3.0.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "3.0.0", "changes": [ @@ -22,7 +40,8 @@ "Modified the `AbstractOrderFilledCancelledFetcher` interface slightly such that `isOrderCancelledAsync` accepts a `signedOrder` instead of an `orderHash` param", "pr": 1235 } - ] + ], + "timestamp": 1542028948 }, { "version": "2.0.1", diff --git a/packages/order-utils/CHANGELOG.md b/packages/order-utils/CHANGELOG.md index 31bd02595c..edf1569a7c 100644 --- a/packages/order-utils/CHANGELOG.md +++ b/packages/order-utils/CHANGELOG.md @@ -5,6 +5,21 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.2 - _November 14, 2018_ + + * Dependencies updated + +## v3.0.1 - _November 13, 2018_ + + * Dependencies updated + +## v3.0.0 - _November 12, 2018_ + + * Add signature validation, regular cancellation and `cancelledUpTo` checks to `validateOrderFillableOrThrowAsync` (#1235) + * Improved the errors thrown by `validateOrderFillableOrThrowAsync` by making them more descriptive (#1235) + * Throw previously swallowed network errors when calling `validateOrderFillableOrThrowAsync` (see issue: #1218) (#1235) + * Modified the `AbstractOrderFilledCancelledFetcher` interface slightly such that `isOrderCancelledAsync` accepts a `signedOrder` instead of an `orderHash` param (#1235) + ## v2.0.1 - _November 9, 2018_ * Dependencies updated diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json index d6fb9892e2..fe5ea70b1d 100644 --- a/packages/order-utils/package.json +++ b/packages/order-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/order-utils", - "version": "2.0.1", + "version": "3.0.2", "engines": { "node": ">=6.12" }, @@ -35,7 +35,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/order-utils/README.md", "devDependencies": { - "@0x/dev-utils": "^1.0.14", + "@0x/dev-utils": "^1.0.17", "@0x/tslint-config": "^1.0.10", "@types/bn.js": "^4.11.0", "@types/lodash": "4.14.104", @@ -53,15 +53,15 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/abi-gen-wrappers": "^1.0.2", - "@0x/assert": "^1.0.15", - "@0x/base-contract": "^3.0.3", + "@0x/abi-gen-wrappers": "^1.0.5", + "@0x/assert": "^1.0.17", + "@0x/base-contract": "^3.0.6", "@0x/contract-artifacts": "^1.1.0", - "@0x/json-schemas": "^2.0.1", + "@0x/json-schemas": "^2.1.1", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "@types/node": "*", "bn.js": "^4.11.8", "ethereum-types": "^1.1.2", diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json index c662903a30..b4d7a1501f 100644 --- a/packages/order-watcher/CHANGELOG.json +++ b/packages/order-watcher/CHANGELOG.json @@ -1,4 +1,38 @@ [ + { + "version": "2.2.4", + "changes": [ + { + "note": + "Fix the bug when order watcher was throwing an error on order removal when maker token was ZRX", + "pr": 1259 + } + ], + "timestamp": 1542208198 + }, + { + "version": "2.2.3", + "changes": [ + { + "note": "Start jsonRpcRequestId at 1, not 0 as 0 breaks the web3.js websocket RPC provider", + "pr": 1227 + }, + { + "note": + "Fix the bug when order watcher was trying to convert undefined to an object in case of CancelUpTo event" + } + ], + "timestamp": 1542134075 + }, + { + "timestamp": 1542028948, + "version": "2.2.2", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.2.1", "changes": [ diff --git a/packages/order-watcher/CHANGELOG.md b/packages/order-watcher/CHANGELOG.md index b271956c75..c7003f759e 100644 --- a/packages/order-watcher/CHANGELOG.md +++ b/packages/order-watcher/CHANGELOG.md @@ -5,6 +5,19 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.2.4 - _November 14, 2018_ + + * Fix the bug when order watcher was throwing an error on order removal when maker token was ZRX (#1259) + +## v2.2.3 - _November 13, 2018_ + + * Start jsonRpcRequestId at 1, not 0 as 0 breaks the web3.js websocket RPC provider (#1227) + * Fix the bug when order watcher was trying to convert undefined to an object in case of CancelUpTo event + +## v2.2.2 - _November 12, 2018_ + + * Dependencies updated + ## v2.2.1 - _November 9, 2018_ * Dependencies updated diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json index 174e0a3a63..af88a120e0 100644 --- a/packages/order-watcher/package.json +++ b/packages/order-watcher/package.json @@ -1,6 +1,6 @@ { "name": "@0x/order-watcher", - "version": "2.2.1", + "version": "2.2.4", "description": "An order watcher daemon that watches for order validity", "keywords": [ "0x", @@ -33,8 +33,8 @@ "node": ">=6.0.0" }, "devDependencies": { - "@0x/dev-utils": "^1.0.14", - "@0x/migrations": "^2.0.1", + "@0x/dev-utils": "^1.0.17", + "@0x/migrations": "^2.0.4", "@0x/tslint-config": "^1.0.10", "@types/bintrees": "^1.0.2", "@types/lodash": "4.14.104", @@ -57,19 +57,19 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/abi-gen-wrappers": "^1.0.2", - "@0x/assert": "^1.0.15", - "@0x/base-contract": "^3.0.3", + "@0x/abi-gen-wrappers": "^1.0.5", + "@0x/assert": "^1.0.17", + "@0x/base-contract": "^3.0.6", "@0x/contract-addresses": "^1.1.0", "@0x/contract-artifacts": "^1.1.0", - "@0x/contract-wrappers": "^3.0.1", - "@0x/fill-scenarios": "^1.0.9", - "@0x/json-schemas": "^2.0.1", - "@0x/order-utils": "^2.0.1", + "@0x/contract-wrappers": "^4.0.2", + "@0x/fill-scenarios": "^1.0.12", + "@0x/json-schemas": "^2.1.1", + "@0x/order-utils": "^3.0.2", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "bintrees": "^1.0.2", "ethereum-types": "^1.1.2", "ethereumjs-blockstream": "6.0.0", diff --git a/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts b/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts index dbcc25186f..a956a94db2 100644 --- a/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts +++ b/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts @@ -50,7 +50,7 @@ export class DependentOrderHashesTracker { return uniqueOrderHashList; } public getDependentOrderHashesByMaker(makerAddress: string): string[] { - const dependentOrderHashes = Array.from(this._orderHashesByMakerAddress[makerAddress]); + const dependentOrderHashes = Array.from(this._orderHashesByMakerAddress[makerAddress] || {}); return dependentOrderHashes; } public getDependentOrderHashesByAssetDataByMaker(makerAddress: string, assetData: string): string[] { @@ -89,7 +89,10 @@ export class DependentOrderHashesTracker { (decodedMakerAssetData as ERC721AssetData).tokenId, ); } - this._removeFromERC20DependentOrderhashes(signedOrder, this._zrxTokenAddress); + // If makerToken === ZRX then we already removed it and we don't need to remove it again. + if ((decodedMakerAssetData as ERC20AssetData).tokenAddress !== this._zrxTokenAddress) { + this._removeFromERC20DependentOrderhashes(signedOrder, this._zrxTokenAddress); + } this._removeFromMakerDependentOrderhashes(signedOrder); } private _getDependentOrderHashesByERC20AssetData(makerAddress: string, erc20AssetData: string): string[] { diff --git a/packages/react-docs/CHANGELOG.json b/packages/react-docs/CHANGELOG.json index 228dfab4fb..0e9afc32a7 100644 --- a/packages/react-docs/CHANGELOG.json +++ b/packages/react-docs/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "1.0.18", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "1.0.17", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "1.0.16", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.15", "changes": [ diff --git a/packages/react-docs/CHANGELOG.md b/packages/react-docs/CHANGELOG.md index 991b3a490a..db574e41b7 100644 --- a/packages/react-docs/CHANGELOG.md +++ b/packages/react-docs/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.18 - _November 14, 2018_ + + * Dependencies updated + +## v1.0.17 - _November 13, 2018_ + + * Dependencies updated + +## v1.0.16 - _November 12, 2018_ + + * Dependencies updated + ## v1.0.15 - _November 9, 2018_ * Dependencies updated diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json index 827a54fdb1..3e77a9a07b 100644 --- a/packages/react-docs/package.json +++ b/packages/react-docs/package.json @@ -1,6 +1,6 @@ { "name": "@0x/react-docs", - "version": "1.0.15", + "version": "1.0.18", "engines": { "node": ">=6.12" }, @@ -24,7 +24,7 @@ "url": "https://github.com/0xProject/0x-monorepo.git" }, "devDependencies": { - "@0x/dev-utils": "^1.0.14", + "@0x/dev-utils": "^1.0.17", "@0x/tslint-config": "^1.0.10", "@types/compare-versions": "^3.0.0", "@types/styled-components": "^4.0.0", @@ -34,9 +34,9 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/react-shared": "^1.0.18", + "@0x/react-shared": "^1.0.21", "@0x/types": "^1.2.1", - "@0x/utils": "^2.0.4", + "@0x/utils": "^2.0.5", "@types/lodash": "4.14.104", "@types/material-ui": "^0.20.0", "@types/node": "*", diff --git a/packages/react-docs/src/components/type.tsx b/packages/react-docs/src/components/type.tsx index 412b99b9df..fa3b658b4c 100644 --- a/packages/react-docs/src/components/type.tsx +++ b/packages/react-docs/src/components/type.tsx @@ -1,9 +1,8 @@ -import { colors, constants as sharedConstants, Link, utils as sharedUtils } from '@0x/react-shared'; +import { colors, Link, utils as sharedUtils } from '@0x/react-shared'; import { Type as TypeDef, TypeDefinitionByName, TypeDocTypes } from '@0x/types'; import { errorUtils } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; -import { Link as ScrollLink } from 'react-scroll'; import * as ReactTooltip from 'react-tooltip'; import { DocsInfo } from '../docs_info'; @@ -224,13 +223,7 @@ export const Type: React.SFC = (props: TypeProps): any => { {sharedUtils.isUserOnMobile() || props.isInPopover || isExportedClassReference ? ( {typeName} ) : ( - + = (props: TypeProps): any => { /> - + )} ); diff --git a/packages/react-docs/src/docs_info.ts b/packages/react-docs/src/docs_info.ts index 54b59ef1f0..76f7784bae 100644 --- a/packages/react-docs/src/docs_info.ts +++ b/packages/react-docs/src/docs_info.ts @@ -10,6 +10,7 @@ import { SectionsMap, SupportedDocJson, } from './types'; +import { constants } from './utils/constants'; export class DocsInfo { public id: string; @@ -64,7 +65,7 @@ export class DocsInfo { const docSections = _.keys(this.sections); _.each(docSections, sectionName => { const docSection = docAgnosticFormat[sectionName]; - if (_.isUndefined(docSection)) { + if (_.isUndefined(docSection) || sectionName === constants.EXTERNAL_EXPORTS_SECTION_NAME) { return; // no-op } diff --git a/packages/react-shared/CHANGELOG.json b/packages/react-shared/CHANGELOG.json index 4dd11398b7..cb8ae1bf06 100644 --- a/packages/react-shared/CHANGELOG.json +++ b/packages/react-shared/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "1.0.21", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "1.0.20", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "1.0.19", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.18", "changes": [ diff --git a/packages/react-shared/CHANGELOG.md b/packages/react-shared/CHANGELOG.md index 54ca77b168..0ecb66a27c 100644 --- a/packages/react-shared/CHANGELOG.md +++ b/packages/react-shared/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.21 - _November 14, 2018_ + + * Dependencies updated + +## v1.0.20 - _November 13, 2018_ + + * Dependencies updated + +## v1.0.19 - _November 12, 2018_ + + * Dependencies updated + ## v1.0.18 - _November 9, 2018_ * Dependencies updated diff --git a/packages/react-shared/package.json b/packages/react-shared/package.json index 35a69f1056..d2a00ca9c3 100644 --- a/packages/react-shared/package.json +++ b/packages/react-shared/package.json @@ -1,6 +1,6 @@ { "name": "@0x/react-shared", - "version": "1.0.18", + "version": "1.0.21", "engines": { "node": ">=6.12" }, @@ -25,7 +25,7 @@ "url": "https://github.com/0xProject/0x-monorepo.git" }, "devDependencies": { - "@0x/dev-utils": "^1.0.14", + "@0x/dev-utils": "^1.0.17", "@0x/tslint-config": "^1.0.10", "make-promises-safe": "^1.1.0", "shx": "^0.2.2", diff --git a/packages/react-shared/src/components/anchor_title.tsx b/packages/react-shared/src/components/anchor_title.tsx index bd99edcab6..a9105e1325 100644 --- a/packages/react-shared/src/components/anchor_title.tsx +++ b/packages/react-shared/src/components/anchor_title.tsx @@ -1,15 +1,9 @@ import * as React from 'react'; -import { Link as ScrollLink } from 'react-scroll'; import styled from 'styled-components'; +import { Link } from '../components/link'; import { HeaderSizes, Styles } from '../types'; import { colors } from '../utils/colors'; -import { constants } from '../utils/constants'; - -const headerSizeToScrollOffset: { [headerSize: string]: number } = { - h2: -20, - h3: 0, -}; export interface AnchorTitleProps { title: string | React.ReactNode; @@ -73,15 +67,9 @@ export class AnchorTitle extends React.Component {!this.props.isDisabled && ( - + - + )} ); diff --git a/packages/sol-compiler/CHANGELOG.json b/packages/sol-compiler/CHANGELOG.json index 724e68a68c..fc39106dc5 100644 --- a/packages/sol-compiler/CHANGELOG.json +++ b/packages/sol-compiler/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "1.1.12", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "1.1.11", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "1.1.10", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.1.9", "changes": [ diff --git a/packages/sol-compiler/CHANGELOG.md b/packages/sol-compiler/CHANGELOG.md index 322313f9e0..b69976cdc4 100644 --- a/packages/sol-compiler/CHANGELOG.md +++ b/packages/sol-compiler/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.1.12 - _November 14, 2018_ + + * Dependencies updated + +## v1.1.11 - _November 13, 2018_ + + * Dependencies updated + +## v1.1.10 - _November 12, 2018_ + + * Dependencies updated + ## v1.1.9 - _November 9, 2018_ * Dependencies updated diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json index 766c789dfe..2904cfd23e 100644 --- a/packages/sol-compiler/package.json +++ b/packages/sol-compiler/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-compiler", - "version": "1.1.9", + "version": "1.1.12", "engines": { "node": ">=6.12" }, @@ -42,7 +42,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-compiler/README.md", "devDependencies": { - "@0x/dev-utils": "^1.0.14", + "@0x/dev-utils": "^1.0.17", "@0x/tslint-config": "^1.0.10", "@types/mkdirp": "^0.5.2", "@types/require-from-string": "^1.2.0", @@ -65,13 +65,13 @@ "zeppelin-solidity": "1.8.0" }, "dependencies": { - "@0x/assert": "^1.0.15", - "@0x/json-schemas": "^2.0.1", + "@0x/assert": "^1.0.17", + "@0x/json-schemas": "^2.1.1", "@0x/sol-resolver": "^1.0.16", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "@types/yargs": "^11.0.0", "chalk": "^2.3.0", "ethereum-types": "^1.1.2", diff --git a/packages/sol-cov/CHANGELOG.json b/packages/sol-cov/CHANGELOG.json index e331d608f0..bdeda8a963 100644 --- a/packages/sol-cov/CHANGELOG.json +++ b/packages/sol-cov/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "2.1.12", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "2.1.11", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "2.1.10", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.1.9", "changes": [ diff --git a/packages/sol-cov/CHANGELOG.md b/packages/sol-cov/CHANGELOG.md index e9d9d6952f..906c0dd52c 100644 --- a/packages/sol-cov/CHANGELOG.md +++ b/packages/sol-cov/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.1.12 - _November 14, 2018_ + + * Dependencies updated + +## v2.1.11 - _November 13, 2018_ + + * Dependencies updated + +## v2.1.10 - _November 12, 2018_ + + * Dependencies updated + ## v2.1.9 - _November 9, 2018_ * Dependencies updated diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json index 34e7a85592..159a2207d0 100644 --- a/packages/sol-cov/package.json +++ b/packages/sol-cov/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-cov", - "version": "2.1.9", + "version": "2.1.12", "engines": { "node": ">=6.12" }, @@ -42,12 +42,12 @@ }, "homepage": "https://github.com/0xProject/0x.js/packages/sol-cov/README.md", "dependencies": { - "@0x/dev-utils": "^1.0.14", - "@0x/sol-compiler": "^1.1.9", - "@0x/subproviders": "^2.1.1", + "@0x/dev-utils": "^1.0.17", + "@0x/sol-compiler": "^1.1.12", + "@0x/subproviders": "^2.1.4", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "@types/solidity-parser-antlr": "^0.2.0", "ethereum-types": "^1.1.2", "ethereumjs-util": "^5.1.1", diff --git a/packages/sol-doc/CHANGELOG.json b/packages/sol-doc/CHANGELOG.json index d54569a4d4..a9547c8836 100644 --- a/packages/sol-doc/CHANGELOG.json +++ b/packages/sol-doc/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "1.0.7", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "1.0.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "1.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.4", "changes": [ diff --git a/packages/sol-doc/CHANGELOG.md b/packages/sol-doc/CHANGELOG.md index d44af5d7fb..74a736c752 100644 --- a/packages/sol-doc/CHANGELOG.md +++ b/packages/sol-doc/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.7 - _November 14, 2018_ + + * Dependencies updated + +## v1.0.6 - _November 13, 2018_ + + * Dependencies updated + +## v1.0.5 - _November 12, 2018_ + + * Dependencies updated + ## v1.0.4 - _November 9, 2018_ * Dependencies updated diff --git a/packages/sol-doc/package.json b/packages/sol-doc/package.json index 0eb5d6fd59..e56408f982 100644 --- a/packages/sol-doc/package.json +++ b/packages/sol-doc/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-doc", - "version": "1.0.4", + "version": "1.0.7", "description": "Solidity documentation generator", "main": "lib/src/index.js", "types": "lib/src/index.d.js", @@ -25,9 +25,9 @@ "author": "F. Eugene Aumson", "license": "Apache-2.0", "dependencies": { - "@0x/sol-compiler": "^1.1.9", + "@0x/sol-compiler": "^1.1.12", "@0x/types": "^1.2.1", - "@0x/utils": "^2.0.4", + "@0x/utils": "^2.0.5", "ethereum-types": "^1.1.2", "ethereumjs-util": "^5.1.1", "lodash": "^4.17.10", diff --git a/packages/sra-spec/CHANGELOG.json b/packages/sra-spec/CHANGELOG.json index e053b3163e..3cc917e5ac 100644 --- a/packages/sra-spec/CHANGELOG.json +++ b/packages/sra-spec/CHANGELOG.json @@ -1,4 +1,22 @@ [ + { + "timestamp": 1542208198, + "version": "1.0.10", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "1.0.9", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.8", "changes": [ diff --git a/packages/sra-spec/CHANGELOG.md b/packages/sra-spec/CHANGELOG.md index 02d22431ff..8b2b7747b7 100644 --- a/packages/sra-spec/CHANGELOG.md +++ b/packages/sra-spec/CHANGELOG.md @@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.10 - _November 14, 2018_ + + * Dependencies updated + +## v1.0.9 - _November 12, 2018_ + + * Dependencies updated + ## v1.0.8 - _November 9, 2018_ * Dependencies updated diff --git a/packages/sra-spec/package.json b/packages/sra-spec/package.json index e3b6ad9794..fac5a5a4b9 100644 --- a/packages/sra-spec/package.json +++ b/packages/sra-spec/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sra-spec", - "version": "1.0.8", + "version": "1.0.10", "engines": { "node": ">=6.12" }, @@ -35,7 +35,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sra-spec/README.md", "dependencies": { - "@0x/json-schemas": "^2.0.1", + "@0x/json-schemas": "^2.1.1", "@loopback/openapi-v3-types": "^0.8.2" }, "devDependencies": { diff --git a/packages/subproviders/CHANGELOG.json b/packages/subproviders/CHANGELOG.json index 816c776a56..cdc150c3a7 100644 --- a/packages/subproviders/CHANGELOG.json +++ b/packages/subproviders/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "2.1.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "2.1.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "2.1.2", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.1.1", "changes": [ diff --git a/packages/subproviders/CHANGELOG.md b/packages/subproviders/CHANGELOG.md index 72ac9d1f7c..eda76bd2fe 100644 --- a/packages/subproviders/CHANGELOG.md +++ b/packages/subproviders/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.1.4 - _November 14, 2018_ + + * Dependencies updated + +## v2.1.3 - _November 13, 2018_ + + * Dependencies updated + +## v2.1.2 - _November 12, 2018_ + + * Dependencies updated + ## v2.1.1 - _November 9, 2018_ * Dependencies updated diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index 1a25b5e323..d249e4d6d0 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -1,6 +1,6 @@ { "name": "@0x/subproviders", - "version": "2.1.1", + "version": "2.1.4", "engines": { "node": ">=6.12" }, @@ -29,11 +29,11 @@ } }, "dependencies": { - "@0x/assert": "^1.0.15", + "@0x/assert": "^1.0.17", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "@ledgerhq/hw-app-eth": "^4.3.0", "@ledgerhq/hw-transport-u2f": "4.24.0", "@types/eth-lightwallet": "^3.0.0", diff --git a/packages/subproviders/src/subproviders/ledger.ts b/packages/subproviders/src/subproviders/ledger.ts index 28e348f909..b5ca10ce13 100644 --- a/packages/subproviders/src/subproviders/ledger.ts +++ b/packages/subproviders/src/subproviders/ledger.ts @@ -32,7 +32,6 @@ const DEFAULT_ADDRESS_SEARCH_LIMIT = 1000; */ export class LedgerSubprovider extends BaseWalletSubprovider { // tslint:disable-next-line:no-unused-variable - private readonly _nonceLock = new Lock(); private readonly _connectionLock = new Lock(); private readonly _networkId: number; private _baseDerivationPath: string; diff --git a/packages/subproviders/src/utils/wallet_utils.ts b/packages/subproviders/src/utils/wallet_utils.ts index 4c233645b2..7027ca8a0a 100644 --- a/packages/subproviders/src/utils/wallet_utils.ts +++ b/packages/subproviders/src/utils/wallet_utils.ts @@ -56,10 +56,11 @@ export const walletUtils = { parentDerivedKeyInfo: DerivedHDKeyInfo, searchLimit: number, ): DerivedHDKeyInfo | undefined { + const lowercaseAddress = address.toLowerCase(); let matchedKey: DerivedHDKeyInfo | undefined; const derivedKeyIterator = new DerivedHDKeyInfoIterator(parentDerivedKeyInfo, searchLimit); for (const key of derivedKeyIterator) { - if (key.address === address) { + if (key.address === lowercaseAddress) { matchedKey = key; break; } diff --git a/packages/testnet-faucets/package.json b/packages/testnet-faucets/package.json index c46f5465ac..ac720a748b 100644 --- a/packages/testnet-faucets/package.json +++ b/packages/testnet-faucets/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@0x/testnet-faucets", - "version": "1.0.53", + "version": "1.0.56", "engines": { "node": ">=6.12" }, @@ -18,11 +18,11 @@ "author": "Fabio Berger", "license": "Apache-2.0", "dependencies": { - "0x.js": "^2.0.1", - "@0x/subproviders": "^2.1.1", + "0x.js": "^2.0.4", + "@0x/subproviders": "^2.1.4", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "body-parser": "^1.17.1", "ethereum-types": "^1.1.2", "ethereumjs-tx": "^1.3.5", diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json index 6c9da5f370..1ef16e112a 100644 --- a/packages/utils/CHANGELOG.json +++ b/packages/utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1542208198, + "version": "2.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.4", "changes": [ diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index 4fdd13d9cb..9846dd344f 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.5 - _November 14, 2018_ + + * Dependencies updated + ## v2.0.4 - _November 9, 2018_ * Dependencies updated diff --git a/packages/utils/package.json b/packages/utils/package.json index 24c2496b03..4b924226fc 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/utils", - "version": "2.0.4", + "version": "2.0.5", "engines": { "node": ">=6.12" }, diff --git a/packages/utils/test/sign_typed_data_utils_test.ts b/packages/utils/test/sign_typed_data_utils_test.ts index dcba08b044..3d2cb2496c 100644 --- a/packages/utils/test/sign_typed_data_utils_test.ts +++ b/packages/utils/test/sign_typed_data_utils_test.ts @@ -136,5 +136,28 @@ describe('signTypedDataUtils', () => { const hashHex = `0x${hash}`; expect(hashHex).to.be.eq(orderSignTypedDataHashHex); }); + it('creates a hash of an uninitialized order', () => { + const uninitializedOrder = { + ...orderSignTypedData, + message: { + makerAddress: '0x0000000000000000000000000000000000000000', + takerAddress: '0x0000000000000000000000000000000000000000', + makerAssetAmount: 0, + takerAssetAmount: 0, + expirationTimeSeconds: 0, + makerFee: 0, + takerFee: 0, + feeRecipientAddress: '0x0000000000000000000000000000000000000000', + senderAddress: '0x0000000000000000000000000000000000000000', + salt: 0, + makerAssetData: '0x0000000000000000000000000000000000000000', + takerAssetData: '0x0000000000000000000000000000000000000000', + exchangeAddress: '0x0000000000000000000000000000000000000000', + }, + }; + const hash = signTypedDataUtils.generateTypedDataHash(uninitializedOrder).toString('hex'); + const hashHex = `0x${hash}`; + expect(hashHex).to.be.eq('0xfaa49b35faeb9197e9c3ba7a52075e6dad19739549f153b77dfcf59408a4b422'); + }); }); }); diff --git a/packages/web3-wrapper/CHANGELOG.json b/packages/web3-wrapper/CHANGELOG.json index 7b21da73af..b938f69862 100644 --- a/packages/web3-wrapper/CHANGELOG.json +++ b/packages/web3-wrapper/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1542208198, + "version": "3.1.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542134075, + "version": "3.1.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1542028948, + "version": "3.1.2", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "3.1.1", "changes": [ diff --git a/packages/web3-wrapper/CHANGELOG.md b/packages/web3-wrapper/CHANGELOG.md index ebbef2c48d..70a00ee1e5 100644 --- a/packages/web3-wrapper/CHANGELOG.md +++ b/packages/web3-wrapper/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.1.4 - _November 14, 2018_ + + * Dependencies updated + +## v3.1.3 - _November 13, 2018_ + + * Dependencies updated + +## v3.1.2 - _November 12, 2018_ + + * Dependencies updated + ## v3.1.1 - _November 9, 2018_ * Fix bug in `getTransactionByHashAsync` which was causing the return value to have the wrong type (raw fields instead of unmarshalled fields). (#1177) diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json index 2b87cc92ad..2469f7627f 100644 --- a/packages/web3-wrapper/package.json +++ b/packages/web3-wrapper/package.json @@ -1,6 +1,6 @@ { "name": "@0x/web3-wrapper", - "version": "3.1.1", + "version": "3.1.4", "engines": { "node": ">=6.12" }, @@ -53,10 +53,10 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/assert": "^1.0.15", - "@0x/json-schemas": "^2.0.1", + "@0x/assert": "^1.0.17", + "@0x/json-schemas": "^2.1.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", + "@0x/utils": "^2.0.5", "ethereum-types": "^1.1.2", "ethereumjs-util": "^5.1.1", "ethers": "~4.0.4", diff --git a/packages/web3-wrapper/src/web3_wrapper.ts b/packages/web3-wrapper/src/web3_wrapper.ts index 23204e6160..be1713f208 100644 --- a/packages/web3-wrapper/src/web3_wrapper.ts +++ b/packages/web3-wrapper/src/web3_wrapper.ts @@ -157,7 +157,7 @@ export class Web3Wrapper { this.abiDecoder = new AbiDecoder([]); this._provider = provider; this._txDefaults = txDefaults || {}; - this._jsonRpcRequestId = 0; + this._jsonRpcRequestId = 1; } /** * Get the contract defaults set to the Web3Wrapper instance diff --git a/packages/website/package.json b/packages/website/package.json index fd671d85da..bb64b24db8 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "@0x/website", - "version": "0.0.56", + "version": "0.0.59", "engines": { "node": ">=6.12" }, @@ -20,16 +20,16 @@ "author": "Fabio Berger", "license": "Apache-2.0", "dependencies": { - "@0x/contract-wrappers": "^3.0.1", - "@0x/json-schemas": "^2.0.1", - "@0x/order-utils": "^2.0.1", - "@0x/react-docs": "^1.0.15", - "@0x/react-shared": "^1.0.18", - "@0x/subproviders": "^2.1.1", + "@0x/contract-wrappers": "^4.0.2", + "@0x/json-schemas": "^2.1.1", + "@0x/order-utils": "^3.0.2", + "@0x/react-docs": "^1.0.18", + "@0x/react-shared": "^1.0.21", + "@0x/subproviders": "^2.1.4", "@0x/types": "^1.2.1", "@0x/typescript-typings": "^3.0.4", - "@0x/utils": "^2.0.4", - "@0x/web3-wrapper": "^3.1.1", + "@0x/utils": "^2.0.5", + "@0x/web3-wrapper": "^3.1.4", "accounting": "^0.4.1", "basscss": "^8.0.3", "blockies": "^0.0.2", diff --git a/packages/website/public/images/developers/logo/0x.svg b/packages/website/public/images/developers/logo/0x.svg new file mode 100644 index 0000000000..f029039257 --- /dev/null +++ b/packages/website/public/images/developers/logo/0x.svg @@ -0,0 +1,24 @@ + + + +Asset 1 + + + + + + + + + + + diff --git a/packages/website/public/images/developers/logo/docs.svg b/packages/website/public/images/developers/logo/docs.svg new file mode 100644 index 0000000000..d3d14f66ee --- /dev/null +++ b/packages/website/public/images/developers/logo/docs.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/website/public/images/docs_logo.svg b/packages/website/public/images/docs_logo.svg deleted file mode 100644 index e3c4b628b7..0000000000 --- a/packages/website/public/images/docs_logo.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/website/translations/chinese.json b/packages/website/translations/chinese.json index 83ecef40e4..eb88b43d0f 100644 --- a/packages/website/translations/chinese.json +++ b/packages/website/translations/chinese.json @@ -83,7 +83,7 @@ "BUILD_A_RELAYER_DESCRIPTION": "Learn how to build your own 0x relayer from scratch", "DEVELOP_ON_ETHEREUM": "develop on Ethereum", "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications ontop of Ethereum", - "ORDER_BASICS": "0x order basics", + "ORDER_BASICS": "Make & take orders", "ORDER_BASICS_DESCRIPTION": "Tutorial on how to create, validate and fill an order using 0x", "USE_NETWORKED_LIQUIDITY": "use networked liquidity", "USE_NETWORKED_LIQUIDITY_DESCRIPTION": "Access the shared liquidity pool using the Standard Relayer API", diff --git a/packages/website/translations/english.json b/packages/website/translations/english.json index 663587e6a6..5fba7a0fff 100644 --- a/packages/website/translations/english.json +++ b/packages/website/translations/english.json @@ -87,7 +87,7 @@ "BUILD_A_RELAYER_DESCRIPTION": "Learn how to build your own 0x relayer from scratch", "DEVELOP_ON_ETHEREUM": "develop on Ethereum", "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications ontop of Ethereum", - "ORDER_BASICS": "0x order basics", + "ORDER_BASICS": "Make & take orders", "ORDER_BASICS_DESCRIPTION": "Tutorial on how to create, validate and fill an order using 0x", "USE_NETWORKED_LIQUIDITY": "use networked liquidity", "USE_NETWORKED_LIQUIDITY_DESCRIPTION": "Learn how to tap into networked liquidity using the Standard Relayer API", diff --git a/packages/website/translations/korean.json b/packages/website/translations/korean.json index 2ce7e52c4c..e3ce746760 100644 --- a/packages/website/translations/korean.json +++ b/packages/website/translations/korean.json @@ -83,7 +83,7 @@ "BUILD_A_RELAYER_DESCRIPTION": "Learn how to build your own 0x relayer from scratch", "DEVELOP_ON_ETHEREUM": "develop on Ethereum", "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications ontop of Ethereum", - "ORDER_BASICS": "0x order basics", + "ORDER_BASICS": "Make & take orders", "ORDER_BASICS_DESCRIPTION": "Tutorial on how to create, validate and fill an order using 0x", "USE_NETWORKED_LIQUIDITY": "use networked liquidity", "USE_NETWORKED_LIQUIDITY_DESCRIPTION": "Learn how to tap into networked liquidity using the Standard Relayer API", diff --git a/packages/website/translations/russian.json b/packages/website/translations/russian.json index 2bb047510a..c74fb5e32a 100644 --- a/packages/website/translations/russian.json +++ b/packages/website/translations/russian.json @@ -83,7 +83,7 @@ "BUILD_A_RELAYER_DESCRIPTION": "Learn how to build your own 0x relayer from scratch", "DEVELOP_ON_ETHEREUM": "develop on Ethereum", "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications ontop of Ethereum", - "ORDER_BASICS": "0x order basics", + "ORDER_BASICS": "Make & take orders", "ORDER_BASICS_DESCRIPTION": "Tutorial on how to create, validate and fill an order using 0x", "USE_NETWORKED_LIQUIDITY": "use networked liquidity", "USE_NETWORKED_LIQUIDITY_DESCRIPTION": "Learn how to tap into networked liquidity using the Standard Relayer API", diff --git a/packages/website/translations/spanish.json b/packages/website/translations/spanish.json index 88ea54c404..e29db711b7 100644 --- a/packages/website/translations/spanish.json +++ b/packages/website/translations/spanish.json @@ -84,7 +84,7 @@ "BUILD_A_RELAYER_DESCRIPTION": "Learn how to build your own 0x relayer from scratch", "DEVELOP_ON_ETHEREUM": "develop on Ethereum", "DEVELOP_ON_ETHEREUM_DESCRIPTION": "Learn more about building applications ontop of Ethereum", - "ORDER_BASICS": "0x order basics", + "ORDER_BASICS": "Make & take orders", "ORDER_BASICS_DESCRIPTION": "Tutorial on how to create, validate and fill an order using 0x", "USE_NETWORKED_LIQUIDITY": "use networked liquidity", "USE_NETWORKED_LIQUIDITY_DESCRIPTION": "Learn how to tap into networked liquidity using the Standard Relayer API", diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts index 25430c1c71..37f746f7ca 100644 --- a/packages/website/ts/blockchain.ts +++ b/packages/website/ts/blockchain.ts @@ -591,7 +591,7 @@ export class Blockchain { } } else { const injectedWeb3IfExists = (window as any).web3; - if (!_.isUndefined(injectedWeb3IfExists.currentProvider)) { + if (!_.isUndefined(injectedWeb3IfExists) && !_.isUndefined(injectedWeb3IfExists.currentProvider)) { injectedProviderIfExists = injectedWeb3IfExists.currentProvider; } else { return undefined; diff --git a/packages/website/ts/components/documentation/docs_logo.tsx b/packages/website/ts/components/documentation/docs_logo.tsx index 2840d59601..ac331db791 100644 --- a/packages/website/ts/components/documentation/docs_logo.tsx +++ b/packages/website/ts/components/documentation/docs_logo.tsx @@ -1,17 +1,34 @@ import { Link } from '@0x/react-shared'; import * as React from 'react'; +import { styled } from 'ts/style/theme'; import { WebsitePaths } from 'ts/types'; +import { Container } from '../ui/container'; + export interface DocsLogoProps { - height: number; containerStyle?: React.CSSProperties; } +const Image = styled.img` + &:hover { + opacity: 0.7; + } +`; + export const DocsLogo: React.StatelessComponent = props => { return ( - - - + + + + + + + + + + + + ); }; diff --git a/packages/website/ts/components/documentation/docs_top_bar.tsx b/packages/website/ts/components/documentation/docs_top_bar.tsx index 2054d08604..c4291b78f8 100644 --- a/packages/website/ts/components/documentation/docs_top_bar.tsx +++ b/packages/website/ts/components/documentation/docs_top_bar.tsx @@ -38,17 +38,17 @@ export class DocsTopBar extends React.Component - + {this._renderMenuItems(constants.DEVELOPER_TOPBAR_LINKS)} - + @@ -63,7 +63,7 @@ export class DocsTopBar extends React.Component - + {this.props.screenWidth === ScreenWidths.Sm && this._renderDrawer()} ); diff --git a/packages/website/ts/components/documentation/sidebar_header.tsx b/packages/website/ts/components/documentation/sidebar_header.tsx index fece2704be..9ced52c74a 100644 --- a/packages/website/ts/components/documentation/sidebar_header.tsx +++ b/packages/website/ts/components/documentation/sidebar_header.tsx @@ -29,6 +29,7 @@ export const SidebarHeader: React.StatelessComponent = ({ fontColor={colors.lightLinkBlue} fontSize={screenWidth === ScreenWidths.Sm ? '20px' : '22px'} fontWeight="bold" + lineHeight="26px" > {title} @@ -36,7 +37,7 @@ export const SidebarHeader: React.StatelessComponent = ({ {!_.isUndefined(docsVersion) && !_.isUndefined(availableDocVersions) && !_.isUndefined(onVersionSelected) && ( -
+
= ({ className, const ActiveNode = styled(PlainActiveNode)` cursor: pointer; - border: 2px solid ${colors.beigeWhite}; + border: 1px solid ${colors.beigeWhite}; border-radius: 4px; padding: 4px 6px 4px 8px; `; diff --git a/packages/website/ts/components/dropdowns/developers_drop_down.tsx b/packages/website/ts/components/dropdowns/developers_drop_down.tsx index 6e85c1499f..b8a35fab08 100644 --- a/packages/website/ts/components/dropdowns/developers_drop_down.tsx +++ b/packages/website/ts/components/dropdowns/developers_drop_down.tsx @@ -89,7 +89,7 @@ export class DevelopersDropDown extends React.Component diff --git a/packages/website/ts/components/nested_sidebar_menu.tsx b/packages/website/ts/components/nested_sidebar_menu.tsx index db7d55261b..4d4bc46176 100644 --- a/packages/website/ts/components/nested_sidebar_menu.tsx +++ b/packages/website/ts/components/nested_sidebar_menu.tsx @@ -4,11 +4,13 @@ import * as _ from 'lodash'; import * as React from 'react'; import { Button } from 'ts/components/ui/button'; import { Text } from 'ts/components/ui/text'; +import { ScreenWidths } from 'ts/types'; export interface NestedSidebarMenuProps { sectionNameToLinks: ObjectMap; sidebarHeader?: React.ReactNode; shouldReformatMenuItemNames?: boolean; + screenWidth: ScreenWidths; } export const NestedSidebarMenu = (props: NestedSidebarMenuProps) => { @@ -22,7 +24,7 @@ export const NestedSidebarMenu = (props: NestedSidebarMenuProps) => { ...link, title: menuItemTitle, }; - return ; + return ; }); // tslint:disable-next-line:no-unused-variable return ( @@ -44,6 +46,7 @@ export const NestedSidebarMenu = (props: NestedSidebarMenuProps) => { export interface MenuItemProps { link: ALink; + screenWidth: ScreenWidths; } export interface MenuItemState { @@ -70,7 +73,13 @@ export class MenuItem extends React.Component { borderRadius="4px" padding="0.4em 0.375em" width="100%" - backgroundColor={isActive ? colors.lightLinkBlue : colors.grey100} + backgroundColor={ + isActive + ? colors.lightLinkBlue + : this.props.screenWidth === ScreenWidths.Sm + ? 'white' + : colors.grey100 + } fontSize="14px" textAlign="left" > diff --git a/packages/website/ts/pages/documentation/developers_page.tsx b/packages/website/ts/pages/documentation/developers_page.tsx index 89389e4881..a84be7bfe2 100644 --- a/packages/website/ts/pages/documentation/developers_page.tsx +++ b/packages/website/ts/pages/documentation/developers_page.tsx @@ -157,9 +157,10 @@ export class DevelopersPage extends React.Component - + diff --git a/packages/website/ts/pages/documentation/doc_page.tsx b/packages/website/ts/pages/documentation/doc_page.tsx index 8392c90e42..adf2261b58 100644 --- a/packages/website/ts/pages/documentation/doc_page.tsx +++ b/packages/website/ts/pages/documentation/doc_page.tsx @@ -94,7 +94,11 @@ export class DocPage extends React.Component { const sidebar = _.isUndefined(this.state.docAgnosticFormat) ? (
) : ( - + ); return ( { sidebarHeader={isSmallScreen ? this._renderSidebarHeader() : undefined} sectionNameToLinks={sectionNameToLinks} shouldReformatMenuItemNames={false} + screenWidth={this.props.screenWidth} /> ); return ( diff --git a/packages/website/ts/pages/wiki/wiki.tsx b/packages/website/ts/pages/wiki/wiki.tsx index c1802b1f81..c3c1600a58 100644 --- a/packages/website/ts/pages/wiki/wiki.tsx +++ b/packages/website/ts/pages/wiki/wiki.tsx @@ -76,6 +76,7 @@ export class Wiki extends React.Component { ); return ( diff --git a/packages/website/ts/utils/constants.ts b/packages/website/ts/utils/constants.ts index 75ffe338fe..5ff9850eb4 100644 --- a/packages/website/ts/utils/constants.ts +++ b/packages/website/ts/utils/constants.ts @@ -105,10 +105,6 @@ export const constants = { URL_BIGNUMBERJS_GITHUB: 'http://mikemcl.github.io/bignumber.js', URL_MISSION_AND_VALUES_BLOG_POST: 'https://blog.0xproject.com/the-0x-mission-and-values-181a58706f9f', DEVELOPER_TOPBAR_LINKS: [ - { - title: Key.Home, - to: WebsitePaths.Home, - }, { title: Key.Wiki, to: WebsitePaths.Wiki, diff --git a/packages/website/webpack.config.js b/packages/website/webpack.config.js index ec265be93d..33d5f648bc 100644 --- a/packages/website/webpack.config.js +++ b/packages/website/webpack.config.js @@ -100,7 +100,6 @@ module.exports = (_env, argv) => { new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), new webpack.DefinePlugin({ 'process.env': { - NODE_ENV: JSON.stringify(process.env.NODE_ENV), GIT_SHA: JSON.stringify(GIT_SHA), }, }), diff --git a/python-packages/order_utils/.pylintrc b/python-packages/order_utils/.pylintrc new file mode 100644 index 0000000000..937bc6313b --- /dev/null +++ b/python-packages/order_utils/.pylintrc @@ -0,0 +1,3 @@ +[MESSAGES CONTROL] +disable=C0330,line-too-long,fixme,too-few-public-methods,too-many-ancestors +# C0330 is "bad hanging indent". we use indents per `black`. diff --git a/python-packages/order_utils/setup.py b/python-packages/order_utils/setup.py index 1b07b612c4..679bfb4b21 100755 --- a/python-packages/order_utils/setup.py +++ b/python-packages/order_utils/setup.py @@ -24,7 +24,6 @@ class TestCommandExtension(TestCommand): exit(pytest.main()) -# pylint: disable=too-many-ancestors class LintCommand(distutils.command.build_py.build_py): """Custom setuptools command class for running linters.""" @@ -90,7 +89,6 @@ class CleanCommandExtension(clean): rmtree("src/0x_order_utils.egg-info", ignore_errors=True) -# pylint: disable=too-many-ancestors class TestPublishCommand(distutils.command.build_py.build_py): """Custom command to publish to test.pypi.org.""" @@ -108,7 +106,6 @@ class TestPublishCommand(distutils.command.build_py.build_py): ) -# pylint: disable=too-many-ancestors class PublishCommand(distutils.command.build_py.build_py): """Custom command to publish to pypi.org.""" @@ -119,7 +116,6 @@ class PublishCommand(distutils.command.build_py.build_py): subprocess.check_call("twine upload dist/*".split()) # nosec -# pylint: disable=too-many-ancestors class GanacheCommand(distutils.command.build_py.build_py): """Custom command to publish to pypi.org.""" @@ -160,7 +156,13 @@ setup( "publish": PublishCommand, "ganache": GanacheCommand, }, - install_requires=["eth-abi", "eth_utils", "mypy_extensions", "web3"], + install_requires=[ + "eth-abi", + "eth_utils", + "jsonschema", + "mypy_extensions", + "web3", + ], extras_require={ "dev": [ "bandit", @@ -182,6 +184,7 @@ setup( package_data={ "zero_ex.order_utils": ["py.typed"], "zero_ex.contract_artifacts": ["artifacts/*"], + "zero_ex.json_schemas": ["schemas/*"], }, package_dir={"": "src"}, license="Apache 2.0", diff --git a/python-packages/order_utils/src/index.rst b/python-packages/order_utils/src/index.rst index b99addabd1..551487ab17 100644 --- a/python-packages/order_utils/src/index.rst +++ b/python-packages/order_utils/src/index.rst @@ -7,6 +7,11 @@ Python zero_ex.order_utils :maxdepth: 2 :caption: Contents: +.. autoclass:: zero_ex.order_utils.Order + :members: + +See source for class properties. Sphinx does not easily generate class property docs; pull requests welcome. + .. automodule:: zero_ex.order_utils :members: @@ -17,9 +22,7 @@ Python zero_ex.order_utils .. autoclass:: zero_ex.order_utils.asset_data_utils.ERC721AssetData -See source for class properties. Sphinx does not easily generate class property docs; pull requests welcome. - -.. automodule:: zero_ex.order_utils.signature_utils +.. automodule:: zero_ex.json_schemas :members: Indices and tables diff --git a/python-packages/order_utils/src/zero_ex/dev_utils/abi_utils.py b/python-packages/order_utils/src/zero_ex/dev_utils/abi_utils.py index 71b6128ca5..3fec775b05 100644 --- a/python-packages/order_utils/src/zero_ex/dev_utils/abi_utils.py +++ b/python-packages/order_utils/src/zero_ex/dev_utils/abi_utils.py @@ -10,8 +10,8 @@ from typing import Any, List from mypy_extensions import TypedDict -from eth_abi import encode_abi from web3 import Web3 +from eth_abi import encode_abi from .type_assertions import assert_is_string, assert_is_list @@ -84,7 +84,6 @@ def method_id(name: str, types: List[str]) -> str: def simple_encode(method: str, *args: Any) -> bytes: - # docstring considered all one line by pylint: disable=line-too-long r"""Encode a method ABI. >>> simple_encode("ERC20Token(address)", "0x1dc4c1cefef38a777b15aa20260a54e584b16c48") diff --git a/python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py b/python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py index 08c1b0ea5e..1dcfb39a9f 100644 --- a/python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py +++ b/python-packages/order_utils/src/zero_ex/dev_utils/type_assertions.py @@ -2,6 +2,9 @@ from typing import Any +from eth_utils import is_address +from web3.providers.base import BaseProvider + def assert_is_string(value: Any, name: str) -> None: """If :param value: isn't of type str, raise a TypeError. @@ -56,3 +59,31 @@ def assert_is_hex_string(value: Any, name: str) -> None: """ assert_is_string(value, name) int(value, 16) # raises a ValueError if value isn't a base-16 str + + +def assert_is_address(value: Any, name: str) -> None: + """Assert that `value` is a valid Ethereum address. + + If `value` isn't a hex string, raise a TypeError. If it isn't a valid + Ethereum address, raise a ValueError. + """ + assert_is_hex_string(value, name) + if not is_address(value): + raise ValueError( + f"Expected variable '{name}' to be a valid Ethereum" + + " address, but it's not." + ) + + +def assert_is_provider(value: Any, name: str) -> None: + """Assert that `value` is a Web3 provider. + + If `value` isn't a Web3 provider, raise a TypeError. + """ + # TODO: make this provider check more flexible. + # https://app.asana.com/0/684263176955174/901300863045491/f + if not isinstance(value, BaseProvider): + raise TypeError( + f"Expected variable '{name}' to be an instance of a Web3 provider," + + " but it's not." + ) diff --git a/python-packages/order_utils/src/zero_ex/json_schemas/__init__.py b/python-packages/order_utils/src/zero_ex/json_schemas/__init__.py new file mode 100644 index 0000000000..2a1728b8af --- /dev/null +++ b/python-packages/order_utils/src/zero_ex/json_schemas/__init__.py @@ -0,0 +1,61 @@ +"""JSON schemas and associated utilities.""" + +from os import path +import json +from typing import Mapping + +from pkg_resources import resource_string +import jsonschema + + +def assert_valid(data: Mapping, schema_id: str) -> None: + """Validate the given `data` against the specified `schema`. + + :param data: Python dictionary to be validated as a JSON object. + :param schema_id: id property of the JSON schema to validate against. Must + be one of those listed in `the 0x JSON schema files + `_. + + Raises an exception if validation fails. + + >>> assert_valid( + ... {'v': 27, 'r': '0x'+'f'*64, 's': '0x'+'f'*64}, + ... '/ECSignature', + ... ) + """ + # noqa + class LocalRefResolver(jsonschema.RefResolver): + """Resolve package-local JSON schema id's.""" + + def __init__(self): + self.ref_to_file = { + "/addressSchema": "address_schema.json", + "/hexSchema": "hex_schema.json", + "/orderSchema": "order_schema.json", + "/wholeNumberSchema": "whole_number_schema.json", + "/ECSignature": "ec_signature_schema.json", + "/ecSignatureParameterSchema": ( + "ec_signature_parameter_schema.json" + "" + ), + } + jsonschema.RefResolver.__init__(self, "", "") + + def resolve_from_url(self, url): + """Resolve the given URL.""" + ref = url.replace("file://", "") + if ref in self.ref_to_file: + return json.loads( + resource_string( + "zero_ex.json_schemas", + f"schemas/{self.ref_to_file[ref]}", + ) + ) + raise jsonschema.ValidationError( + f"Unknown ref '{ref}'. " + + f"Known refs: {list(self.ref_to_file.keys())}." + ) + + resolver = LocalRefResolver() + jsonschema.validate( + data, resolver.resolve_from_url(schema_id), resolver=resolver + ) diff --git a/python-packages/order_utils/src/zero_ex/json_schemas/schemas b/python-packages/order_utils/src/zero_ex/json_schemas/schemas new file mode 120000 index 0000000000..b8257372c3 --- /dev/null +++ b/python-packages/order_utils/src/zero_ex/json_schemas/schemas @@ -0,0 +1 @@ +../../../../../packages/json-schemas/schemas/ \ No newline at end of file diff --git a/python-packages/order_utils/src/zero_ex/order_utils/__init__.py b/python-packages/order_utils/src/zero_ex/order_utils/__init__.py index 80445cb6ec..24c6bfd4e8 100644 --- a/python-packages/order_utils/src/zero_ex/order_utils/__init__.py +++ b/python-packages/order_utils/src/zero_ex/order_utils/__init__.py @@ -9,3 +9,397 @@ just this purpose. To start it: ``docker run -d -p 8545:8545 0xorg/ganache-cli --networkId 50 -m "concert load couple harbor equip island argue ramp clarify fence smart topic"``. """ + +from enum import auto, Enum +import json +from typing import Dict, Tuple +from pkg_resources import resource_string + +from mypy_extensions import TypedDict + +from eth_utils import keccak, to_bytes, to_checksum_address +from web3 import Web3 +import web3.exceptions +from web3.providers.base import BaseProvider +from web3.utils import datatypes + +from zero_ex.dev_utils.type_assertions import ( + assert_is_address, + assert_is_hex_string, + assert_is_provider, +) +from zero_ex.json_schemas import assert_valid + + +class _Constants: + """Static data used by order utilities.""" + + _contract_name_to_abi: Dict[str, Dict] = {} # class data, not instance + + @classmethod + def contract_name_to_abi(cls, contract_name: str) -> Dict: + """Return the ABI for the given contract name. + + First tries to get data from the class level storage + `_contract_name_to_abi`. If it's not there, loads it from disk, stores + it in the class data (for the next caller), and then returns it. + """ + try: + return cls._contract_name_to_abi[contract_name] + except KeyError: + cls._contract_name_to_abi[contract_name] = json.loads( + resource_string( + "zero_ex.contract_artifacts", + f"artifacts/{contract_name}.json", + ) + )["compilerOutput"]["abi"] + return cls._contract_name_to_abi[contract_name] + + network_to_exchange_addr: Dict[str, str] = { + "1": "0x4f833a24e1f95d70f028921e27040ca56e09ab0b", + "3": "0x4530c0483a1633c7a1c97d2c53721caff2caaaaf", + "42": "0x35dd2932454449b14cee11a94d3674a936d5d7b2", + "50": "0x48bacb9266a570d521063ef5dd96e61686dbe788", + } + + null_address = "0x0000000000000000000000000000000000000000" + + eip191_header = b"\x19\x01" + + eip712_domain_separator_schema_hash = keccak( + b"EIP712Domain(string name,string version,address verifyingContract)" + ) + + eip712_domain_struct_header = ( + eip712_domain_separator_schema_hash + + keccak(b"0x Protocol") + + keccak(b"2") + ) + + eip712_order_schema_hash = keccak( + b"Order(" + + b"address makerAddress," + + b"address takerAddress," + + b"address feeRecipientAddress," + + b"address senderAddress," + + b"uint256 makerAssetAmount," + + b"uint256 takerAssetAmount," + + b"uint256 makerFee," + + b"uint256 takerFee," + + b"uint256 expirationTimeSeconds," + + b"uint256 salt," + + b"bytes makerAssetData," + + b"bytes takerAssetData" + + b")" + ) + + class SignatureType(Enum): + """Enumeration of known signature types.""" + + ILLEGAL = 0 + INVALID = auto() + EIP712 = auto() + ETH_SIGN = auto() + WALLET = auto() + VALIDATOR = auto() + PRE_SIGNED = auto() + N_SIGNATURE_TYPES = auto() + + +class Order(TypedDict): # pylint: disable=too-many-instance-attributes + """Object representation of a 0x order.""" + + makerAddress: str + takerAddress: str + feeRecipientAddress: str + senderAddress: str + makerAssetAmount: str + takerAssetAmount: str + makerFee: str + takerFee: str + expirationTimeSeconds: str + salt: str + makerAssetData: str + takerAssetData: str + exchangeAddress: str + + +def make_empty_order() -> Order: + """Construct an empty order. + + Initializes all strings to "0x0000000000000000000000000000000000000000" + and all numbers to 0. + """ + return { + "makerAddress": _Constants.null_address, + "takerAddress": _Constants.null_address, + "senderAddress": _Constants.null_address, + "feeRecipientAddress": _Constants.null_address, + "makerAssetData": _Constants.null_address, + "takerAssetData": _Constants.null_address, + "salt": "0", + "makerFee": "0", + "takerFee": "0", + "makerAssetAmount": "0", + "takerAssetAmount": "0", + "expirationTimeSeconds": "0", + "exchangeAddress": _Constants.null_address, + } + + +def generate_order_hash_hex(order: Order) -> str: + """Calculate the hash of the given order as a hexadecimal string. + + :param order: The order to be hashed. Must conform to `the 0x order JSON schema `_. + :param exchange_address: The address to which the 0x Exchange smart + contract has been deployed. + :rtype: A string, of ASCII hex digits, representing the order hash. + + >>> generate_order_hash_hex( + ... { + ... 'makerAddress': "0x0000000000000000000000000000000000000000", + ... 'takerAddress': "0x0000000000000000000000000000000000000000", + ... 'feeRecipientAddress': "0x0000000000000000000000000000000000000000", + ... 'senderAddress': "0x0000000000000000000000000000000000000000", + ... 'makerAssetAmount': "1000000000000000000", + ... 'takerAssetAmount': "1000000000000000000", + ... 'makerFee': "0", + ... 'takerFee': "0", + ... 'expirationTimeSeconds': "12345", + ... 'salt': "12345", + ... 'makerAssetData': "0x0000000000000000000000000000000000000000", + ... 'takerAssetData': "0x0000000000000000000000000000000000000000", + ... 'exchangeAddress': "0x0000000000000000000000000000000000000000", + ... }, + ... ) + '55eaa6ec02f3224d30873577e9ddd069a288c16d6fb407210eecbc501fa76692' + """ # noqa: E501 (line too long) + assert_valid(order, "/orderSchema") + + def pad_20_bytes_to_32(twenty_bytes: bytes): + return bytes(12) + twenty_bytes + + def int_to_32_big_endian_bytes(i: int): + return i.to_bytes(32, byteorder="big") + + eip712_domain_struct_hash = keccak( + _Constants.eip712_domain_struct_header + + pad_20_bytes_to_32(to_bytes(hexstr=order["exchangeAddress"])) + ) + + eip712_order_struct_hash = keccak( + _Constants.eip712_order_schema_hash + + pad_20_bytes_to_32(to_bytes(hexstr=order["makerAddress"])) + + pad_20_bytes_to_32(to_bytes(hexstr=order["takerAddress"])) + + pad_20_bytes_to_32(to_bytes(hexstr=order["feeRecipientAddress"])) + + pad_20_bytes_to_32(to_bytes(hexstr=order["senderAddress"])) + + int_to_32_big_endian_bytes(int(order["makerAssetAmount"])) + + int_to_32_big_endian_bytes(int(order["takerAssetAmount"])) + + int_to_32_big_endian_bytes(int(order["makerFee"])) + + int_to_32_big_endian_bytes(int(order["takerFee"])) + + int_to_32_big_endian_bytes(int(order["expirationTimeSeconds"])) + + int_to_32_big_endian_bytes(int(order["salt"])) + + keccak(to_bytes(hexstr=order["makerAssetData"])) + + keccak(to_bytes(hexstr=order["takerAssetData"])) + ) + + return keccak( + _Constants.eip191_header + + eip712_domain_struct_hash + + eip712_order_struct_hash + ).hex() + + +def is_valid_signature( + provider: BaseProvider, data: str, signature: str, signer_address: str +) -> Tuple[bool, str]: + """Check the validity of the supplied signature. + + Check if the supplied ``signature`` corresponds to signing ``data`` with + the private key corresponding to ``signer_address``. + + :param provider: A Web3 provider able to access the 0x Exchange contract. + :param data: The hex encoded data signed by the supplied signature. + :param signature: The hex encoded signature. + :param signer_address: The hex encoded address that signed the data to + produce the supplied signature. + :rtype: Tuple consisting of a boolean and a string. Boolean is true if + valid, false otherwise. If false, the string describes the reason. + + >>> is_valid_signature( + ... Web3.HTTPProvider("http://127.0.0.1:8545"), + ... '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0', + ... '0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403', + ... '0x5409ed021d9299bf6814279a6a1411a7e866a631', + ... ) + (True, '') + """ # noqa: E501 (line too long) + assert_is_provider(provider, "provider") + assert_is_hex_string(data, "data") + assert_is_hex_string(signature, "signature") + assert_is_address(signer_address, "signer_address") + + web3_instance = Web3(provider) + # false positive from pylint: disable=no-member + network_id = web3_instance.net.version + contract_address = _Constants.network_to_exchange_addr[network_id] + # false positive from pylint: disable=no-member + contract: datatypes.Contract = web3_instance.eth.contract( + address=to_checksum_address(contract_address), + abi=_Constants.contract_name_to_abi("Exchange"), + ) + try: + return ( + contract.call().isValidSignature( + data, to_checksum_address(signer_address), signature + ), + "", + ) + except web3.exceptions.BadFunctionCallOutput as exception: + known_revert_reasons = [ + "LENGTH_GREATER_THAN_0_REQUIRED", + "SIGNATURE_ILLEGAL", + "SIGNATURE_UNSUPPORTED", + "LENGTH_0_REQUIRED", + "LENGTH_65_REQUIRED", + ] + for known_revert_reason in known_revert_reasons: + if known_revert_reason in str(exception): + return (False, known_revert_reason) + return (False, f"Unknown: {exception}") + + +class ECSignature(TypedDict): + """Object representation of an elliptic curve signature's parameters.""" + + v: int + r: str + s: str + + +def _parse_signature_hex_as_vrs(signature_hex: str) -> ECSignature: + """Parse signature hex as a concatentation of EC parameters ordered V, R, S. + + >>> _parse_signature_hex_as_vrs('0x1b117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d872871137feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b03') + {'v': 27, 'r': '117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d87287113', 's': '7feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b'} + """ # noqa: E501 (line too long) + signature: ECSignature = { + "v": int(signature_hex[2:4], 16), + "r": signature_hex[4:68], + "s": signature_hex[68:132], + } + if signature["v"] == 0 or signature["v"] == 1: + signature["v"] = signature["v"] + 27 + return signature + + +def _parse_signature_hex_as_rsv(signature_hex: str) -> ECSignature: + """Parse signature hex as a concatentation of EC parameters ordered R, S, V. + + >>> _parse_signature_hex_as_rsv('0x117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d872871137feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b00') + {'r': '117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d87287113', 's': '7feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b', 'v': 27} + """ # noqa: E501 (line too long) + signature: ECSignature = { + "r": signature_hex[2:66], + "s": signature_hex[66:130], + "v": int(signature_hex[130:132], 16), + } + if signature["v"] == 0 or signature["v"] == 1: + signature["v"] = signature["v"] + 27 + return signature + + +def _convert_ec_signature_to_vrs_hex(signature: ECSignature) -> str: + """Convert elliptic curve signature object to hex hash string. + + >>> _convert_ec_signature_to_vrs_hex( + ... { + ... 'r': '117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d87287113', + ... 's': '7feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b', + ... 'v': 27 + ... } + ... ) + '0x1b117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d872871137feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b' + """ # noqa: E501 (line too long) + return ( + "0x" + + signature["v"].to_bytes(1, byteorder="big").hex() + + signature["r"] + + signature["s"] + ) + + +def sign_hash( + provider: BaseProvider, signer_address: str, hash_hex: str +) -> str: + """Sign a message with the given hash, and return the signature. + + :param provider: A Web3 provider. + :param signer_address: The address of the signing account. + :param hash_hex: A hex string representing the hash, like that returned + from `generate_order_hash_hex()`. + :rtype: A string, of ASCII hex digits, representing the signature. + + >>> provider = Web3.HTTPProvider("http://127.0.0.1:8545") + >>> sign_hash( + ... provider, + ... Web3(provider).personal.listAccounts[0], + ... '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004', + ... ) + '0x1b117902c86dfb95fe0d1badd983ee166ad259b27acb220174cbb4460d872871137feabdfe76e05924b484789f79af4ee7fa29ec006cedce1bbf369320d034e10b03' + """ # noqa: E501 (line too long) + assert_is_provider(provider, "provider") + assert_is_address(signer_address, "signer_address") + assert_is_hex_string(hash_hex, "hash_hex") + + web3_instance = Web3(provider) + # false positive from pylint: disable=no-member + signature = web3_instance.eth.sign( # type: ignore + signer_address, hexstr=hash_hex.replace("0x", "") + ).hex() + + valid_v_param_values = [27, 28] + + # HACK: There is no consensus on whether the signatureHex string should be + # formatted as v + r + s OR r + s + v, and different clients (even + # different versions of the same client) return the signature params in + # different orders. In order to support all client implementations, we + # parse the signature in both ways, and evaluate if either one is a valid + # signature. r + s + v is the most prevalent format from eth_sign, so we + # attempt this first. + + ec_signature = _parse_signature_hex_as_rsv(signature) + if ec_signature["v"] in valid_v_param_values: + signature_as_vrst_hex = ( + _convert_ec_signature_to_vrs_hex(ec_signature) + + _Constants.SignatureType.ETH_SIGN.value.to_bytes( + 1, byteorder="big" + ).hex() + ) + + (valid, _) = is_valid_signature( + provider, hash_hex, signature_as_vrst_hex, signer_address + ) + + if valid is True: + return signature_as_vrst_hex + + ec_signature = _parse_signature_hex_as_vrs(signature) + if ec_signature["v"] in valid_v_param_values: + signature_as_vrst_hex = ( + _convert_ec_signature_to_vrs_hex(ec_signature) + + _Constants.SignatureType.ETH_SIGN.value.to_bytes( + 1, byteorder="big" + ).hex() + ) + (valid, _) = is_valid_signature( + provider, hash_hex, signature_as_vrst_hex, signer_address + ) + + if valid is True: + return signature_as_vrst_hex + + raise RuntimeError( + "Signature returned from web3 provider is in an unknown format." + + " Attempted to parse as RSV and as VRS." + ) diff --git a/python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py b/python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py index e6f9a07c11..fab7479d2e 100644 --- a/python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py +++ b/python-packages/order_utils/src/zero_ex/order_utils/asset_data_utils.py @@ -47,7 +47,6 @@ def encode_erc20_asset_data(token_address: str) -> str: def decode_erc20_asset_data(asset_data: str) -> ERC20AssetData: - # docstring considered all one line by pylint: disable=line-too-long """Decode an ERC20 asset data hex string. :param asset_data: String produced by prior call to encode_erc20_asset_data() @@ -82,7 +81,6 @@ def decode_erc20_asset_data(asset_data: str) -> ERC20AssetData: def encode_erc721_asset_data(token_address: str, token_id: int) -> str: - # docstring considered all one line by pylint: disable=line-too-long """Encode an ERC721 asset data hex string. :param token_address: the ERC721 token's contract address. @@ -105,7 +103,6 @@ def encode_erc721_asset_data(token_address: str, token_id: int) -> str: def decode_erc721_asset_data(asset_data: str) -> ERC721AssetData: - # docstring considered all one line by pylint: disable=line-too-long """Decode an ERC721 asset data hex string. >>> decode_erc721_asset_data('0x025717920000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c480000000000000000000000000000000000000000000000000000000000000001') @@ -121,7 +118,6 @@ def decode_erc721_asset_data(asset_data: str) -> ERC721AssetData: ) asset_proxy_id: str = asset_data[0:SELECTOR_LENGTH] - # prefer `black` formatting. pylint: disable=C0330 if asset_proxy_id != abi_utils.method_id( "ERC721Token", ["address", "uint256"] ): diff --git a/python-packages/order_utils/src/zero_ex/order_utils/signature_utils.py b/python-packages/order_utils/src/zero_ex/order_utils/signature_utils.py deleted file mode 100644 index 12525ba88c..0000000000 --- a/python-packages/order_utils/src/zero_ex/order_utils/signature_utils.py +++ /dev/null @@ -1,88 +0,0 @@ -"""Signature utilities.""" - -from typing import Dict, Tuple -import json -from pkg_resources import resource_string - -from eth_utils import is_address, to_checksum_address -from web3 import Web3 -import web3.exceptions -from web3.utils import datatypes - -from zero_ex.dev_utils.type_assertions import assert_is_hex_string - - -# prefer `black` formatting. pylint: disable=C0330 -EXCHANGE_ABI = json.loads( - resource_string("zero_ex.contract_artifacts", "artifacts/Exchange.json") -)["compilerOutput"]["abi"] - -network_to_exchange_addr: Dict[str, str] = { - "1": "0x4f833a24e1f95d70f028921e27040ca56e09ab0b", - "3": "0x4530c0483a1633c7a1c97d2c53721caff2caaaaf", - "42": "0x35dd2932454449b14cee11a94d3674a936d5d7b2", - "50": "0x48bacb9266a570d521063ef5dd96e61686dbe788", -} - - -# prefer `black` formatting. pylint: disable=C0330 -def is_valid_signature( - provider: Web3.HTTPProvider, data: str, signature: str, signer_address: str -) -> Tuple[bool, str]: - # docstring considered all one line by pylint: disable=line-too-long - """Check the validity of the supplied signature. - - Check if the supplied ``signature`` corresponds to signing ``data`` with - the private key corresponding to ``signer_address``. - - :param provider: A Web3 provider able to access the 0x Exchange contract. - :param data: The hex encoded data signed by the supplied signature. - :param signature: The hex encoded signature. - :param signer_address: The hex encoded address that signed the data to - produce the supplied signature. - :rtype: Boolean indicating whether the given signature is valid. - - >>> is_valid_signature( - ... Web3.HTTPProvider("http://127.0.0.1:8545"), - ... '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0', - ... '0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403', - ... '0x5409ed021d9299bf6814279a6a1411a7e866a631', - ... ) - (True, '') - """ # noqa: E501 (line too long) - # TODO: make this provider check more flexible. pylint: disable=fixme - # https://app.asana.com/0/684263176955174/901300863045491/f - if not isinstance(provider, Web3.HTTPProvider): - raise TypeError("provider is not a Web3.HTTPProvider") - assert_is_hex_string(data, "data") - assert_is_hex_string(signature, "signature") - assert_is_hex_string(signer_address, "signer_address") - if not is_address(signer_address): - raise ValueError("signer_address is not a valid address") - - web3_instance = Web3(provider) - # false positive from pylint: disable=no-member - network_id = web3_instance.net.version - contract_address = network_to_exchange_addr[network_id] - # false positive from pylint: disable=no-member - contract: datatypes.Contract = web3_instance.eth.contract( - address=to_checksum_address(contract_address), abi=EXCHANGE_ABI - ) - try: - return ( - contract.call().isValidSignature( - data, to_checksum_address(signer_address), signature - ), - "", - ) - except web3.exceptions.BadFunctionCallOutput as exception: - known_revert_reasons = [ - "LENGTH_GREATER_THAN_0_REQUIRED", - "SIGNATURE_UNSUPPORTED", - "LENGTH_0_REQUIRED", - "LENGTH_65_REQUIRED", - ] - for known_revert_reason in known_revert_reasons: - if known_revert_reason in str(exception): - return (False, known_revert_reason) - return (False, f"Unknown: {exception}") diff --git a/python-packages/order_utils/stubs/jsonschema/__init__.pyi b/python-packages/order_utils/stubs/jsonschema/__init__.pyi new file mode 100644 index 0000000000..762b58b224 --- /dev/null +++ b/python-packages/order_utils/stubs/jsonschema/__init__.pyi @@ -0,0 +1,5 @@ +from typing import Any, Dict + +class RefResolver: pass + +def validate(instance: Any, schema: Dict, cls=None, *args, **kwargs) -> None: pass diff --git a/python-packages/order_utils/stubs/jsonschema/exceptions.pyi b/python-packages/order_utils/stubs/jsonschema/exceptions.pyi new file mode 100644 index 0000000000..e69de29bb2 diff --git a/python-packages/order_utils/stubs/sha3/__init__.pyi b/python-packages/order_utils/stubs/sha3/__init__.pyi new file mode 100644 index 0000000000..e69de29bb2 diff --git a/python-packages/order_utils/stubs/web3/__init__.pyi b/python-packages/order_utils/stubs/web3/__init__.pyi index fcecc7434c..b2af954753 100644 --- a/python-packages/order_utils/stubs/web3/__init__.pyi +++ b/python-packages/order_utils/stubs/web3/__init__.pyi @@ -1,12 +1,14 @@ from typing import Dict, Optional, Union from web3.utils import datatypes +from web3.providers.base import BaseProvider class Web3: - class HTTPProvider: ... + class HTTPProvider(BaseProvider): + ... - def __init__(self, provider: HTTPProvider) -> None: ... + def __init__(self, provider: BaseProvider) -> None: ... @staticmethod def sha3( diff --git a/python-packages/order_utils/stubs/web3/providers/__init__.pyi b/python-packages/order_utils/stubs/web3/providers/__init__.pyi new file mode 100644 index 0000000000..e69de29bb2 diff --git a/python-packages/order_utils/stubs/web3/providers/base.pyi b/python-packages/order_utils/stubs/web3/providers/base.pyi new file mode 100644 index 0000000000..82ca9e3da1 --- /dev/null +++ b/python-packages/order_utils/stubs/web3/providers/base.pyi @@ -0,0 +1,2 @@ +class BaseProvider: + ... diff --git a/python-packages/order_utils/test/test_doctest.py b/python-packages/order_utils/test/test_doctest.py index 2b0350ac0f..f692b3b6cf 100644 --- a/python-packages/order_utils/test/test_doctest.py +++ b/python-packages/order_utils/test/test_doctest.py @@ -8,7 +8,6 @@ import zero_ex def test_all_doctests(): """Gather zero_ex.* modules and doctest them.""" - # prefer `black` formatting. pylint: disable=bad-continuation for (importer, modname, _) in pkgutil.walk_packages( path=zero_ex.__path__, prefix="zero_ex." ): diff --git a/python-packages/order_utils/test/test_generate_order_hash_hex.py b/python-packages/order_utils/test/test_generate_order_hash_hex.py new file mode 100644 index 0000000000..6869a40ed3 --- /dev/null +++ b/python-packages/order_utils/test/test_generate_order_hash_hex.py @@ -0,0 +1,12 @@ +"""Test zero_ex.order_utils.get_order_hash_hex().""" + +from zero_ex.order_utils import generate_order_hash_hex, make_empty_order + + +def test_get_order_hash_hex__empty_order(): + """Test the hashing of an uninitialized order.""" + expected_hash_hex = ( + "faa49b35faeb9197e9c3ba7a52075e6dad19739549f153b77dfcf59408a4b422" + ) + actual_hash_hex = generate_order_hash_hex(make_empty_order()) + assert actual_hash_hex == expected_hash_hex diff --git a/python-packages/order_utils/test/test_signature_utils.py b/python-packages/order_utils/test/test_signature_utils.py index b688e03a18..c5acc9d627 100644 --- a/python-packages/order_utils/test/test_signature_utils.py +++ b/python-packages/order_utils/test/test_signature_utils.py @@ -3,7 +3,7 @@ import pytest from web3 import Web3 -from zero_ex.order_utils.signature_utils import is_valid_signature +from zero_ex.order_utils import is_valid_signature def test_is_valid_signature__provider_wrong_type(): diff --git a/yarn.lock b/yarn.lock index f33adb2270..e4304acd5f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3197,6 +3197,10 @@ bowser@^1.7.3, bowser@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.9.3.tgz#6643ae4d783f31683f6d23156976b74183862162" +bowser@^1.9.4: + version "1.9.4" + resolved "https://registry.npmjs.org/bowser/-/bowser-1.9.4.tgz#890c58a2813a9d3243704334fa81b96a5c150c9a" + boxen@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" @@ -7966,7 +7970,7 @@ ip-regex@^2.1.0: ip@^1.1.0, ip@^1.1.5: version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + resolved "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" ipaddr.js@1.6.0: version "1.6.0"