Compare commits
	
		
			143 Commits
		
	
	
		
			@0x/asset-
			...
			@0x/abi-ge
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | fe1b7f15e8 | ||
|  | 3f647c259a | ||
|  | 06dcf24496 | ||
|  | 77c77631e1 | ||
|  | b0e9f58033 | ||
|  | 4fc457b78b | ||
|  | 2f6b1273aa | ||
|  | da9de70bbc | ||
|  | b174a891bc | ||
|  | bb79a5e324 | ||
|  | 9e0c232a73 | ||
|  | e02dc13805 | ||
|  | 820ab062a6 | ||
|  | 7b4f63a39c | ||
|  | 3a3fe0e69a | ||
|  | 5c21d3f6af | ||
|  | baba78f545 | ||
|  | f03afe6f1b | ||
|  | a824264da2 | ||
|  | a66c03aa21 | ||
|  | bed134c1da | ||
|  | d36cf58b82 | ||
|  | 5527de62ff | ||
|  | 11f0bebd7f | ||
|  | 3fb29041b0 | ||
|  | 161a935003 | ||
|  | e8afc66a5a | ||
|  | 49a9345bf4 | ||
|  | d73faf1b81 | ||
|  | 0c6110b736 | ||
|  | 2da258f5be | ||
|  | e9bf7206bd | ||
|  | 2b4dcb419e | ||
|  | c67632dff5 | ||
|  | 01b36b4949 | ||
|  | 711b307e6c | ||
|  | 1ab19a7c23 | ||
|  | 7068f7b4d1 | ||
|  | 79f0324abc | ||
|  | b82148ea60 | ||
|  | add1cfd261 | ||
|  | cdf78494d5 | ||
|  | 789f573452 | ||
|  | 22f217807d | ||
|  | 08797392e0 | ||
|  | 853c77dc09 | ||
|  | 0ebbbdfca4 | ||
|  | 085d34834b | ||
|  | b866ce787c | ||
|  | 4d5bc8b8ee | ||
|  | 7f013515e7 | ||
|  | a4a46dc076 | ||
|  | 33dbdb0184 | ||
|  | 0d565fe32f | ||
|  | 320460feb9 | ||
|  | dbce3f8935 | ||
|  | c41622c20a | ||
|  | 348556a544 | ||
|  | 6fa6579c31 | ||
|  | 6f61268514 | ||
|  | 8efc6c2112 | ||
|  | b21c1bea46 | ||
|  | fd7ba3ecea | ||
|  | 8aeb18bcc3 | ||
|  | 9e4a594eb1 | ||
|  | 3b421ef796 | ||
|  | e0c4f58970 | ||
|  | df8fd36c94 | ||
|  | 76b3caa124 | ||
|  | 0101cd73aa | ||
|  | 6ef628613e | ||
|  | bc960fe8f8 | ||
|  | 517c620397 | ||
|  | 498be7ac41 | ||
|  | 0391f93490 | ||
|  | 399a7d5fec | ||
|  | 0d201173ef | ||
|  | 2d43f312c8 | ||
|  | 1ec8a4115f | ||
|  | 753b33aec5 | ||
|  | 7626d1d6fe | ||
|  | d3592d362e | ||
|  | a8a1ea92a6 | ||
|  | ff027ee36a | ||
|  | 397b4e2890 | ||
|  | ba292ead45 | ||
|  | 5355f3c538 | ||
|  | 478330c12d | ||
|  | 38896c9358 | ||
|  | 26cbe7ae66 | ||
|  | fd83ca2cb8 | ||
|  | b1376059d3 | ||
|  | 4072076965 | ||
|  | 2bba01c664 | ||
|  | 93054ae52b | ||
|  | 5c1b1a1203 | ||
|  | 433fb3597d | ||
|  | acb7e876b2 | ||
|  | 2c585bfbdc | ||
|  | 1f0ac47bd9 | ||
|  | 7460f2796a | ||
|  | 7249cc7b49 | ||
|  | b598827708 | ||
|  | 128abb39dd | ||
|  | 79a533940e | ||
|  | 773cf3cd14 | ||
|  | 53d0f5b98e | ||
|  | 3a51bd1e69 | ||
|  | 3f1f19e344 | ||
|  | 3aa831ad77 | ||
|  | 3fd667b3be | ||
|  | fa7bd072d0 | ||
|  | cc8debe53b | ||
|  | 36b8c9c5dd | ||
|  | 474db7c18d | ||
|  | daa011f7cb | ||
|  | 39657b633b | ||
|  | 2e8f74abce | ||
|  | 239eada7d9 | ||
|  | df91d34315 | ||
|  | 3980bf39a9 | ||
|  | a50f0ca997 | ||
|  | d703c13f8e | ||
|  | 3dacc6157b | ||
|  | fd12bdbbd5 | ||
|  | 297a62fe80 | ||
|  | 1e39d56cf7 | ||
|  | 39ae21d693 | ||
|  | e45b6c7e98 | ||
|  | fc138cd73d | ||
|  | 990d510d05 | ||
|  | dd4d3b10cf | ||
|  | eb5f514d25 | ||
|  | 57318a6ef2 | ||
|  | 857a35d4f7 | ||
|  | 624f5cee8d | ||
|  | 7acaae37a9 | ||
|  | 801004be66 | ||
|  | 81fb8d614f | ||
|  | 3e75daafa1 | ||
|  | 6696aa46ee | ||
|  | 14a9770d57 | ||
|  | b8d2cc1221 | 
| @@ -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": [ | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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": [ | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1542208198, | ||||
|         "version": "1.0.16", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.0.15", | ||||
|         "changes": [ | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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": [ | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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" | ||||
|     }, | ||||
|   | ||||
| @@ -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": [ | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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" | ||||
|     }, | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
|     }, | ||||
|   | ||||
| @@ -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, | ||||
|     }; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|         }); | ||||
|   | ||||
| @@ -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": [ | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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": [ | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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<AssetPairsResponse> { | ||||
|         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<OrdersResponse> { | ||||
|         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<APIOrder> { | ||||
|         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<OrderbookResponse> { | ||||
|         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<OrderConfigResponse> { | ||||
|         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<FeeRecipientsResponse> { | ||||
|         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, | ||||
|   | ||||
| @@ -1,8 +0,0 @@ | ||||
| export const assetPairsRequestOptsSchema = { | ||||
|     id: '/AssetPairsRequestOpts', | ||||
|     type: 'object', | ||||
|     properties: { | ||||
|         assetDataA: { $ref: '/hexSchema' }, | ||||
|         assetDataB: { $ref: '/hexSchema' }, | ||||
|     }, | ||||
| }; | ||||
| @@ -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', | ||||
|     ], | ||||
| }; | ||||
| @@ -1,9 +0,0 @@ | ||||
| export const orderBookRequestSchema = { | ||||
|     id: '/OrderBookRequest', | ||||
|     type: 'object', | ||||
|     properties: { | ||||
|         baseAssetData: { $ref: '/hexSchema' }, | ||||
|         quoteAssetData: { $ref: '/hexSchema' }, | ||||
|     }, | ||||
|     required: ['baseAssetData', 'quoteAssetData'], | ||||
| }; | ||||
| @@ -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' }, | ||||
|     }, | ||||
| }; | ||||
| @@ -1,8 +0,0 @@ | ||||
| export const pagedRequestOptsSchema = { | ||||
|     id: '/PagedRequestOpts', | ||||
|     type: 'object', | ||||
|     properties: { | ||||
|         page: { type: 'number' }, | ||||
|         perPage: { type: 'number' }, | ||||
|     }, | ||||
| }; | ||||
| @@ -1,7 +0,0 @@ | ||||
| export const requestOptsSchema = { | ||||
|     id: '/RequestOpts', | ||||
|     type: 'object', | ||||
|     properties: { | ||||
|         networkId: { type: 'number' }, | ||||
|     }, | ||||
| }; | ||||
| @@ -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, | ||||
| }; | ||||
| @@ -1,4 +1,43 @@ | ||||
| [ | ||||
|     { | ||||
|         "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": [ | ||||
|             { | ||||
|                 "note": | ||||
|                     "Add signature validation, regular cancellation and `cancelledUpTo` checks to `validateOrderFillableOrThrowAsync`", | ||||
|                 "pr": 1235 | ||||
|             }, | ||||
|             { | ||||
|                 "note": | ||||
|                     "Improved the errors thrown by `validateOrderFillableOrThrowAsync` by making them more descriptive", | ||||
|                 "pr": 1235 | ||||
|             }, | ||||
|             { | ||||
|                 "note": | ||||
|                     "Throw previously swallowed network errors when calling `validateOrderFillableOrThrowAsync` (see issue: #1218)", | ||||
|                 "pr": 1235 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1542028948 | ||||
|     }, | ||||
|     { | ||||
|         "version": "3.0.1", | ||||
|         "changes": [ | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -18,6 +18,7 @@ import { OrderFilledCancelledFetcher } from '../fetchers/order_filled_cancelled_ | ||||
| import { methodOptsSchema } from '../schemas/method_opts_schema'; | ||||
| import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; | ||||
| import { txOptsSchema } from '../schemas/tx_opts_schema'; | ||||
| import { validateOrderFillableOptsSchema } from '../schemas/validate_order_fillable_opts_schema'; | ||||
| import { | ||||
|     BlockRange, | ||||
|     EventCallback, | ||||
| @@ -1114,6 +1115,9 @@ export class ExchangeWrapper extends ContractWrapper { | ||||
|         signedOrder: SignedOrder, | ||||
|         opts: ValidateOrderFillableOpts = {}, | ||||
|     ): Promise<void> { | ||||
|         assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); | ||||
|         assert.doesConformToSchema('opts', opts, validateOrderFillableOptsSchema); | ||||
|  | ||||
|         const balanceAllowanceFetcher = new AssetBalanceAndProxyAllowanceFetcher( | ||||
|             this._erc20TokenWrapper, | ||||
|             this._erc721TokenWrapper, | ||||
| @@ -1124,7 +1128,7 @@ export class ExchangeWrapper extends ContractWrapper { | ||||
|  | ||||
|         const expectedFillTakerTokenAmountIfExists = opts.expectedFillTakerTokenAmount; | ||||
|         const filledCancelledFetcher = new OrderFilledCancelledFetcher(this, BlockParamLiteral.Latest); | ||||
|         const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher); | ||||
|         const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher, this._web3Wrapper.getProvider()); | ||||
|         await orderValidationUtils.validateOrderFillableOrThrowAsync( | ||||
|             exchangeTradeSimulator, | ||||
|             signedOrder, | ||||
| @@ -1152,7 +1156,7 @@ export class ExchangeWrapper extends ContractWrapper { | ||||
|         const exchangeTradeSimulator = new ExchangeTransferSimulator(balanceAllowanceStore); | ||||
|  | ||||
|         const filledCancelledFetcher = new OrderFilledCancelledFetcher(this, BlockParamLiteral.Latest); | ||||
|         const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher); | ||||
|         const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher, this._web3Wrapper.getProvider()); | ||||
|         await orderValidationUtils.validateFillOrderThrowIfInvalidAsync( | ||||
|             exchangeTradeSimulator, | ||||
|             this._web3Wrapper.getProvider(), | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| // tslint:disable:no-unnecessary-type-assertion | ||||
| import { AbstractOrderFilledCancelledFetcher } from '@0x/order-utils'; | ||||
| import { AbstractOrderFilledCancelledFetcher, orderHashUtils } from '@0x/order-utils'; | ||||
| import { SignedOrder } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import { BlockParamLiteral } from 'ethereum-types'; | ||||
|  | ||||
| @@ -18,9 +19,18 @@ export class OrderFilledCancelledFetcher implements AbstractOrderFilledCancelled | ||||
|         }); | ||||
|         return filledTakerAmount; | ||||
|     } | ||||
|     public async isOrderCancelledAsync(orderHash: string): Promise<boolean> { | ||||
|     public async isOrderCancelledAsync(signedOrder: SignedOrder): Promise<boolean> { | ||||
|         const orderHash = orderHashUtils.getOrderHashHex(signedOrder); | ||||
|         const isCancelled = await this._exchange.isCancelledAsync(orderHash); | ||||
|         return isCancelled; | ||||
|         const orderEpoch = await this._exchange.getOrderEpochAsync( | ||||
|             signedOrder.makerAddress, | ||||
|             signedOrder.senderAddress, | ||||
|             { | ||||
|                 defaultBlock: this._stateLayer, | ||||
|             }, | ||||
|         ); | ||||
|         const isCancelledByOrderEpoch = orderEpoch > signedOrder.salt; | ||||
|         return isCancelled || isCancelledByOrderEpoch; | ||||
|     } | ||||
|     public getZRXAssetData(): string { | ||||
|         const zrxAssetData = this._exchange.getZRXAssetData(); | ||||
|   | ||||
| @@ -0,0 +1,7 @@ | ||||
| export const validateOrderFillableOptsSchema = { | ||||
|     id: '/ValidateOrderFillableOpts', | ||||
|     properties: { | ||||
|         expectedFillTakerTokenAmount: { $ref: '/wholeNumberSchema' }, | ||||
|     }, | ||||
|     type: 'object', | ||||
| }; | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils'; | ||||
| import { FillScenarios } from '@0x/fill-scenarios'; | ||||
| import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; | ||||
| import { DoneCallback, SignedOrder } from '@0x/types'; | ||||
| import { DoneCallback, RevertReason, SignedOrder } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import * as chai from 'chai'; | ||||
| import { BlockParamLiteral } from 'ethereum-types'; | ||||
| @@ -282,6 +282,19 @@ describe('ExchangeWrapper', () => { | ||||
|             expect(ordersInfo[1].orderHash).to.be.equal(anotherOrderHash); | ||||
|         }); | ||||
|     }); | ||||
|     describe('#validateOrderFillableOrThrowAsync', () => { | ||||
|         it('should throw if signature is invalid', async () => { | ||||
|             const signedOrderWithInvalidSignature = { | ||||
|                 ...signedOrder, | ||||
|                 signature: | ||||
|                     '0x1b61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403', | ||||
|             }; | ||||
|  | ||||
|             expect( | ||||
|                 contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrderWithInvalidSignature), | ||||
|             ).to.eventually.to.be.rejectedWith(RevertReason.InvalidOrderSignature); | ||||
|         }); | ||||
|     }); | ||||
|     describe('#isValidSignature', () => { | ||||
|         it('should check if the signature is valid', async () => { | ||||
|             const orderHash = orderHashUtils.getOrderHashHex(signedOrder); | ||||
|   | ||||
							
								
								
									
										115
									
								
								packages/contracts/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								packages/contracts/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | ||||
| [ | ||||
|     { | ||||
|         "name": "Forwarder", | ||||
|         "version": "1.1.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Round up when calculating remaining amounts in marketBuy functions", | ||||
|                 "pr": 1162, | ||||
|                 "networks": { | ||||
|                     "1": "0x5468a1dc173652ee28d249c271fa9933144746b1", | ||||
|                     "3": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e", | ||||
|                     "42": "0x17992e4ffb22730138e4b62aaa6367fa9d3699a6" | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "name": "Forwarder", | ||||
|         "version": "1.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "protocol v2 deploy", | ||||
|                 "networks": { | ||||
|                     "1": "0x7afc2d5107af94c462a194d2c21b5bdd238709d6", | ||||
|                     "3": "0x3983e204b12b3c02fb0638caf2cd406a62e0ead3", | ||||
|                     "42": "0xd85e2fa7e7e252b27b01bf0d65c946959d2f45b8" | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "name": "OrderValidator", | ||||
|         "version": "1.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "protocol v2 deploy", | ||||
|                 "networks": { | ||||
|                     "1": "0x9463e518dea6810309563c81d5266c1b1d149138", | ||||
|                     "3": "0x90431a90516ab49af23a0530e04e8c7836e7122f", | ||||
|                     "42": "0xb389da3d204b412df2f75c6afb3d0a7ce0bc283d" | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "name": "Exchange", | ||||
|         "version": "2.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "protocol v2 deploy", | ||||
|                 "networks": { | ||||
|                     "1": "0x4f833a24e1f95d70f028921e27040ca56e09ab0b", | ||||
|                     "3": "0x4530c0483a1633c7a1c97d2c53721caff2caaaaf", | ||||
|                     "42": "0x35dd2932454449b14cee11a94d3674a936d5d7b2" | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "name": "ERC20Proxy", | ||||
|         "version": "1.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "protocol v2 deploy", | ||||
|                 "networks": { | ||||
|                     "1": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e", | ||||
|                     "3": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa", | ||||
|                     "42": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e" | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "name": "ERC721Proxy", | ||||
|         "version": "1.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "protocol v2 deploy", | ||||
|                 "networks": { | ||||
|                     "1": "0x208e41fb445f1bb1b6780d58356e81405f3e6127", | ||||
|                     "3": "0xe654aac058bfbf9f83fcaee7793311dd82f6ddb4", | ||||
|                     "42": "0x2a9127c745688a165106c11cd4d647d2220af821" | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "name": "AssetProxyOwner", | ||||
|         "version": "1.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "protocol v2 deploy", | ||||
|                 "networks": { | ||||
|                     "1": "0x17992e4ffb22730138e4b62aaa6367fa9d3699a6", | ||||
|                     "3": "0xf5fa5b5fed2727a0e44ac67f6772e97977aa358b", | ||||
|                     "42": "0x2c824d2882baa668e0d5202b1e7f2922278703f8" | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "name": "ZRXToken", | ||||
|         "version": "1.0.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "protocol v1 deploy", | ||||
|                 "networks": { | ||||
|                     "1": "0xe41d2489571d322189246dafa5ebde1f4699f498", | ||||
|                     "3": "0xff67881f8d12f372d91baae9752eb3631ff0ed00", | ||||
|                     "42": "0x2002d3812f58e35f0ea1ffbf80a75a38c32175fa" | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
|     } | ||||
| ] | ||||
| @@ -1,6 +1,6 @@ | ||||
| ## Contracts | ||||
|  | ||||
| Smart contracts that implement the 0x protocol. Addresses of the deployed contracts can be found [here](https://0xproject.com/wiki#Deployed-Addresses). | ||||
| Smart contracts that implement the 0x protocol. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [CHANGELOG](./CHANGELOG.json) of this package. | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -212,13 +212,17 @@ export class ExchangeWrapper { | ||||
|         return tx; | ||||
|     } | ||||
|     public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> { | ||||
|         const filledAmount = new BigNumber(await this._exchange.filled.callAsync(orderHashHex)); | ||||
|         const filledAmount = await this._exchange.filled.callAsync(orderHashHex); | ||||
|         return filledAmount; | ||||
|     } | ||||
|     public async isCancelledAsync(orderHashHex: string): Promise<boolean> { | ||||
|         const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex); | ||||
|         return isCancelled; | ||||
|     } | ||||
|     public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> { | ||||
|         const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress); | ||||
|         return orderEpoch; | ||||
|     } | ||||
|     public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> { | ||||
|         const orderInfo = (await this._exchange.getOrderInfo.callAsync(signedOrder)) as OrderInfo; | ||||
|         return orderInfo; | ||||
|   | ||||
| @@ -392,7 +392,7 @@ export class FillOrderCombinatorialUtils { | ||||
|         ); | ||||
|  | ||||
|         // 5. If I fill it by X, what are the resulting balances/allowances/filled amounts expected? | ||||
|         const orderValidationUtils = new OrderValidationUtils(orderFilledCancelledFetcher); | ||||
|         const orderValidationUtils = new OrderValidationUtils(orderFilledCancelledFetcher, provider); | ||||
|         const lazyStore = new BalanceAndProxyAllowanceLazyStore(balanceAndProxyAllowanceFetcher); | ||||
|         const exchangeTransferSimulator = new ExchangeTransferSimulator(lazyStore); | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { AbstractOrderFilledCancelledFetcher } from '@0x/order-utils'; | ||||
| import { AbstractOrderFilledCancelledFetcher, orderHashUtils } from '@0x/order-utils'; | ||||
| import { SignedOrder } from '@0x/types'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
|  | ||||
| import { ExchangeWrapper } from './exchange_wrapper'; | ||||
| @@ -14,9 +15,15 @@ export class SimpleOrderFilledCancelledFetcher implements AbstractOrderFilledCan | ||||
|         const filledTakerAmount = new BigNumber(await this._exchangeWrapper.getTakerAssetFilledAmountAsync(orderHash)); | ||||
|         return filledTakerAmount; | ||||
|     } | ||||
|     public async isOrderCancelledAsync(orderHash: string): Promise<boolean> { | ||||
|     public async isOrderCancelledAsync(signedOrder: SignedOrder): Promise<boolean> { | ||||
|         const orderHash = orderHashUtils.getOrderHashHex(signedOrder); | ||||
|         const isCancelled = await this._exchangeWrapper.isCancelledAsync(orderHash); | ||||
|         return isCancelled; | ||||
|         const orderEpoch = await this._exchangeWrapper.getOrderEpochAsync( | ||||
|             signedOrder.makerAddress, | ||||
|             signedOrder.senderAddress, | ||||
|         ); | ||||
|         const isCancelledByOrderEpoch = orderEpoch > signedOrder.salt; | ||||
|         return isCancelled || isCancelledByOrderEpoch; | ||||
|     } | ||||
|     public getZRXAssetData(): string { | ||||
|         return this._zrxAssetData; | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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": [ | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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": [ | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/instant", | ||||
|     "version": "0.0.4", | ||||
|     "version": "0.0.7", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -45,15 +45,15 @@ | ||||
|     }, | ||||
|     "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", | ||||
|         "copy-to-clipboard": "^3.0.8", | ||||
|         "ethereum-types": "^1.1.2", | ||||
|         "lodash": "^4.17.10", | ||||
|   | ||||
| @@ -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<PositionAnimationSettings>; | ||||
|   | ||||
| @@ -43,7 +43,6 @@ export class BuyButton extends React.Component<BuyButtonProps> { | ||||
|                 onClick={this._handleClick} | ||||
|                 isDisabled={shouldDisableButton} | ||||
|                 fontColor={ColorOption.white} | ||||
|                 fontSize="20px" | ||||
|             > | ||||
|                 Buy | ||||
|             </Button> | ||||
|   | ||||
| @@ -12,7 +12,6 @@ export interface BuyOrderProgressProps { | ||||
|  | ||||
| export const BuyOrderProgress: React.StatelessComponent<BuyOrderProgressProps> = props => { | ||||
|     const { buyOrderState } = props; | ||||
|  | ||||
|     if ( | ||||
|         buyOrderState.processState === OrderProcessState.Processing || | ||||
|         buyOrderState.processState === OrderProcessState.Success || | ||||
| @@ -30,6 +29,5 @@ export const BuyOrderProgress: React.StatelessComponent<BuyOrderProgressProps> = | ||||
|             </Container> | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     return null; | ||||
| }; | ||||
|   | ||||
| @@ -35,7 +35,7 @@ export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonP | ||||
|     if (props.buyOrderProcessingState === OrderProcessState.Failure) { | ||||
|         return ( | ||||
|             <Flex justify="space-between"> | ||||
|                 <Button width="48%" onClick={props.onRetry} fontColor={ColorOption.white} fontSize="16px"> | ||||
|                 <Button width="48%" onClick={props.onRetry} fontColor={ColorOption.white}> | ||||
|                     Back | ||||
|                 </Button> | ||||
|                 <SecondaryButton width="48%" onClick={props.onViewTransaction}> | ||||
|   | ||||
| @@ -29,13 +29,18 @@ export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps> | ||||
|         const { tokens, onTokenSelect } = this.props; | ||||
|         return ( | ||||
|             <Container height="100%"> | ||||
|                 <Container marginBottom="10px"> | ||||
|                     <Text fontColor={ColorOption.darkGrey} fontSize="18px" fontWeight="600" lineHeight="22px"> | ||||
|                         Select Token | ||||
|                     </Text> | ||||
|                 </Container> | ||||
|                 <SearchInput | ||||
|                     placeholder="Search tokens..." | ||||
|                     width="100%" | ||||
|                     value={this.state.searchQuery} | ||||
|                     onChange={this._handleSearchInputChange} | ||||
|                 /> | ||||
|                 <Container overflow="scroll" height="calc(100% - 80px)" marginTop="10px"> | ||||
|                 <Container overflow="scroll" height="calc(100% - 90px)" marginTop="10px"> | ||||
|                     {_.map(tokens, token => { | ||||
|                         if (!this._isTokenQueryMatch(token)) { | ||||
|                             return null; | ||||
|   | ||||
| @@ -0,0 +1,32 @@ | ||||
| import * as React from 'react'; | ||||
|  | ||||
| import { META_MASK_CHROME_STORE_URL, META_MASK_SITE_URL } from '../constants'; | ||||
| import { ColorOption } from '../style/theme'; | ||||
|  | ||||
| import { MetaMaskLogo } from './meta_mask_logo'; | ||||
| import { StandardPanelContent } from './standard_panel_content'; | ||||
| import { Button } from './ui/button'; | ||||
|  | ||||
| export interface InstallWalletPanelContentProps {} | ||||
|  | ||||
| export const InstallWalletPanelContent: React.StatelessComponent<InstallWalletPanelContentProps> = () => ( | ||||
|     <StandardPanelContent | ||||
|         image={<MetaMaskLogo width={85} height={80} />} | ||||
|         title="Install MetaMask" | ||||
|         description="Please install the MetaMask wallet extension from the Chrome Store." | ||||
|         moreInfoSettings={{ | ||||
|             href: META_MASK_SITE_URL, | ||||
|             text: 'What is MetaMask?', | ||||
|         }} | ||||
|         action={ | ||||
|             <Button | ||||
|                 href={META_MASK_CHROME_STORE_URL} | ||||
|                 width="100%" | ||||
|                 fontColor={ColorOption.white} | ||||
|                 backgroundColor={ColorOption.darkOrange} | ||||
|             > | ||||
|                 Get Chrome Extension | ||||
|             </Button> | ||||
|         } | ||||
|     /> | ||||
| ); | ||||
| @@ -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; | ||||
| @@ -104,7 +104,7 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> { | ||||
|         if (this.props.quoteRequestState === AsyncProcessState.Pending) { | ||||
|             return <AmountPlaceholder isPulsating={true} color={PLACEHOLDER_COLOR} />; | ||||
|         } | ||||
|         if (_.isUndefined(this.props.selectedAssetAmount)) { | ||||
|         if (_.isUndefined(this.props.selectedAssetUnitAmount)) { | ||||
|             return <AmountPlaceholder isPulsating={false} color={PLACEHOLDER_COLOR} />; | ||||
|         } | ||||
|         return amountFunction(); | ||||
| @@ -113,8 +113,8 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> { | ||||
|     private readonly _renderEthAmount = (): React.ReactNode => { | ||||
|         return ( | ||||
|             <Text fontSize="16px" fontColor={ColorOption.white} fontWeight={500}> | ||||
|                 {format.ethBaseAmount( | ||||
|                     this.props.totalEthBaseAmount, | ||||
|                 {format.ethBaseUnitAmount( | ||||
|                     this.props.totalEthBaseUnitAmount, | ||||
|                     4, | ||||
|                     <AmountPlaceholder isPulsating={false} color={PLACEHOLDER_COLOR} />, | ||||
|                 )} | ||||
| @@ -125,8 +125,8 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> { | ||||
|     private readonly _renderDollarAmount = (): React.ReactNode => { | ||||
|         return ( | ||||
|             <Text fontSize="16px" fontColor={ColorOption.white}> | ||||
|                 {format.ethBaseAmountInUsd( | ||||
|                     this.props.totalEthBaseAmount, | ||||
|                 {format.ethBaseUnitAmountInUsd( | ||||
|                     this.props.totalEthBaseUnitAmount, | ||||
|                     this.props.ethUsdPrice, | ||||
|                     2, | ||||
|                     <AmountPlaceholder isPulsating={false} color={ColorOption.white} />, | ||||
|   | ||||
							
								
								
									
										78
									
								
								packages/instant/src/components/meta_mask_logo.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								packages/instant/src/components/meta_mask_logo.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| import * as React from 'react'; | ||||
|  | ||||
| export interface MetaMaskLogoProps { | ||||
|     width?: number; | ||||
|     height?: number; | ||||
| } | ||||
|  | ||||
| export const MetaMaskLogo: React.StatelessComponent<MetaMaskLogoProps> = ({ width, height }) => ( | ||||
|     <svg width={width} height={height} viewBox="0 0 85 80" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||||
|         <path d="M80.578 0L47.7107 24.8648L53.542 10.2702L80.578 0Z" fill="#E2761B" /> | ||||
|         <path d="M4.24075 0L37.1081 25.4053L31.2768 10.2702L4.24075 0Z" fill="#E4761B" /> | ||||
|         <path d="M68.9152 57.8379L59.9032 71.8919L78.9874 77.2973L84.2886 58.3785L68.9152 57.8379Z" fill="#E4761B" /> | ||||
|         <path d="M0.53006 58.3785L5.83124 77.2973L24.9155 71.8919L15.9035 57.8379L0.53006 58.3785Z" fill="#E4761B" /> | ||||
|         <path d="M23.8552 34.5941L18.554 42.7022L37.1082 43.7833L36.5781 23.2428L23.8552 34.5941Z" fill="#E4761B" /> | ||||
|         <path d="M60.9635 34.5941L47.7106 23.2428V43.7833L66.2647 42.7022L60.9635 34.5941Z" fill="#E4761B" /> | ||||
|         <path d="M24.9156 71.8914L36.0481 66.4861L26.5059 58.378L24.9156 71.8914Z" fill="#E4761B" /> | ||||
|         <path d="M48.7709 66.4861L59.9034 71.8914L58.313 58.378L48.7709 66.4861Z" fill="#E4761B" /> | ||||
|         <path d="M59.9034 71.8919L48.7709 66.4865L49.301 73.5135V76.7567L59.9034 71.8919Z" fill="#D7C1B3" /> | ||||
|         <path d="M24.9157 71.892L35.518 76.7568V73.5136L36.0482 66.4866L24.9157 71.892Z" fill="#D7C1B3" /> | ||||
|         <path d="M35.5179 53.5138L25.9758 50.8111L32.8673 47.5678L35.5179 53.5138Z" fill="#233447" /> | ||||
|         <path d="M49.3009 53.5138L51.9515 47.5678L58.843 50.8111L49.3009 53.5138Z" fill="#233447" /> | ||||
|         <path d="M24.9155 71.892L26.5059 57.838L15.9035 58.3785L24.9155 71.892Z" fill="#CD6116" /> | ||||
|         <path d="M58.313 57.838L59.9034 71.892L68.9154 58.3785L58.313 57.838Z" fill="#CD6116" /> | ||||
|         <path | ||||
|             d="M66.2648 42.7025L47.7106 43.7836L49.301 53.5132L51.9516 47.5673L58.8431 50.8106L66.2648 42.7025Z" | ||||
|             fill="#CD6116" | ||||
|         /> | ||||
|         <path | ||||
|             d="M25.9758 50.8106L32.8673 47.5673L35.5179 53.5132L37.1083 43.7836L18.5541 42.7025L25.9758 50.8106Z" | ||||
|             fill="#CD6116" | ||||
|         /> | ||||
|         <path d="M18.5541 42.7024L26.5059 58.378L25.9758 50.8105L18.5541 42.7024Z" fill="#E4751F" /> | ||||
|         <path d="M58.8431 50.8106L58.313 58.3781L66.2647 42.7025L58.8431 50.8106Z" fill="#E4751F" /> | ||||
|         <path d="M37.1083 43.7838L35.518 53.5135L37.6384 65.4053L38.1686 49.7297L37.1083 43.7838Z" fill="#E4751F" /> | ||||
|         <path d="M47.7105 43.7838L46.6503 49.7297L47.1804 65.4053L49.3009 53.5135L47.7105 43.7838Z" fill="#E4751F" /> | ||||
|         <path | ||||
|             d="M49.301 53.5134L47.1805 65.4052L48.7709 66.4863L58.313 58.3782L58.8431 50.8107L49.301 53.5134Z" | ||||
|             fill="#F6851B" | ||||
|         /> | ||||
|         <path | ||||
|             d="M25.9758 50.8107L26.5059 58.3782L36.048 66.4863L37.6384 65.4052L35.5179 53.5134L25.9758 50.8107Z" | ||||
|             fill="#F6851B" | ||||
|         /> | ||||
|         <path | ||||
|             d="M49.3011 76.7568V73.5135L48.771 72.973H36.0482L35.518 73.5135V76.7568L24.9157 71.8919L28.6265 75.1351L36.0482 80H48.771L56.1927 75.1351L59.9035 71.8919L49.3011 76.7568Z" | ||||
|             fill="#C0AD9E" | ||||
|         /> | ||||
|         <path | ||||
|             d="M48.771 66.486L47.1806 65.405H37.6385L36.0482 66.486L35.518 73.513L36.0482 72.9725H48.771L49.3011 73.513L48.771 66.486Z" | ||||
|             fill="#161616" | ||||
|         /> | ||||
|         <path | ||||
|             d="M82.1685 26.4864L84.8191 12.9729L80.5781 0L48.771 24.3242L60.9637 34.5945L78.4576 39.9998L82.1685 35.6755L80.5781 34.0539L83.2287 31.8918L81.1082 30.2702L83.7588 28.108L82.1685 26.4864Z" | ||||
|             fill="#763D16" | ||||
|         /> | ||||
|         <path | ||||
|             d="M0 12.9729L2.65059 26.4864L1.06024 28.108L3.71083 30.2702L1.59036 31.8918L4.24095 34.0539L2.65059 35.6755L6.36142 39.9998L23.8553 34.5945L36.0481 24.3242L4.24095 0L0 12.9729Z" | ||||
|             fill="#763D16" | ||||
|         /> | ||||
|         <path | ||||
|             d="M78.4575 39.9993L60.9636 34.5939L66.2648 42.702L58.313 58.3776H68.9154H84.2888L78.4575 39.9993Z" | ||||
|             fill="#F6851B" | ||||
|         /> | ||||
|         <path | ||||
|             d="M23.8554 34.5939L6.36147 39.9993L0.530167 58.3776H15.9036H26.506L18.5542 42.702L23.8554 34.5939Z" | ||||
|             fill="#F6851B" | ||||
|         /> | ||||
|         <path | ||||
|             d="M47.7106 43.7833L48.7709 24.3239L53.5419 10.2699H31.2769L36.048 24.3239L37.1083 43.7833L37.6384 49.7292V65.4048H47.1805V49.7292L47.7106 43.7833Z" | ||||
|             fill="#F6851B" | ||||
|         /> | ||||
|     </svg> | ||||
| ); | ||||
|  | ||||
| MetaMaskLogo.defaultProps = { | ||||
|     width: 85, | ||||
|     height: 80, | ||||
| }; | ||||
| @@ -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<OrderDetailsProps> { | ||||
|     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 ( | ||||
|             <Container padding="20px" width="100%" flexGrow={1}> | ||||
|                 <Container marginBottom="10px"> | ||||
| @@ -40,20 +48,19 @@ export class OrderDetails extends React.Component<OrderDetailsProps> { | ||||
|                 </Container> | ||||
|                 <EthAmountRow | ||||
|                     rowLabel="Token Price" | ||||
|                     ethAmount={ethAssetPrice} | ||||
|                     ethAmount={pricePerTokenEth} | ||||
|                     ethUsdPrice={ethUsdPrice} | ||||
|                     isEthAmountInBaseUnits={false} | ||||
|                     isLoading={this.props.isLoading} | ||||
|                 /> | ||||
|                 <EthAmountRow | ||||
|                     rowLabel="Fee" | ||||
|                     ethAmount={ethTokenFee} | ||||
|                     ethAmount={feeEthBaseUnitAmount} | ||||
|                     ethUsdPrice={ethUsdPrice} | ||||
|                     isLoading={this.props.isLoading} | ||||
|                 /> | ||||
|                 <EthAmountRow | ||||
|                     rowLabel="Total Cost" | ||||
|                     ethAmount={totalEthAmount} | ||||
|                     ethAmount={totalEthBaseUnitAmount} | ||||
|                     ethUsdPrice={ethUsdPrice} | ||||
|                     shouldEmphasize={true} | ||||
|                     isLoading={this.props.isLoading} | ||||
| @@ -81,7 +88,7 @@ export class EthAmountRow extends React.Component<EthAmountRowProps> { | ||||
|         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 ( | ||||
|             <Container padding="10px 0px" borderTop="1px dashed" borderColor={ColorOption.feintGrey}> | ||||
|                 <Flex justify="space-between"> | ||||
| @@ -105,7 +112,9 @@ export class EthAmountRow extends React.Component<EthAmountRowProps> { | ||||
|         ); | ||||
|     } | ||||
|     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 : ( | ||||
|             <Container marginRight="3px" display="inline-block"> | ||||
|   | ||||
| @@ -1,45 +1,132 @@ | ||||
| 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 { 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'; | ||||
|  | ||||
| export interface PaymentMethodProps {} | ||||
| export interface PaymentMethodProps { | ||||
|     account: Account; | ||||
|     network: Network; | ||||
|     onInstallWalletClick: () => void; | ||||
|     onUnlockWalletClick: () => void; | ||||
| } | ||||
|  | ||||
| export const PaymentMethod: React.StatelessComponent<PaymentMethodProps> = () => ( | ||||
|     <Container padding="20px" width="100%"> | ||||
|         <Container marginBottom="10px"> | ||||
|             <Flex justify="space-between"> | ||||
|                 <Text | ||||
|                     letterSpacing="1px" | ||||
|                     fontColor={ColorOption.primaryColor} | ||||
|                     fontWeight={600} | ||||
|                     textTransform="uppercase" | ||||
|                     fontSize="14px" | ||||
|                 > | ||||
|                     Payment Method | ||||
|                 </Text> | ||||
|                 <Flex> | ||||
|                     <Circle color={ColorOption.green} diameter={8} /> | ||||
| export class PaymentMethod extends React.Component<PaymentMethodProps> { | ||||
|     public render(): React.ReactNode { | ||||
|         return ( | ||||
|             <Container padding="20px" width="100%"> | ||||
|                 <Container marginBottom="12px"> | ||||
|                     <Flex justify="space-between"> | ||||
|                         <Text | ||||
|                             letterSpacing="1px" | ||||
|                             fontColor={ColorOption.primaryColor} | ||||
|                             fontWeight={600} | ||||
|                             textTransform="uppercase" | ||||
|                             fontSize="14px" | ||||
|                         > | ||||
|                             {this._renderTitleText()} | ||||
|                         </Text> | ||||
|                         <Flex>{this._renderTitleLabel()}</Flex> | ||||
|                     </Flex> | ||||
|                 </Container> | ||||
|                 {this._renderMainContent()} | ||||
|             </Container> | ||||
|         ); | ||||
|     } | ||||
|     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 ( | ||||
|                 <React.Fragment> | ||||
|                     <Circle diameter={8} color={circleColor} /> | ||||
|                     <Container marginLeft="3px"> | ||||
|                         <Text fontColor={ColorOption.darkGrey} fontSize="12px"> | ||||
|                             MetaMask | ||||
|                         </Text> | ||||
|                     </Container> | ||||
|                 </Flex> | ||||
|             </Flex> | ||||
|         </Container> | ||||
|         <PaymentMethodDropdown | ||||
|             accountAddress="0xa1b2c3d4e5f6g7h8j9k10" | ||||
|             accountEthBalanceInWei={new BigNumber(10500000000000000000)} | ||||
|             network={Network.Mainnet} | ||||
|         /> | ||||
|                 </React.Fragment> | ||||
|             ); | ||||
|         } | ||||
|         return null; | ||||
|     }; | ||||
|     private readonly _renderMainContent = (): React.ReactNode => { | ||||
|         const { account, network } = this.props; | ||||
|         switch (account.state) { | ||||
|             case AccountState.Loading: | ||||
|                 // Just take up the same amount of space as the other states. | ||||
|                 return <Container height="52px" />; | ||||
|             case AccountState.Locked: | ||||
|                 return ( | ||||
|                     <WalletPrompt | ||||
|                         onClick={this.props.onUnlockWalletClick} | ||||
|                         image={<Icon width={13} icon="lock" color={ColorOption.black} />} | ||||
|                     > | ||||
|                         Please Unlock MetaMask | ||||
|                     </WalletPrompt> | ||||
|                 ); | ||||
|             case AccountState.None: | ||||
|                 return ( | ||||
|                     <WalletPrompt | ||||
|                         onClick={this.props.onInstallWalletClick} | ||||
|                         image={<MetaMaskLogo width={19} height={18} />} | ||||
|                     > | ||||
|                         Install MetaMask | ||||
|                     </WalletPrompt> | ||||
|                 ); | ||||
|             case AccountState.Ready: | ||||
|                 return ( | ||||
|                     <PaymentMethodDropdown | ||||
|                         accountAddress={account.address} | ||||
|                         accountEthBalanceInWei={account.ethBalanceInWei} | ||||
|                         network={network} | ||||
|                     /> | ||||
|                 ); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| interface WalletPromptProps { | ||||
|     image: React.ReactNode; | ||||
|     onClick?: () => void; | ||||
| } | ||||
|  | ||||
| const WalletPrompt: React.StatelessComponent<WalletPromptProps> = ({ onClick, image, children }) => ( | ||||
|     <Container | ||||
|         padding="14.5px" | ||||
|         border={`1px solid ${ColorOption.darkOrange}`} | ||||
|         backgroundColor={ColorOption.lightOrange} | ||||
|         width="100%" | ||||
|         borderRadius="4px" | ||||
|         onClick={onClick} | ||||
|         cursor={onClick ? 'pointer' : undefined} | ||||
|         boxShadowOnHover={!!onClick} | ||||
|     > | ||||
|         <Flex> | ||||
|             <Container marginRight="10px">{image}</Container> | ||||
|             <Text fontSize="16px" fontColor={ColorOption.darkOrange}> | ||||
|                 {children} | ||||
|             </Text> | ||||
|         </Flex> | ||||
|     </Container> | ||||
| ); | ||||
|   | ||||
| @@ -18,7 +18,7 @@ export class PaymentMethodDropdown extends React.Component<PaymentMethodDropdown | ||||
|     public render(): React.ReactNode { | ||||
|         const { accountAddress, accountEthBalanceInWei } = this.props; | ||||
|         const value = format.ethAddress(accountAddress); | ||||
|         const label = format.ethBaseAmount(accountEthBalanceInWei, 4, '') as string; | ||||
|         const label = format.ethBaseUnitAmount(accountEthBalanceInWei, 4, '') as string; | ||||
|         return <Dropdown value={value} label={label} items={this._getDropdownItemConfigs()} />; | ||||
|     } | ||||
|     private readonly _getDropdownItemConfigs = (): DropdownItemConfig[] => { | ||||
|   | ||||
| @@ -7,9 +7,9 @@ import { Container } from './ui/container'; | ||||
| import { Spinner } from './ui/spinner'; | ||||
|  | ||||
| export const PlacingOrderButton: React.StatelessComponent<{}> = props => ( | ||||
|     <Button isDisabled={true} width="100%" fontColor={ColorOption.white} fontSize="20px"> | ||||
|     <Button isDisabled={true} width="100%" fontColor={ColorOption.white}> | ||||
|         <Container display="inline-block" position="relative" top="3px" marginRight="8px"> | ||||
|             <Spinner widthPx={20} heightPx={20} /> | ||||
|             <Spinner widthPx={16} heightPx={16} /> | ||||
|         </Container> | ||||
|         Placing Order… | ||||
|     </Button> | ||||
|   | ||||
| @@ -156,8 +156,6 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu | ||||
|                     return `${width}px`; | ||||
|                 } | ||||
|                 return `${textLengthThreshold}ch`; | ||||
|             default: | ||||
|                 return '1ch'; | ||||
|         } | ||||
|     }; | ||||
|     private readonly _calculateFontSize = (phase: ScalingInputPhase): number => { | ||||
|   | ||||
| @@ -15,8 +15,6 @@ export const SecondaryButton: React.StatelessComponent<SecondaryButtonProps> = p | ||||
|             borderColor={ColorOption.lightGrey} | ||||
|             width={props.width} | ||||
|             onClick={props.onClick} | ||||
|             fontColor={ColorOption.primaryColor} | ||||
|             fontSize="16px" | ||||
|             {...buttonProps} | ||||
|         > | ||||
|             {props.children} | ||||
|   | ||||
| @@ -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'; | ||||
|   | ||||
| @@ -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<PanelProps> = ({ title, children, onClose }) => ( | ||||
| export const Panel: React.StatelessComponent<PanelProps> = ({ children, onClose }) => ( | ||||
|     <Container backgroundColor={ColorOption.white} width="100%" height="100%" zIndex={zIndex.panel} padding="20px"> | ||||
|         <Flex justify="space-between"> | ||||
|             {title && ( | ||||
|                 <Container marginTop="3px"> | ||||
|                     <Text fontColor={ColorOption.darkGrey} fontSize="18px" fontWeight="600" lineHeight="22px"> | ||||
|                         {title} | ||||
|                     </Text> | ||||
|                 </Container> | ||||
|             )} | ||||
|             <Container position="relative" bottom="7px"> | ||||
|                 <Icon width={12} color={ColorOption.lightGrey} icon="closeX" onClick={onClose} /> | ||||
|             </Container> | ||||
|         <Flex justify="flex-end"> | ||||
|             <Icon padding="5px" width={12} color={ColorOption.lightGrey} icon="closeX" onClick={onClose} /> | ||||
|         </Flex> | ||||
|         <Container marginTop="10px" height="100%"> | ||||
|         <Container position="relative" top="-10px" height="100%"> | ||||
|             {children} | ||||
|         </Container> | ||||
|     </Container> | ||||
|   | ||||
							
								
								
									
										60
									
								
								packages/instant/src/components/standard_panel_content.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								packages/instant/src/components/standard_panel_content.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| 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<StandardPanelContentProps> = ({ | ||||
|     image, | ||||
|     title, | ||||
|     description, | ||||
|     moreInfoSettings, | ||||
|     action, | ||||
| }) => ( | ||||
|     <Container height="100%"> | ||||
|         <Flex direction="column" height="calc(100% - 58px)"> | ||||
|             <Container marginBottom={SPACING_BETWEEN_PX}>{image}</Container> | ||||
|             <Container marginBottom={SPACING_BETWEEN_PX}> | ||||
|                 <Text fontSize="20px" fontWeight={700} fontColor={ColorOption.black}> | ||||
|                     {title} | ||||
|                 </Text> | ||||
|             </Container> | ||||
|             <Container marginBottom={SPACING_BETWEEN_PX}> | ||||
|                 <Text fontSize="14px" fontColor={ColorOption.grey} center={true}> | ||||
|                     {description} | ||||
|                 </Text> | ||||
|             </Container> | ||||
|             <Container marginBottom={SPACING_BETWEEN_PX}> | ||||
|                 {moreInfoSettings && ( | ||||
|                     <Text | ||||
|                         center={true} | ||||
|                         fontSize="13px" | ||||
|                         textDecorationLine="underline" | ||||
|                         fontColor={ColorOption.lightGrey} | ||||
|                         href={moreInfoSettings.href} | ||||
|                     > | ||||
|                         {moreInfoSettings.text} | ||||
|                     </Text> | ||||
|                 )} | ||||
|             </Container> | ||||
|         </Flex> | ||||
|         <Container>{action}</Container> | ||||
|     </Container> | ||||
| ); | ||||
							
								
								
									
										29
									
								
								packages/instant/src/components/standard_sliding_panel.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								packages/instant/src/components/standard_sliding_panel.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -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<StandardSlidingPanelProps> { | ||||
|     public render(): React.ReactNode { | ||||
|         const { animationState, content, onClose } = this.props; | ||||
|         return ( | ||||
|             <SlidingPanel animationState={animationState} onClose={onClose}> | ||||
|                 {this._getNodeForContent(content)} | ||||
|             </SlidingPanel> | ||||
|         ); | ||||
|     } | ||||
|     private readonly _getNodeForContent = (content: StandardSlidingPanelContent): React.ReactNode => { | ||||
|         switch (content) { | ||||
|             case StandardSlidingPanelContent.InstallWallet: | ||||
|                 return <InstallWalletPanelContent />; | ||||
|             case StandardSlidingPanelContent.None: | ||||
|                 return null; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| @@ -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<TimedProgressBarProps, {}> | ||||
|     private readonly _barRef = React.createRef<HTMLDivElement>(); | ||||
|  | ||||
|     public render(): React.ReactNode { | ||||
|         const timedProgressProps = this._calculateTimedProgressProps(); | ||||
|         return ( | ||||
|             <Container width="100%" backgroundColor={ColorOption.lightGrey} borderRadius="6px"> | ||||
|                 <TimedProgress {...timedProgressProps} ref={this._barRef as any} /> | ||||
|             </Container> | ||||
|         ); | ||||
|         const widthAnimationSettings = this._calculateWidthAnimationSettings(); | ||||
|         return <ProgressBar animationSettings={widthAnimationSettings} ref={this._barRef} />; | ||||
|     } | ||||
|  | ||||
|     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<ProgressBarProps & React.ClassAttributes<{}>> = React.forwardRef( | ||||
|     (props, ref) => ( | ||||
|         <Container width="100%" backgroundColor={ColorOption.lightGrey} borderRadius="6px"> | ||||
|             <Progress {...props} ref={ref as any} /> | ||||
|         </Container> | ||||
|     ), | ||||
| ); | ||||
|   | ||||
| @@ -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<HTMLElement>) => void; | ||||
|  | ||||
| export interface ButtonProps { | ||||
|     backgroundColor?: ColorOption; | ||||
| @@ -12,15 +15,26 @@ export interface ButtonProps { | ||||
|     padding?: string; | ||||
|     type?: string; | ||||
|     isDisabled?: boolean; | ||||
|     onClick?: (event: React.MouseEvent<HTMLElement>) => void; | ||||
|     href?: string; | ||||
|     onClick?: ButtonOnClickHandler; | ||||
|     className?: string; | ||||
| } | ||||
|  | ||||
| const PlainButton: React.StatelessComponent<ButtonProps> = ({ children, isDisabled, onClick, type, className }) => ( | ||||
|     <button type={type} className={className} onClick={isDisabled ? undefined : onClick} disabled={isDisabled}> | ||||
|         {children} | ||||
|     </button> | ||||
| ); | ||||
| const PlainButton: React.StatelessComponent<ButtonProps> = ({ | ||||
|     children, | ||||
|     isDisabled, | ||||
|     onClick, | ||||
|     href, | ||||
|     type, | ||||
|     className, | ||||
| }) => { | ||||
|     const computedOnClick = isDisabled ? undefined : href ? util.createOpenUrlInNewWindow(href) : onClick; | ||||
|     return ( | ||||
|         <button type={type} className={className} onClick={computedOnClick} disabled={isDisabled}> | ||||
|             {children} | ||||
|         </button> | ||||
|     ); | ||||
| }; | ||||
|  | ||||
| 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'; | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -1,11 +1,15 @@ | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { overlayBlack, styled } from '../../style/theme'; | ||||
| import { generateMediaWrapper, ScreenWidths } from '../../style/media'; | ||||
| import { generateOverlayBlack, styled } from '../../style/theme'; | ||||
| import { zIndex } from '../../style/z_index'; | ||||
|  | ||||
| export interface OverlayProps { | ||||
|     zIndex?: number; | ||||
|     backgroundColor?: string; | ||||
|     width?: string; | ||||
|     height?: string; | ||||
|     showMaxWidth?: ScreenWidths; | ||||
| } | ||||
|  | ||||
| export const Overlay = | ||||
| @@ -20,12 +24,16 @@ export const Overlay = | ||||
|         left: 0; | ||||
|         z-index: ${props => props.zIndex} | ||||
|         background-color: ${props => props.backgroundColor}; | ||||
|         ${props => props.width && `width: ${props.width};`} | ||||
|         ${props => props.height && `height: ${props.height};`} | ||||
|         display: ${props => (props.showMaxWidth ? 'none' : 'block')}; | ||||
|         ${props => props.showMaxWidth && generateMediaWrapper(props.showMaxWidth)`display: block;`} | ||||
|     } | ||||
| `; | ||||
|  | ||||
| Overlay.defaultProps = { | ||||
|     zIndex: zIndex.overlayDefault, | ||||
|     backgroundColor: overlayBlack, | ||||
|     backgroundColor: generateOverlayBlack(0.6), | ||||
| }; | ||||
|  | ||||
| Overlay.displayName = 'Overlay'; | ||||
|   | ||||
| @@ -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<HTMLElement>) => void; | ||||
|     noWrap?: boolean; | ||||
|     display?: string; | ||||
|     href?: string; | ||||
| } | ||||
|  | ||||
| export const Text: React.StatelessComponent<TextProps> = ({ href, onClick, ...rest }) => { | ||||
|     const computedOnClick = href ? util.createOpenUrlInNewWindow(href) : onClick; | ||||
|     return <StyledText {...rest} onClick={computedOnClick} />; | ||||
| }; | ||||
|  | ||||
| const darkenOnHoverAmount = 0.3; | ||||
| export const Text = | ||||
| export const StyledText = | ||||
|     styled.div < | ||||
|     TextProps > | ||||
|     ` | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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<ZeroExInstantContainerProps, ZeroExInstantContainerState> { | ||||
| export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantContainerState> { | ||||
|     public state = { | ||||
|         tokenSelectionPanelAnimationState: 'none' as SlideAnimationState, | ||||
|     }; | ||||
| @@ -47,19 +50,19 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain | ||||
|                     > | ||||
|                         <Flex direction="column" justify="flex-start" height="100%"> | ||||
|                             <SelectedAssetInstantHeading onSelectAssetClick={this._handleSymbolClick} /> | ||||
|                             <SelectedAssetBuyOrderProgress /> | ||||
|                             <ConnectedBuyOrderProgressOrPaymentMethod /> | ||||
|                             <LatestBuyQuoteOrderDetails /> | ||||
|                             <Container padding="20px" width="100%"> | ||||
|                                 <SelectedAssetBuyOrderStateButtons /> | ||||
|                             </Container> | ||||
|                         </Flex> | ||||
|                         <SlidingPanel | ||||
|                             title="Select Token" | ||||
|                             animationState={this.state.tokenSelectionPanelAnimationState} | ||||
|                             onClose={this._handlePanelClose} | ||||
|                         > | ||||
|                             <AvailableERC20TokenSelector onTokenSelect={this._handlePanelClose} /> | ||||
|                         </SlidingPanel> | ||||
|                         <CurrentStandardSlidingPanel /> | ||||
|                     </Container> | ||||
|                 </Container> | ||||
|             </React.Fragment> | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -5,15 +5,18 @@ import * as _ from 'lodash'; | ||||
| import * as React from 'react'; | ||||
| import { Provider as ReduxProvider } from 'react-redux'; | ||||
|  | ||||
| import { ACCOUNT_UPDATE_INTERVAL_TIME_MS, BUY_QUOTE_UPDATE_INTERVAL_TIME_MS } from '../constants'; | ||||
| import { SelectedAssetThemeProvider } from '../containers/selected_asset_theme_provider'; | ||||
| import { asyncData } from '../redux/async_data'; | ||||
| import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer'; | ||||
| import { store, Store } from '../redux/store'; | ||||
| import { fonts } from '../style/fonts'; | ||||
| import { AffiliateInfo, AssetMetaData, Network, OrderSource } from '../types'; | ||||
| import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource } from '../types'; | ||||
| import { assetUtils } from '../util/asset'; | ||||
| import { errorFlasher } from '../util/error_flasher'; | ||||
| import { gasPriceEstimator } from '../util/gas_price_estimator'; | ||||
| import { Heartbeater } from '../util/heartbeater'; | ||||
| import { generateAccountHeartbeater, generateBuyQuoteHeartbeater } from '../util/heartbeater_factory'; | ||||
| import { providerStateFactory } from '../util/provider_state_factory'; | ||||
|  | ||||
| fonts.include(); | ||||
| @@ -37,6 +40,9 @@ export interface ZeroExInstantProviderOptionalProps { | ||||
|  | ||||
| export class ZeroExInstantProvider extends React.Component<ZeroExInstantProviderProps> { | ||||
|     private readonly _store: Store; | ||||
|     private _accountUpdateHeartbeat?: Heartbeater; | ||||
|     private _buyQuoteHeartbeat?: Heartbeater; | ||||
|  | ||||
|     // TODO(fragosti): Write tests for this beast once we inject a provider. | ||||
|     private static _mergeDefaultStateWithProps( | ||||
|         props: ZeroExInstantProviderProps, | ||||
| @@ -67,7 +73,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider | ||||
|                       completeAssetMetaDataMap, | ||||
|                       networkId, | ||||
|                   ), | ||||
|             selectedAssetAmount: _.isUndefined(props.defaultAssetBuyAmount) | ||||
|             selectedAssetUnitAmount: _.isUndefined(props.defaultAssetBuyAmount) | ||||
|                 ? undefined | ||||
|                 : new BigNumber(props.defaultAssetBuyAmount), | ||||
|             availableAssets: _.isUndefined(props.availableAssetDatas) | ||||
| @@ -85,17 +91,29 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider | ||||
|     } | ||||
|     public componentDidMount(): void { | ||||
|         const state = this._store.getState(); | ||||
|         const dispatch = this._store.dispatch; | ||||
|         // tslint:disable-next-line:no-floating-promises | ||||
|         asyncData.fetchEthPriceAndDispatchToStore(this._store); | ||||
|         asyncData.fetchEthPriceAndDispatchToStore(dispatch); | ||||
|         // fetch available assets if none are specified | ||||
|         if (_.isUndefined(state.availableAssets)) { | ||||
|             // tslint:disable-next-line:no-floating-promises | ||||
|             asyncData.fetchAvailableAssetDatasAndDispatchToStore(this._store); | ||||
|             asyncData.fetchAvailableAssetDatasAndDispatchToStore(state, dispatch); | ||||
|         } | ||||
|         if (state.providerState.account.state !== AccountState.None) { | ||||
|             this._accountUpdateHeartbeat = generateAccountHeartbeater({ | ||||
|                 store: this._store, | ||||
|                 shouldPerformImmediatelyOnStart: true, | ||||
|             }); | ||||
|             this._accountUpdateHeartbeat.start(ACCOUNT_UPDATE_INTERVAL_TIME_MS); | ||||
|         } | ||||
|  | ||||
|         this._buyQuoteHeartbeat = generateBuyQuoteHeartbeater({ | ||||
|             store: this._store, | ||||
|             shouldPerformImmediatelyOnStart: false, | ||||
|         }); | ||||
|         this._buyQuoteHeartbeat.start(BUY_QUOTE_UPDATE_INTERVAL_TIME_MS); | ||||
|         // tslint:disable-next-line:no-floating-promises | ||||
|         asyncData.fetchAccountInfoAndDispatchToStore(this._store); | ||||
|         // tslint:disable-next-line:no-floating-promises | ||||
|         asyncData.fetchCurrentBuyQuoteAndDispatchToStore(this._store); | ||||
|         asyncData.fetchCurrentBuyQuoteAndDispatchToStore(state, dispatch, true); | ||||
|         // warm up the gas price estimator cache just in case we can't | ||||
|         // grab the gas price estimate when submitting the transaction | ||||
|         // tslint:disable-next-line:no-floating-promises | ||||
| @@ -103,6 +121,14 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider | ||||
|         // tslint:disable-next-line:no-floating-promises | ||||
|         this._flashErrorIfWrongNetwork(); | ||||
|     } | ||||
|     public componentWillUnmount(): void { | ||||
|         if (this._accountUpdateHeartbeat) { | ||||
|             this._accountUpdateHeartbeat.stop(); | ||||
|         } | ||||
|         if (this._buyQuoteHeartbeat) { | ||||
|             this._buyQuoteHeartbeat.stop(); | ||||
|         } | ||||
|     } | ||||
|     public render(): React.ReactNode { | ||||
|         return ( | ||||
|             <ReduxProvider store={this._store}> | ||||
|   | ||||
| @@ -11,12 +11,17 @@ export const WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX = 'Transaction fa | ||||
| export const GWEI_IN_WEI = new BigNumber(1000000000); | ||||
| export const ONE_SECOND_MS = 1000; | ||||
| export const ONE_MINUTE_MS = ONE_SECOND_MS * 60; | ||||
| export const ACCOUNT_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 5; | ||||
| export const BUY_QUOTE_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15; | ||||
| export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); | ||||
| export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2; | ||||
| export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; | ||||
| export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; | ||||
| export const PROGRESS_STALL_AT_WIDTH = '95%'; | ||||
| export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; | ||||
| export const META_MASK_CHROME_STORE_URL = | ||||
|     'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn?hl=en'; | ||||
| export const META_MASK_SITE_URL = 'https://metamask.io/'; | ||||
| export const ETHEREUM_NODE_URL_BY_NETWORK = { | ||||
|     [Network.Mainnet]: 'https://mainnet.infura.io/', | ||||
|     [Network.Kovan]: 'https://kovan.infura.io/', | ||||
| @@ -31,6 +36,3 @@ export const LOADING_ACCOUNT: AccountNotReady = { | ||||
| export const LOCKED_ACCOUNT: AccountNotReady = { | ||||
|     state: AccountState.Locked, | ||||
| }; | ||||
| export const ERROR_ACCOUNT: AccountNotReady = { | ||||
|     state: AccountState.Error, | ||||
| }; | ||||
|   | ||||
| @@ -0,0 +1,59 @@ | ||||
| import * as React from 'react'; | ||||
| import { connect } from 'react-redux'; | ||||
| import { Dispatch } from 'redux'; | ||||
|  | ||||
| import { PaymentMethod, PaymentMethodProps } from '../components/payment_method'; | ||||
| import { Action, actions } from '../redux/actions'; | ||||
| import { asyncData } from '../redux/async_data'; | ||||
| import { State } from '../redux/reducer'; | ||||
| import { Network, Omit, ProviderState, StandardSlidingPanelContent } from '../types'; | ||||
|  | ||||
| export interface ConnectedAccountPaymentMethodProps {} | ||||
|  | ||||
| interface ConnectedState { | ||||
|     network: Network; | ||||
|     providerState: ProviderState; | ||||
| } | ||||
|  | ||||
| interface ConnectedDispatch { | ||||
|     onInstallWalletClick: () => void; | ||||
|     unlockWalletAndDispatchToStore: (providerState: ProviderState) => void; | ||||
| } | ||||
|  | ||||
| type ConnectedProps = Omit<PaymentMethodProps, keyof ConnectedAccountPaymentMethodProps>; | ||||
|  | ||||
| type FinalProps = ConnectedProps & ConnectedAccountPaymentMethodProps; | ||||
|  | ||||
| const mapStateToProps = (state: State, _ownProps: ConnectedAccountPaymentMethodProps): ConnectedState => ({ | ||||
|     network: state.network, | ||||
|     providerState: state.providerState, | ||||
| }); | ||||
|  | ||||
| const mapDispatchToProps = ( | ||||
|     dispatch: Dispatch<Action>, | ||||
|     ownProps: ConnectedAccountPaymentMethodProps, | ||||
| ): ConnectedDispatch => ({ | ||||
|     onInstallWalletClick: () => 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, | ||||
|     onInstallWalletClick: connectedDispatch.onInstallWalletClick, | ||||
|     onUnlockWalletClick: () => { | ||||
|         connectedDispatch.unlockWalletAndDispatchToStore(connectedState.providerState); | ||||
|     }, | ||||
| }); | ||||
|  | ||||
| export const ConnectedAccountPaymentMethod: React.ComponentClass<ConnectedAccountPaymentMethodProps> = connect( | ||||
|     mapStateToProps, | ||||
|     mapDispatchToProps, | ||||
|     mergeProps, | ||||
| )(PaymentMethod); | ||||
| @@ -0,0 +1,36 @@ | ||||
| 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 <SelectedAssetBuyOrderProgress />; | ||||
|     } | ||||
|     if (orderProcessState === OrderProcessState.None) { | ||||
|         return <ConnectedAccountPaymentMethod />; | ||||
|     } | ||||
|     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); | ||||
| @@ -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<Action>, | ||||
|     ownProps: CurrentStandardSlidingPanelProps, | ||||
| ): ConnectedDispatch => ({ | ||||
|     onClose: () => dispatch(actions.closeStandardSlidingPanel()), | ||||
| }); | ||||
|  | ||||
| export const CurrentStandardSlidingPanel: React.ComponentClass<CurrentStandardSlidingPanelProps> = connect( | ||||
|     mapStateToProps, | ||||
|     mapDispatchToProps, | ||||
| )(StandardSlidingPanel); | ||||
| @@ -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, | ||||
| }); | ||||
|   | ||||
| @@ -1,35 +1,59 @@ | ||||
| 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'; | ||||
| import { State } from '../redux/reducer'; | ||||
| import { Asset, DisplayStatus } from '../types'; | ||||
| import { ScreenWidths } from '../style/media'; | ||||
| import { generateOverlayBlack } from '../style/theme'; | ||||
| import { zIndex } from '../style/z_index'; | ||||
| import { Asset, DisplayStatus, Omit, SlideAnimationState } from '../types'; | ||||
| import { errorFlasher } from '../util/error_flasher'; | ||||
|  | ||||
| export interface LatestErrorComponentProps { | ||||
|     asset?: Asset; | ||||
|     latestErrorMessage?: string; | ||||
|     animationState: SlideAnimationState; | ||||
|     shouldRenderOverlay: boolean; | ||||
|     onOverlayClick: () => void; | ||||
| } | ||||
|  | ||||
| export const LatestErrorComponent: React.StatelessComponent<LatestErrorComponentProps> = props => { | ||||
|     if (!props.latestErrorMessage) { | ||||
|         return <div />; | ||||
|     } | ||||
|     return <SlidingError animationState={props.animationState} icon="😢" message={props.latestErrorMessage} />; | ||||
|     return ( | ||||
|         <React.Fragment> | ||||
|             <SlidingError animationState={props.animationState} icon="😢" message={props.latestErrorMessage} /> | ||||
|             {props.shouldRenderOverlay && ( | ||||
|                 <Overlay | ||||
|                     onClick={props.onOverlayClick} | ||||
|                     zIndex={zIndex.containerOverlay} | ||||
|                     showMaxWidth={ScreenWidths.Sm} | ||||
|                     backgroundColor={generateOverlayBlack(0.4)} | ||||
|                 /> | ||||
|             )} | ||||
|         </React.Fragment> | ||||
|     ); | ||||
| }; | ||||
|  | ||||
| interface ConnectedState { | ||||
|     asset?: Asset; | ||||
|     latestErrorMessage?: string; | ||||
|     animationState: SlideAnimationState; | ||||
| } | ||||
| export interface LatestErrorProps {} | ||||
| interface ConnectedState extends Omit<LatestErrorComponentProps, 'onOverlayClick'> {} | ||||
| const mapStateToProps = (state: State, _ownProps: LatestErrorProps): ConnectedState => ({ | ||||
|     asset: state.selectedAsset, | ||||
|     latestErrorMessage: state.latestErrorMessage, | ||||
|     animationState: state.latestErrorDisplayStatus === DisplayStatus.Present ? 'slidIn' : 'slidOut', | ||||
|     shouldRenderOverlay: state.latestErrorDisplayStatus === DisplayStatus.Present, | ||||
| }); | ||||
|  | ||||
| export const LatestError = connect(mapStateToProps)(LatestErrorComponent); | ||||
| type ConnectedDispatch = Pick<LatestErrorComponentProps, 'onOverlayClick'>; | ||||
| const mapDispatchToProps = (dispatch: Dispatch<Action>, _ownProps: LatestErrorProps): ConnectedDispatch => ({ | ||||
|     onOverlayClick: () => { | ||||
|         errorFlasher.clearError(dispatch); | ||||
|     }, | ||||
| }); | ||||
|  | ||||
| export const LatestError = connect(mapStateToProps, mapDispatchToProps)(LatestErrorComponent); | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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<ERC20AssetAmountInputProps, keyof SelectedERC20AssetAmountInputProps>; | ||||
|  | ||||
| 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, | ||||
| @@ -69,7 +63,7 @@ const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputP | ||||
|  | ||||
| const debouncedUpdateBuyQuoteAsync = _.debounce(buyQuoteUpdater.updateBuyQuoteAsync.bind(buyQuoteUpdater), 200, { | ||||
|     trailing: true, | ||||
| }); | ||||
| }) as typeof buyQuoteUpdater.updateBuyQuoteAsync; | ||||
|  | ||||
| const mapDispatchToProps = ( | ||||
|     dispatch: Dispatch<Action>, | ||||
| @@ -87,7 +81,7 @@ 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, affiliateInfo); | ||||
|             debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value, true, affiliateInfo); | ||||
|         } | ||||
|     }, | ||||
| }); | ||||
|   | ||||
| @@ -8,42 +8,42 @@ export const assetMetaDataMap: ObjectMap<AssetMetaData> = { | ||||
|     '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<AssetMetaData> = { | ||||
|         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<AssetMetaData> = { | ||||
|         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', | ||||
|     }, | ||||
| }; | ||||
|   | ||||
| @@ -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<T extends string> { | ||||
|     type: T; | ||||
| @@ -23,11 +23,10 @@ function createAction<T extends string, P>(type: T, data?: P): PlainAction<T> | | ||||
| export enum ActionTypes { | ||||
|     SET_ACCOUNT_STATE_LOADING = 'SET_ACCOUNT_STATE_LOADING', | ||||
|     SET_ACCOUNT_STATE_LOCKED = 'SET_ACCOUNT_STATE_LOCKED', | ||||
|     SET_ACCOUNT_STATE_ERROR = 'SET_ACCOUNT_STATE_ERROR', | ||||
|     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', | ||||
| @@ -42,17 +41,19 @@ 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 = { | ||||
|     setAccountStateLoading: () => createAction(ActionTypes.SET_ACCOUNT_STATE_LOADING), | ||||
|     setAccountStateLocked: () => createAction(ActionTypes.SET_ACCOUNT_STATE_LOCKED), | ||||
|     setAccountStateError: () => createAction(ActionTypes.SET_ACCOUNT_STATE_ERROR), | ||||
|     setAccountStateReady: (address: string) => createAction(ActionTypes.SET_ACCOUNT_STATE_READY, address), | ||||
|     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) => | ||||
| @@ -68,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), | ||||
| }; | ||||
|   | ||||
| @@ -1,92 +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 } 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 (store: Store) => { | ||||
|         const { providerState } = store.getState(); | ||||
|     fetchAccountInfoAndDispatchToStore: async ( | ||||
|         providerState: ProviderState, | ||||
|         dispatch: Dispatch, | ||||
|         shouldAttemptUnlock: boolean = false, | ||||
|         shouldSetToLoading: boolean = false, | ||||
|     ) => { | ||||
|         const web3Wrapper = providerState.web3Wrapper; | ||||
|         if (providerState.account.state !== AccountState.Loading) { | ||||
|             store.dispatch(actions.setAccountStateLoading()); | ||||
|         const provider = providerState.provider; | ||||
|         if (shouldSetToLoading && providerState.account.state !== AccountState.Loading) { | ||||
|             dispatch(actions.setAccountStateLoading()); | ||||
|         } | ||||
|         let availableAddresses: string[]; | ||||
|         try { | ||||
|             availableAddresses = await web3Wrapper.getAvailableAddressesAsync(); | ||||
|             // 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 && shouldAttemptUnlock | ||||
|                     ? await (provider as any).enable() | ||||
|                     : await web3Wrapper.getAvailableAddressesAsync(); | ||||
|         } catch (e) { | ||||
|             store.dispatch(actions.setAccountStateError()); | ||||
|             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 (store: Store) => { | ||||
|         const { providerState, selectedAsset, selectedAssetAmount, affiliateInfo } = store.getState(); | ||||
|     fetchCurrentBuyQuoteAndDispatchToStore: async ( | ||||
|         state: State, | ||||
|         dispatch: Dispatch, | ||||
|         shouldSetPending: boolean = false, | ||||
|     ) => { | ||||
|         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, | ||||
|                 selectedAssetUnitAmount, | ||||
|                 shouldSetPending, | ||||
|                 affiliateInfo, | ||||
|             ); | ||||
|         } | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import { BigNumber } from '@0x/utils'; | ||||
| import { Web3Wrapper } from '@0x/web3-wrapper'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { ERROR_ACCOUNT, LOADING_ACCOUNT, LOCKED_ACCOUNT } from '../constants'; | ||||
| import { LOADING_ACCOUNT, LOCKED_ACCOUNT } from '../constants'; | ||||
| import { assetMetaDataMap } from '../data/asset_meta_data_map'; | ||||
| import { | ||||
|     Account, | ||||
| @@ -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) => { | ||||
| @@ -65,14 +72,20 @@ export const createReducer = (initialState: State) => { | ||||
|                 return reduceStateWithAccount(state, LOADING_ACCOUNT); | ||||
|             case ActionTypes.SET_ACCOUNT_STATE_LOCKED: | ||||
|                 return reduceStateWithAccount(state, LOCKED_ACCOUNT); | ||||
|             case ActionTypes.SET_ACCOUNT_STATE_ERROR: | ||||
|                 return reduceStateWithAccount(state, ERROR_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; | ||||
| @@ -92,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; | ||||
| @@ -206,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; | ||||
|         } | ||||
| @@ -234,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 | ||||
| @@ -248,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); | ||||
|   | ||||
| @@ -8,7 +8,7 @@ export enum ScreenWidths { | ||||
|     Lg = 64, | ||||
| } | ||||
|  | ||||
| const generateMediaWrapper = (screenWidth: ScreenWidths) => (...args: any[]) => css` | ||||
| export const generateMediaWrapper = (screenWidth: ScreenWidths) => (...args: any[]) => css` | ||||
|     @media (max-width: ${screenWidth}em) { | ||||
|         ${css.apply(css, args)}; | ||||
|     } | ||||
|   | ||||
| @@ -35,7 +35,10 @@ export const theme: Theme = { | ||||
| }; | ||||
|  | ||||
| export const transparentWhite = 'rgba(255,255,255,0.3)'; | ||||
| export const overlayBlack = 'rgba(0, 0, 0, 0.6)'; | ||||
| export const completelyTransparent = 'rga(0, 0, 0, 0)'; | ||||
|  | ||||
| export const generateOverlayBlack = (opacity = 0.6) => { | ||||
|     return `rgba(0, 0, 0, ${opacity})`; | ||||
| }; | ||||
|  | ||||
| export { styled, css, keyframes, withTheme, createGlobalStyle, ThemeProvider }; | ||||
|   | ||||
| @@ -3,6 +3,7 @@ export const zIndex = { | ||||
|     mainContainer: 20, | ||||
|     dropdownItems: 30, | ||||
|     panel: 40, | ||||
|     containerOverlay: 45, | ||||
|     errorPopup: 50, | ||||
|     overlayDefault: 100, | ||||
| }; | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import { Web3Wrapper } from '@0x/web3-wrapper'; | ||||
| import { Provider } from 'ethereum-types'; | ||||
|  | ||||
| // Reusable | ||||
| export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; | ||||
| export type Maybe<T> = T | undefined; | ||||
| export enum AsyncProcessState { | ||||
|     None = 'NONE', | ||||
| @@ -101,11 +102,10 @@ export interface ProviderState { | ||||
| } | ||||
|  | ||||
| export enum AccountState { | ||||
|     None = 'NONE,', | ||||
|     Loading = 'LOADING', | ||||
|     Ready = 'READY', | ||||
|     Locked = 'LOCKED', // TODO(bmillman): break this up into locked / privacy mode enabled | ||||
|     Error = 'ERROR', | ||||
|     None = 'NONE,', | ||||
|     Locked = 'LOCKED', | ||||
| } | ||||
|  | ||||
| export interface AccountReady { | ||||
| @@ -114,7 +114,7 @@ export interface AccountReady { | ||||
|     ethBalanceInWei?: BigNumber; | ||||
| } | ||||
| export interface AccountNotReady { | ||||
|     state: AccountState.None | AccountState.Loading | AccountState.Locked | AccountState.Error; | ||||
|     state: AccountState.None | AccountState.Loading | AccountState.Locked; | ||||
| } | ||||
|  | ||||
| export type Account = AccountReady | AccountNotReady; | ||||
| @@ -125,3 +125,15 @@ 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; | ||||
| } | ||||
|   | ||||
| @@ -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 => { | ||||
|   | ||||
| @@ -15,13 +15,16 @@ export const buyQuoteUpdater = { | ||||
|         assetBuyer: AssetBuyer, | ||||
|         dispatch: Dispatch<Action>, | ||||
|         asset: ERC20Asset, | ||||
|         assetAmount: BigNumber, | ||||
|         assetUnitAmount: BigNumber, | ||||
|         setPending = true, | ||||
|         affiliateInfo?: AffiliateInfo, | ||||
|     ): Promise<void> => { | ||||
|         // get a new buy quote. | ||||
|         const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, asset.metaData.decimals); | ||||
|         // mark quote as pending | ||||
|         dispatch(actions.setQuoteRequestStatePending()); | ||||
|         const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetUnitAmount, asset.metaData.decimals); | ||||
|         if (setPending) { | ||||
|             // mark quote as pending | ||||
|             dispatch(actions.setQuoteRequestStatePending()); | ||||
|         } | ||||
|         const feePercentage = oc(affiliateInfo).feePercentage(); | ||||
|         let newBuyQuote: BuyQuote | undefined; | ||||
|         try { | ||||
|   | ||||
| @@ -8,9 +8,8 @@ const etherscanPrefix = (networkId: number): string | undefined => { | ||||
|             return 'kovan.'; | ||||
|         case Network.Mainnet: | ||||
|             return ''; | ||||
|         default: | ||||
|             return undefined; | ||||
|     } | ||||
|     return ''; | ||||
| }; | ||||
|  | ||||
| export const etherscanUtil = { | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user