Merge branch 'development' into patch-1
This commit is contained in:
commit
0101cd73aa
@ -31,7 +31,7 @@ jobs:
|
|||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run: cd packages/website && yarn build
|
- run: cd packages/website && yarn build:prod
|
||||||
test-contracts-ganache:
|
test-contracts-ganache:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/node:9
|
- image: circleci/node:9
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "packages/instant/public/main.bundle.js",
|
"path": "packages/instant/public/main.bundle.js",
|
||||||
"maxSize": "500kB"
|
"maxSize": "1000kB"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ci": {
|
"ci": {
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "2.0.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1541740904
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v2.0.1 - _November 9, 2018_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v2.0.0 - _October 18, 2018_
|
## v2.0.0 - _October 18, 2018_
|
||||||
|
|
||||||
* Add support for `eth_signTypedData`. (#1102)
|
* Add support for `eth_signTypedData`. (#1102)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "0x.js",
|
"name": "0x.js",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -42,12 +42,12 @@
|
|||||||
},
|
},
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^1.0.14",
|
"@0x/abi-gen": "^1.0.15",
|
||||||
"@0x/abi-gen-wrappers": "^1.0.1",
|
"@0x/abi-gen-wrappers": "^1.0.2",
|
||||||
"@0x/contract-addresses": "^1.0.1",
|
"@0x/contract-addresses": "^1.1.0",
|
||||||
"@0x/dev-utils": "^1.0.13",
|
"@0x/dev-utils": "^1.0.14",
|
||||||
"@0x/migrations": "^2.0.0",
|
"@0x/migrations": "^2.0.1",
|
||||||
"@0x/tslint-config": "^1.0.9",
|
"@0x/tslint-config": "^1.0.10",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
@ -73,18 +73,18 @@
|
|||||||
"webpack": "^4.20.2"
|
"webpack": "^4.20.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/assert": "^1.0.14",
|
"@0x/assert": "^1.0.15",
|
||||||
"@0x/base-contract": "^3.0.2",
|
"@0x/base-contract": "^3.0.3",
|
||||||
"@0x/contract-wrappers": "^3.0.0",
|
"@0x/contract-wrappers": "^3.0.1",
|
||||||
"@0x/order-utils": "^2.0.0",
|
"@0x/order-utils": "^2.0.1",
|
||||||
"@0x/order-watcher": "^2.2.0",
|
"@0x/order-watcher": "^2.2.1",
|
||||||
"@0x/subproviders": "^2.1.0",
|
"@0x/subproviders": "^2.1.1",
|
||||||
"@0x/types": "^1.2.0",
|
"@0x/types": "^1.2.1",
|
||||||
"@0x/typescript-typings": "^3.0.3",
|
"@0x/typescript-typings": "^3.0.4",
|
||||||
"@0x/utils": "^2.0.3",
|
"@0x/utils": "^2.0.4",
|
||||||
"@0x/web3-wrapper": "^3.1.0",
|
"@0x/web3-wrapper": "^3.1.1",
|
||||||
"@types/web3-provider-engine": "^14.0.0",
|
"@types/web3-provider-engine": "^14.0.0",
|
||||||
"ethereum-types": "^1.1.1",
|
"ethereum-types": "^1.1.2",
|
||||||
"ethers": "~4.0.4",
|
"ethers": "~4.0.4",
|
||||||
"lodash": "^4.17.5",
|
"lodash": "^4.17.5",
|
||||||
"web3-provider-engine": "14.0.6"
|
"web3-provider-engine": "14.0.6"
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "1.0.2",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1541740904
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1539871071,
|
"timestamp": 1539871071,
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.0.2 - _November 9, 2018_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v1.0.1 - _October 18, 2018_
|
## v1.0.1 - _October 18, 2018_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/abi-gen-wrappers",
|
"name": "@0x/abi-gen-wrappers",
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -30,17 +30,17 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen-wrappers/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen-wrappers/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^1.0.14",
|
"@0x/abi-gen": "^1.0.15",
|
||||||
"@0x/tslint-config": "^1.0.9",
|
"@0x/tslint-config": "^1.0.10",
|
||||||
"@0x/utils": "^2.0.3",
|
"@0x/utils": "^2.0.4",
|
||||||
"@0x/web3-wrapper": "^3.1.0",
|
"@0x/web3-wrapper": "^3.1.1",
|
||||||
"ethereum-types": "^1.1.1",
|
"ethereum-types": "^1.1.2",
|
||||||
"ethers": "~4.0.4",
|
"ethers": "~4.0.4",
|
||||||
"lodash": "^4.17.5",
|
"lodash": "^4.17.5",
|
||||||
"shx": "^0.2.2"
|
"shx": "^0.2.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^3.0.2"
|
"@0x/base-contract": "^3.0.3"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "1.0.15",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1541740904
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1539871071,
|
"timestamp": 1539871071,
|
||||||
"version": "1.0.14",
|
"version": "1.0.14",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.0.15 - _November 9, 2018_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v1.0.14 - _October 18, 2018_
|
## v1.0.14 - _October 18, 2018_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/abi-gen",
|
"name": "@0x/abi-gen",
|
||||||
"version": "1.0.14",
|
"version": "1.0.15",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -31,10 +31,10 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/typescript-typings": "^3.0.3",
|
"@0x/typescript-typings": "^3.0.4",
|
||||||
"@0x/utils": "^2.0.3",
|
"@0x/utils": "^2.0.4",
|
||||||
"chalk": "^2.3.0",
|
"chalk": "^2.3.0",
|
||||||
"ethereum-types": "^1.1.1",
|
"ethereum-types": "^1.1.2",
|
||||||
"glob": "^7.1.2",
|
"glob": "^7.1.2",
|
||||||
"handlebars": "^4.0.11",
|
"handlebars": "^4.0.11",
|
||||||
"lodash": "^4.17.5",
|
"lodash": "^4.17.5",
|
||||||
@ -45,7 +45,7 @@
|
|||||||
"yargs": "^10.0.3"
|
"yargs": "^10.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/tslint-config": "^1.0.9",
|
"@0x/tslint-config": "^1.0.10",
|
||||||
"@types/glob": "5.0.35",
|
"@types/glob": "5.0.35",
|
||||||
"@types/handlebars": "^4.0.36",
|
"@types/handlebars": "^4.0.36",
|
||||||
"@types/mkdirp": "^0.5.1",
|
"@types/mkdirp": "^0.5.1",
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "1.0.15",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1541740904
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1539871071,
|
"timestamp": 1539871071,
|
||||||
"version": "1.0.14",
|
"version": "1.0.14",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.0.15 - _November 9, 2018_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v1.0.14 - _October 18, 2018_
|
## v1.0.14 - _October 18, 2018_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/assert",
|
"name": "@0x/assert",
|
||||||
"version": "1.0.14",
|
"version": "1.0.15",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/assert/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/packages/assert/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/tslint-config": "^1.0.9",
|
"@0x/tslint-config": "^1.0.10",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
"@types/valid-url": "^1.0.2",
|
"@types/valid-url": "^1.0.2",
|
||||||
@ -44,9 +44,9 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/json-schemas": "^2.0.0",
|
"@0x/json-schemas": "^2.0.1",
|
||||||
"@0x/typescript-typings": "^3.0.3",
|
"@0x/typescript-typings": "^3.0.4",
|
||||||
"@0x/utils": "^2.0.3",
|
"@0x/utils": "^2.0.4",
|
||||||
"lodash": "^4.17.5",
|
"lodash": "^4.17.5",
|
||||||
"valid-url": "^1.0.9"
|
"valid-url": "^1.0.9"
|
||||||
},
|
},
|
||||||
|
@ -29,7 +29,8 @@
|
|||||||
"note": "Lower default expiry buffer from 5 minutes to 2 minutes",
|
"note": "Lower default expiry buffer from 5 minutes to 2 minutes",
|
||||||
"pr": 1217
|
"pr": 1217
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1541740904
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
|
@ -5,6 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v2.2.0 - _November 9, 2018_
|
||||||
|
|
||||||
|
* `getAssetBuyerForProvidedOrders` factory function now takes 3 args instead of 4 (#1187)
|
||||||
|
* the `OrderProvider` now requires a new method `getAvailableMakerAssetDatasAsync` and the `StandardRelayerAPIOrderProvider` requires the network id at init. (#1203)
|
||||||
|
* No longer require that provided orders all have the same maker and taker asset data (#1197)
|
||||||
|
* Fix bug where `BuyQuoteInfo` objects could return `totalEthAmount` and `feeEthAmount` that were not whole numbers (#1207)
|
||||||
|
* Fix bug where default values for `AssetBuyer` public facing methods could get overriden by `undefined` values (#1207)
|
||||||
|
* Lower default expiry buffer from 5 minutes to 2 minutes (#1217)
|
||||||
|
|
||||||
## v2.1.0 - _October 18, 2018_
|
## v2.1.0 - _October 18, 2018_
|
||||||
|
|
||||||
* Add `gasLimit` and `gasPrice` as optional properties on `BuyQuoteExecutionOpts`
|
* Add `gasLimit` and `gasPrice` as optional properties on `BuyQuoteExecutionOpts`
|
||||||
@ -13,6 +22,7 @@ CHANGELOG
|
|||||||
* Add `gasLimit` and `gasPrice` as optional properties on `BuyQuoteExecutionOpts` (#1116)
|
* Add `gasLimit` and `gasPrice` as optional properties on `BuyQuoteExecutionOpts` (#1116)
|
||||||
* Add `docs:json` command to package.json (#1139)
|
* Add `docs:json` command to package.json (#1139)
|
||||||
* Add missing types to public interface (#1139)
|
* Add missing types to public interface (#1139)
|
||||||
|
* Throw `SignatureRequestDenied` and `TransactionValueTooLow` errors when executing buy (#1147)
|
||||||
|
|
||||||
## v2.0.0 - _October 4, 2018_
|
## v2.0.0 - _October 4, 2018_
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/asset-buyer",
|
"name": "@0x/asset-buyer",
|
||||||
"version": "2.1.0",
|
"version": "2.2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -36,21 +36,21 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/asset-buyer/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/packages/asset-buyer/README.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/assert": "^1.0.14",
|
"@0x/assert": "^1.0.15",
|
||||||
"@0x/connect": "^3.0.2",
|
"@0x/connect": "^3.0.3",
|
||||||
"@0x/contract-wrappers": "^3.0.0",
|
"@0x/contract-wrappers": "^3.0.1",
|
||||||
"@0x/json-schemas": "^2.0.0",
|
"@0x/json-schemas": "^2.0.1",
|
||||||
"@0x/order-utils": "^2.0.0",
|
"@0x/order-utils": "^2.0.1",
|
||||||
"@0x/subproviders": "^2.1.0",
|
"@0x/subproviders": "^2.1.1",
|
||||||
"@0x/types": "^1.2.0",
|
"@0x/types": "^1.2.1",
|
||||||
"@0x/typescript-typings": "^3.0.3",
|
"@0x/typescript-typings": "^3.0.4",
|
||||||
"@0x/utils": "^2.0.3",
|
"@0x/utils": "^2.0.4",
|
||||||
"@0x/web3-wrapper": "^3.1.0",
|
"@0x/web3-wrapper": "^3.1.1",
|
||||||
"ethereum-types": "^1.1.1",
|
"ethereum-types": "^1.1.2",
|
||||||
"lodash": "^4.17.10"
|
"lodash": "^4.17.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/tslint-config": "^1.0.9",
|
"@0x/tslint-config": "^1.0.10",
|
||||||
"@types/lodash": "^4.14.116",
|
"@types/lodash": "^4.14.116",
|
||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "3.0.3",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1541740904
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1539871071,
|
"timestamp": 1539871071,
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v3.0.3 - _November 9, 2018_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v3.0.2 - _October 18, 2018_
|
## v3.0.2 - _October 18, 2018_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/base-contract",
|
"name": "@0x/base-contract",
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/base-contract/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/packages/base-contract/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/tslint-config": "^1.0.9",
|
"@0x/tslint-config": "^1.0.10",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
@ -40,10 +40,10 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/typescript-typings": "^3.0.3",
|
"@0x/typescript-typings": "^3.0.4",
|
||||||
"@0x/utils": "^2.0.3",
|
"@0x/utils": "^2.0.4",
|
||||||
"@0x/web3-wrapper": "^3.1.0",
|
"@0x/web3-wrapper": "^3.1.1",
|
||||||
"ethereum-types": "^1.1.1",
|
"ethereum-types": "^1.1.2",
|
||||||
"ethers": "~4.0.4",
|
"ethers": "~4.0.4",
|
||||||
"lodash": "^4.17.5"
|
"lodash": "^4.17.5"
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "3.0.3",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1541740904
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1539871071,
|
"timestamp": 1539871071,
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v3.0.3 - _November 9, 2018_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v3.0.2 - _October 18, 2018_
|
## v3.0.2 - _October 18, 2018_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/connect",
|
"name": "@0x/connect",
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -44,12 +44,12 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/connect/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/packages/connect/README.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/assert": "^1.0.14",
|
"@0x/assert": "^1.0.15",
|
||||||
"@0x/json-schemas": "^2.0.0",
|
"@0x/json-schemas": "^2.0.1",
|
||||||
"@0x/order-utils": "^2.0.0",
|
"@0x/order-utils": "^2.0.1",
|
||||||
"@0x/types": "^1.2.0",
|
"@0x/types": "^1.2.1",
|
||||||
"@0x/typescript-typings": "^3.0.3",
|
"@0x/typescript-typings": "^3.0.4",
|
||||||
"@0x/utils": "^2.0.3",
|
"@0x/utils": "^2.0.4",
|
||||||
"lodash": "^4.17.5",
|
"lodash": "^4.17.5",
|
||||||
"query-string": "^5.0.1",
|
"query-string": "^5.0.1",
|
||||||
"sinon": "^4.0.0",
|
"sinon": "^4.0.0",
|
||||||
@ -57,7 +57,7 @@
|
|||||||
"websocket": "^1.0.25"
|
"websocket": "^1.0.25"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/tslint-config": "^1.0.9",
|
"@0x/tslint-config": "^1.0.10",
|
||||||
"@types/fetch-mock": "^6.0.3",
|
"@types/fetch-mock": "^6.0.3",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
"pr": 1192,
|
"pr": 1192,
|
||||||
"note": "Update Forwarder addresses"
|
"note": "Update Forwarder addresses"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1541740904
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.1.0 - _November 9, 2018_
|
||||||
|
|
||||||
|
* Update Forwarder addresses (#1192)
|
||||||
|
|
||||||
## v1.0.1 - _October 18, 2018_
|
## v1.0.1 - _October 18, 2018_
|
||||||
|
|
||||||
* Initial release (#1105)
|
* Initial release (#1105)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contract-addresses",
|
"name": "@0x/contract-addresses",
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
"pr": 1192,
|
"pr": 1192,
|
||||||
"note": "Update Forwarder artifact"
|
"note": "Update Forwarder artifact"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1541740904
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.1.0 - _November 9, 2018_
|
||||||
|
|
||||||
|
* Update Forwarder artifact (#1192)
|
||||||
|
|
||||||
## v1.0.1 - _October 18, 2018_
|
## v1.0.1 - _October 18, 2018_
|
||||||
|
|
||||||
* Initial release (#1105)
|
* Initial release (#1105)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contract-artifacts",
|
"name": "@0x/contract-artifacts",
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
"note": "Fix bug in `ForwarderWrapper` where `feeRecipientAddress` was not correctly normalized.",
|
"note": "Fix bug in `ForwarderWrapper` where `feeRecipientAddress` was not correctly normalized.",
|
||||||
"pr": 1178
|
"pr": 1178
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1541740904
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v3.0.1 - _November 9, 2018_
|
||||||
|
|
||||||
|
* Fix bug in `ForwarderWrapper` where `feeRecipientAddress` was not correctly normalized. (#1178)
|
||||||
|
|
||||||
## v3.0.0 - _October 18, 2018_
|
## v3.0.0 - _October 18, 2018_
|
||||||
|
|
||||||
* Add optional validation to the forwarder wrapper methods
|
* Add optional validation to the forwarder wrapper methods
|
||||||
@ -15,6 +19,8 @@ CHANGELOG
|
|||||||
* Removed `setProvider` method in top-level `ContractWrapper` class and added new `unsubscribeAll` method. (#1105)
|
* Removed `setProvider` method in top-level `ContractWrapper` class and added new `unsubscribeAll` method. (#1105)
|
||||||
* Some properties and methods have been renamed. For example, some methods that previously could throw no longer can, and so their names have been updated accordingly. (#1105)
|
* Some properties and methods have been renamed. For example, some methods that previously could throw no longer can, and so their names have been updated accordingly. (#1105)
|
||||||
* Removed ContractNotFound errors. Checking for this error was somewhat ineffecient. Relevant methods/functions now return the default error from web3-wrapper, which we feel provides enough information. (#1105)
|
* Removed ContractNotFound errors. Checking for this error was somewhat ineffecient. Relevant methods/functions now return the default error from web3-wrapper, which we feel provides enough information. (#1105)
|
||||||
|
* Add `ForwarderWrapperError` to public interface (#1147)
|
||||||
|
* Add `ContractWrapperError.SignatureRequestDenied` to public interface (#1147)
|
||||||
|
|
||||||
## v2.0.2 - _October 4, 2018_
|
## v2.0.2 - _October 4, 2018_
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contract-wrappers",
|
"name": "@0x/contract-wrappers",
|
||||||
"version": "3.0.0",
|
"version": "3.0.1",
|
||||||
"description": "Smart TS wrappers for 0x smart contracts",
|
"description": "Smart TS wrappers for 0x smart contracts",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"0xproject",
|
"0xproject",
|
||||||
@ -37,10 +37,10 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/dev-utils": "^1.0.13",
|
"@0x/dev-utils": "^1.0.14",
|
||||||
"@0x/migrations": "^2.0.0",
|
"@0x/migrations": "^2.0.1",
|
||||||
"@0x/subproviders": "^2.1.0",
|
"@0x/subproviders": "^2.1.1",
|
||||||
"@0x/tslint-config": "^1.0.9",
|
"@0x/tslint-config": "^1.0.10",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
@ -65,18 +65,18 @@
|
|||||||
"web3-provider-engine": "14.0.6"
|
"web3-provider-engine": "14.0.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/abi-gen-wrappers": "^1.0.1",
|
"@0x/abi-gen-wrappers": "^1.0.2",
|
||||||
"@0x/assert": "^1.0.14",
|
"@0x/assert": "^1.0.15",
|
||||||
"@0x/contract-addresses": "^1.0.1",
|
"@0x/contract-addresses": "^1.1.0",
|
||||||
"@0x/contract-artifacts": "^1.0.1",
|
"@0x/contract-artifacts": "^1.1.0",
|
||||||
"@0x/fill-scenarios": "^1.0.8",
|
"@0x/fill-scenarios": "^1.0.9",
|
||||||
"@0x/json-schemas": "^2.0.0",
|
"@0x/json-schemas": "^2.0.1",
|
||||||
"@0x/order-utils": "^2.0.0",
|
"@0x/order-utils": "^2.0.1",
|
||||||
"@0x/types": "^1.2.0",
|
"@0x/types": "^1.2.1",
|
||||||
"@0x/typescript-typings": "^3.0.3",
|
"@0x/typescript-typings": "^3.0.4",
|
||||||
"@0x/utils": "^2.0.3",
|
"@0x/utils": "^2.0.4",
|
||||||
"@0x/web3-wrapper": "^3.1.0",
|
"@0x/web3-wrapper": "^3.1.1",
|
||||||
"ethereum-types": "^1.1.1",
|
"ethereum-types": "^1.1.2",
|
||||||
"ethereumjs-blockstream": "6.0.0",
|
"ethereumjs-blockstream": "6.0.0",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"ethers": "~4.0.4",
|
"ethers": "~4.0.4",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "contracts",
|
"name": "contracts",
|
||||||
"version": "2.1.50",
|
"version": "2.1.51",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -45,12 +45,12 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^1.0.14",
|
"@0x/abi-gen": "^1.0.15",
|
||||||
"@0x/dev-utils": "^1.0.13",
|
"@0x/dev-utils": "^1.0.14",
|
||||||
"@0x/sol-compiler": "^1.1.8",
|
"@0x/sol-compiler": "^1.1.9",
|
||||||
"@0x/sol-cov": "^2.1.8",
|
"@0x/sol-cov": "^2.1.9",
|
||||||
"@0x/subproviders": "^2.1.0",
|
"@0x/subproviders": "^2.1.1",
|
||||||
"@0x/tslint-config": "^1.0.9",
|
"@0x/tslint-config": "^1.0.10",
|
||||||
"@types/bn.js": "^4.11.0",
|
"@types/bn.js": "^4.11.0",
|
||||||
"@types/ethereumjs-abi": "^0.6.0",
|
"@types/ethereumjs-abi": "^0.6.0",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
@ -71,15 +71,15 @@
|
|||||||
"yargs": "^10.0.3"
|
"yargs": "^10.0.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^3.0.2",
|
"@0x/base-contract": "^3.0.3",
|
||||||
"@0x/order-utils": "^2.0.0",
|
"@0x/order-utils": "^2.0.1",
|
||||||
"@0x/types": "^1.2.0",
|
"@0x/types": "^1.2.1",
|
||||||
"@0x/typescript-typings": "^3.0.3",
|
"@0x/typescript-typings": "^3.0.4",
|
||||||
"@0x/utils": "^2.0.3",
|
"@0x/utils": "^2.0.4",
|
||||||
"@0x/web3-wrapper": "^3.1.0",
|
"@0x/web3-wrapper": "^3.1.1",
|
||||||
"@types/js-combinatorics": "^0.5.29",
|
"@types/js-combinatorics": "^0.5.29",
|
||||||
"bn.js": "^4.11.8",
|
"bn.js": "^4.11.8",
|
||||||
"ethereum-types": "^1.1.1",
|
"ethereum-types": "^1.1.2",
|
||||||
"ethereumjs-abi": "0.6.5",
|
"ethereumjs-abi": "0.6.5",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"ethers": "~4.0.4",
|
"ethers": "~4.0.4",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/dev-tools-pages",
|
"name": "@0x/dev-tools-pages",
|
||||||
"version": "0.0.2",
|
"version": "0.0.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/react-shared": "^1.0.17",
|
"@0x/react-shared": "^1.0.18",
|
||||||
"basscss": "^8.0.3",
|
"basscss": "^8.0.3",
|
||||||
"bowser": "^1.9.3",
|
"bowser": "^1.9.3",
|
||||||
"less": "^2.7.2",
|
"less": "^2.7.2",
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "1.0.14",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1541740904
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.0.13",
|
"version": "1.0.13",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.0.14 - _November 9, 2018_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v1.0.13 - _October 18, 2018_
|
## v1.0.13 - _October 18, 2018_
|
||||||
|
|
||||||
* Make web3-provider-engine types a 'dependency' so it's available to users of the library (#1105)
|
* Make web3-provider-engine types a 'dependency' so it's available to users of the library (#1105)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/dev-utils",
|
"name": "@0x/dev-utils",
|
||||||
"version": "1.0.13",
|
"version": "1.0.14",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/dev-utils/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/packages/dev-utils/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/tslint-config": "^1.0.9",
|
"@0x/tslint-config": "^1.0.10",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
@ -41,14 +41,14 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/subproviders": "^2.1.0",
|
"@0x/subproviders": "^2.1.1",
|
||||||
"@0x/types": "^1.2.0",
|
"@0x/types": "^1.2.1",
|
||||||
"@0x/typescript-typings": "^3.0.3",
|
"@0x/typescript-typings": "^3.0.4",
|
||||||
"@0x/utils": "^2.0.3",
|
"@0x/utils": "^2.0.4",
|
||||||
"@0x/web3-wrapper": "^3.1.0",
|
"@0x/web3-wrapper": "^3.1.1",
|
||||||
"@types/web3-provider-engine": "^14.0.0",
|
"@types/web3-provider-engine": "^14.0.0",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"ethereum-types": "^1.1.1",
|
"ethereum-types": "^1.1.2",
|
||||||
"lodash": "^4.17.5"
|
"lodash": "^4.17.5"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "1.1.2",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1541740904
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.1.2 - _November 9, 2018_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v1.1.1 - _October 18, 2018_
|
## v1.1.1 - _October 18, 2018_
|
||||||
|
|
||||||
* Add `JSONRPCResponseError` and error field on `JSONRPCResponsePayload`. (#1102)
|
* Add `JSONRPCResponseError` and error field on `JSONRPCResponsePayload`. (#1102)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ethereum-types",
|
"name": "ethereum-types",
|
||||||
"version": "1.1.1",
|
"version": "1.1.2",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/ethereum-types/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/packages/ethereum-types/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/tslint-config": "^1.0.9",
|
"@0x/tslint-config": "^1.0.10",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
"tslint": "5.11.0",
|
"tslint": "5.11.0",
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "1.0.9",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1541740904
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.0.9 - _November 9, 2018_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v1.0.8 - _October 18, 2018_
|
## v1.0.8 - _October 18, 2018_
|
||||||
|
|
||||||
* Updated to use new @0xproject/contract-artifacts and @0xproject/abi-gen-wrappers packages (#1105)
|
* Updated to use new @0xproject/contract-artifacts and @0xproject/abi-gen-wrappers packages (#1105)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/fill-scenarios",
|
"name": "@0x/fill-scenarios",
|
||||||
"version": "1.0.8",
|
"version": "1.0.9",
|
||||||
"description": "0x order fill scenario generator",
|
"description": "0x order fill scenario generator",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
@ -20,7 +20,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/fill-scenarios/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/packages/fill-scenarios/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/tslint-config": "^1.0.9",
|
"@0x/tslint-config": "^1.0.10",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
@ -28,15 +28,15 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/abi-gen-wrappers": "^1.0.1",
|
"@0x/abi-gen-wrappers": "^1.0.2",
|
||||||
"@0x/base-contract": "^3.0.2",
|
"@0x/base-contract": "^3.0.3",
|
||||||
"@0x/contract-artifacts": "^1.0.1",
|
"@0x/contract-artifacts": "^1.1.0",
|
||||||
"@0x/order-utils": "^2.0.0",
|
"@0x/order-utils": "^2.0.1",
|
||||||
"@0x/types": "^1.2.0",
|
"@0x/types": "^1.2.1",
|
||||||
"@0x/typescript-typings": "^3.0.3",
|
"@0x/typescript-typings": "^3.0.4",
|
||||||
"@0x/utils": "^2.0.3",
|
"@0x/utils": "^2.0.4",
|
||||||
"@0x/web3-wrapper": "^3.1.0",
|
"@0x/web3-wrapper": "^3.1.1",
|
||||||
"ethereum-types": "^1.1.1",
|
"ethereum-types": "^1.1.2",
|
||||||
"ethers": "~4.0.4",
|
"ethers": "~4.0.4",
|
||||||
"lodash": "^4.17.5"
|
"lodash": "^4.17.5"
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/instant",
|
"name": "@0x/instant",
|
||||||
"version": "0.0.3",
|
"version": "0.0.4",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -45,15 +45,17 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/instant/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/packages/instant/README.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/assert": "^1.0.14",
|
"@0x/assert": "^1.0.15",
|
||||||
"@0x/asset-buyer": "^2.1.0",
|
"@0x/asset-buyer": "^2.2.0",
|
||||||
"@0x/json-schemas": "^2.0.0",
|
"@0x/json-schemas": "^2.0.1",
|
||||||
"@0x/order-utils": "^2.0.0",
|
"@0x/order-utils": "^2.0.1",
|
||||||
"@0x/types": "^1.2.0",
|
"@0x/subproviders": "^2.1.1",
|
||||||
"@0x/typescript-typings": "^3.0.3",
|
"@0x/types": "^1.2.1",
|
||||||
"@0x/utils": "^2.0.3",
|
"@0x/typescript-typings": "^3.0.4",
|
||||||
"@0x/web3-wrapper": "^3.1.0",
|
"@0x/utils": "^2.0.4",
|
||||||
"ethereum-types": "^1.1.1",
|
"@0x/web3-wrapper": "^3.1.1",
|
||||||
|
"copy-to-clipboard": "^3.0.8",
|
||||||
|
"ethereum-types": "^1.1.2",
|
||||||
"lodash": "^4.17.10",
|
"lodash": "^4.17.10",
|
||||||
"polished": "^2.2.0",
|
"polished": "^2.2.0",
|
||||||
"react": "^16.5.2",
|
"react": "^16.5.2",
|
||||||
@ -65,7 +67,7 @@
|
|||||||
"ts-optchain": "^0.1.1"
|
"ts-optchain": "^0.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/tslint-config": "^1.0.9",
|
"@0x/tslint-config": "^1.0.10",
|
||||||
"@static/discharge": "https://github.com/0xProject/discharge.git",
|
"@static/discharge": "https://github.com/0xProject/discharge.git",
|
||||||
"@types/enzyme": "^3.1.14",
|
"@types/enzyme": "^3.1.14",
|
||||||
"@types/enzyme-adapter-react-16": "^1.0.3",
|
"@types/enzyme-adapter-react-16": "^1.0.3",
|
||||||
|
25
packages/instant/public/external.css
Normal file
25
packages/instant/public/external.css
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
CSS file meant to represent an external (integrators) stylesheet and
|
||||||
|
help ensure that instant looks consistent across environments.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-size: 50px;
|
||||||
|
height: 200px;
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
padding: 100px;
|
||||||
|
font-size: 50px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
background-color: green;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
@ -5,6 +5,7 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>0x Instant Dev Environment</title>
|
<title>0x Instant Dev Environment</title>
|
||||||
|
<link rel="stylesheet" href="/external.css">
|
||||||
<script type="text/javascript" src="/main.bundle.js" charset="utf-8"></script>
|
<script type="text/javascript" src="/main.bundle.js" charset="utf-8"></script>
|
||||||
<script type="text/javascript" src="https://unpkg.com/jsuri@1.3.1/Uri.js" charset="utf-8"></script>
|
<script type="text/javascript" src="https://unpkg.com/jsuri@1.3.1/Uri.js" charset="utf-8"></script>
|
||||||
<script type="text/javascript" src="https://unpkg.com/bignumber.js@4.1.0/bignumber.js" charset="utf-8"></script>
|
<script type="text/javascript" src="https://unpkg.com/bignumber.js@4.1.0/bignumber.js" charset="utf-8"></script>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Keyframes } from 'styled-components';
|
import { InterpolationValue } from 'styled-components';
|
||||||
|
|
||||||
|
import { media, OptionallyScreenSpecific, stylesForMedia } from '../../style/media';
|
||||||
import { css, keyframes, styled } from '../../style/theme';
|
import { css, keyframes, styled } from '../../style/theme';
|
||||||
|
|
||||||
export interface TransitionInfo {
|
export interface TransitionInfo {
|
||||||
@ -51,30 +52,59 @@ export interface PositionAnimationSettings {
|
|||||||
right?: TransitionInfo;
|
right?: TransitionInfo;
|
||||||
timingFunction: string;
|
timingFunction: string;
|
||||||
duration?: string;
|
duration?: string;
|
||||||
|
position?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PositionAnimationProps extends PositionAnimationSettings {
|
const generatePositionAnimationCss = (positionSettings: PositionAnimationSettings) => {
|
||||||
position: string;
|
return css`
|
||||||
|
animation-name: ${slideKeyframeGenerator(
|
||||||
|
positionSettings.position || 'relative',
|
||||||
|
positionSettings.top,
|
||||||
|
positionSettings.bottom,
|
||||||
|
positionSettings.left,
|
||||||
|
positionSettings.right,
|
||||||
|
)};
|
||||||
|
animation-duration: ${positionSettings.duration || '0.3s'};
|
||||||
|
animation-timing-function: ${positionSettings.timingFunction};
|
||||||
|
animation-delay: 0s;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
position: ${positionSettings.position || 'relative'};
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface PositionAnimationProps {
|
||||||
|
positionSettings: OptionallyScreenSpecific<PositionAnimationSettings>;
|
||||||
|
zIndex?: OptionallyScreenSpecific<number>;
|
||||||
|
height?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultAnimation = (positionSettings: OptionallyScreenSpecific<PositionAnimationSettings>) => {
|
||||||
|
const bestDefault = 'default' in positionSettings ? positionSettings.default : positionSettings;
|
||||||
|
return generatePositionAnimationCss(bestDefault);
|
||||||
|
};
|
||||||
|
const animationForSize = (
|
||||||
|
positionSettings: OptionallyScreenSpecific<PositionAnimationSettings>,
|
||||||
|
sizeKey: 'sm' | 'md' | 'lg',
|
||||||
|
mediaFn: (...args: any[]) => InterpolationValue[],
|
||||||
|
) => {
|
||||||
|
// checking default makes sure we have a PositionAnimationSettings object
|
||||||
|
// and then we check to see if we have a setting for the specific `sizeKey`
|
||||||
|
const animationSettingsForSize = 'default' in positionSettings && positionSettings[sizeKey];
|
||||||
|
return animationSettingsForSize && mediaFn`${generatePositionAnimationCss(animationSettingsForSize)}`;
|
||||||
|
};
|
||||||
|
|
||||||
export const PositionAnimation =
|
export const PositionAnimation =
|
||||||
styled.div <
|
styled.div <
|
||||||
PositionAnimationProps >
|
PositionAnimationProps >
|
||||||
`
|
`
|
||||||
animation-name: ${props =>
|
&& {
|
||||||
css`
|
${props => props.zIndex && stylesForMedia<number>('z-index', props.zIndex)}
|
||||||
${slideKeyframeGenerator(props.position, props.top, props.bottom, props.left, props.right)};
|
${props => defaultAnimation(props.positionSettings)}
|
||||||
`};
|
${props => animationForSize(props.positionSettings, 'sm', media.small)}
|
||||||
animation-duration: ${props => props.duration || '0.3s'};
|
${props => animationForSize(props.positionSettings, 'md', media.medium)}
|
||||||
animation-timing-function: ${props => props.timingFunction};
|
${props => animationForSize(props.positionSettings, 'lg', media.large)}
|
||||||
animation-delay: 0s;
|
${props => (props.height ? `height: ${props.height};` : '')}
|
||||||
animation-iteration-count: 1;
|
}
|
||||||
animation-fill-mode: forwards;
|
|
||||||
position: ${props => props.position};
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
PositionAnimation.defaultProps = {
|
|
||||||
position: 'relative',
|
|
||||||
};
|
|
||||||
|
@ -1,22 +1,25 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { OptionallyScreenSpecific } from '../../style/media';
|
||||||
|
|
||||||
import { PositionAnimation, PositionAnimationSettings } from './position_animation';
|
import { PositionAnimation, PositionAnimationSettings } from './position_animation';
|
||||||
|
|
||||||
export type SlideAnimationState = 'slidIn' | 'slidOut' | 'none';
|
export type SlideAnimationState = 'slidIn' | 'slidOut' | 'none';
|
||||||
export interface SlideAnimationProps {
|
export interface SlideAnimationProps {
|
||||||
position: string;
|
|
||||||
animationState: SlideAnimationState;
|
animationState: SlideAnimationState;
|
||||||
slideInSettings: PositionAnimationSettings;
|
slideInSettings: OptionallyScreenSpecific<PositionAnimationSettings>;
|
||||||
slideOutSettings: PositionAnimationSettings;
|
slideOutSettings: OptionallyScreenSpecific<PositionAnimationSettings>;
|
||||||
|
zIndex?: OptionallyScreenSpecific<number>;
|
||||||
|
height?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SlideAnimation: React.StatelessComponent<SlideAnimationProps> = props => {
|
export const SlideAnimation: React.StatelessComponent<SlideAnimationProps> = props => {
|
||||||
if (props.animationState === 'none') {
|
if (props.animationState === 'none') {
|
||||||
return <React.Fragment>{props.children}</React.Fragment>;
|
return <React.Fragment>{props.children}</React.Fragment>;
|
||||||
}
|
}
|
||||||
const propsToUse = props.animationState === 'slidIn' ? props.slideInSettings : props.slideOutSettings;
|
const positionSettings = props.animationState === 'slidIn' ? props.slideInSettings : props.slideOutSettings;
|
||||||
return (
|
return (
|
||||||
<PositionAnimation position={props.position} {...propsToUse}>
|
<PositionAnimation height={props.height} positionSettings={positionSettings} zIndex={props.zIndex}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</PositionAnimation>
|
</PositionAnimation>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
|
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
@ -7,17 +8,17 @@ import { oc } from 'ts-optchain';
|
|||||||
import { WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants';
|
import { WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants';
|
||||||
import { ColorOption } from '../style/theme';
|
import { ColorOption } from '../style/theme';
|
||||||
import { AffiliateInfo, ZeroExInstantError } from '../types';
|
import { AffiliateInfo, ZeroExInstantError } from '../types';
|
||||||
import { getBestAddress } from '../util/address';
|
|
||||||
import { balanceUtil } from '../util/balance';
|
|
||||||
import { gasPriceEstimator } from '../util/gas_price_estimator';
|
import { gasPriceEstimator } from '../util/gas_price_estimator';
|
||||||
import { util } from '../util/util';
|
import { util } from '../util/util';
|
||||||
|
|
||||||
import { Button } from './ui/button';
|
import { Button } from './ui/button';
|
||||||
import { Text } from './ui/text';
|
|
||||||
|
|
||||||
export interface BuyButtonProps {
|
export interface BuyButtonProps {
|
||||||
|
accountAddress?: string;
|
||||||
|
accountEthBalanceInWei?: BigNumber;
|
||||||
buyQuote?: BuyQuote;
|
buyQuote?: BuyQuote;
|
||||||
assetBuyer?: AssetBuyer;
|
assetBuyer: AssetBuyer;
|
||||||
|
web3Wrapper: Web3Wrapper;
|
||||||
affiliateInfo?: AffiliateInfo;
|
affiliateInfo?: AffiliateInfo;
|
||||||
onValidationPending: (buyQuote: BuyQuote) => void;
|
onValidationPending: (buyQuote: BuyQuote) => void;
|
||||||
onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void;
|
onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void;
|
||||||
@ -34,39 +35,41 @@ export class BuyButton extends React.Component<BuyButtonProps> {
|
|||||||
onBuyFailure: util.boundNoop,
|
onBuyFailure: util.boundNoop,
|
||||||
};
|
};
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const shouldDisableButton = _.isUndefined(this.props.buyQuote) || _.isUndefined(this.props.assetBuyer);
|
const { buyQuote, accountAddress } = this.props;
|
||||||
|
const shouldDisableButton = _.isUndefined(buyQuote) || _.isUndefined(accountAddress);
|
||||||
return (
|
return (
|
||||||
<Button width="100%" onClick={this._handleClick} isDisabled={shouldDisableButton}>
|
<Button
|
||||||
<Text fontColor={ColorOption.white} fontWeight={600} fontSize="20px">
|
width="100%"
|
||||||
|
onClick={this._handleClick}
|
||||||
|
isDisabled={shouldDisableButton}
|
||||||
|
fontColor={ColorOption.white}
|
||||||
|
fontSize="20px"
|
||||||
|
>
|
||||||
Buy
|
Buy
|
||||||
</Text>
|
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private readonly _handleClick = async () => {
|
private readonly _handleClick = async () => {
|
||||||
// The button is disabled when there is no buy quote anyway.
|
// The button is disabled when there is no buy quote anyway.
|
||||||
const { buyQuote, assetBuyer, affiliateInfo } = this.props;
|
const { buyQuote, assetBuyer, affiliateInfo, accountAddress, accountEthBalanceInWei, web3Wrapper } = this.props;
|
||||||
if (_.isUndefined(buyQuote) || _.isUndefined(assetBuyer)) {
|
if (_.isUndefined(buyQuote) || _.isUndefined(accountAddress)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.onValidationPending(buyQuote);
|
this.props.onValidationPending(buyQuote);
|
||||||
const web3Wrapper = new Web3Wrapper(assetBuyer.provider);
|
const ethNeededForBuy = buyQuote.worstCaseQuoteInfo.totalEthAmount;
|
||||||
const takerAddress = await getBestAddress(web3Wrapper);
|
// if we don't have a balance for the user, let the transaction through, it will be handled by the wallet
|
||||||
|
const hasSufficientEth = _.isUndefined(accountEthBalanceInWei) || accountEthBalanceInWei.gte(ethNeededForBuy);
|
||||||
const hasSufficientEth = await balanceUtil.hasSufficientEth(takerAddress, buyQuote, web3Wrapper);
|
|
||||||
if (!hasSufficientEth) {
|
if (!hasSufficientEth) {
|
||||||
this.props.onValidationFail(buyQuote, ZeroExInstantError.InsufficientETH);
|
this.props.onValidationFail(buyQuote, ZeroExInstantError.InsufficientETH);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let txHash: string | undefined;
|
let txHash: string | undefined;
|
||||||
const gasInfo = await gasPriceEstimator.getGasInfoAsync();
|
const gasInfo = await gasPriceEstimator.getGasInfoAsync();
|
||||||
const feeRecipient = oc(affiliateInfo).feeRecipient();
|
const feeRecipient = oc(affiliateInfo).feeRecipient();
|
||||||
try {
|
try {
|
||||||
txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote, {
|
txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote, {
|
||||||
feeRecipient,
|
feeRecipient,
|
||||||
takerAddress,
|
takerAddress: accountAddress,
|
||||||
gasPrice: gasInfo.gasPriceInWei,
|
gasPrice: gasInfo.gasPriceInWei,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -81,7 +84,6 @@ export class BuyButton extends React.Component<BuyButtonProps> {
|
|||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
const startTimeUnix = new Date().getTime();
|
const startTimeUnix = new Date().getTime();
|
||||||
const expectedEndTimeUnix = startTimeUnix + gasInfo.estimatedTimeMs;
|
const expectedEndTimeUnix = startTimeUnix + gasInfo.estimatedTimeMs;
|
||||||
this.props.onBuyProcessing(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix);
|
this.props.onBuyProcessing(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix);
|
||||||
@ -94,7 +96,6 @@ export class BuyButton extends React.Component<BuyButtonProps> {
|
|||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.onBuySuccess(buyQuote, txHash);
|
this.props.onBuySuccess(buyQuote, txHash);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,12 @@ export const BuyOrderProgress: React.StatelessComponent<BuyOrderProgressProps> =
|
|||||||
const { buyOrderState } = props;
|
const { buyOrderState } = props;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
buyOrderState.processState === OrderProcessState.PROCESSING ||
|
buyOrderState.processState === OrderProcessState.Processing ||
|
||||||
buyOrderState.processState === OrderProcessState.SUCCESS ||
|
buyOrderState.processState === OrderProcessState.Success ||
|
||||||
buyOrderState.processState === OrderProcessState.FAILURE
|
buyOrderState.processState === OrderProcessState.Failure
|
||||||
) {
|
) {
|
||||||
const progress = buyOrderState.progress;
|
const progress = buyOrderState.progress;
|
||||||
const hasEnded = buyOrderState.processState !== OrderProcessState.PROCESSING;
|
const hasEnded = buyOrderState.processState !== OrderProcessState.Processing;
|
||||||
const expectedTimeMs = progress.expectedEndTimeUnix - progress.startTimeUnix;
|
const expectedTimeMs = progress.expectedEndTimeUnix - progress.startTimeUnix;
|
||||||
return (
|
return (
|
||||||
<Container padding="20px 20px 0px 20px" width="100%">
|
<Container padding="20px 20px 0px 20px" width="100%">
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
|
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { ColorOption } from '../style/theme';
|
import { ColorOption } from '../style/theme';
|
||||||
@ -10,12 +12,14 @@ import { SecondaryButton } from './secondary_button';
|
|||||||
|
|
||||||
import { Button } from './ui/button';
|
import { Button } from './ui/button';
|
||||||
import { Flex } from './ui/flex';
|
import { Flex } from './ui/flex';
|
||||||
import { Text } from './ui/text';
|
|
||||||
|
|
||||||
export interface BuyOrderStateButtonProps {
|
export interface BuyOrderStateButtonProps {
|
||||||
|
accountAddress?: string;
|
||||||
|
accountEthBalanceInWei?: BigNumber;
|
||||||
buyQuote?: BuyQuote;
|
buyQuote?: BuyQuote;
|
||||||
buyOrderProcessingState: OrderProcessState;
|
buyOrderProcessingState: OrderProcessState;
|
||||||
assetBuyer?: AssetBuyer;
|
assetBuyer: AssetBuyer;
|
||||||
|
web3Wrapper: Web3Wrapper;
|
||||||
affiliateInfo?: AffiliateInfo;
|
affiliateInfo?: AffiliateInfo;
|
||||||
onViewTransaction: () => void;
|
onViewTransaction: () => void;
|
||||||
onValidationPending: (buyQuote: BuyQuote) => void;
|
onValidationPending: (buyQuote: BuyQuote) => void;
|
||||||
@ -28,13 +32,11 @@ export interface BuyOrderStateButtonProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonProps> = props => {
|
export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonProps> = props => {
|
||||||
if (props.buyOrderProcessingState === OrderProcessState.FAILURE) {
|
if (props.buyOrderProcessingState === OrderProcessState.Failure) {
|
||||||
return (
|
return (
|
||||||
<Flex justify="space-between">
|
<Flex justify="space-between">
|
||||||
<Button width="48%" onClick={props.onRetry}>
|
<Button width="48%" onClick={props.onRetry} fontColor={ColorOption.white} fontSize="16px">
|
||||||
<Text fontColor={ColorOption.white} fontWeight={600} fontSize="16px">
|
|
||||||
Back
|
Back
|
||||||
</Text>
|
|
||||||
</Button>
|
</Button>
|
||||||
<SecondaryButton width="48%" onClick={props.onViewTransaction}>
|
<SecondaryButton width="48%" onClick={props.onViewTransaction}>
|
||||||
Details
|
Details
|
||||||
@ -42,18 +44,21 @@ export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonP
|
|||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
props.buyOrderProcessingState === OrderProcessState.SUCCESS ||
|
props.buyOrderProcessingState === OrderProcessState.Success ||
|
||||||
props.buyOrderProcessingState === OrderProcessState.PROCESSING
|
props.buyOrderProcessingState === OrderProcessState.Processing
|
||||||
) {
|
) {
|
||||||
return <SecondaryButton onClick={props.onViewTransaction}>View Transaction</SecondaryButton>;
|
return <SecondaryButton onClick={props.onViewTransaction}>View Transaction</SecondaryButton>;
|
||||||
} else if (props.buyOrderProcessingState === OrderProcessState.VALIDATING) {
|
} else if (props.buyOrderProcessingState === OrderProcessState.Validating) {
|
||||||
return <PlacingOrderButton />;
|
return <PlacingOrderButton />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BuyButton
|
<BuyButton
|
||||||
|
accountAddress={props.accountAddress}
|
||||||
|
accountEthBalanceInWei={props.accountEthBalanceInWei}
|
||||||
buyQuote={props.buyQuote}
|
buyQuote={props.buyQuote}
|
||||||
assetBuyer={props.assetBuyer}
|
assetBuyer={props.assetBuyer}
|
||||||
|
web3Wrapper={props.web3Wrapper}
|
||||||
affiliateInfo={props.affiliateInfo}
|
affiliateInfo={props.affiliateInfo}
|
||||||
onValidationPending={props.onValidationPending}
|
onValidationPending={props.onValidationPending}
|
||||||
onValidationFail={props.onValidationFail}
|
onValidationFail={props.onValidationFail}
|
||||||
|
32
packages/instant/src/components/css_reset.tsx
Normal file
32
packages/instant/src/components/css_reset.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { INJECTED_DIV_CLASS } from '../constants';
|
||||||
|
import { createGlobalStyle } from '../style/theme';
|
||||||
|
|
||||||
|
export interface CSSResetProps {}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Derived from
|
||||||
|
* https://github.com/jtrost/Complete-CSS-Reset
|
||||||
|
*/
|
||||||
|
export const CSSReset = createGlobalStyle`
|
||||||
|
.${INJECTED_DIV_CLASS} {
|
||||||
|
a, abbr, area, article, aside, audio, b, bdo, blockquote, body, button,
|
||||||
|
canvas, caption, cite, code, col, colgroup, command, datalist, dd, del,
|
||||||
|
details, dialog, dfn, div, dl, dt, em, embed, fieldset, figure, form,
|
||||||
|
h1, h2, h3, h4, h5, h6, head, header, hgroup, hr, html, i, iframe, img,
|
||||||
|
input, ins, keygen, kbd, label, legend, li, map, mark, menu, meter, nav,
|
||||||
|
noscript, object, ol, optgroup, option, output, p, param, pre, progress,
|
||||||
|
q, rp, rt, ruby, samp, section, select, small, span, strong, sub, sup,
|
||||||
|
table, tbody, td, textarea, tfoot, th, thead, time, tr, ul, var, video {
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
margin: 0;
|
||||||
|
outline: none;
|
||||||
|
padding: 0;
|
||||||
|
text-align: left;
|
||||||
|
text-decoration: none;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
@ -113,7 +113,7 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Container marginLeft="5px">
|
<Container marginLeft="5px">
|
||||||
<Icon icon="chevron" width={12} onClick={this._handleSelectAssetClick} />
|
<Icon icon="chevron" width={12} stroke={ColorOption.white} onClick={this._handleSelectAssetClick} />
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -28,14 +28,14 @@ export class ERC20TokenSelector extends React.Component<ERC20TokenSelectorProps>
|
|||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const { tokens, onTokenSelect } = this.props;
|
const { tokens, onTokenSelect } = this.props;
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container height="100%">
|
||||||
<SearchInput
|
<SearchInput
|
||||||
placeholder="Search tokens..."
|
placeholder="Search tokens..."
|
||||||
width="100%"
|
width="100%"
|
||||||
value={this.state.searchQuery}
|
value={this.state.searchQuery}
|
||||||
onChange={this._handleSearchInputChange}
|
onChange={this._handleSearchInputChange}
|
||||||
/>
|
/>
|
||||||
<Container overflow="scroll" height="275px" marginTop="10px">
|
<Container overflow="scroll" height="calc(100% - 80px)" marginTop="10px">
|
||||||
{_.map(tokens, token => {
|
{_.map(tokens, token => {
|
||||||
if (!this._isTokenQueryMatch(token)) {
|
if (!this._isTokenQueryMatch(token)) {
|
||||||
return null;
|
return null;
|
||||||
@ -85,7 +85,7 @@ class TokenSelectorRow extends React.Component<TokenSelectorRowProps> {
|
|||||||
<Container marginLeft="5px">
|
<Container marginLeft="5px">
|
||||||
<Flex justify="flex-start">
|
<Flex justify="flex-start">
|
||||||
<Container marginRight="10px">
|
<Container marginRight="10px">
|
||||||
<Circle diameter={30} fillColor={token.metaData.primaryColor}>
|
<Circle diameter={30} rawColor={token.metaData.primaryColor}>
|
||||||
<Flex height="100%">
|
<Flex height="100%">
|
||||||
<Text fontColor={ColorOption.white} fontSize="8px">
|
<Text fontColor={ColorOption.white} fontSize="8px">
|
||||||
{displaySymbol}
|
{displaySymbol}
|
||||||
|
@ -77,11 +77,11 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
|
|||||||
private _renderIcon(): React.ReactNode {
|
private _renderIcon(): React.ReactNode {
|
||||||
const processState = this.props.buyOrderState.processState;
|
const processState = this.props.buyOrderState.processState;
|
||||||
|
|
||||||
if (processState === OrderProcessState.FAILURE) {
|
if (processState === OrderProcessState.Failure) {
|
||||||
return <Icon icon="failed" width={ICON_WIDTH} height={ICON_HEIGHT} color={ICON_COLOR} />;
|
return <Icon icon="failed" width={ICON_WIDTH} height={ICON_HEIGHT} color={ICON_COLOR} />;
|
||||||
} else if (processState === OrderProcessState.PROCESSING) {
|
} else if (processState === OrderProcessState.Processing) {
|
||||||
return <Spinner widthPx={ICON_HEIGHT} heightPx={ICON_HEIGHT} />;
|
return <Spinner widthPx={ICON_HEIGHT} heightPx={ICON_HEIGHT} />;
|
||||||
} else if (processState === OrderProcessState.SUCCESS) {
|
} else if (processState === OrderProcessState.Success) {
|
||||||
return <Icon icon="success" width={ICON_WIDTH} height={ICON_HEIGHT} color={ICON_COLOR} />;
|
return <Icon icon="success" width={ICON_WIDTH} height={ICON_HEIGHT} color={ICON_COLOR} />;
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -89,11 +89,11 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
|
|||||||
|
|
||||||
private _renderTopText(): React.ReactNode {
|
private _renderTopText(): React.ReactNode {
|
||||||
const processState = this.props.buyOrderState.processState;
|
const processState = this.props.buyOrderState.processState;
|
||||||
if (processState === OrderProcessState.FAILURE) {
|
if (processState === OrderProcessState.Failure) {
|
||||||
return 'Order failed';
|
return 'Order failed';
|
||||||
} else if (processState === OrderProcessState.PROCESSING) {
|
} else if (processState === OrderProcessState.Processing) {
|
||||||
return 'Processing Order...';
|
return 'Processing Order...';
|
||||||
} else if (processState === OrderProcessState.SUCCESS) {
|
} else if (processState === OrderProcessState.Success) {
|
||||||
return 'Tokens received!';
|
return 'Tokens received!';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _renderPlaceholderOrAmount(amountFunction: () => React.ReactNode): React.ReactNode {
|
private _renderPlaceholderOrAmount(amountFunction: () => React.ReactNode): React.ReactNode {
|
||||||
if (this.props.quoteRequestState === AsyncProcessState.PENDING) {
|
if (this.props.quoteRequestState === AsyncProcessState.Pending) {
|
||||||
return <AmountPlaceholder isPulsating={true} color={PLACEHOLDER_COLOR} />;
|
return <AmountPlaceholder isPulsating={true} color={PLACEHOLDER_COLOR} />;
|
||||||
}
|
}
|
||||||
if (_.isUndefined(this.props.selectedAssetAmount)) {
|
if (_.isUndefined(this.props.selectedAssetAmount)) {
|
||||||
|
@ -26,7 +26,7 @@ export class OrderDetails extends React.Component<OrderDetailsProps> {
|
|||||||
const ethTokenFee = buyQuoteAccessor.feeEthAmount();
|
const ethTokenFee = buyQuoteAccessor.feeEthAmount();
|
||||||
const totalEthAmount = buyQuoteAccessor.totalEthAmount();
|
const totalEthAmount = buyQuoteAccessor.totalEthAmount();
|
||||||
return (
|
return (
|
||||||
<Container padding="20px" width="100%">
|
<Container padding="20px" width="100%" flexGrow={1}>
|
||||||
<Container marginBottom="10px">
|
<Container marginBottom="10px">
|
||||||
<Text
|
<Text
|
||||||
letterSpacing="1px"
|
letterSpacing="1px"
|
||||||
|
45
packages/instant/src/components/payment_method.tsx
Normal file
45
packages/instant/src/components/payment_method.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { ColorOption } from '../style/theme';
|
||||||
|
import { Network } from '../types';
|
||||||
|
|
||||||
|
import { PaymentMethodDropdown } from './payment_method_dropdown';
|
||||||
|
import { Circle } from './ui/circle';
|
||||||
|
import { Container } from './ui/container';
|
||||||
|
import { Flex } from './ui/flex';
|
||||||
|
import { Text } from './ui/text';
|
||||||
|
|
||||||
|
export interface PaymentMethodProps {}
|
||||||
|
|
||||||
|
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} />
|
||||||
|
<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}
|
||||||
|
/>
|
||||||
|
</Container>
|
||||||
|
);
|
44
packages/instant/src/components/payment_method_dropdown.tsx
Normal file
44
packages/instant/src/components/payment_method_dropdown.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import copy from 'copy-to-clipboard';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { Network } from '../types';
|
||||||
|
import { etherscanUtil } from '../util/etherscan';
|
||||||
|
import { format } from '../util/format';
|
||||||
|
|
||||||
|
import { Dropdown, DropdownItemConfig } from './ui/dropdown';
|
||||||
|
|
||||||
|
export interface PaymentMethodDropdownProps {
|
||||||
|
accountAddress: string;
|
||||||
|
accountEthBalanceInWei?: BigNumber;
|
||||||
|
network: Network;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PaymentMethodDropdown extends React.Component<PaymentMethodDropdownProps> {
|
||||||
|
public render(): React.ReactNode {
|
||||||
|
const { accountAddress, accountEthBalanceInWei } = this.props;
|
||||||
|
const value = format.ethAddress(accountAddress);
|
||||||
|
const label = format.ethBaseAmount(accountEthBalanceInWei, 4, '') as string;
|
||||||
|
return <Dropdown value={value} label={label} items={this._getDropdownItemConfigs()} />;
|
||||||
|
}
|
||||||
|
private readonly _getDropdownItemConfigs = (): DropdownItemConfig[] => {
|
||||||
|
const viewOnEtherscan = {
|
||||||
|
text: 'View on Etherscan',
|
||||||
|
onClick: this._handleEtherscanClick,
|
||||||
|
};
|
||||||
|
const copyAddressToClipboard = {
|
||||||
|
text: 'Copy address to clipboard',
|
||||||
|
onClick: this._handleCopyToClipboardClick,
|
||||||
|
};
|
||||||
|
return [viewOnEtherscan, copyAddressToClipboard];
|
||||||
|
};
|
||||||
|
private readonly _handleEtherscanClick = (): void => {
|
||||||
|
const { accountAddress, network } = this.props;
|
||||||
|
const etherscanUrl = etherscanUtil.getEtherScanEthAddressIfExists(accountAddress, network);
|
||||||
|
window.open(etherscanUrl, '_blank');
|
||||||
|
};
|
||||||
|
private readonly _handleCopyToClipboardClick = (): void => {
|
||||||
|
const { accountAddress } = this.props;
|
||||||
|
copy(accountAddress);
|
||||||
|
};
|
||||||
|
}
|
@ -5,15 +5,12 @@ import { ColorOption } from '../style/theme';
|
|||||||
import { Button } from './ui/button';
|
import { Button } from './ui/button';
|
||||||
import { Container } from './ui/container';
|
import { Container } from './ui/container';
|
||||||
import { Spinner } from './ui/spinner';
|
import { Spinner } from './ui/spinner';
|
||||||
import { Text } from './ui/text';
|
|
||||||
|
|
||||||
export const PlacingOrderButton: React.StatelessComponent<{}> = props => (
|
export const PlacingOrderButton: React.StatelessComponent<{}> = props => (
|
||||||
<Button isDisabled={true} width="100%">
|
<Button isDisabled={true} width="100%" fontColor={ColorOption.white} fontSize="20px">
|
||||||
<Container display="inline-block" position="relative" top="3px" marginRight="8px">
|
<Container display="inline-block" position="relative" top="3px" marginRight="8px">
|
||||||
<Spinner widthPx={20} heightPx={20} />
|
<Spinner widthPx={20} heightPx={20} />
|
||||||
</Container>
|
</Container>
|
||||||
<Text fontColor={ColorOption.white} fontWeight={600} fontSize="20px">
|
|
||||||
Placing Order…
|
Placing Order…
|
||||||
</Text>
|
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,6 @@ import * as React from 'react';
|
|||||||
import { ColorOption } from '../style/theme';
|
import { ColorOption } from '../style/theme';
|
||||||
|
|
||||||
import { Button, ButtonProps } from './ui/button';
|
import { Button, ButtonProps } from './ui/button';
|
||||||
import { Text } from './ui/text';
|
|
||||||
|
|
||||||
export interface SecondaryButtonProps extends ButtonProps {}
|
export interface SecondaryButtonProps extends ButtonProps {}
|
||||||
|
|
||||||
@ -16,11 +15,11 @@ export const SecondaryButton: React.StatelessComponent<SecondaryButtonProps> = p
|
|||||||
borderColor={ColorOption.lightGrey}
|
borderColor={ColorOption.lightGrey}
|
||||||
width={props.width}
|
width={props.width}
|
||||||
onClick={props.onClick}
|
onClick={props.onClick}
|
||||||
|
fontColor={ColorOption.primaryColor}
|
||||||
|
fontSize="16px"
|
||||||
{...buttonProps}
|
{...buttonProps}
|
||||||
>
|
>
|
||||||
<Text fontColor={ColorOption.primaryColor} fontWeight={600} fontSize="16px">
|
|
||||||
{props.children}
|
{props.children}
|
||||||
</Text>
|
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { ScreenSpecification } from '../style/media';
|
||||||
import { ColorOption } from '../style/theme';
|
import { ColorOption } from '../style/theme';
|
||||||
|
import { zIndex } from '../style/z_index';
|
||||||
|
|
||||||
import { PositionAnimationSettings } from './animations/position_animation';
|
import { PositionAnimationSettings } from './animations/position_animation';
|
||||||
import { SlideAnimation, SlideAnimationState } from './animations/slide_animation';
|
import { SlideAnimation, SlideAnimationState } from './animations/slide_animation';
|
||||||
@ -21,6 +23,7 @@ export const Error: React.StatelessComponent<ErrorProps> = props => (
|
|||||||
backgroundColor={ColorOption.lightOrange}
|
backgroundColor={ColorOption.lightOrange}
|
||||||
width="100%"
|
width="100%"
|
||||||
borderRadius="6px"
|
borderRadius="6px"
|
||||||
|
marginTop="10px"
|
||||||
marginBottom="10px"
|
marginBottom="10px"
|
||||||
>
|
>
|
||||||
<Flex justify="flex-start">
|
<Flex justify="flex-start">
|
||||||
@ -39,25 +42,51 @@ export interface SlidingErrorProps extends ErrorProps {
|
|||||||
}
|
}
|
||||||
export const SlidingError: React.StatelessComponent<SlidingErrorProps> = props => {
|
export const SlidingError: React.StatelessComponent<SlidingErrorProps> = props => {
|
||||||
const slideAmount = '120px';
|
const slideAmount = '120px';
|
||||||
const slideUpSettings: PositionAnimationSettings = {
|
|
||||||
|
const desktopSlideIn: PositionAnimationSettings = {
|
||||||
timingFunction: 'ease-in',
|
timingFunction: 'ease-in',
|
||||||
top: {
|
top: {
|
||||||
from: slideAmount,
|
from: slideAmount,
|
||||||
to: '0px',
|
to: '0px',
|
||||||
},
|
},
|
||||||
|
position: 'relative',
|
||||||
};
|
};
|
||||||
const slideDownSettings: PositionAnimationSettings = {
|
const desktopSlideOut: PositionAnimationSettings = {
|
||||||
timingFunction: 'cubic-bezier(0.25, 0.1, 0.25, 1)',
|
timingFunction: 'cubic-bezier(0.25, 0.1, 0.25, 1)',
|
||||||
top: {
|
top: {
|
||||||
from: '0px',
|
from: '0px',
|
||||||
to: slideAmount,
|
to: slideAmount,
|
||||||
},
|
},
|
||||||
|
position: 'relative',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mobileSlideIn: PositionAnimationSettings = {
|
||||||
|
duration: '0.5s',
|
||||||
|
timingFunction: 'ease-in',
|
||||||
|
top: { from: '-120px', to: '0px' },
|
||||||
|
position: 'fixed',
|
||||||
|
};
|
||||||
|
const moblieSlideOut: PositionAnimationSettings = {
|
||||||
|
duration: '0.5s',
|
||||||
|
timingFunction: 'ease-in',
|
||||||
|
top: { from: '0px', to: '-120px' },
|
||||||
|
position: 'fixed',
|
||||||
|
};
|
||||||
|
|
||||||
|
const slideUpSettings: ScreenSpecification<PositionAnimationSettings> = {
|
||||||
|
default: desktopSlideIn,
|
||||||
|
sm: mobileSlideIn,
|
||||||
|
};
|
||||||
|
const slideOutSettings: ScreenSpecification<PositionAnimationSettings> = {
|
||||||
|
default: desktopSlideOut,
|
||||||
|
sm: moblieSlideOut,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SlideAnimation
|
<SlideAnimation
|
||||||
position="relative"
|
|
||||||
slideInSettings={slideUpSettings}
|
slideInSettings={slideUpSettings}
|
||||||
slideOutSettings={slideDownSettings}
|
slideOutSettings={slideOutSettings}
|
||||||
|
zIndex={{ sm: zIndex.errorPopup, default: zIndex.errorPopBehind }}
|
||||||
animationState={props.animationState}
|
animationState={props.animationState}
|
||||||
>
|
>
|
||||||
<Error icon={props.icon} message={props.message} />
|
<Error icon={props.icon} message={props.message} />
|
||||||
|
@ -30,7 +30,9 @@ export const Panel: React.StatelessComponent<PanelProps> = ({ title, children, o
|
|||||||
<Icon width={12} color={ColorOption.lightGrey} icon="closeX" onClick={onClose} />
|
<Icon width={12} color={ColorOption.lightGrey} icon="closeX" onClick={onClose} />
|
||||||
</Container>
|
</Container>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Container marginTop="10px">{children}</Container>
|
<Container marginTop="10px" height="100%">
|
||||||
|
{children}
|
||||||
|
</Container>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -51,6 +53,7 @@ export const SlidingPanel: React.StatelessComponent<SlidingPanelProps> = props =
|
|||||||
from: slideAmount,
|
from: slideAmount,
|
||||||
to: '0px',
|
to: '0px',
|
||||||
},
|
},
|
||||||
|
position: 'absolute',
|
||||||
};
|
};
|
||||||
const slideDownSettings: PositionAnimationSettings = {
|
const slideDownSettings: PositionAnimationSettings = {
|
||||||
duration: '0.3s',
|
duration: '0.3s',
|
||||||
@ -59,13 +62,14 @@ export const SlidingPanel: React.StatelessComponent<SlidingPanelProps> = props =
|
|||||||
from: '0px',
|
from: '0px',
|
||||||
to: slideAmount,
|
to: slideAmount,
|
||||||
},
|
},
|
||||||
|
position: 'absolute',
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<SlideAnimation
|
<SlideAnimation
|
||||||
position="absolute"
|
|
||||||
slideInSettings={slideUpSettings}
|
slideInSettings={slideUpSettings}
|
||||||
slideOutSettings={slideDownSettings}
|
slideOutSettings={slideDownSettings}
|
||||||
animationState={animationState}
|
animationState={animationState}
|
||||||
|
height="100%"
|
||||||
>
|
>
|
||||||
<Panel {...rest} />
|
<Panel {...rest} />
|
||||||
</SlideAnimation>
|
</SlideAnimation>
|
||||||
|
@ -70,9 +70,11 @@ export const TimedProgress =
|
|||||||
styled.div <
|
styled.div <
|
||||||
TimedProgressProps >
|
TimedProgressProps >
|
||||||
`
|
`
|
||||||
|
&& {
|
||||||
background-color: ${props => props.theme[ColorOption.primaryColor]};
|
background-color: ${props => props.theme[ColorOption.primaryColor]};
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
animation: ${props => expandingWidthKeyframes(props.fromWidth, props.toWidth)}
|
animation: ${props => expandingWidthKeyframes(props.fromWidth, props.toWidth)}
|
||||||
${props => props.timeMs}ms linear 1 forwards;
|
${props => props.timeMs}ms linear 1 forwards;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -6,6 +6,8 @@ import { ColorOption, styled } from '../../style/theme';
|
|||||||
export interface ButtonProps {
|
export interface ButtonProps {
|
||||||
backgroundColor?: ColorOption;
|
backgroundColor?: ColorOption;
|
||||||
borderColor?: ColorOption;
|
borderColor?: ColorOption;
|
||||||
|
fontColor?: ColorOption;
|
||||||
|
fontSize?: string;
|
||||||
width?: string;
|
width?: string;
|
||||||
padding?: string;
|
padding?: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
@ -24,10 +26,18 @@ const darkenOnHoverAmount = 0.1;
|
|||||||
const darkenOnActiveAmount = 0.2;
|
const darkenOnActiveAmount = 0.2;
|
||||||
const saturateOnFocusAmount = 0.2;
|
const saturateOnFocusAmount = 0.2;
|
||||||
export const Button = styled(PlainButton)`
|
export const Button = styled(PlainButton)`
|
||||||
|
&& {
|
||||||
|
all: initial;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: ${props => props.fontSize};
|
||||||
|
font-family: 'Inter UI', sans-serif;
|
||||||
|
font-weight: 600;
|
||||||
|
color: ${props => props.fontColor && props.theme[props.fontColor]};
|
||||||
cursor: ${props => (props.isDisabled ? 'default' : 'pointer')};
|
cursor: ${props => (props.isDisabled ? 'default' : 'pointer')};
|
||||||
transition: background-color, opacity 0.5s ease;
|
transition: background-color, opacity 0.5s ease;
|
||||||
padding: ${props => props.padding};
|
padding: ${props => props.padding};
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
text-align: center;
|
||||||
outline: none;
|
outline: none;
|
||||||
width: ${props => props.width};
|
width: ${props => props.width};
|
||||||
background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
|
background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
|
||||||
@ -46,7 +56,9 @@ export const Button = styled(PlainButton)`
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
&:focus {
|
&:focus {
|
||||||
background-color: ${props => saturate(saturateOnFocusAmount, props.theme[props.backgroundColor || 'white'])};
|
background-color: ${props =>
|
||||||
|
saturate(saturateOnFocusAmount, props.theme[props.backgroundColor || 'white'])};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -55,7 +67,8 @@ Button.defaultProps = {
|
|||||||
borderColor: ColorOption.primaryColor,
|
borderColor: ColorOption.primaryColor,
|
||||||
width: 'auto',
|
width: 'auto',
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
padding: '1em 2.2em',
|
padding: '.6em 1.2em',
|
||||||
|
fontSize: '15px',
|
||||||
};
|
};
|
||||||
|
|
||||||
Button.displayName = 'Button';
|
Button.displayName = 'Button';
|
||||||
|
@ -1,22 +1,27 @@
|
|||||||
import { styled } from '../../style/theme';
|
import { ColorOption, styled, Theme, withTheme } from '../../style/theme';
|
||||||
|
|
||||||
export interface CircleProps {
|
export interface CircleProps {
|
||||||
diameter: number;
|
diameter: number;
|
||||||
fillColor?: string;
|
rawColor?: string;
|
||||||
|
color?: ColorOption;
|
||||||
|
theme: Theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Circle =
|
export const Circle = withTheme(
|
||||||
styled.div <
|
styled.div <
|
||||||
CircleProps >
|
CircleProps >
|
||||||
`
|
`
|
||||||
|
&& {
|
||||||
width: ${props => props.diameter}px;
|
width: ${props => props.diameter}px;
|
||||||
height: ${props => props.diameter}px;
|
height: ${props => props.diameter}px;
|
||||||
background-color: ${props => props.fillColor};
|
background-color: ${props => (props.rawColor ? props.rawColor : props.theme[props.color || ColorOption.white])};
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
`;
|
}
|
||||||
|
`,
|
||||||
|
);
|
||||||
|
|
||||||
Circle.displayName = 'Circle';
|
Circle.displayName = 'Circle';
|
||||||
|
|
||||||
Circle.defaultProps = {
|
Circle.defaultProps = {
|
||||||
fillColor: 'white',
|
color: ColorOption.white,
|
||||||
};
|
};
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
import { darken } from 'polished';
|
import { darken } from 'polished';
|
||||||
|
|
||||||
|
import { MediaChoice, stylesForMedia } from '../../style/media';
|
||||||
import { ColorOption, styled } from '../../style/theme';
|
import { ColorOption, styled } from '../../style/theme';
|
||||||
import { cssRuleIfExists } from '../../style/util';
|
import { cssRuleIfExists } from '../../style/util';
|
||||||
|
|
||||||
export interface ContainerProps {
|
export interface ContainerProps {
|
||||||
display?: string;
|
display?: MediaChoice;
|
||||||
position?: string;
|
position?: string;
|
||||||
top?: string;
|
top?: string;
|
||||||
right?: string;
|
right?: string;
|
||||||
bottom?: string;
|
bottom?: string;
|
||||||
left?: string;
|
left?: string;
|
||||||
width?: string;
|
width?: MediaChoice;
|
||||||
height?: string;
|
height?: MediaChoice;
|
||||||
maxWidth?: string;
|
maxWidth?: string;
|
||||||
margin?: string;
|
margin?: string;
|
||||||
marginTop?: string;
|
marginTop?: string;
|
||||||
@ -33,21 +34,22 @@ export interface ContainerProps {
|
|||||||
cursor?: string;
|
cursor?: string;
|
||||||
overflow?: string;
|
overflow?: string;
|
||||||
darkenOnHover?: boolean;
|
darkenOnHover?: boolean;
|
||||||
|
boxShadowOnHover?: boolean;
|
||||||
|
flexGrow?: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Container =
|
export const Container =
|
||||||
styled.div <
|
styled.div <
|
||||||
ContainerProps >
|
ContainerProps >
|
||||||
`
|
`
|
||||||
|
&& {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
${props => cssRuleIfExists(props, 'display')}
|
${props => cssRuleIfExists(props, 'flex-grow')}
|
||||||
${props => cssRuleIfExists(props, 'position')}
|
${props => cssRuleIfExists(props, 'position')}
|
||||||
${props => cssRuleIfExists(props, 'top')}
|
${props => cssRuleIfExists(props, 'top')}
|
||||||
${props => cssRuleIfExists(props, 'right')}
|
${props => cssRuleIfExists(props, 'right')}
|
||||||
${props => cssRuleIfExists(props, 'bottom')}
|
${props => cssRuleIfExists(props, 'bottom')}
|
||||||
${props => cssRuleIfExists(props, 'left')}
|
${props => cssRuleIfExists(props, 'left')}
|
||||||
${props => cssRuleIfExists(props, 'width')}
|
|
||||||
${props => cssRuleIfExists(props, 'height')}
|
|
||||||
${props => cssRuleIfExists(props, 'max-width')}
|
${props => cssRuleIfExists(props, 'max-width')}
|
||||||
${props => cssRuleIfExists(props, 'margin')}
|
${props => cssRuleIfExists(props, 'margin')}
|
||||||
${props => cssRuleIfExists(props, 'margin-top')}
|
${props => cssRuleIfExists(props, 'margin-top')}
|
||||||
@ -65,6 +67,9 @@ export const Container =
|
|||||||
${props => cssRuleIfExists(props, 'cursor')}
|
${props => cssRuleIfExists(props, 'cursor')}
|
||||||
${props => cssRuleIfExists(props, 'overflow')}
|
${props => cssRuleIfExists(props, 'overflow')}
|
||||||
${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')};
|
${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')};
|
||||||
|
${props => props.display && stylesForMedia<string>('display', props.display)}
|
||||||
|
${props => props.width && stylesForMedia<string>('width', props.width)}
|
||||||
|
${props => props.height && stylesForMedia<string>('height', props.height)}
|
||||||
background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
|
background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
|
||||||
border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')};
|
border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')};
|
||||||
&:hover {
|
&:hover {
|
||||||
@ -74,6 +79,8 @@ export const Container =
|
|||||||
props.backgroundColor ? darken(0.05, props.theme[props.backgroundColor]) : 'none'
|
props.backgroundColor ? darken(0.05, props.theme[props.backgroundColor]) : 'none'
|
||||||
}`
|
}`
|
||||||
: ''};
|
: ''};
|
||||||
|
${props => (props.boxShadowOnHover ? 'box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)' : '')};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
134
packages/instant/src/components/ui/dropdown.tsx
Normal file
134
packages/instant/src/components/ui/dropdown.tsx
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
import * as _ from 'lodash';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { ColorOption, completelyTransparent } from '../../style/theme';
|
||||||
|
import { zIndex } from '../../style/z_index';
|
||||||
|
|
||||||
|
import { Container } from './container';
|
||||||
|
import { Flex } from './flex';
|
||||||
|
import { Icon } from './icon';
|
||||||
|
import { Overlay } from './overlay';
|
||||||
|
import { Text } from './text';
|
||||||
|
|
||||||
|
export interface DropdownItemConfig {
|
||||||
|
text: string;
|
||||||
|
onClick?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DropdownProps {
|
||||||
|
value: string;
|
||||||
|
label?: string;
|
||||||
|
items: DropdownItemConfig[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DropdownState {
|
||||||
|
isOpen: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Dropdown extends React.Component<DropdownProps, DropdownState> {
|
||||||
|
public static defaultProps = {
|
||||||
|
items: [],
|
||||||
|
};
|
||||||
|
public state: DropdownState = {
|
||||||
|
isOpen: false,
|
||||||
|
};
|
||||||
|
public render(): React.ReactNode {
|
||||||
|
const { value, label, items } = this.props;
|
||||||
|
const { isOpen } = this.state;
|
||||||
|
const hasItems = !_.isEmpty(items);
|
||||||
|
const borderRadius = isOpen ? '4px 4px 0px 0px' : '4px';
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{isOpen && (
|
||||||
|
<Overlay
|
||||||
|
zIndex={zIndex.dropdownItems - 1}
|
||||||
|
backgroundColor={completelyTransparent}
|
||||||
|
onClick={this._closeDropdown}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Container position="relative">
|
||||||
|
<Container
|
||||||
|
cursor={hasItems ? 'pointer' : undefined}
|
||||||
|
onClick={this._handleDropdownClick}
|
||||||
|
hasBoxShadow={isOpen}
|
||||||
|
boxShadowOnHover={true}
|
||||||
|
borderRadius={borderRadius}
|
||||||
|
border="1px solid"
|
||||||
|
borderColor={ColorOption.feintGrey}
|
||||||
|
padding="0.8em"
|
||||||
|
>
|
||||||
|
<Flex justify="space-between">
|
||||||
|
<Text fontSize="16px" fontColor={ColorOption.darkGrey}>
|
||||||
|
{value}
|
||||||
|
</Text>
|
||||||
|
<Container>
|
||||||
|
{label && (
|
||||||
|
<Text fontSize="16px" fontColor={ColorOption.lightGrey}>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
{hasItems && (
|
||||||
|
<Container marginLeft="5px" display="inline-block" position="relative" bottom="2px">
|
||||||
|
<Icon padding="3px" icon="chevron" width={12} stroke={ColorOption.grey} />
|
||||||
|
</Container>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
|
</Flex>
|
||||||
|
</Container>
|
||||||
|
{isOpen && (
|
||||||
|
<Container
|
||||||
|
width="100%"
|
||||||
|
position="absolute"
|
||||||
|
onClick={this._closeDropdown}
|
||||||
|
backgroundColor={ColorOption.white}
|
||||||
|
hasBoxShadow={true}
|
||||||
|
zIndex={zIndex.dropdownItems}
|
||||||
|
>
|
||||||
|
{_.map(items, (item, index) => (
|
||||||
|
<DropdownItem key={item.text} {...item} isLast={index === items.length - 1} />
|
||||||
|
))}
|
||||||
|
</Container>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private readonly _handleDropdownClick = (): void => {
|
||||||
|
if (_.isEmpty(this.props.items)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
isOpen: !this.state.isOpen,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
private readonly _closeDropdown = (): void => {
|
||||||
|
this.setState({
|
||||||
|
isOpen: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DropdownItemProps extends DropdownItemConfig {
|
||||||
|
text: string;
|
||||||
|
onClick?: () => void;
|
||||||
|
isLast: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DropdownItem: React.StatelessComponent<DropdownItemProps> = ({ text, onClick, isLast }) => (
|
||||||
|
<Container
|
||||||
|
onClick={onClick}
|
||||||
|
cursor="pointer"
|
||||||
|
darkenOnHover={true}
|
||||||
|
backgroundColor={ColorOption.white}
|
||||||
|
padding="0.8em"
|
||||||
|
borderTop="0"
|
||||||
|
border="1px solid"
|
||||||
|
borderRadius={isLast ? '0px 0px 4px 4px' : undefined}
|
||||||
|
width="100%"
|
||||||
|
borderColor={ColorOption.feintGrey}
|
||||||
|
>
|
||||||
|
<Text fontSize="14px" fontColor={ColorOption.darkGrey}>
|
||||||
|
{text}
|
||||||
|
</Text>
|
||||||
|
</Container>
|
||||||
|
);
|
@ -1,3 +1,4 @@
|
|||||||
|
import { MediaChoice, stylesForMedia } from '../../style/media';
|
||||||
import { ColorOption, styled } from '../../style/theme';
|
import { ColorOption, styled } from '../../style/theme';
|
||||||
import { cssRuleIfExists } from '../../style/util';
|
import { cssRuleIfExists } from '../../style/util';
|
||||||
|
|
||||||
@ -6,24 +7,28 @@ export interface FlexProps {
|
|||||||
flexWrap?: 'wrap' | 'nowrap';
|
flexWrap?: 'wrap' | 'nowrap';
|
||||||
justify?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end';
|
justify?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end';
|
||||||
align?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end';
|
align?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end';
|
||||||
width?: string;
|
width?: MediaChoice;
|
||||||
height?: string;
|
height?: MediaChoice;
|
||||||
backgroundColor?: ColorOption;
|
backgroundColor?: ColorOption;
|
||||||
inline?: boolean;
|
inline?: boolean;
|
||||||
|
flexGrow?: number | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Flex =
|
export const Flex =
|
||||||
styled.div <
|
styled.div <
|
||||||
FlexProps >
|
FlexProps >
|
||||||
`
|
`
|
||||||
|
&& {
|
||||||
display: ${props => (props.inline ? 'inline-flex' : 'flex')};
|
display: ${props => (props.inline ? 'inline-flex' : 'flex')};
|
||||||
flex-direction: ${props => props.direction};
|
flex-direction: ${props => props.direction};
|
||||||
flex-wrap: ${props => props.flexWrap};
|
flex-wrap: ${props => props.flexWrap};
|
||||||
|
${props => cssRuleIfExists(props, 'flexGrow')}
|
||||||
justify-content: ${props => props.justify};
|
justify-content: ${props => props.justify};
|
||||||
align-items: ${props => props.align};
|
align-items: ${props => props.align};
|
||||||
${props => cssRuleIfExists(props, 'width')}
|
|
||||||
${props => cssRuleIfExists(props, 'height')}
|
|
||||||
background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
|
background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
|
||||||
|
${props => (props.width ? stylesForMedia('width', props.width) : '')}
|
||||||
|
${props => (props.height ? stylesForMedia('height', props.height) : '')}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Flex.defaultProps = {
|
Flex.defaultProps = {
|
||||||
|
@ -9,7 +9,6 @@ interface IconInfo {
|
|||||||
path: string;
|
path: string;
|
||||||
fillRule?: svgRule;
|
fillRule?: svgRule;
|
||||||
clipRule?: svgRule;
|
clipRule?: svgRule;
|
||||||
stroke?: string;
|
|
||||||
strokeOpacity?: number;
|
strokeOpacity?: number;
|
||||||
strokeWidth?: number;
|
strokeWidth?: number;
|
||||||
strokeLinecap?: 'butt' | 'round' | 'square' | 'inherit';
|
strokeLinecap?: 'butt' | 'round' | 'square' | 'inherit';
|
||||||
@ -47,7 +46,6 @@ const ICONS: IconInfoMapping = {
|
|||||||
chevron: {
|
chevron: {
|
||||||
viewBox: '0 0 12 7',
|
viewBox: '0 0 12 7',
|
||||||
path: 'M11 1L6 6L1 1',
|
path: 'M11 1L6 6L1 1',
|
||||||
stroke: 'white',
|
|
||||||
strokeOpacity: 0.5,
|
strokeOpacity: 0.5,
|
||||||
strokeWidth: 1.5,
|
strokeWidth: 1.5,
|
||||||
strokeLinecap: 'round',
|
strokeLinecap: 'round',
|
||||||
@ -67,6 +65,7 @@ export interface IconProps {
|
|||||||
width: number;
|
width: number;
|
||||||
height?: number;
|
height?: number;
|
||||||
color?: ColorOption;
|
color?: ColorOption;
|
||||||
|
stroke?: ColorOption;
|
||||||
icon: keyof IconInfoMapping;
|
icon: keyof IconInfoMapping;
|
||||||
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
||||||
padding?: string;
|
padding?: string;
|
||||||
@ -75,6 +74,7 @@ export interface IconProps {
|
|||||||
const PlainIcon: React.StatelessComponent<IconProps> = props => {
|
const PlainIcon: React.StatelessComponent<IconProps> = props => {
|
||||||
const iconInfo = ICONS[props.icon];
|
const iconInfo = ICONS[props.icon];
|
||||||
const colorValue = _.isUndefined(props.color) ? undefined : props.theme[props.color];
|
const colorValue = _.isUndefined(props.color) ? undefined : props.theme[props.color];
|
||||||
|
const strokeValue = _.isUndefined(props.stroke) ? undefined : props.theme[props.stroke];
|
||||||
return (
|
return (
|
||||||
<div onClick={props.onClick} className={props.className}>
|
<div onClick={props.onClick} className={props.className}>
|
||||||
<svg
|
<svg
|
||||||
@ -89,7 +89,7 @@ const PlainIcon: React.StatelessComponent<IconProps> = props => {
|
|||||||
fill={colorValue}
|
fill={colorValue}
|
||||||
fillRule={iconInfo.fillRule || 'nonzero'}
|
fillRule={iconInfo.fillRule || 'nonzero'}
|
||||||
clipRule={iconInfo.clipRule || 'nonzero'}
|
clipRule={iconInfo.clipRule || 'nonzero'}
|
||||||
stroke={iconInfo.stroke}
|
stroke={strokeValue}
|
||||||
strokeOpacity={iconInfo.strokeOpacity}
|
strokeOpacity={iconInfo.strokeOpacity}
|
||||||
strokeWidth={iconInfo.strokeWidth}
|
strokeWidth={iconInfo.strokeWidth}
|
||||||
strokeLinecap={iconInfo.strokeLinecap}
|
strokeLinecap={iconInfo.strokeLinecap}
|
||||||
@ -101,7 +101,9 @@ const PlainIcon: React.StatelessComponent<IconProps> = props => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const Icon = withTheme(styled(PlainIcon)`
|
export const Icon = withTheme(styled(PlainIcon)`
|
||||||
cursor: ${props => (!_.isUndefined(props.onClick) ? 'pointer' : 'default')};
|
&& {
|
||||||
|
display: inline-block;
|
||||||
|
${props => (!_.isUndefined(props.onClick) ? 'cursor: pointer' : '')};
|
||||||
transition: opacity 0.5s ease;
|
transition: opacity 0.5s ease;
|
||||||
padding: ${props => props.padding};
|
padding: ${props => props.padding};
|
||||||
opacity: ${props => (!_.isUndefined(props.onClick) ? 0.7 : 1)};
|
opacity: ${props => (!_.isUndefined(props.onClick) ? 0.7 : 1)};
|
||||||
@ -111,6 +113,7 @@ export const Icon = withTheme(styled(PlainIcon)`
|
|||||||
&:active {
|
&:active {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
Icon.defaultProps = {
|
Icon.defaultProps = {
|
||||||
|
@ -16,6 +16,8 @@ export const Input =
|
|||||||
styled.input <
|
styled.input <
|
||||||
InputProps >
|
InputProps >
|
||||||
`
|
`
|
||||||
|
&& {
|
||||||
|
all: initial;
|
||||||
font-size: ${props => props.fontSize};
|
font-size: ${props => props.fontSize};
|
||||||
width: ${props => props.width};
|
width: ${props => props.width};
|
||||||
padding: 0.1em 0em;
|
padding: 0.1em 0em;
|
||||||
@ -28,6 +30,7 @@ export const Input =
|
|||||||
color: ${props => props.theme[props.fontColor || 'white']};
|
color: ${props => props.theme[props.fontColor || 'white']};
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Input.defaultProps = {
|
Input.defaultProps = {
|
||||||
|
@ -1,38 +1,39 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import { ColorOption, overlayBlack, styled } from '../../style/theme';
|
import { generateMediaWrapper, ScreenWidths } from '../../style/media';
|
||||||
|
import { generateOverlayBlack, styled } from '../../style/theme';
|
||||||
import { Container } from './container';
|
import { zIndex } from '../../style/z_index';
|
||||||
import { Flex } from './flex';
|
|
||||||
import { Icon } from './icon';
|
|
||||||
|
|
||||||
export interface OverlayProps {
|
export interface OverlayProps {
|
||||||
className?: string;
|
|
||||||
onClose?: () => void;
|
|
||||||
zIndex?: number;
|
zIndex?: number;
|
||||||
|
backgroundColor?: string;
|
||||||
|
width?: string;
|
||||||
|
height?: string;
|
||||||
|
showMaxWidth?: ScreenWidths;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PlainOverlay: React.StatelessComponent<OverlayProps> = ({ children, className, onClose }) => (
|
export const Overlay =
|
||||||
<Flex height="100vh" className={className}>
|
styled.div <
|
||||||
<Container position="absolute" top="0px" right="0px">
|
OverlayProps >
|
||||||
<Icon height={18} width={18} color={ColorOption.white} icon="closeX" onClick={onClose} padding="2em 2em" />
|
`
|
||||||
</Container>
|
&& {
|
||||||
<div>{children}</div>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
export const Overlay = styled(PlainOverlay)`
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: ${props => props.zIndex}
|
z-index: ${props => props.zIndex}
|
||||||
background-color: ${overlayBlack};
|
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 = {
|
Overlay.defaultProps = {
|
||||||
zIndex: 100,
|
zIndex: zIndex.overlayDefault,
|
||||||
|
backgroundColor: generateOverlayBlack(0.6),
|
||||||
};
|
};
|
||||||
|
|
||||||
Overlay.displayName = 'Overlay';
|
Overlay.displayName = 'Overlay';
|
||||||
|
@ -27,7 +27,8 @@ export const Text =
|
|||||||
styled.div <
|
styled.div <
|
||||||
TextProps >
|
TextProps >
|
||||||
`
|
`
|
||||||
font-family: ${props => props.fontFamily};
|
&& {
|
||||||
|
font-family: 'Inter UI', sans-serif;
|
||||||
font-style: ${props => props.fontStyle};
|
font-style: ${props => props.fontStyle};
|
||||||
font-weight: ${props => props.fontWeight};
|
font-weight: ${props => props.fontWeight};
|
||||||
font-size: ${props => props.fontSize};
|
font-size: ${props => props.fontSize};
|
||||||
@ -47,6 +48,7 @@ export const Text =
|
|||||||
${props =>
|
${props =>
|
||||||
props.onClick ? `color: ${darken(darkenOnHoverAmount, props.theme[props.fontColor || 'white'])}` : ''};
|
props.onClick ? `color: ${darken(darkenOnHoverAmount, props.theme[props.fontColor || 'white'])}` : ''};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Text.defaultProps = {
|
Text.defaultProps = {
|
||||||
@ -61,14 +63,3 @@ Text.defaultProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Text.displayName = 'Text';
|
Text.displayName = 'Text';
|
||||||
|
|
||||||
export const Title: React.StatelessComponent<TextProps> = props => <Text {...props} />;
|
|
||||||
|
|
||||||
Title.defaultProps = {
|
|
||||||
fontSize: '20px',
|
|
||||||
fontWeight: 600,
|
|
||||||
opacity: 1,
|
|
||||||
fontColor: ColorOption.primaryColor,
|
|
||||||
};
|
|
||||||
|
|
||||||
Title.displayName = 'Title';
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { INJECTED_DIV_CLASS } from '../constants';
|
||||||
|
|
||||||
import { ZeroExInstantContainer } from './zero_ex_instant_container';
|
import { ZeroExInstantContainer } from './zero_ex_instant_container';
|
||||||
import { ZeroExInstantProvider, ZeroExInstantProviderProps } from './zero_ex_instant_provider';
|
import { ZeroExInstantProvider, ZeroExInstantProviderProps } from './zero_ex_instant_provider';
|
||||||
|
|
||||||
@ -7,8 +9,10 @@ export type ZeroExInstantProps = ZeroExInstantProviderProps;
|
|||||||
|
|
||||||
export const ZeroExInstant: React.StatelessComponent<ZeroExInstantProps> = props => {
|
export const ZeroExInstant: React.StatelessComponent<ZeroExInstantProps> = props => {
|
||||||
return (
|
return (
|
||||||
|
<div className={INJECTED_DIV_CLASS}>
|
||||||
<ZeroExInstantProvider {...props}>
|
<ZeroExInstantProvider {...props}>
|
||||||
<ZeroExInstantContainer />
|
<ZeroExInstantContainer />
|
||||||
</ZeroExInstantProvider>
|
</ZeroExInstantProvider>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -3,15 +3,14 @@ import * as React from 'react';
|
|||||||
import { AvailableERC20TokenSelector } from '../containers/available_erc20_token_selector';
|
import { AvailableERC20TokenSelector } from '../containers/available_erc20_token_selector';
|
||||||
import { LatestBuyQuoteOrderDetails } from '../containers/latest_buy_quote_order_details';
|
import { LatestBuyQuoteOrderDetails } from '../containers/latest_buy_quote_order_details';
|
||||||
import { LatestError } from '../containers/latest_error';
|
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 { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_buy_order_state_buttons';
|
||||||
import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading';
|
import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading';
|
||||||
|
|
||||||
import { SelectedAssetBuyOrderProgress } from '../containers/selected_asset_buy_order_progress';
|
|
||||||
|
|
||||||
import { ColorOption } from '../style/theme';
|
import { ColorOption } from '../style/theme';
|
||||||
import { zIndex } from '../style/z_index';
|
import { zIndex } from '../style/z_index';
|
||||||
|
|
||||||
import { SlideAnimationState } from './animations/slide_animation';
|
import { SlideAnimationState } from './animations/slide_animation';
|
||||||
|
import { CSSReset } from './css_reset';
|
||||||
import { SlidingPanel } from './sliding_panel';
|
import { SlidingPanel } from './sliding_panel';
|
||||||
import { Container } from './ui/container';
|
import { Container } from './ui/container';
|
||||||
import { Flex } from './ui/flex';
|
import { Flex } from './ui/flex';
|
||||||
@ -27,8 +26,14 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain
|
|||||||
};
|
};
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
return (
|
return (
|
||||||
<Container width="350px" position="relative">
|
<React.Fragment>
|
||||||
<Container zIndex={zIndex.errorPopup} position="relative">
|
<CSSReset />
|
||||||
|
<Container
|
||||||
|
width={{ default: '350px', sm: '100%' }}
|
||||||
|
height={{ default: 'auto', sm: '100%' }}
|
||||||
|
position="relative"
|
||||||
|
>
|
||||||
|
<Container position="relative">
|
||||||
<LatestError />
|
<LatestError />
|
||||||
</Container>
|
</Container>
|
||||||
<Container
|
<Container
|
||||||
@ -38,8 +43,9 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain
|
|||||||
borderRadius="3px"
|
borderRadius="3px"
|
||||||
hasBoxShadow={true}
|
hasBoxShadow={true}
|
||||||
overflow="hidden"
|
overflow="hidden"
|
||||||
|
height="100%"
|
||||||
>
|
>
|
||||||
<Flex direction="column" justify="flex-start">
|
<Flex direction="column" justify="flex-start" height="100%">
|
||||||
<SelectedAssetInstantHeading onSelectAssetClick={this._handleSymbolClick} />
|
<SelectedAssetInstantHeading onSelectAssetClick={this._handleSymbolClick} />
|
||||||
<SelectedAssetBuyOrderProgress />
|
<SelectedAssetBuyOrderProgress />
|
||||||
<LatestBuyQuoteOrderDetails />
|
<LatestBuyQuoteOrderDetails />
|
||||||
@ -56,6 +62,7 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain
|
|||||||
</SlidingPanel>
|
</SlidingPanel>
|
||||||
</Container>
|
</Container>
|
||||||
</Container>
|
</Container>
|
||||||
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private readonly _handleSymbolClick = (): void => {
|
private readonly _handleSymbolClick = (): void => {
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
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 { Overlay } from './ui/overlay';
|
||||||
import { ZeroExInstantContainer } from './zero_ex_instant_container';
|
import { ZeroExInstantContainer } from './zero_ex_instant_container';
|
||||||
import { ZeroExInstantProvider, ZeroExInstantProviderProps } from './zero_ex_instant_provider';
|
import { ZeroExInstantProvider, ZeroExInstantProviderProps } from './zero_ex_instant_provider';
|
||||||
@ -13,8 +18,22 @@ export const ZeroExInstantOverlay: React.StatelessComponent<ZeroExInstantOverlay
|
|||||||
const { onClose, zIndex, ...rest } = props;
|
const { onClose, zIndex, ...rest } = props;
|
||||||
return (
|
return (
|
||||||
<ZeroExInstantProvider {...rest}>
|
<ZeroExInstantProvider {...rest}>
|
||||||
<Overlay onClose={onClose} zIndex={zIndex}>
|
<Overlay zIndex={zIndex}>
|
||||||
|
<Flex height="100vh">
|
||||||
|
<Container position="absolute" top="0px" right="0px" display={{ default: 'initial', sm: 'none' }}>
|
||||||
|
<Icon
|
||||||
|
height={18}
|
||||||
|
width={18}
|
||||||
|
color={ColorOption.white}
|
||||||
|
icon="closeX"
|
||||||
|
onClick={onClose}
|
||||||
|
padding="2em 2em"
|
||||||
|
/>
|
||||||
|
</Container>
|
||||||
|
<Container width={{ default: 'auto', sm: '100%' }} height={{ default: 'auto', sm: '100%' }}>
|
||||||
<ZeroExInstantContainer />
|
<ZeroExInstantContainer />
|
||||||
|
</Container>
|
||||||
|
</Flex>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
</ZeroExInstantProvider>
|
</ZeroExInstantProvider>
|
||||||
);
|
);
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
import { AssetBuyer } from '@0x/asset-buyer';
|
import { ObjectMap } from '@0x/types';
|
||||||
import { ObjectMap, SignedOrder } from '@0x/types';
|
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
|
||||||
import { Provider } from 'ethereum-types';
|
import { Provider } from 'ethereum-types';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Provider as ReduxProvider } from 'react-redux';
|
import { Provider as ReduxProvider } from 'react-redux';
|
||||||
import { oc } from 'ts-optchain';
|
|
||||||
|
|
||||||
|
import { ACCOUNT_UPDATE_INTERVAL_TIME_MS, BUY_QUOTE_UPDATE_INTERVAL_TIME_MS } from '../constants';
|
||||||
import { SelectedAssetThemeProvider } from '../containers/selected_asset_theme_provider';
|
import { SelectedAssetThemeProvider } from '../containers/selected_asset_theme_provider';
|
||||||
import { asyncData } from '../redux/async_data';
|
import { asyncData } from '../redux/async_data';
|
||||||
import { INITIAL_STATE, State } from '../redux/reducer';
|
import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer';
|
||||||
import { store, Store } from '../redux/store';
|
import { store, Store } from '../redux/store';
|
||||||
import { fonts } from '../style/fonts';
|
import { fonts } from '../style/fonts';
|
||||||
import { AffiliateInfo, AssetMetaData, Network } from '../types';
|
import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource } from '../types';
|
||||||
import { assetUtils } from '../util/asset';
|
import { assetUtils } from '../util/asset';
|
||||||
import { errorFlasher } from '../util/error_flasher';
|
import { errorFlasher } from '../util/error_flasher';
|
||||||
import { gasPriceEstimator } from '../util/gas_price_estimator';
|
import { gasPriceEstimator } from '../util/gas_price_estimator';
|
||||||
import { getInjectedProvider } from '../util/injected_provider';
|
import { Heartbeater } from '../util/heartbeater';
|
||||||
|
import { generateAccountHeartbeater, generateBuyQuoteHeartbeater } from '../util/heartbeater_factory';
|
||||||
|
import { providerStateFactory } from '../util/provider_state_factory';
|
||||||
|
|
||||||
fonts.include();
|
fonts.include();
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ export type ZeroExInstantProviderProps = ZeroExInstantProviderRequiredProps &
|
|||||||
Partial<ZeroExInstantProviderOptionalProps>;
|
Partial<ZeroExInstantProviderOptionalProps>;
|
||||||
|
|
||||||
export interface ZeroExInstantProviderRequiredProps {
|
export interface ZeroExInstantProviderRequiredProps {
|
||||||
orderSource: string | SignedOrder[];
|
orderSource: OrderSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ZeroExInstantProviderOptionalProps {
|
export interface ZeroExInstantProviderOptionalProps {
|
||||||
@ -40,31 +40,31 @@ export interface ZeroExInstantProviderOptionalProps {
|
|||||||
|
|
||||||
export class ZeroExInstantProvider extends React.Component<ZeroExInstantProviderProps> {
|
export class ZeroExInstantProvider extends React.Component<ZeroExInstantProviderProps> {
|
||||||
private readonly _store: Store;
|
private readonly _store: Store;
|
||||||
|
private _accountUpdateHeartbeat?: Heartbeater;
|
||||||
|
private _buyQuoteHeartbeat?: Heartbeater;
|
||||||
|
|
||||||
// TODO(fragosti): Write tests for this beast once we inject a provider.
|
// TODO(fragosti): Write tests for this beast once we inject a provider.
|
||||||
private static _mergeInitialStateWithProps(props: ZeroExInstantProviderProps, state: State = INITIAL_STATE): State {
|
private static _mergeDefaultStateWithProps(
|
||||||
const networkId = props.networkId || state.network;
|
props: ZeroExInstantProviderProps,
|
||||||
// TODO: Proper wallet connect flow
|
defaultState: DefaultState = DEFAULT_STATE,
|
||||||
const provider = props.provider || getInjectedProvider();
|
): State {
|
||||||
const assetBuyerOptions = {
|
// use the networkId passed in with the props, otherwise default to that of the default state (1, mainnet)
|
||||||
networkId,
|
const networkId = props.networkId || defaultState.network;
|
||||||
};
|
// construct the ProviderState
|
||||||
let assetBuyer;
|
const providerState = providerStateFactory.getInitialProviderState(
|
||||||
if (_.isString(props.orderSource)) {
|
|
||||||
assetBuyer = AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl(
|
|
||||||
provider,
|
|
||||||
props.orderSource,
|
props.orderSource,
|
||||||
assetBuyerOptions,
|
networkId,
|
||||||
|
props.provider,
|
||||||
);
|
);
|
||||||
} else {
|
// merge the additional additionalAssetMetaDataMap with our default map
|
||||||
assetBuyer = AssetBuyer.getAssetBuyerForProvidedOrders(provider, props.orderSource, assetBuyerOptions);
|
|
||||||
}
|
|
||||||
const completeAssetMetaDataMap = {
|
const completeAssetMetaDataMap = {
|
||||||
...props.additionalAssetMetaDataMap,
|
...props.additionalAssetMetaDataMap,
|
||||||
...state.assetMetaDataMap,
|
...defaultState.assetMetaDataMap,
|
||||||
};
|
};
|
||||||
|
// construct the final state
|
||||||
const storeStateFromProps: State = {
|
const storeStateFromProps: State = {
|
||||||
...state,
|
...defaultState,
|
||||||
assetBuyer,
|
providerState,
|
||||||
network: networkId,
|
network: networkId,
|
||||||
selectedAsset: _.isUndefined(props.defaultSelectedAssetData)
|
selectedAsset: _.isUndefined(props.defaultSelectedAssetData)
|
||||||
? undefined
|
? undefined
|
||||||
@ -74,7 +74,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
|
|||||||
networkId,
|
networkId,
|
||||||
),
|
),
|
||||||
selectedAssetAmount: _.isUndefined(props.defaultAssetBuyAmount)
|
selectedAssetAmount: _.isUndefined(props.defaultAssetBuyAmount)
|
||||||
? state.selectedAssetAmount
|
? undefined
|
||||||
: new BigNumber(props.defaultAssetBuyAmount),
|
: new BigNumber(props.defaultAssetBuyAmount),
|
||||||
availableAssets: _.isUndefined(props.availableAssetDatas)
|
availableAssets: _.isUndefined(props.availableAssetDatas)
|
||||||
? undefined
|
? undefined
|
||||||
@ -86,10 +86,9 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
|
|||||||
}
|
}
|
||||||
constructor(props: ZeroExInstantProviderProps) {
|
constructor(props: ZeroExInstantProviderProps) {
|
||||||
super(props);
|
super(props);
|
||||||
const initialAppState = ZeroExInstantProvider._mergeInitialStateWithProps(this.props, INITIAL_STATE);
|
const initialAppState = ZeroExInstantProvider._mergeDefaultStateWithProps(this.props);
|
||||||
this._store = store.create(initialAppState);
|
this._store = store.create(initialAppState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
const state = this._store.getState();
|
const state = this._store.getState();
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
@ -99,16 +98,36 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
|
|||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
asyncData.fetchAvailableAssetDatasAndDispatchToStore(this._store);
|
asyncData.fetchAvailableAssetDatasAndDispatchToStore(this._store);
|
||||||
}
|
}
|
||||||
|
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.fetchCurrentBuyQuoteAndDispatchToStore({ store: this._store, shouldSetPending: true });
|
||||||
// warm up the gas price estimator cache just in case we can't
|
// warm up the gas price estimator cache just in case we can't
|
||||||
// grab the gas price estimate when submitting the transaction
|
// grab the gas price estimate when submitting the transaction
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
gasPriceEstimator.getGasInfoAsync();
|
gasPriceEstimator.getGasInfoAsync();
|
||||||
|
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
this._flashErrorIfWrongNetwork();
|
this._flashErrorIfWrongNetwork();
|
||||||
}
|
}
|
||||||
|
public componentWillUnmount(): void {
|
||||||
|
if (this._accountUpdateHeartbeat) {
|
||||||
|
this._accountUpdateHeartbeat.stop();
|
||||||
|
}
|
||||||
|
if (this._buyQuoteHeartbeat) {
|
||||||
|
this._buyQuoteHeartbeat.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
return (
|
return (
|
||||||
<ReduxProvider store={this._store}>
|
<ReduxProvider store={this._store}>
|
||||||
@ -116,19 +135,15 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
|
|||||||
</ReduxProvider>
|
</ReduxProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly _flashErrorIfWrongNetwork = async (): Promise<void> => {
|
private readonly _flashErrorIfWrongNetwork = async (): Promise<void> => {
|
||||||
const msToShowError = 30000; // 30 seconds
|
const msToShowError = 30000; // 30 seconds
|
||||||
const network = this._store.getState().network;
|
const state = this._store.getState();
|
||||||
const assetBuyerIfExists = this._store.getState().assetBuyer;
|
const network = state.network;
|
||||||
const providerIfExists = oc(assetBuyerIfExists).provider();
|
const web3Wrapper = state.providerState.web3Wrapper;
|
||||||
if (!_.isUndefined(providerIfExists)) {
|
|
||||||
const web3Wrapper = new Web3Wrapper(providerIfExists);
|
|
||||||
const networkOfProvider = await web3Wrapper.getNetworkIdAsync();
|
const networkOfProvider = await web3Wrapper.getNetworkIdAsync();
|
||||||
if (network !== networkOfProvider) {
|
if (network !== networkOfProvider) {
|
||||||
const errorMessage = `Wrong network detected. Try switching to ${Network[network]}.`;
|
const errorMessage = `Wrong network detected. Try switching to ${Network[network]}.`;
|
||||||
errorFlasher.flashNewErrorMessage(this._store.dispatch, errorMessage, msToShowError);
|
errorFlasher.flashNewErrorMessage(this._store.dispatch, errorMessage, msToShowError);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,35 @@
|
|||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
|
import { AccountNotReady, AccountState, Network } from './types';
|
||||||
|
|
||||||
export const BIG_NUMBER_ZERO = new BigNumber(0);
|
export const BIG_NUMBER_ZERO = new BigNumber(0);
|
||||||
export const ETH_DECIMALS = 18;
|
export const ETH_DECIMALS = 18;
|
||||||
export const DEFAULT_ZERO_EX_CONTAINER_SELECTOR = '#zeroExInstantContainer';
|
export const DEFAULT_ZERO_EX_CONTAINER_SELECTOR = '#zeroExInstantContainer';
|
||||||
|
export const INJECTED_DIV_CLASS = 'zeroExInstantResetRoot';
|
||||||
export const INJECTED_DIV_ID = 'zeroExInstant';
|
export const INJECTED_DIV_ID = 'zeroExInstant';
|
||||||
export const WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX = 'Transaction failed';
|
export const WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX = 'Transaction failed';
|
||||||
export const GWEI_IN_WEI = new BigNumber(1000000000);
|
export const GWEI_IN_WEI = new BigNumber(1000000000);
|
||||||
export const ONE_SECOND_MS = 1000;
|
export const ONE_SECOND_MS = 1000;
|
||||||
export const ONE_MINUTE_MS = ONE_SECOND_MS * 60;
|
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_GAS_PRICE = GWEI_IN_WEI.mul(6);
|
||||||
export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2;
|
export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2;
|
||||||
export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info';
|
export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info';
|
||||||
export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2';
|
export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2';
|
||||||
export const PROGRESS_STALL_AT_WIDTH = '95%';
|
export const PROGRESS_STALL_AT_WIDTH = '95%';
|
||||||
export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200;
|
export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200;
|
||||||
|
export const ETHEREUM_NODE_URL_BY_NETWORK = {
|
||||||
|
[Network.Mainnet]: 'https://mainnet.infura.io/',
|
||||||
|
[Network.Kovan]: 'https://kovan.infura.io/',
|
||||||
|
};
|
||||||
|
export const BLOCK_POLLING_INTERVAL_MS = 10000; // 10s
|
||||||
|
export const NO_ACCOUNT: AccountNotReady = {
|
||||||
|
state: AccountState.None,
|
||||||
|
};
|
||||||
|
export const LOADING_ACCOUNT: AccountNotReady = {
|
||||||
|
state: AccountState.Loading,
|
||||||
|
};
|
||||||
|
export const LOCKED_ACCOUNT: AccountNotReady = {
|
||||||
|
state: AccountState.Locked,
|
||||||
|
};
|
||||||
|
@ -22,7 +22,7 @@ const mapStateToProps = (state: State, _ownProps: LatestBuyQuoteOrderDetailsProp
|
|||||||
// use the worst case quote info
|
// use the worst case quote info
|
||||||
buyQuoteInfo: oc(state).latestBuyQuote.worstCaseQuoteInfo(),
|
buyQuoteInfo: oc(state).latestBuyQuote.worstCaseQuoteInfo(),
|
||||||
ethUsdPrice: state.ethUsdPrice,
|
ethUsdPrice: state.ethUsdPrice,
|
||||||
isLoading: state.quoteRequestState === AsyncProcessState.PENDING,
|
isLoading: state.quoteRequestState === AsyncProcessState.Pending,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const LatestBuyQuoteOrderDetails: React.ComponentClass<LatestBuyQuoteOrderDetailsProps> = connect(
|
export const LatestBuyQuoteOrderDetails: React.ComponentClass<LatestBuyQuoteOrderDetailsProps> = connect(
|
||||||
|
@ -1,35 +1,60 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { Dispatch } from 'redux';
|
||||||
|
|
||||||
import { SlideAnimationState } from '../components/animations/slide_animation';
|
import { SlideAnimationState } from '../components/animations/slide_animation';
|
||||||
import { SlidingError } from '../components/sliding_error';
|
import { SlidingError } from '../components/sliding_error';
|
||||||
|
import { Overlay } from '../components/ui/overlay';
|
||||||
|
import { Action } from '../redux/actions';
|
||||||
import { State } from '../redux/reducer';
|
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 } from '../types';
|
||||||
|
import { errorFlasher } from '../util/error_flasher';
|
||||||
|
|
||||||
export interface LatestErrorComponentProps {
|
export interface LatestErrorComponentProps {
|
||||||
asset?: Asset;
|
asset?: Asset;
|
||||||
latestErrorMessage?: string;
|
latestErrorMessage?: string;
|
||||||
animationState: SlideAnimationState;
|
animationState: SlideAnimationState;
|
||||||
|
shouldRenderOverlay: boolean;
|
||||||
|
onOverlayClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LatestErrorComponent: React.StatelessComponent<LatestErrorComponentProps> = props => {
|
export const LatestErrorComponent: React.StatelessComponent<LatestErrorComponentProps> = props => {
|
||||||
if (!props.latestErrorMessage) {
|
if (!props.latestErrorMessage) {
|
||||||
return <div />;
|
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 {}
|
export interface LatestErrorProps {}
|
||||||
|
interface ConnectedState extends Omit<LatestErrorComponentProps, 'onOverlayClick'> {}
|
||||||
const mapStateToProps = (state: State, _ownProps: LatestErrorProps): ConnectedState => ({
|
const mapStateToProps = (state: State, _ownProps: LatestErrorProps): ConnectedState => ({
|
||||||
asset: state.selectedAsset,
|
asset: state.selectedAsset,
|
||||||
latestErrorMessage: state.latestErrorMessage,
|
latestErrorMessage: state.latestErrorMessage,
|
||||||
animationState: state.latestErrorDisplayStatus === DisplayStatus.Present ? 'slidIn' : 'slidOut',
|
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);
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
|
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
@ -7,14 +9,17 @@ import { Dispatch } from 'redux';
|
|||||||
import { BuyOrderStateButtons } from '../components/buy_order_state_buttons';
|
import { BuyOrderStateButtons } from '../components/buy_order_state_buttons';
|
||||||
import { Action, actions } from '../redux/actions';
|
import { Action, actions } from '../redux/actions';
|
||||||
import { State } from '../redux/reducer';
|
import { State } from '../redux/reducer';
|
||||||
import { AffiliateInfo, OrderProcessState, ZeroExInstantError } from '../types';
|
import { AccountState, AffiliateInfo, OrderProcessState, ZeroExInstantError } from '../types';
|
||||||
import { errorFlasher } from '../util/error_flasher';
|
import { errorFlasher } from '../util/error_flasher';
|
||||||
import { etherscanUtil } from '../util/etherscan';
|
import { etherscanUtil } from '../util/etherscan';
|
||||||
|
|
||||||
interface ConnectedState {
|
interface ConnectedState {
|
||||||
|
accountAddress?: string;
|
||||||
|
accountEthBalanceInWei?: BigNumber;
|
||||||
buyQuote?: BuyQuote;
|
buyQuote?: BuyQuote;
|
||||||
buyOrderProcessingState: OrderProcessState;
|
buyOrderProcessingState: OrderProcessState;
|
||||||
assetBuyer?: AssetBuyer;
|
assetBuyer: AssetBuyer;
|
||||||
|
web3Wrapper: Web3Wrapper;
|
||||||
affiliateInfo?: AffiliateInfo;
|
affiliateInfo?: AffiliateInfo;
|
||||||
onViewTransaction: () => void;
|
onViewTransaction: () => void;
|
||||||
}
|
}
|
||||||
@ -29,21 +34,29 @@ interface ConnectedDispatch {
|
|||||||
onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void;
|
onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void;
|
||||||
}
|
}
|
||||||
export interface SelectedAssetBuyOrderStateButtons {}
|
export interface SelectedAssetBuyOrderStateButtons {}
|
||||||
const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButtons): ConnectedState => ({
|
const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButtons): ConnectedState => {
|
||||||
|
const assetBuyer = state.providerState.assetBuyer;
|
||||||
|
const web3Wrapper = state.providerState.web3Wrapper;
|
||||||
|
const account = state.providerState.account;
|
||||||
|
const accountAddress = account.state === AccountState.Ready ? account.address : undefined;
|
||||||
|
const accountEthBalanceInWei = account.state === AccountState.Ready ? account.ethBalanceInWei : undefined;
|
||||||
|
return {
|
||||||
|
accountAddress,
|
||||||
|
accountEthBalanceInWei,
|
||||||
buyOrderProcessingState: state.buyOrderState.processState,
|
buyOrderProcessingState: state.buyOrderState.processState,
|
||||||
assetBuyer: state.assetBuyer,
|
assetBuyer,
|
||||||
|
web3Wrapper,
|
||||||
buyQuote: state.latestBuyQuote,
|
buyQuote: state.latestBuyQuote,
|
||||||
affiliateInfo: state.affiliateInfo,
|
affiliateInfo: state.affiliateInfo,
|
||||||
onViewTransaction: () => {
|
onViewTransaction: () => {
|
||||||
if (
|
if (
|
||||||
state.assetBuyer &&
|
state.buyOrderState.processState === OrderProcessState.Processing ||
|
||||||
(state.buyOrderState.processState === OrderProcessState.PROCESSING ||
|
state.buyOrderState.processState === OrderProcessState.Success ||
|
||||||
state.buyOrderState.processState === OrderProcessState.SUCCESS ||
|
state.buyOrderState.processState === OrderProcessState.Failure
|
||||||
state.buyOrderState.processState === OrderProcessState.FAILURE)
|
|
||||||
) {
|
) {
|
||||||
const etherscanUrl = etherscanUtil.getEtherScanTxnAddressIfExists(
|
const etherscanUrl = etherscanUtil.getEtherScanTxnAddressIfExists(
|
||||||
state.buyOrderState.txHash,
|
state.buyOrderState.txHash,
|
||||||
state.assetBuyer.networkId,
|
assetBuyer.networkId,
|
||||||
);
|
);
|
||||||
if (etherscanUrl) {
|
if (etherscanUrl) {
|
||||||
window.open(etherscanUrl, '_blank');
|
window.open(etherscanUrl, '_blank');
|
||||||
@ -51,7 +64,8 @@ const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const mapDispatchToProps = (
|
const mapDispatchToProps = (
|
||||||
dispatch: Dispatch<Action>,
|
dispatch: Dispatch<Action>,
|
||||||
|
@ -1,20 +1,17 @@
|
|||||||
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
|
import { AssetBuyer } from '@0x/asset-buyer';
|
||||||
import { AssetProxyId } from '@0x/types';
|
import { AssetProxyId } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Dispatch } from 'redux';
|
import { Dispatch } from 'redux';
|
||||||
import { oc } from 'ts-optchain';
|
|
||||||
|
|
||||||
import { ERC20AssetAmountInput } from '../components/erc20_asset_amount_input';
|
import { ERC20AssetAmountInput } from '../components/erc20_asset_amount_input';
|
||||||
import { Action, actions } from '../redux/actions';
|
import { Action, actions } from '../redux/actions';
|
||||||
import { State } from '../redux/reducer';
|
import { State } from '../redux/reducer';
|
||||||
import { ColorOption } from '../style/theme';
|
import { ColorOption } from '../style/theme';
|
||||||
import { AffiliateInfo, ERC20Asset, OrderProcessState } from '../types';
|
import { AffiliateInfo, ERC20Asset, OrderProcessState } from '../types';
|
||||||
import { assetUtils } from '../util/asset';
|
import { buyQuoteUpdater } from '../util/buy_quote_updater';
|
||||||
import { errorFlasher } from '../util/error_flasher';
|
|
||||||
|
|
||||||
export interface SelectedERC20AssetAmountInputProps {
|
export interface SelectedERC20AssetAmountInputProps {
|
||||||
fontColor?: ColorOption;
|
fontColor?: ColorOption;
|
||||||
@ -23,7 +20,7 @@ export interface SelectedERC20AssetAmountInputProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ConnectedState {
|
interface ConnectedState {
|
||||||
assetBuyer?: AssetBuyer;
|
assetBuyer: AssetBuyer;
|
||||||
value?: BigNumber;
|
value?: BigNumber;
|
||||||
asset?: ERC20Asset;
|
asset?: ERC20Asset;
|
||||||
isDisabled: boolean;
|
isDisabled: boolean;
|
||||||
@ -33,7 +30,7 @@ interface ConnectedState {
|
|||||||
|
|
||||||
interface ConnectedDispatch {
|
interface ConnectedDispatch {
|
||||||
updateBuyQuote: (
|
updateBuyQuote: (
|
||||||
assetBuyer?: AssetBuyer,
|
assetBuyer: AssetBuyer,
|
||||||
value?: BigNumber,
|
value?: BigNumber,
|
||||||
asset?: ERC20Asset,
|
asset?: ERC20Asset,
|
||||||
affiliateInfo?: AffiliateInfo,
|
affiliateInfo?: AffiliateInfo,
|
||||||
@ -52,15 +49,16 @@ type FinalProps = ConnectedProps & SelectedERC20AssetAmountInputProps;
|
|||||||
|
|
||||||
const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputProps): ConnectedState => {
|
const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputProps): ConnectedState => {
|
||||||
const processState = state.buyOrderState.processState;
|
const processState = state.buyOrderState.processState;
|
||||||
const isEnabled = processState === OrderProcessState.NONE || processState === OrderProcessState.FAILURE;
|
const isEnabled = processState === OrderProcessState.None || processState === OrderProcessState.Failure;
|
||||||
const isDisabled = !isEnabled;
|
const isDisabled = !isEnabled;
|
||||||
const selectedAsset =
|
const selectedAsset =
|
||||||
!_.isUndefined(state.selectedAsset) && state.selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20
|
!_.isUndefined(state.selectedAsset) && state.selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20
|
||||||
? (state.selectedAsset as ERC20Asset)
|
? (state.selectedAsset as ERC20Asset)
|
||||||
: undefined;
|
: undefined;
|
||||||
const numberOfAssetsAvailable = _.isUndefined(state.availableAssets) ? undefined : state.availableAssets.length;
|
const numberOfAssetsAvailable = _.isUndefined(state.availableAssets) ? undefined : state.availableAssets.length;
|
||||||
|
const assetBuyer = state.providerState.assetBuyer;
|
||||||
return {
|
return {
|
||||||
assetBuyer: state.assetBuyer,
|
assetBuyer,
|
||||||
value: state.selectedAssetAmount,
|
value: state.selectedAssetAmount,
|
||||||
asset: selectedAsset,
|
asset: selectedAsset,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
@ -69,52 +67,9 @@ const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputP
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateBuyQuoteAsync = async (
|
const debouncedUpdateBuyQuoteAsync = _.debounce(buyQuoteUpdater.updateBuyQuoteAsync.bind(buyQuoteUpdater), 200, {
|
||||||
assetBuyer: AssetBuyer,
|
trailing: true,
|
||||||
dispatch: Dispatch<Action>,
|
}) as typeof buyQuoteUpdater.updateBuyQuoteAsync;
|
||||||
asset: ERC20Asset,
|
|
||||||
assetAmount: BigNumber,
|
|
||||||
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 feePercentage = oc(affiliateInfo).feePercentage();
|
|
||||||
let newBuyQuote: BuyQuote | undefined;
|
|
||||||
try {
|
|
||||||
newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue, { feePercentage });
|
|
||||||
} catch (error) {
|
|
||||||
dispatch(actions.setQuoteRequestStateFailure());
|
|
||||||
let errorMessage;
|
|
||||||
if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
|
|
||||||
const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
|
|
||||||
errorMessage = `Not enough ${assetName} available`;
|
|
||||||
} else if (error.message === AssetBuyerError.InsufficientZrxLiquidity) {
|
|
||||||
errorMessage = 'Not enough ZRX available';
|
|
||||||
} else if (
|
|
||||||
error.message === AssetBuyerError.StandardRelayerApiError ||
|
|
||||||
error.message.startsWith(AssetBuyerError.AssetUnavailable)
|
|
||||||
) {
|
|
||||||
const assetName = assetUtils.bestNameForAsset(asset, 'This asset');
|
|
||||||
errorMessage = `${assetName} is currently unavailable`;
|
|
||||||
}
|
|
||||||
if (!_.isUndefined(errorMessage)) {
|
|
||||||
errorFlasher.flashNewErrorMessage(dispatch, errorMessage);
|
|
||||||
} else {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// We have a successful new buy quote
|
|
||||||
errorFlasher.clearError(dispatch);
|
|
||||||
// invalidate the last buy quote.
|
|
||||||
dispatch(actions.updateLatestBuyQuote(newBuyQuote));
|
|
||||||
};
|
|
||||||
|
|
||||||
const debouncedUpdateBuyQuoteAsync = _.debounce(updateBuyQuoteAsync, 200, { trailing: true });
|
|
||||||
|
|
||||||
const mapDispatchToProps = (
|
const mapDispatchToProps = (
|
||||||
dispatch: Dispatch<Action>,
|
dispatch: Dispatch<Action>,
|
||||||
@ -128,11 +83,11 @@ const mapDispatchToProps = (
|
|||||||
// reset our buy state
|
// reset our buy state
|
||||||
dispatch(actions.setBuyOrderStateNone());
|
dispatch(actions.setBuyOrderStateNone());
|
||||||
|
|
||||||
if (!_.isUndefined(value) && value.greaterThan(0) && !_.isUndefined(asset) && !_.isUndefined(assetBuyer)) {
|
if (!_.isUndefined(value) && value.greaterThan(0) && !_.isUndefined(asset)) {
|
||||||
// even if it's debounced, give them the illusion it's loading
|
// even if it's debounced, give them the illusion it's loading
|
||||||
dispatch(actions.setQuoteRequestStatePending());
|
dispatch(actions.setQuoteRequestStatePending());
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value, affiliateInfo);
|
debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value, true, affiliateInfo);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,7 @@ import * as _ from 'lodash';
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import * as ReactDOM from 'react-dom';
|
import * as ReactDOM from 'react-dom';
|
||||||
|
|
||||||
import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR, INJECTED_DIV_ID } from './constants';
|
import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR, INJECTED_DIV_CLASS, INJECTED_DIV_ID } from './constants';
|
||||||
import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index';
|
import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index';
|
||||||
import { assert } from './util/assert';
|
import { assert } from './util/assert';
|
||||||
|
|
||||||
@ -41,6 +41,7 @@ export const render = (props: ZeroExInstantOverlayProps, selector: string = DEFA
|
|||||||
const appendTo = appendToIfExists as Element;
|
const appendTo = appendToIfExists as Element;
|
||||||
const injectedDiv = document.createElement('div');
|
const injectedDiv = document.createElement('div');
|
||||||
injectedDiv.setAttribute('id', INJECTED_DIV_ID);
|
injectedDiv.setAttribute('id', INJECTED_DIV_ID);
|
||||||
|
injectedDiv.setAttribute('class', INJECTED_DIV_CLASS);
|
||||||
appendTo.appendChild(injectedDiv);
|
appendTo.appendChild(injectedDiv);
|
||||||
const instantOverlayProps = {
|
const instantOverlayProps = {
|
||||||
...props,
|
...props,
|
||||||
|
@ -2,7 +2,7 @@ import { BuyQuote } from '@0x/asset-buyer';
|
|||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { ActionsUnion, Asset } from '../types';
|
import { ActionsUnion, AddressAndEthBalanceInWei, Asset } from '../types';
|
||||||
|
|
||||||
export interface PlainAction<T extends string> {
|
export interface PlainAction<T extends string> {
|
||||||
type: T;
|
type: T;
|
||||||
@ -21,6 +21,10 @@ function createAction<T extends string, P>(type: T, data?: P): PlainAction<T> |
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum ActionTypes {
|
export enum ActionTypes {
|
||||||
|
SET_ACCOUNT_STATE_LOADING = 'SET_ACCOUNT_STATE_LOADING',
|
||||||
|
SET_ACCOUNT_STATE_LOCKED = 'SET_ACCOUNT_STATE_LOCKED',
|
||||||
|
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_ETH_USD_PRICE = 'UPDATE_ETH_USD_PRICE',
|
||||||
UPDATE_SELECTED_ASSET_AMOUNT = 'UPDATE_SELECTED_ASSET_AMOUNT',
|
UPDATE_SELECTED_ASSET_AMOUNT = 'UPDATE_SELECTED_ASSET_AMOUNT',
|
||||||
SET_BUY_ORDER_STATE_NONE = 'SET_BUY_ORDER_STATE_NONE',
|
SET_BUY_ORDER_STATE_NONE = 'SET_BUY_ORDER_STATE_NONE',
|
||||||
@ -40,6 +44,11 @@ export enum ActionTypes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
|
setAccountStateLoading: () => createAction(ActionTypes.SET_ACCOUNT_STATE_LOADING),
|
||||||
|
setAccountStateLocked: () => createAction(ActionTypes.SET_ACCOUNT_STATE_LOCKED),
|
||||||
|
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),
|
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_AMOUNT, amount),
|
||||||
setBuyOrderStateNone: () => createAction(ActionTypes.SET_BUY_ORDER_STATE_NONE),
|
setBuyOrderStateNone: () => createAction(ActionTypes.SET_BUY_ORDER_STATE_NONE),
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
|
import { AssetProxyId } from '@0x/types';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { BIG_NUMBER_ZERO } from '../constants';
|
import { BIG_NUMBER_ZERO } from '../constants';
|
||||||
|
import { AccountState, ERC20Asset, OrderProcessState } from '../types';
|
||||||
import { assetUtils } from '../util/asset';
|
import { assetUtils } from '../util/asset';
|
||||||
|
import { buyQuoteUpdater } from '../util/buy_quote_updater';
|
||||||
import { coinbaseApi } from '../util/coinbase_api';
|
import { coinbaseApi } from '../util/coinbase_api';
|
||||||
import { errorFlasher } from '../util/error_flasher';
|
import { errorFlasher } from '../util/error_flasher';
|
||||||
|
|
||||||
@ -20,8 +23,8 @@ export const asyncData = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
fetchAvailableAssetDatasAndDispatchToStore: async (store: Store) => {
|
fetchAvailableAssetDatasAndDispatchToStore: async (store: Store) => {
|
||||||
const { assetBuyer, assetMetaDataMap, network } = store.getState();
|
const { providerState, assetMetaDataMap, network } = store.getState();
|
||||||
if (!_.isUndefined(assetBuyer)) {
|
const assetBuyer = providerState.assetBuyer;
|
||||||
try {
|
try {
|
||||||
const assetDatas = await assetBuyer.getAvailableAssetDatasAsync();
|
const assetDatas = await assetBuyer.getAvailableAssetDatasAsync();
|
||||||
const assets = assetUtils.createAssetsFromAssetDatas(assetDatas, assetMetaDataMap, network);
|
const assets = assetUtils.createAssetsFromAssetDatas(assetDatas, assetMetaDataMap, network);
|
||||||
@ -32,6 +35,69 @@ export const asyncData = {
|
|||||||
// On error, just specify that none are available
|
// On error, just specify that none are available
|
||||||
store.dispatch(actions.setAvailableAssets([]));
|
store.dispatch(actions.setAvailableAssets([]));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
fetchAccountInfoAndDispatchToStore: async (options: { store: Store; shouldSetToLoading: boolean }) => {
|
||||||
|
const { store, shouldSetToLoading } = options;
|
||||||
|
const { providerState } = store.getState();
|
||||||
|
const web3Wrapper = providerState.web3Wrapper;
|
||||||
|
const provider = providerState.provider;
|
||||||
|
if (shouldSetToLoading && providerState.account.state !== AccountState.Loading) {
|
||||||
|
store.dispatch(actions.setAccountStateLoading());
|
||||||
|
}
|
||||||
|
let availableAddresses: string[];
|
||||||
|
try {
|
||||||
|
// TODO(bmillman): Add support at the web3Wrapper level for calling `eth_requestAccounts` instead of calling enable here
|
||||||
|
const isPrivacyModeEnabled = !_.isUndefined((provider as any).enable);
|
||||||
|
availableAddresses = isPrivacyModeEnabled
|
||||||
|
? await (provider as any).enable()
|
||||||
|
: await web3Wrapper.getAvailableAddressesAsync();
|
||||||
|
} catch (e) {
|
||||||
|
store.dispatch(actions.setAccountStateLocked());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_.isEmpty(availableAddresses)) {
|
||||||
|
const activeAddress = availableAddresses[0];
|
||||||
|
store.dispatch(actions.setAccountStateReady(activeAddress));
|
||||||
|
// tslint:disable-next-line:no-floating-promises
|
||||||
|
asyncData.fetchAccountBalanceAndDispatchToStore(store);
|
||||||
|
} else {
|
||||||
|
store.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;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const address = account.address;
|
||||||
|
const ethBalanceInWei = await web3Wrapper.getBalanceInWeiAsync(address);
|
||||||
|
store.dispatch(actions.updateAccountEthBalance({ address, ethBalanceInWei }));
|
||||||
|
} catch (e) {
|
||||||
|
// leave balance as is
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchCurrentBuyQuoteAndDispatchToStore: async (options: { store: Store; shouldSetPending: boolean }) => {
|
||||||
|
const { store, shouldSetPending } = options;
|
||||||
|
const { buyOrderState, providerState, selectedAsset, selectedAssetAmount, affiliateInfo } = store.getState();
|
||||||
|
const assetBuyer = providerState.assetBuyer;
|
||||||
|
if (
|
||||||
|
!_.isUndefined(selectedAssetAmount) &&
|
||||||
|
!_.isUndefined(selectedAsset) &&
|
||||||
|
buyOrderState.processState === OrderProcessState.None &&
|
||||||
|
selectedAsset.metaData.assetProxyId === AssetProxyId.ERC20
|
||||||
|
) {
|
||||||
|
await buyQuoteUpdater.updateBuyQuoteAsync(
|
||||||
|
assetBuyer,
|
||||||
|
store.dispatch,
|
||||||
|
selectedAsset as ERC20Asset,
|
||||||
|
selectedAssetAmount,
|
||||||
|
shouldSetPending,
|
||||||
|
affiliateInfo,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
import { AssetBuyer, BuyQuote } from '@0x/asset-buyer';
|
import { BuyQuote } from '@0x/asset-buyer';
|
||||||
import { AssetProxyId, ObjectMap } from '@0x/types';
|
import { AssetProxyId, ObjectMap } from '@0x/types';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { LOADING_ACCOUNT, LOCKED_ACCOUNT } from '../constants';
|
||||||
import { assetMetaDataMap } from '../data/asset_meta_data_map';
|
import { assetMetaDataMap } from '../data/asset_meta_data_map';
|
||||||
import {
|
import {
|
||||||
|
Account,
|
||||||
|
AccountReady,
|
||||||
|
AccountState,
|
||||||
AffiliateInfo,
|
AffiliateInfo,
|
||||||
Asset,
|
Asset,
|
||||||
AssetMetaData,
|
AssetMetaData,
|
||||||
@ -14,42 +18,73 @@ import {
|
|||||||
Network,
|
Network,
|
||||||
OrderProcessState,
|
OrderProcessState,
|
||||||
OrderState,
|
OrderState,
|
||||||
|
ProviderState,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
import { Action, ActionTypes } from './actions';
|
import { Action, ActionTypes } from './actions';
|
||||||
|
|
||||||
export interface State {
|
// State that is required and we have defaults for, before props are passed in
|
||||||
|
export interface DefaultState {
|
||||||
network: Network;
|
network: Network;
|
||||||
assetBuyer?: AssetBuyer;
|
|
||||||
assetMetaDataMap: ObjectMap<AssetMetaData>;
|
assetMetaDataMap: ObjectMap<AssetMetaData>;
|
||||||
selectedAsset?: Asset;
|
|
||||||
availableAssets?: Asset[];
|
|
||||||
selectedAssetAmount?: BigNumber;
|
|
||||||
buyOrderState: OrderState;
|
buyOrderState: OrderState;
|
||||||
ethUsdPrice?: BigNumber;
|
|
||||||
latestBuyQuote?: BuyQuote;
|
|
||||||
quoteRequestState: AsyncProcessState;
|
|
||||||
latestErrorMessage?: string;
|
|
||||||
latestErrorDisplayStatus: DisplayStatus;
|
latestErrorDisplayStatus: DisplayStatus;
|
||||||
affiliateInfo?: AffiliateInfo;
|
quoteRequestState: AsyncProcessState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const INITIAL_STATE: State = {
|
// State that is required but needs to be derived from the props
|
||||||
|
interface PropsDerivedState {
|
||||||
|
providerState: ProviderState;
|
||||||
|
}
|
||||||
|
|
||||||
|
// State that is optional
|
||||||
|
interface OptionalState {
|
||||||
|
selectedAsset: Asset;
|
||||||
|
availableAssets: Asset[];
|
||||||
|
selectedAssetAmount: BigNumber;
|
||||||
|
ethUsdPrice: BigNumber;
|
||||||
|
latestBuyQuote: BuyQuote;
|
||||||
|
latestErrorMessage: string;
|
||||||
|
affiliateInfo: AffiliateInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type State = DefaultState & PropsDerivedState & Partial<OptionalState>;
|
||||||
|
|
||||||
|
export const DEFAULT_STATE: DefaultState = {
|
||||||
network: Network.Mainnet,
|
network: Network.Mainnet,
|
||||||
selectedAssetAmount: undefined,
|
|
||||||
availableAssets: undefined,
|
|
||||||
assetMetaDataMap,
|
assetMetaDataMap,
|
||||||
buyOrderState: { processState: OrderProcessState.NONE },
|
buyOrderState: { processState: OrderProcessState.None },
|
||||||
ethUsdPrice: undefined,
|
|
||||||
latestBuyQuote: undefined,
|
|
||||||
latestErrorMessage: undefined,
|
|
||||||
latestErrorDisplayStatus: DisplayStatus.Hidden,
|
latestErrorDisplayStatus: DisplayStatus.Hidden,
|
||||||
quoteRequestState: AsyncProcessState.NONE,
|
quoteRequestState: AsyncProcessState.None,
|
||||||
affiliateInfo: undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const reducer = (state: State = INITIAL_STATE, action: Action): State => {
|
export const createReducer = (initialState: State) => {
|
||||||
|
const reducer = (state: State = initialState, action: Action): State => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case ActionTypes.SET_ACCOUNT_STATE_LOADING:
|
||||||
|
return reduceStateWithAccount(state, LOADING_ACCOUNT);
|
||||||
|
case ActionTypes.SET_ACCOUNT_STATE_LOCKED:
|
||||||
|
return reduceStateWithAccount(state, LOCKED_ACCOUNT);
|
||||||
|
case ActionTypes.SET_ACCOUNT_STATE_READY: {
|
||||||
|
const account: AccountReady = {
|
||||||
|
state: AccountState.Ready,
|
||||||
|
address: action.data,
|
||||||
|
};
|
||||||
|
return reduceStateWithAccount(state, account);
|
||||||
|
}
|
||||||
|
case ActionTypes.UPDATE_ACCOUNT_ETH_BALANCE: {
|
||||||
|
const { address, ethBalanceInWei } = action.data;
|
||||||
|
const currentAccount = state.providerState.account;
|
||||||
|
if (currentAccount.state !== AccountState.Ready || currentAccount.address !== address) {
|
||||||
|
return state;
|
||||||
|
} else {
|
||||||
|
const newAccount: AccountReady = {
|
||||||
|
...currentAccount,
|
||||||
|
ethBalanceInWei,
|
||||||
|
};
|
||||||
|
return reduceStateWithAccount(state, newAccount);
|
||||||
|
}
|
||||||
|
}
|
||||||
case ActionTypes.UPDATE_ETH_USD_PRICE:
|
case ActionTypes.UPDATE_ETH_USD_PRICE:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
@ -68,33 +103,32 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
latestBuyQuote: newBuyQuoteIfExists,
|
latestBuyQuote: newBuyQuoteIfExists,
|
||||||
quoteRequestState: AsyncProcessState.SUCCESS,
|
quoteRequestState: AsyncProcessState.Success,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING:
|
case ActionTypes.SET_QUOTE_REQUEST_STATE_PENDING:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
latestBuyQuote: undefined,
|
latestBuyQuote: undefined,
|
||||||
quoteRequestState: AsyncProcessState.PENDING,
|
quoteRequestState: AsyncProcessState.Pending,
|
||||||
};
|
};
|
||||||
case ActionTypes.SET_QUOTE_REQUEST_STATE_FAILURE:
|
case ActionTypes.SET_QUOTE_REQUEST_STATE_FAILURE:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
latestBuyQuote: undefined,
|
latestBuyQuote: undefined,
|
||||||
quoteRequestState: AsyncProcessState.FAILURE,
|
quoteRequestState: AsyncProcessState.Failure,
|
||||||
};
|
};
|
||||||
case ActionTypes.SET_BUY_ORDER_STATE_NONE:
|
case ActionTypes.SET_BUY_ORDER_STATE_NONE:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
buyOrderState: { processState: OrderProcessState.NONE },
|
buyOrderState: { processState: OrderProcessState.None },
|
||||||
};
|
};
|
||||||
case ActionTypes.SET_BUY_ORDER_STATE_VALIDATING:
|
case ActionTypes.SET_BUY_ORDER_STATE_VALIDATING:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
buyOrderState: { processState: OrderProcessState.VALIDATING },
|
buyOrderState: { processState: OrderProcessState.Validating },
|
||||||
};
|
};
|
||||||
case ActionTypes.SET_BUY_ORDER_STATE_PROCESSING:
|
case ActionTypes.SET_BUY_ORDER_STATE_PROCESSING:
|
||||||
const processingData = action.data;
|
const processingData = action.data;
|
||||||
@ -102,7 +136,7 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
buyOrderState: {
|
buyOrderState: {
|
||||||
processState: OrderProcessState.PROCESSING,
|
processState: OrderProcessState.Processing,
|
||||||
txHash: processingData.txHash,
|
txHash: processingData.txHash,
|
||||||
progress: {
|
progress: {
|
||||||
startTimeUnix,
|
startTimeUnix,
|
||||||
@ -118,7 +152,7 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
buyOrderState: {
|
buyOrderState: {
|
||||||
processState: OrderProcessState.FAILURE,
|
processState: OrderProcessState.Failure,
|
||||||
txHash,
|
txHash,
|
||||||
progress,
|
progress,
|
||||||
},
|
},
|
||||||
@ -134,7 +168,7 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
buyOrderState: {
|
buyOrderState: {
|
||||||
processState: OrderProcessState.SUCCESS,
|
processState: OrderProcessState.Success,
|
||||||
txHash,
|
txHash,
|
||||||
progress,
|
progress,
|
||||||
},
|
},
|
||||||
@ -168,8 +202,8 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
latestBuyQuote: undefined,
|
latestBuyQuote: undefined,
|
||||||
quoteRequestState: AsyncProcessState.NONE,
|
quoteRequestState: AsyncProcessState.None,
|
||||||
buyOrderState: { processState: OrderProcessState.NONE },
|
buyOrderState: { processState: OrderProcessState.None },
|
||||||
selectedAssetAmount: undefined,
|
selectedAssetAmount: undefined,
|
||||||
};
|
};
|
||||||
case ActionTypes.SET_AVAILABLE_ASSETS:
|
case ActionTypes.SET_AVAILABLE_ASSETS:
|
||||||
@ -181,6 +215,20 @@ export const reducer = (state: State = INITIAL_STATE, action: Action): State =>
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
return reducer;
|
||||||
|
};
|
||||||
|
|
||||||
|
const reduceStateWithAccount = (state: State, account: Account) => {
|
||||||
|
const oldProviderState = state.providerState;
|
||||||
|
const newProviderState: ProviderState = {
|
||||||
|
...oldProviderState,
|
||||||
|
account,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
providerState: newProviderState,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const doesBuyQuoteMatchState = (buyQuote: BuyQuote, state: State): boolean => {
|
const doesBuyQuoteMatchState = (buyQuote: BuyQuote, state: State): boolean => {
|
||||||
const selectedAssetIfExists = state.selectedAsset;
|
const selectedAssetIfExists = state.selectedAsset;
|
||||||
|
@ -2,12 +2,13 @@ import * as _ from 'lodash';
|
|||||||
import { createStore, Store as ReduxStore } from 'redux';
|
import { createStore, Store as ReduxStore } from 'redux';
|
||||||
import { devToolsEnhancer } from 'redux-devtools-extension/developmentOnly';
|
import { devToolsEnhancer } from 'redux-devtools-extension/developmentOnly';
|
||||||
|
|
||||||
import { reducer, State } from './reducer';
|
import { createReducer, State } from './reducer';
|
||||||
|
|
||||||
export type Store = ReduxStore<State>;
|
export type Store = ReduxStore<State>;
|
||||||
|
|
||||||
export const store = {
|
export const store = {
|
||||||
create: (state: State): Store => {
|
create: (initialState: State): Store => {
|
||||||
return createStore(reducer, state, devToolsEnhancer({}));
|
const reducer = createReducer(initialState);
|
||||||
|
return createStore(reducer, initialState, devToolsEnhancer({}));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
51
packages/instant/src/style/media.ts
Normal file
51
packages/instant/src/style/media.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { InterpolationValue } from 'styled-components';
|
||||||
|
|
||||||
|
import { css } from './theme';
|
||||||
|
|
||||||
|
export enum ScreenWidths {
|
||||||
|
Sm = 40,
|
||||||
|
Md = 52,
|
||||||
|
Lg = 64,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateMediaWrapper = (screenWidth: ScreenWidths) => (...args: any[]) => css`
|
||||||
|
@media (max-width: ${screenWidth}em) {
|
||||||
|
${css.apply(css, args)};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const media = {
|
||||||
|
small: generateMediaWrapper(ScreenWidths.Sm),
|
||||||
|
medium: generateMediaWrapper(ScreenWidths.Md),
|
||||||
|
large: generateMediaWrapper(ScreenWidths.Lg),
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ScreenSpecification<T> {
|
||||||
|
default: T;
|
||||||
|
sm?: T;
|
||||||
|
md?: T;
|
||||||
|
lg?: T;
|
||||||
|
}
|
||||||
|
export type OptionallyScreenSpecific<T> = T | ScreenSpecification<T>;
|
||||||
|
export type MediaChoice = OptionallyScreenSpecific<string>;
|
||||||
|
/**
|
||||||
|
* Given a css property name and a OptionallyScreenSpecific value,
|
||||||
|
* generates css properties with screen-specific viewport styling
|
||||||
|
*/
|
||||||
|
export function stylesForMedia<T extends string | number>(
|
||||||
|
cssPropertyName: string,
|
||||||
|
choice: OptionallyScreenSpecific<T>,
|
||||||
|
): InterpolationValue[] {
|
||||||
|
if (typeof choice === 'object') {
|
||||||
|
return css`
|
||||||
|
${cssPropertyName}: ${choice.default};
|
||||||
|
${choice.lg && media.large`${cssPropertyName}: ${choice.lg}`}
|
||||||
|
${choice.md && media.medium`${cssPropertyName}: ${choice.md}`}
|
||||||
|
${choice.sm && media.small`${cssPropertyName}: ${choice.sm}`}
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
return css`
|
||||||
|
${cssPropertyName}: ${choice};
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import * as styledComponents from 'styled-components';
|
import * as styledComponents from 'styled-components';
|
||||||
|
|
||||||
const { default: styled, css, keyframes, withTheme, ThemeProvider } = styledComponents;
|
const { default: styled, css, keyframes, withTheme, createGlobalStyle, ThemeProvider } = styledComponents;
|
||||||
|
|
||||||
export type Theme = { [key in ColorOption]: string };
|
export type Theme = { [key in ColorOption]: string };
|
||||||
|
|
||||||
@ -15,6 +15,8 @@ export enum ColorOption {
|
|||||||
white = 'white',
|
white = 'white',
|
||||||
lightOrange = 'lightOrange',
|
lightOrange = 'lightOrange',
|
||||||
darkOrange = 'darkOrange',
|
darkOrange = 'darkOrange',
|
||||||
|
green = 'green',
|
||||||
|
red = 'red',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const theme: Theme = {
|
export const theme: Theme = {
|
||||||
@ -28,9 +30,15 @@ export const theme: Theme = {
|
|||||||
white: 'white',
|
white: 'white',
|
||||||
lightOrange: '#F9F2ED',
|
lightOrange: '#F9F2ED',
|
||||||
darkOrange: '#F2994C',
|
darkOrange: '#F2994C',
|
||||||
|
green: '#3CB34F',
|
||||||
|
red: '#D00000',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const transparentWhite = 'rgba(255,255,255,0.3)';
|
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 { styled, css, keyframes, withTheme, ThemeProvider };
|
export const generateOverlayBlack = (opacity = 0.6) => {
|
||||||
|
return `rgba(0, 0, 0, ${opacity})`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { styled, css, keyframes, withTheme, createGlobalStyle, ThemeProvider };
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
export const zIndex = {
|
export const zIndex = {
|
||||||
errorPopup: 1,
|
errorPopBehind: 10,
|
||||||
mainContainer: 2,
|
mainContainer: 20,
|
||||||
panel: 3,
|
dropdownItems: 30,
|
||||||
|
panel: 40,
|
||||||
|
containerOverlay: 45,
|
||||||
|
errorPopup: 50,
|
||||||
|
overlayDefault: 100,
|
||||||
};
|
};
|
||||||
|
@ -1,20 +1,24 @@
|
|||||||
import { AssetProxyId, ObjectMap } from '@0x/types';
|
import { AssetBuyer, BigNumber } from '@0x/asset-buyer';
|
||||||
|
import { AssetProxyId, ObjectMap, SignedOrder } from '@0x/types';
|
||||||
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
|
import { Provider } from 'ethereum-types';
|
||||||
|
|
||||||
// Reusable
|
// Reusable
|
||||||
|
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||||
export type Maybe<T> = T | undefined;
|
export type Maybe<T> = T | undefined;
|
||||||
export enum AsyncProcessState {
|
export enum AsyncProcessState {
|
||||||
NONE = 'None',
|
None = 'NONE',
|
||||||
PENDING = 'Pending',
|
Pending = 'PENDING',
|
||||||
SUCCESS = 'Success',
|
Success = 'SUCCESS',
|
||||||
FAILURE = 'Failure',
|
Failure = 'FAILURE',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum OrderProcessState {
|
export enum OrderProcessState {
|
||||||
NONE = 'None',
|
None = 'NONE',
|
||||||
VALIDATING = 'Validating',
|
Validating = 'VALIDATING',
|
||||||
PROCESSING = 'Processing',
|
Processing = 'PROCESSING',
|
||||||
SUCCESS = 'Success',
|
Success = 'SUCCESS',
|
||||||
FAILURE = 'Failure',
|
Failure = 'FAILURE',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SimulatedProgress {
|
export interface SimulatedProgress {
|
||||||
@ -23,10 +27,10 @@ export interface SimulatedProgress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface OrderStatePreTx {
|
interface OrderStatePreTx {
|
||||||
processState: OrderProcessState.NONE | OrderProcessState.VALIDATING;
|
processState: OrderProcessState.None | OrderProcessState.Validating;
|
||||||
}
|
}
|
||||||
interface OrderStatePostTx {
|
interface OrderStatePostTx {
|
||||||
processState: OrderProcessState.PROCESSING | OrderProcessState.SUCCESS | OrderProcessState.FAILURE;
|
processState: OrderProcessState.Processing | OrderProcessState.Success | OrderProcessState.Failure;
|
||||||
txHash: string;
|
txHash: string;
|
||||||
progress: SimulatedProgress;
|
progress: SimulatedProgress;
|
||||||
}
|
}
|
||||||
@ -89,3 +93,35 @@ export interface AffiliateInfo {
|
|||||||
feeRecipient: string;
|
feeRecipient: string;
|
||||||
feePercentage: number;
|
feePercentage: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProviderState {
|
||||||
|
provider: Provider;
|
||||||
|
assetBuyer: AssetBuyer;
|
||||||
|
web3Wrapper: Web3Wrapper;
|
||||||
|
account: Account;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum AccountState {
|
||||||
|
None = 'NONE,',
|
||||||
|
Loading = 'LOADING',
|
||||||
|
Ready = 'READY',
|
||||||
|
Locked = 'LOCKED',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AccountReady {
|
||||||
|
state: AccountState.Ready;
|
||||||
|
address: string;
|
||||||
|
ethBalanceInWei?: BigNumber;
|
||||||
|
}
|
||||||
|
export interface AccountNotReady {
|
||||||
|
state: AccountState.None | AccountState.Loading | AccountState.Locked;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Account = AccountReady | AccountNotReady;
|
||||||
|
|
||||||
|
export type OrderSource = string | SignedOrder[];
|
||||||
|
|
||||||
|
export interface AddressAndEthBalanceInWei {
|
||||||
|
address: string;
|
||||||
|
ethBalanceInWei: BigNumber;
|
||||||
|
}
|
||||||
|
17
packages/instant/src/util/asset_buyer_factory.ts
Normal file
17
packages/instant/src/util/asset_buyer_factory.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { AssetBuyer, AssetBuyerOpts } from '@0x/asset-buyer';
|
||||||
|
import { Provider } from 'ethereum-types';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { Network, OrderSource } from '../types';
|
||||||
|
|
||||||
|
export const assetBuyerFactory = {
|
||||||
|
getAssetBuyer: (provider: Provider, orderSource: OrderSource, network: Network): AssetBuyer => {
|
||||||
|
const assetBuyerOptions: Partial<AssetBuyerOpts> = {
|
||||||
|
networkId: network,
|
||||||
|
};
|
||||||
|
const assetBuyer = _.isString(orderSource)
|
||||||
|
? AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl(provider, orderSource, assetBuyerOptions)
|
||||||
|
: AssetBuyer.getAssetBuyerForProvidedOrders(provider, orderSource, assetBuyerOptions);
|
||||||
|
return assetBuyer;
|
||||||
|
},
|
||||||
|
};
|
@ -1,13 +0,0 @@
|
|||||||
import { BuyQuote } from '@0x/asset-buyer';
|
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
|
|
||||||
export const balanceUtil = {
|
|
||||||
hasSufficientEth: async (takerAddress: string | undefined, buyQuote: BuyQuote, web3Wrapper: Web3Wrapper) => {
|
|
||||||
if (_.isUndefined(takerAddress)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const balanceWei = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
|
||||||
return balanceWei.gte(buyQuote.worstCaseQuoteInfo.totalEthAmount);
|
|
||||||
},
|
|
||||||
};
|
|
59
packages/instant/src/util/buy_quote_updater.ts
Normal file
59
packages/instant/src/util/buy_quote_updater.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
import { Dispatch } from 'redux';
|
||||||
|
import { oc } from 'ts-optchain';
|
||||||
|
|
||||||
|
import { Action, actions } from '../redux/actions';
|
||||||
|
import { AffiliateInfo, ERC20Asset } from '../types';
|
||||||
|
import { assetUtils } from '../util/asset';
|
||||||
|
import { errorFlasher } from '../util/error_flasher';
|
||||||
|
|
||||||
|
export const buyQuoteUpdater = {
|
||||||
|
updateBuyQuoteAsync: async (
|
||||||
|
assetBuyer: AssetBuyer,
|
||||||
|
dispatch: Dispatch<Action>,
|
||||||
|
asset: ERC20Asset,
|
||||||
|
assetAmount: BigNumber,
|
||||||
|
setPending = true,
|
||||||
|
affiliateInfo?: AffiliateInfo,
|
||||||
|
): Promise<void> => {
|
||||||
|
// get a new buy quote.
|
||||||
|
const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, asset.metaData.decimals);
|
||||||
|
if (setPending) {
|
||||||
|
// mark quote as pending
|
||||||
|
dispatch(actions.setQuoteRequestStatePending());
|
||||||
|
}
|
||||||
|
const feePercentage = oc(affiliateInfo).feePercentage();
|
||||||
|
let newBuyQuote: BuyQuote | undefined;
|
||||||
|
try {
|
||||||
|
newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue, { feePercentage });
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(actions.setQuoteRequestStateFailure());
|
||||||
|
let errorMessage;
|
||||||
|
if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
|
||||||
|
const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
|
||||||
|
errorMessage = `Not enough ${assetName} available`;
|
||||||
|
} else if (error.message === AssetBuyerError.InsufficientZrxLiquidity) {
|
||||||
|
errorMessage = 'Not enough ZRX available';
|
||||||
|
} else if (
|
||||||
|
error.message === AssetBuyerError.StandardRelayerApiError ||
|
||||||
|
error.message.startsWith(AssetBuyerError.AssetUnavailable)
|
||||||
|
) {
|
||||||
|
const assetName = assetUtils.bestNameForAsset(asset, 'This asset');
|
||||||
|
errorMessage = `${assetName} is currently unavailable`;
|
||||||
|
}
|
||||||
|
if (!_.isUndefined(errorMessage)) {
|
||||||
|
errorFlasher.flashNewErrorMessage(dispatch, errorMessage);
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// We have a successful new buy quote
|
||||||
|
errorFlasher.clearError(dispatch);
|
||||||
|
// invalidate the last buy quote.
|
||||||
|
dispatch(actions.updateLatestBuyQuote(newBuyQuote));
|
||||||
|
},
|
||||||
|
};
|
@ -21,4 +21,11 @@ export const etherscanUtil = {
|
|||||||
}
|
}
|
||||||
return `https://${prefix}etherscan.io/tx/${txHash}`;
|
return `https://${prefix}etherscan.io/tx/${txHash}`;
|
||||||
},
|
},
|
||||||
|
getEtherScanEthAddressIfExists: (ethAddress: string, networkId: number) => {
|
||||||
|
const prefix = etherscanPrefix(networkId);
|
||||||
|
if (_.isUndefined(prefix)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return `https://${prefix}etherscan.io/address/${ethAddress}`;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -50,4 +50,7 @@ export const format = {
|
|||||||
}
|
}
|
||||||
return `$${ethUnitAmount.mul(ethUsdPrice).toFixed(decimalPlaces)}`;
|
return `$${ethUnitAmount.mul(ethUsdPrice).toFixed(decimalPlaces)}`;
|
||||||
},
|
},
|
||||||
|
ethAddress: (address: string): string => {
|
||||||
|
return `0x${address.slice(2, 7)}…${address.slice(-5)}`;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
35
packages/instant/src/util/heartbeater.ts
Normal file
35
packages/instant/src/util/heartbeater.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { intervalUtils } from '@0x/utils';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
type HeartbeatableFunction = () => Promise<void>;
|
||||||
|
export class Heartbeater {
|
||||||
|
private _intervalId?: NodeJS.Timer;
|
||||||
|
private readonly _performImmediatelyOnStart: boolean;
|
||||||
|
private readonly _performFunction: HeartbeatableFunction;
|
||||||
|
|
||||||
|
public constructor(performingFunctionAsync: HeartbeatableFunction, performImmediatelyOnStart: boolean) {
|
||||||
|
this._performFunction = performingFunctionAsync;
|
||||||
|
this._performImmediatelyOnStart = performImmediatelyOnStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public start(intervalTimeMs: number): void {
|
||||||
|
if (!_.isUndefined(this._intervalId)) {
|
||||||
|
throw new Error('Heartbeat is running, please stop before restarting');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._performImmediatelyOnStart) {
|
||||||
|
// tslint:disable-next-line:no-floating-promises
|
||||||
|
this._performFunction();
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line:no-unbound-method
|
||||||
|
this._intervalId = intervalUtils.setAsyncExcludingInterval(this._performFunction, intervalTimeMs, _.noop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public stop(): void {
|
||||||
|
if (this._intervalId) {
|
||||||
|
intervalUtils.clearInterval(this._intervalId);
|
||||||
|
}
|
||||||
|
this._intervalId = undefined;
|
||||||
|
}
|
||||||
|
}
|
22
packages/instant/src/util/heartbeater_factory.ts
Normal file
22
packages/instant/src/util/heartbeater_factory.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { asyncData } from '../redux/async_data';
|
||||||
|
import { Store } from '../redux/store';
|
||||||
|
|
||||||
|
import { Heartbeater } from './heartbeater';
|
||||||
|
|
||||||
|
export interface HeartbeatFactoryOptions {
|
||||||
|
store: Store;
|
||||||
|
shouldPerformImmediatelyOnStart: boolean;
|
||||||
|
}
|
||||||
|
export const generateAccountHeartbeater = (options: HeartbeatFactoryOptions): Heartbeater => {
|
||||||
|
const { store, shouldPerformImmediatelyOnStart } = options;
|
||||||
|
return new Heartbeater(async () => {
|
||||||
|
await asyncData.fetchAccountInfoAndDispatchToStore({ store, shouldSetToLoading: false });
|
||||||
|
}, shouldPerformImmediatelyOnStart);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const generateBuyQuoteHeartbeater = (options: HeartbeatFactoryOptions): Heartbeater => {
|
||||||
|
const { store, shouldPerformImmediatelyOnStart } = options;
|
||||||
|
return new Heartbeater(async () => {
|
||||||
|
await asyncData.fetchCurrentBuyQuoteAndDispatchToStore({ store, shouldSetPending: false });
|
||||||
|
}, shouldPerformImmediatelyOnStart);
|
||||||
|
};
|
@ -1,16 +0,0 @@
|
|||||||
import { Provider } from 'ethereum-types';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
|
|
||||||
export const getInjectedProvider = (): Provider => {
|
|
||||||
const injectedProviderIfExists = (window as any).ethereum;
|
|
||||||
if (!_.isUndefined(injectedProviderIfExists)) {
|
|
||||||
// TODO: call enable here when implementing wallet connection flow
|
|
||||||
return injectedProviderIfExists;
|
|
||||||
}
|
|
||||||
const injectedWeb3IfExists = (window as any).web3;
|
|
||||||
if (!_.isUndefined(injectedWeb3IfExists.currentProvider)) {
|
|
||||||
return injectedWeb3IfExists.currentProvider;
|
|
||||||
} else {
|
|
||||||
throw new Error(`No injected web3 found`);
|
|
||||||
}
|
|
||||||
};
|
|
34
packages/instant/src/util/provider_factory.ts
Normal file
34
packages/instant/src/util/provider_factory.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { EmptyWalletSubprovider, RPCSubprovider, Web3ProviderEngine } from '@0x/subproviders';
|
||||||
|
import { Provider } from 'ethereum-types';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { BLOCK_POLLING_INTERVAL_MS, ETHEREUM_NODE_URL_BY_NETWORK } from '../constants';
|
||||||
|
import { Maybe, Network } from '../types';
|
||||||
|
|
||||||
|
export const providerFactory = {
|
||||||
|
getInjectedProviderIfExists: (): Maybe<Provider> => {
|
||||||
|
const injectedProviderIfExists = (window as any).ethereum;
|
||||||
|
if (!_.isUndefined(injectedProviderIfExists)) {
|
||||||
|
return injectedProviderIfExists;
|
||||||
|
}
|
||||||
|
const injectedWeb3IfExists = (window as any).web3;
|
||||||
|
if (!_.isUndefined(injectedWeb3IfExists) && !_.isUndefined(injectedWeb3IfExists.currentProvider)) {
|
||||||
|
return injectedWeb3IfExists.currentProvider;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
getFallbackNoSigningProvider: (network: Network): Provider => {
|
||||||
|
const providerEngine = new Web3ProviderEngine({
|
||||||
|
pollingInterval: BLOCK_POLLING_INTERVAL_MS,
|
||||||
|
});
|
||||||
|
// Intercept calls to `eth_accounts` and always return empty
|
||||||
|
providerEngine.addProvider(new EmptyWalletSubprovider());
|
||||||
|
// Construct an RPC subprovider, all data based requests will be sent via the RPCSubprovider
|
||||||
|
// TODO(bmillman): make this more resilient to infura failures
|
||||||
|
const rpcUrl = ETHEREUM_NODE_URL_BY_NETWORK[network];
|
||||||
|
providerEngine.addProvider(new RPCSubprovider(rpcUrl));
|
||||||
|
// // Start the Provider Engine
|
||||||
|
providerEngine.start();
|
||||||
|
return providerEngine;
|
||||||
|
},
|
||||||
|
};
|
63
packages/instant/src/util/provider_state_factory.ts
Normal file
63
packages/instant/src/util/provider_state_factory.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
|
import { Provider } from 'ethereum-types';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { LOADING_ACCOUNT, NO_ACCOUNT } from '../constants';
|
||||||
|
import { Maybe, Network, OrderSource, ProviderState } from '../types';
|
||||||
|
|
||||||
|
import { assetBuyerFactory } from './asset_buyer_factory';
|
||||||
|
import { providerFactory } from './provider_factory';
|
||||||
|
|
||||||
|
export const providerStateFactory = {
|
||||||
|
getInitialProviderState: (orderSource: OrderSource, network: Network, provider?: Provider): ProviderState => {
|
||||||
|
if (!_.isUndefined(provider)) {
|
||||||
|
return providerStateFactory.getInitialProviderStateFromProvider(orderSource, network, provider);
|
||||||
|
}
|
||||||
|
const providerStateFromWindowIfExits = providerStateFactory.getInitialProviderStateFromWindowIfExists(
|
||||||
|
orderSource,
|
||||||
|
network,
|
||||||
|
);
|
||||||
|
if (providerStateFromWindowIfExits) {
|
||||||
|
return providerStateFromWindowIfExits;
|
||||||
|
} else {
|
||||||
|
return providerStateFactory.getInitialProviderStateFallback(orderSource, network);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getInitialProviderStateFromProvider: (
|
||||||
|
orderSource: OrderSource,
|
||||||
|
network: Network,
|
||||||
|
provider: Provider,
|
||||||
|
): ProviderState => {
|
||||||
|
const providerState: ProviderState = {
|
||||||
|
provider,
|
||||||
|
web3Wrapper: new Web3Wrapper(provider),
|
||||||
|
assetBuyer: assetBuyerFactory.getAssetBuyer(provider, orderSource, network),
|
||||||
|
account: LOADING_ACCOUNT,
|
||||||
|
};
|
||||||
|
return providerState;
|
||||||
|
},
|
||||||
|
getInitialProviderStateFromWindowIfExists: (orderSource: OrderSource, network: Network): Maybe<ProviderState> => {
|
||||||
|
const injectedProviderIfExists = providerFactory.getInjectedProviderIfExists();
|
||||||
|
if (!_.isUndefined(injectedProviderIfExists)) {
|
||||||
|
const providerState: ProviderState = {
|
||||||
|
provider: injectedProviderIfExists,
|
||||||
|
web3Wrapper: new Web3Wrapper(injectedProviderIfExists),
|
||||||
|
assetBuyer: assetBuyerFactory.getAssetBuyer(injectedProviderIfExists, orderSource, network),
|
||||||
|
account: LOADING_ACCOUNT,
|
||||||
|
};
|
||||||
|
return providerState;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getInitialProviderStateFallback: (orderSource: OrderSource, network: Network): ProviderState => {
|
||||||
|
const provider = providerFactory.getFallbackNoSigningProvider(network);
|
||||||
|
const providerState: ProviderState = {
|
||||||
|
provider,
|
||||||
|
web3Wrapper: new Web3Wrapper(provider),
|
||||||
|
assetBuyer: assetBuyerFactory.getAssetBuyer(provider, orderSource, network),
|
||||||
|
account: NO_ACCOUNT,
|
||||||
|
};
|
||||||
|
return providerState;
|
||||||
|
},
|
||||||
|
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user